|
@@ -19,6 +19,7 @@
|
|
|
#include <linux/dmaengine.h>
|
|
|
#include <linux/err.h>
|
|
|
#include <linux/gpio.h>
|
|
|
+#include <linux/gpio/consumer.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/kernel.h>
|
|
@@ -55,9 +56,14 @@ struct sh_msiof_spi_priv {
|
|
|
void *rx_dma_page;
|
|
|
dma_addr_t tx_dma_addr;
|
|
|
dma_addr_t rx_dma_addr;
|
|
|
+ unsigned short unused_ss;
|
|
|
+ bool native_cs_inited;
|
|
|
+ bool native_cs_high;
|
|
|
bool slave_aborted;
|
|
|
};
|
|
|
|
|
|
+#define MAX_SS 3 /* Maximum number of native chip selects */
|
|
|
+
|
|
|
#define TMDR1 0x00 /* Transmit Mode Register 1 */
|
|
|
#define TMDR2 0x04 /* Transmit Mode Register 2 */
|
|
|
#define TMDR3 0x08 /* Transmit Mode Register 3 */
|
|
@@ -91,6 +97,8 @@ struct sh_msiof_spi_priv {
|
|
|
#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */
|
|
|
/* TMDR1 */
|
|
|
#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 */
|
|
|
#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)
|
|
|
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 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,
|
|
|
tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
|
|
|
tmp |= lsb_first << MDR1_BITLSB_SHIFT;
|
|
|
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);
|
|
|
- else
|
|
|
- sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
|
|
|
+ } else {
|
|
|
+ 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) {
|
|
|
/* These bits are reserved if RX needs TX */
|
|
|
tmp &= ~0x0000ffff;
|
|
@@ -528,8 +539,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
|
|
|
{
|
|
|
struct device_node *np = spi->master->dev.of_node;
|
|
|
struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
|
|
|
-
|
|
|
- pm_runtime_get_sync(&p->pdev->dev);
|
|
|
+ u32 clr, set, tmp;
|
|
|
|
|
|
if (!np) {
|
|
|
/*
|
|
@@ -539,19 +549,31 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
|
|
|
spi->cs_gpio = (uintptr_t)spi->controller_data;
|
|
|
}
|
|
|
|
|
|
- /* Configure pins before deasserting CS */
|
|
|
- sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
|
|
|
- !!(spi->mode & SPI_CPHA),
|
|
|
- !!(spi->mode & SPI_3WIRE),
|
|
|
- !!(spi->mode & SPI_LSB_FIRST),
|
|
|
- !!(spi->mode & SPI_CS_HIGH));
|
|
|
+ if (gpio_is_valid(spi->cs_gpio)) {
|
|
|
+ gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- if (spi->cs_gpio >= 0)
|
|
|
- gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
|
|
|
+ if (spi_controller_is_slave(p->master))
|
|
|
+ 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);
|
|
|
-
|
|
|
+ p->native_cs_high = spi->mode & SPI_CS_HIGH;
|
|
|
+ p->native_cs_inited = true;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -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);
|
|
|
const struct spi_device *spi = msg->spi;
|
|
|
+ u32 ss, cs_high;
|
|
|
|
|
|
/* 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_3WIRE),
|
|
|
- !!(spi->mode & SPI_LSB_FIRST),
|
|
|
- !!(spi->mode & SPI_CS_HIGH));
|
|
|
+ !!(spi->mode & SPI_LSB_FIRST), cs_high);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -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);
|
|
|
if (ret == -EAGAIN) {
|
|
|
- pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
|
|
|
- dev_driver_string(&p->pdev->dev),
|
|
|
- dev_name(&p->pdev->dev));
|
|
|
+ dev_warn_once(&p->pdev->dev,
|
|
|
+ "DMA not available, falling back to PIO\n");
|
|
|
break;
|
|
|
}
|
|
|
if (ret)
|
|
@@ -1081,6 +1109,45 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
|
|
|
}
|
|
|
#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,
|
|
|
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)
|
|
|
if (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 */
|
|
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
|
|
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
|
|
|
master->flags = chipdata->master_flags;
|
|
|
master->bus_num = pdev->id;
|
|
|
master->dev.of_node = pdev->dev.of_node;
|
|
|
- master->num_chipselect = p->info->num_chipselect;
|
|
|
master->setup = sh_msiof_spi_setup;
|
|
|
master->prepare_message = sh_msiof_prepare_message;
|
|
|
master->slave_abort = sh_msiof_slave_abort;
|