Commit 977b06d0 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'spi/topic/pxa2xx', 'spi/topic/s3c64xx',...

Merge remote-tracking branches 'spi/topic/pxa2xx', 'spi/topic/s3c64xx', 'spi/topic/sh-msiof', 'spi/topic/sirf' and 'spi/topic/sun6i' into spi-next
...@@ -36,7 +36,21 @@ Required properties: ...@@ -36,7 +36,21 @@ Required properties:
Optional properties: Optional properties:
- clocks : Must contain a reference to the functional clock. - clocks : Must contain a reference to the functional clock.
- num-cs : Total number of chip-selects (default is 1) - num-cs : Total number of chip selects (default is 1).
Up to 3 native chip selects are supported:
0: MSIOF_SYNC
1: MSIOF_SS1
2: MSIOF_SS2
Hardware limitations related to chip selects:
- Native chip selects are always deasserted in
between transfers that are part of the same
message. Use cs-gpios to work around this.
- All slaves using native chip selects must use the
same spi-cs-high configuration. Use cs-gpios to
work around this.
- When using GPIO chip selects, at least one native
chip select must be left unused, as it will be
driven anyway.
- dmas : Must contain a list of two references to DMA - dmas : Must contain a list of two references to DMA
specifiers, one for transmission, and one for specifiers, one for transmission, and one for
reception. reception.
......
...@@ -1237,7 +1237,7 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, ...@@ -1237,7 +1237,7 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
* different chip_info, release previously requested GPIO * different chip_info, release previously requested GPIO
*/ */
if (chip->gpiod_cs) { if (chip->gpiod_cs) {
gpio_free(desc_to_gpio(chip->gpiod_cs)); gpiod_put(chip->gpiod_cs);
chip->gpiod_cs = NULL; chip->gpiod_cs = NULL;
} }
...@@ -1417,7 +1417,7 @@ static void cleanup(struct spi_device *spi) ...@@ -1417,7 +1417,7 @@ static void cleanup(struct spi_device *spi)
if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods &&
chip->gpiod_cs) chip->gpiod_cs)
gpio_free(desc_to_gpio(chip->gpiod_cs)); gpiod_put(chip->gpiod_cs);
kfree(chip); kfree(chip);
} }
......
/* // SPDX-License-Identifier: GPL-2.0+
* Copyright (C) 2009 Samsung Electronics Ltd. //
* Jaswinder Singh <jassi.brar@samsung.com> // Copyright (c) 2009 Samsung Electronics Co., Ltd.
* // Jaswinder Singh <jassi.brar@samsung.com>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -55,9 +56,14 @@ struct sh_msiof_spi_priv { ...@@ -55,9 +56,14 @@ struct sh_msiof_spi_priv {
void *rx_dma_page; void *rx_dma_page;
dma_addr_t tx_dma_addr; dma_addr_t tx_dma_addr;
dma_addr_t rx_dma_addr; dma_addr_t rx_dma_addr;
unsigned short unused_ss;
bool native_cs_inited;
bool native_cs_high;
bool slave_aborted; bool slave_aborted;
}; };
#define MAX_SS 3 /* Maximum number of native chip selects */
#define TMDR1 0x00 /* Transmit Mode Register 1 */ #define TMDR1 0x00 /* Transmit Mode Register 1 */
#define TMDR2 0x04 /* Transmit Mode Register 2 */ #define TMDR2 0x04 /* Transmit Mode Register 2 */
#define TMDR3 0x08 /* Transmit Mode Register 3 */ #define TMDR3 0x08 /* Transmit Mode Register 3 */
...@@ -91,6 +97,8 @@ struct sh_msiof_spi_priv { ...@@ -91,6 +97,8 @@ struct sh_msiof_spi_priv {
#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */ #define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */
/* TMDR1 */ /* TMDR1 */
#define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */ #define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */
#define TMDR1_SYNCCH_MASK 0xc000000 /* Synchronization Signal Channel Select */
#define TMDR1_SYNCCH_SHIFT 26 /* 0=MSIOF_SYNC, 1=MSIOF_SS1, 2=MSIOF_SS2 */
/* TMDR2 and RMDR2 */ /* TMDR2 and RMDR2 */
#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */ #define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */
...@@ -324,7 +332,7 @@ static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p) ...@@ -324,7 +332,7 @@ static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p)
return val; return val;
} }
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, u32 ss,
u32 cpol, u32 cpha, u32 cpol, u32 cpha,
u32 tx_hi_z, u32 lsb_first, u32 cs_high) u32 tx_hi_z, u32 lsb_first, u32 cs_high)
{ {
...@@ -342,10 +350,13 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, ...@@ -342,10 +350,13 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
tmp |= lsb_first << MDR1_BITLSB_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT;
tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
if (spi_controller_is_slave(p->master)) if (spi_controller_is_slave(p->master)) {
sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON); sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON);
else } else {
sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); sh_msiof_write(p, TMDR1,
tmp | MDR1_TRMD | TMDR1_PCON |
(ss < MAX_SS ? ss : 0) << TMDR1_SYNCCH_SHIFT);
}
if (p->master->flags & SPI_MASTER_MUST_TX) { if (p->master->flags & SPI_MASTER_MUST_TX) {
/* These bits are reserved if RX needs TX */ /* These bits are reserved if RX needs TX */
tmp &= ~0x0000ffff; tmp &= ~0x0000ffff;
...@@ -528,8 +539,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi) ...@@ -528,8 +539,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
{ {
struct device_node *np = spi->master->dev.of_node; struct device_node *np = spi->master->dev.of_node;
struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
u32 clr, set, tmp;
pm_runtime_get_sync(&p->pdev->dev);
if (!np) { if (!np) {
/* /*
...@@ -539,19 +549,31 @@ static int sh_msiof_spi_setup(struct spi_device *spi) ...@@ -539,19 +549,31 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
spi->cs_gpio = (uintptr_t)spi->controller_data; spi->cs_gpio = (uintptr_t)spi->controller_data;
} }
/* Configure pins before deasserting CS */ if (gpio_is_valid(spi->cs_gpio)) {
sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
!!(spi->mode & SPI_CPHA), return 0;
!!(spi->mode & SPI_3WIRE), }
!!(spi->mode & SPI_LSB_FIRST),
!!(spi->mode & SPI_CS_HIGH));
if (spi->cs_gpio >= 0) if (spi_controller_is_slave(p->master))
gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); return 0;
if (p->native_cs_inited &&
(p->native_cs_high == !!(spi->mode & SPI_CS_HIGH)))
return 0;
/* Configure native chip select mode/polarity early */
clr = MDR1_SYNCMD_MASK;
set = MDR1_TRMD | TMDR1_PCON | MDR1_SYNCMD_SPI;
if (spi->mode & SPI_CS_HIGH)
clr |= BIT(MDR1_SYNCAC_SHIFT);
else
set |= BIT(MDR1_SYNCAC_SHIFT);
pm_runtime_get_sync(&p->pdev->dev);
tmp = sh_msiof_read(p, TMDR1) & ~clr;
sh_msiof_write(p, TMDR1, tmp | set);
pm_runtime_put(&p->pdev->dev); pm_runtime_put(&p->pdev->dev);
p->native_cs_high = spi->mode & SPI_CS_HIGH;
p->native_cs_inited = true;
return 0; return 0;
} }
...@@ -560,13 +582,20 @@ static int sh_msiof_prepare_message(struct spi_master *master, ...@@ -560,13 +582,20 @@ static int sh_msiof_prepare_message(struct spi_master *master,
{ {
struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
const struct spi_device *spi = msg->spi; const struct spi_device *spi = msg->spi;
u32 ss, cs_high;
/* Configure pins before asserting CS */ /* Configure pins before asserting CS */
sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), if (gpio_is_valid(spi->cs_gpio)) {
ss = p->unused_ss;
cs_high = p->native_cs_high;
} else {
ss = spi->chip_select;
cs_high = !!(spi->mode & SPI_CS_HIGH);
}
sh_msiof_spi_set_pin_regs(p, ss, !!(spi->mode & SPI_CPOL),
!!(spi->mode & SPI_CPHA), !!(spi->mode & SPI_CPHA),
!!(spi->mode & SPI_3WIRE), !!(spi->mode & SPI_3WIRE),
!!(spi->mode & SPI_LSB_FIRST), !!(spi->mode & SPI_LSB_FIRST), cs_high);
!!(spi->mode & SPI_CS_HIGH));
return 0; return 0;
} }
...@@ -922,9 +951,8 @@ static int sh_msiof_transfer_one(struct spi_master *master, ...@@ -922,9 +951,8 @@ static int sh_msiof_transfer_one(struct spi_master *master,
ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l); ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l);
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
pr_warn_once("%s %s: DMA not available, falling back to PIO\n", dev_warn_once(&p->pdev->dev,
dev_driver_string(&p->pdev->dev), "DMA not available, falling back to PIO\n");
dev_name(&p->pdev->dev));
break; break;
} }
if (ret) if (ret)
...@@ -1081,6 +1109,45 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) ...@@ -1081,6 +1109,45 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
} }
#endif #endif
static int sh_msiof_get_cs_gpios(struct sh_msiof_spi_priv *p)
{
struct device *dev = &p->pdev->dev;
unsigned int used_ss_mask = 0;
unsigned int cs_gpios = 0;
unsigned int num_cs, i;
int ret;
ret = gpiod_count(dev, "cs");
if (ret <= 0)
return 0;
num_cs = max_t(unsigned int, ret, p->master->num_chipselect);
for (i = 0; i < num_cs; i++) {
struct gpio_desc *gpiod;
gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS);
if (!IS_ERR(gpiod)) {
cs_gpios++;
continue;
}
if (PTR_ERR(gpiod) != -ENOENT)
return PTR_ERR(gpiod);
if (i >= MAX_SS) {
dev_err(dev, "Invalid native chip select %d\n", i);
return -EINVAL;
}
used_ss_mask |= BIT(i);
}
p->unused_ss = ffz(used_ss_mask);
if (cs_gpios && p->unused_ss >= MAX_SS) {
dev_err(dev, "No unused native chip select available\n");
return -EINVAL;
}
return 0;
}
static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev, static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev,
enum dma_transfer_direction dir, unsigned int id, dma_addr_t port_addr) enum dma_transfer_direction dir, unsigned int id, dma_addr_t port_addr)
{ {
...@@ -1294,13 +1361,18 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) ...@@ -1294,13 +1361,18 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
if (p->info->rx_fifo_override) if (p->info->rx_fifo_override)
p->rx_fifo_size = p->info->rx_fifo_override; p->rx_fifo_size = p->info->rx_fifo_override;
/* Setup GPIO chip selects */
master->num_chipselect = p->info->num_chipselect;
ret = sh_msiof_get_cs_gpios(p);
if (ret)
goto err1;
/* init master code */ /* init master code */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
master->flags = chipdata->master_flags; master->flags = chipdata->master_flags;
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = p->info->num_chipselect;
master->setup = sh_msiof_spi_setup; master->setup = sh_msiof_spi_setup;
master->prepare_message = sh_msiof_prepare_message; master->prepare_message = sh_msiof_prepare_message;
master->slave_abort = sh_msiof_slave_abort; master->slave_abort = sh_msiof_slave_abort;
......
...@@ -1072,7 +1072,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) ...@@ -1072,7 +1072,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct sirfsoc_spi *sspi; struct sirfsoc_spi *sspi;
struct spi_master *master; struct spi_master *master;
struct resource *mem_res; struct resource *mem_res;
struct sirf_spi_comp_data *spi_comp_data; const struct sirf_spi_comp_data *spi_comp_data;
int irq; int irq;
int ret; int ret;
const struct of_device_id *match; const struct of_device_id *match;
...@@ -1092,7 +1092,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) ...@@ -1092,7 +1092,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master); sspi = spi_master_get_devdata(master);
sspi->fifo_full_offset = ilog2(sspi->fifo_size); sspi->fifo_full_offset = ilog2(sspi->fifo_size);
spi_comp_data = (struct sirf_spi_comp_data *)match->data; spi_comp_data = match->data;
sspi->regs = spi_comp_data->regs; sspi->regs = spi_comp_data->regs;
sspi->type = spi_comp_data->type; sspi->type = spi_comp_data->type;
sspi->fifo_level_chk_mask = (sspi->fifo_size / 4) - 1; sspi->fifo_level_chk_mask = (sspi->fifo_size / 4) - 1;
......
...@@ -541,7 +541,7 @@ static int sun6i_spi_probe(struct platform_device *pdev) ...@@ -541,7 +541,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
static int sun6i_spi_remove(struct platform_device *pdev) static int sun6i_spi_remove(struct platform_device *pdev)
{ {
pm_runtime_disable(&pdev->dev); pm_runtime_force_suspend(&pdev->dev);
return 0; return 0;
} }
......
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Copyright (C) 2009 Samsung Electronics Ltd. * Copyright (C) 2009 Samsung Electronics Ltd.
* Jaswinder Singh <jassi.brar@samsung.com> * Jaswinder Singh <jassi.brar@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/ */
#ifndef __SPI_S3C64XX_H #ifndef __SPI_S3C64XX_H
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment