diff options
author | Girish K S <girishks2000@gmail.com> | 2013-06-21 01:56:12 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-06-25 06:15:33 -0400 |
commit | 3146beec21b64f4551fcf0ac148381d54dc41b1b (patch) | |
tree | b8fd28466973228956af4931df22bbd013c8aeee /drivers/spi | |
parent | 796170733e50405e3039eacdf5cfb2f08f3eb9ba (diff) |
spi: s3c64xx: Added provision for dedicated cs pin
The existing driver supports gpio based /cs signal.
For controller's that have one device per controller,
the slave device's /cs signal might be internally controlled
by the chip select bit of slave select register. They are not
externally asserted/deasserted using gpio pin.
This patch adds support for controllers with dedicated /cs pin.
if "cs-gpio" property doesnt exist in a spi dts node, the controller
would treat the /cs pin as dedicated.
Signed-off-by: Girish K S <ks.giri@samsung.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-s3c64xx.c | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 70b221355400..067f442de2d4 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c | |||
@@ -208,6 +208,7 @@ struct s3c64xx_spi_driver_data { | |||
208 | struct s3c64xx_spi_port_config *port_conf; | 208 | struct s3c64xx_spi_port_config *port_conf; |
209 | unsigned int port_id; | 209 | unsigned int port_id; |
210 | unsigned long gpios[4]; | 210 | unsigned long gpios[4]; |
211 | bool cs_gpio; | ||
211 | }; | 212 | }; |
212 | 213 | ||
213 | static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) | 214 | static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) |
@@ -570,14 +571,16 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, | |||
570 | if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ | 571 | if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ |
571 | /* Deselect the last toggled device */ | 572 | /* Deselect the last toggled device */ |
572 | cs = sdd->tgl_spi->controller_data; | 573 | cs = sdd->tgl_spi->controller_data; |
573 | gpio_set_value(cs->line, | 574 | if (sdd->cs_gpio) |
574 | spi->mode & SPI_CS_HIGH ? 0 : 1); | 575 | gpio_set_value(cs->line, |
576 | spi->mode & SPI_CS_HIGH ? 0 : 1); | ||
575 | } | 577 | } |
576 | sdd->tgl_spi = NULL; | 578 | sdd->tgl_spi = NULL; |
577 | } | 579 | } |
578 | 580 | ||
579 | cs = spi->controller_data; | 581 | cs = spi->controller_data; |
580 | gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); | 582 | if (sdd->cs_gpio) |
583 | gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); | ||
581 | 584 | ||
582 | /* Start the signals */ | 585 | /* Start the signals */ |
583 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | 586 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
@@ -710,7 +713,8 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, | |||
710 | if (sdd->tgl_spi == spi) | 713 | if (sdd->tgl_spi == spi) |
711 | sdd->tgl_spi = NULL; | 714 | sdd->tgl_spi = NULL; |
712 | 715 | ||
713 | gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1); | 716 | if (sdd->cs_gpio) |
717 | gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1); | ||
714 | 718 | ||
715 | /* Quiese the signals */ | 719 | /* Quiese the signals */ |
716 | writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | 720 | writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
@@ -998,8 +1002,10 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( | |||
998 | { | 1002 | { |
999 | struct s3c64xx_spi_csinfo *cs; | 1003 | struct s3c64xx_spi_csinfo *cs; |
1000 | struct device_node *slave_np, *data_np = NULL; | 1004 | struct device_node *slave_np, *data_np = NULL; |
1005 | struct s3c64xx_spi_driver_data *sdd; | ||
1001 | u32 fb_delay = 0; | 1006 | u32 fb_delay = 0; |
1002 | 1007 | ||
1008 | sdd = spi_master_get_devdata(spi->master); | ||
1003 | slave_np = spi->dev.of_node; | 1009 | slave_np = spi->dev.of_node; |
1004 | if (!slave_np) { | 1010 | if (!slave_np) { |
1005 | dev_err(&spi->dev, "device node not found\n"); | 1011 | dev_err(&spi->dev, "device node not found\n"); |
@@ -1019,7 +1025,10 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( | |||
1019 | return ERR_PTR(-ENOMEM); | 1025 | return ERR_PTR(-ENOMEM); |
1020 | } | 1026 | } |
1021 | 1027 | ||
1022 | cs->line = of_get_named_gpio(data_np, "cs-gpio", 0); | 1028 | /* The CS line is asserted/deasserted by the gpio pin */ |
1029 | if (sdd->cs_gpio) | ||
1030 | cs->line = of_get_named_gpio(data_np, "cs-gpio", 0); | ||
1031 | |||
1023 | if (!gpio_is_valid(cs->line)) { | 1032 | if (!gpio_is_valid(cs->line)) { |
1024 | dev_err(&spi->dev, "chip select gpio is not specified or invalid\n"); | 1033 | dev_err(&spi->dev, "chip select gpio is not specified or invalid\n"); |
1025 | kfree(cs); | 1034 | kfree(cs); |
@@ -1059,7 +1068,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
1059 | return -ENODEV; | 1068 | return -ENODEV; |
1060 | } | 1069 | } |
1061 | 1070 | ||
1062 | if (!spi_get_ctldata(spi)) { | 1071 | /* Request gpio only if cs line is asserted by gpio pins */ |
1072 | if (sdd->cs_gpio) { | ||
1063 | err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH, | 1073 | err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH, |
1064 | dev_name(&spi->dev)); | 1074 | dev_name(&spi->dev)); |
1065 | if (err) { | 1075 | if (err) { |
@@ -1068,9 +1078,11 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
1068 | cs->line, err); | 1078 | cs->line, err); |
1069 | goto err_gpio_req; | 1079 | goto err_gpio_req; |
1070 | } | 1080 | } |
1071 | spi_set_ctldata(spi, cs); | ||
1072 | } | 1081 | } |
1073 | 1082 | ||
1083 | if (!spi_get_ctldata(spi)) | ||
1084 | spi_set_ctldata(spi, cs); | ||
1085 | |||
1074 | sci = sdd->cntrlr_info; | 1086 | sci = sdd->cntrlr_info; |
1075 | 1087 | ||
1076 | spin_lock_irqsave(&sdd->lock, flags); | 1088 | spin_lock_irqsave(&sdd->lock, flags); |
@@ -1148,8 +1160,10 @@ err_gpio_req: | |||
1148 | static void s3c64xx_spi_cleanup(struct spi_device *spi) | 1160 | static void s3c64xx_spi_cleanup(struct spi_device *spi) |
1149 | { | 1161 | { |
1150 | struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi); | 1162 | struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi); |
1163 | struct s3c64xx_spi_driver_data *sdd; | ||
1151 | 1164 | ||
1152 | if (cs) { | 1165 | sdd = spi_master_get_devdata(spi->master); |
1166 | if (cs && sdd->cs_gpio) { | ||
1153 | gpio_free(cs->line); | 1167 | gpio_free(cs->line); |
1154 | if (spi->dev.of_node) | 1168 | if (spi->dev.of_node) |
1155 | kfree(cs); | 1169 | kfree(cs); |
@@ -1326,7 +1340,11 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) | |||
1326 | sdd->cntrlr_info = sci; | 1340 | sdd->cntrlr_info = sci; |
1327 | sdd->pdev = pdev; | 1341 | sdd->pdev = pdev; |
1328 | sdd->sfr_start = mem_res->start; | 1342 | sdd->sfr_start = mem_res->start; |
1343 | sdd->cs_gpio = true; | ||
1329 | if (pdev->dev.of_node) { | 1344 | if (pdev->dev.of_node) { |
1345 | if (!of_find_property(pdev->dev.of_node, "cs-gpio", NULL)) | ||
1346 | sdd->cs_gpio = false; | ||
1347 | |||
1330 | ret = of_alias_get_id(pdev->dev.of_node, "spi"); | 1348 | ret = of_alias_get_id(pdev->dev.of_node, "spi"); |
1331 | if (ret < 0) { | 1349 | if (ret < 0) { |
1332 | dev_err(&pdev->dev, "failed to get alias id, errno %d\n", | 1350 | dev_err(&pdev->dev, "failed to get alias id, errno %d\n", |