Loading Documentation/devicetree/bindings/spi/sh-msiof.txt +15 −1 Original line number Diff line number Diff line Loading @@ -36,7 +36,21 @@ Required properties: Optional properties: - 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 specifiers, one for transmission, and one for reception. Loading drivers/spi/spi-pxa2xx.c +2 −2 Original line number Diff line number Diff line Loading @@ -1237,7 +1237,7 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, * different chip_info, release previously requested GPIO */ if (chip->gpiod_cs) { gpio_free(desc_to_gpio(chip->gpiod_cs)); gpiod_put(chip->gpiod_cs); chip->gpiod_cs = NULL; } Loading Loading @@ -1417,7 +1417,7 @@ static void cleanup(struct spi_device *spi) if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && chip->gpiod_cs) gpio_free(desc_to_gpio(chip->gpiod_cs)); gpiod_put(chip->gpiod_cs); kfree(chip); } Loading drivers/spi/spi-s3c64xx.c +4 −14 Original line number Diff line number Diff line /* * Copyright (C) 2009 Samsung Electronics 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. */ // SPDX-License-Identifier: GPL-2.0+ // // Copyright (c) 2009 Samsung Electronics Co., Ltd. // Jaswinder Singh <jassi.brar@samsung.com> #include <linux/init.h> #include <linux/module.h> Loading drivers/spi/spi-sh-msiof.c +94 −22 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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 */ Loading Loading @@ -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) */ Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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) { /* Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -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) Loading Loading @@ -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) { Loading Loading @@ -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; Loading drivers/spi/spi-sirf.c +2 −2 Original line number Diff line number Diff line Loading @@ -1072,7 +1072,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) struct sirfsoc_spi *sspi; struct spi_master *master; struct resource *mem_res; struct sirf_spi_comp_data *spi_comp_data; const struct sirf_spi_comp_data *spi_comp_data; int irq; int ret; const struct of_device_id *match; Loading @@ -1092,7 +1092,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); sspi = spi_master_get_devdata(master); 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->type = spi_comp_data->type; sspi->fifo_level_chk_mask = (sspi->fifo_size / 4) - 1; Loading Loading
Documentation/devicetree/bindings/spi/sh-msiof.txt +15 −1 Original line number Diff line number Diff line Loading @@ -36,7 +36,21 @@ Required properties: Optional properties: - 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 specifiers, one for transmission, and one for reception. Loading
drivers/spi/spi-pxa2xx.c +2 −2 Original line number Diff line number Diff line Loading @@ -1237,7 +1237,7 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, * different chip_info, release previously requested GPIO */ if (chip->gpiod_cs) { gpio_free(desc_to_gpio(chip->gpiod_cs)); gpiod_put(chip->gpiod_cs); chip->gpiod_cs = NULL; } Loading Loading @@ -1417,7 +1417,7 @@ static void cleanup(struct spi_device *spi) if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && chip->gpiod_cs) gpio_free(desc_to_gpio(chip->gpiod_cs)); gpiod_put(chip->gpiod_cs); kfree(chip); } Loading
drivers/spi/spi-s3c64xx.c +4 −14 Original line number Diff line number Diff line /* * Copyright (C) 2009 Samsung Electronics 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. */ // SPDX-License-Identifier: GPL-2.0+ // // Copyright (c) 2009 Samsung Electronics Co., Ltd. // Jaswinder Singh <jassi.brar@samsung.com> #include <linux/init.h> #include <linux/module.h> Loading
drivers/spi/spi-sh-msiof.c +94 −22 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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 */ Loading Loading @@ -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) */ Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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) { /* Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -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) Loading Loading @@ -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) { Loading Loading @@ -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; Loading
drivers/spi/spi-sirf.c +2 −2 Original line number Diff line number Diff line Loading @@ -1072,7 +1072,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) struct sirfsoc_spi *sspi; struct spi_master *master; struct resource *mem_res; struct sirf_spi_comp_data *spi_comp_data; const struct sirf_spi_comp_data *spi_comp_data; int irq; int ret; const struct of_device_id *match; Loading @@ -1092,7 +1092,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); sspi = spi_master_get_devdata(master); 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->type = spi_comp_data->type; sspi->fifo_level_chk_mask = (sspi->fifo_size / 4) - 1; Loading