diff options
author | Moritz Fischer <mdf@kernel.org> | 2017-04-25 14:30:14 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-04-26 10:23:45 -0400 |
commit | b42a33bd93fe0b2438511b1c7c00cfd47e17841b (patch) | |
tree | bd3830bc64e969303294e19540e18d288e177f12 /drivers/spi/spi-cadence.c | |
parent | c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201 (diff) |
spi: cadence: Allow for GPIO pins to be used as chipselects
This adds support for using GPIOs for chipselects as described by the
default dt-bindings.
Signed-off-by: Moritz Fischer <mdf@kernel.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi-cadence.c')
-rw-r--r-- | drivers/spi/spi-cadence.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 1c57ce64abba..f0b5c7b91f37 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/gpio.h> | ||
16 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
@@ -127,6 +128,10 @@ struct cdns_spi { | |||
127 | u32 is_decoded_cs; | 128 | u32 is_decoded_cs; |
128 | }; | 129 | }; |
129 | 130 | ||
131 | struct cdns_spi_device_data { | ||
132 | bool gpio_requested; | ||
133 | }; | ||
134 | |||
130 | /* Macros for the SPI controller read/write */ | 135 | /* Macros for the SPI controller read/write */ |
131 | static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset) | 136 | static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset) |
132 | { | 137 | { |
@@ -456,6 +461,64 @@ static int cdns_unprepare_transfer_hardware(struct spi_master *master) | |||
456 | return 0; | 461 | return 0; |
457 | } | 462 | } |
458 | 463 | ||
464 | static int cdns_spi_setup(struct spi_device *spi) | ||
465 | { | ||
466 | |||
467 | int ret = -EINVAL; | ||
468 | struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); | ||
469 | |||
470 | /* this is a pin managed by the controller, leave it alone */ | ||
471 | if (spi->cs_gpio == -ENOENT) | ||
472 | return 0; | ||
473 | |||
474 | /* this seems to be the first time we're here */ | ||
475 | if (!cdns_spi_data) { | ||
476 | cdns_spi_data = kzalloc(sizeof(*cdns_spi_data), GFP_KERNEL); | ||
477 | if (!cdns_spi_data) | ||
478 | return -ENOMEM; | ||
479 | cdns_spi_data->gpio_requested = false; | ||
480 | spi_set_ctldata(spi, cdns_spi_data); | ||
481 | } | ||
482 | |||
483 | /* if we haven't done so, grab the gpio */ | ||
484 | if (!cdns_spi_data->gpio_requested && gpio_is_valid(spi->cs_gpio)) { | ||
485 | ret = gpio_request_one(spi->cs_gpio, | ||
486 | (spi->mode & SPI_CS_HIGH) ? | ||
487 | GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, | ||
488 | dev_name(&spi->dev)); | ||
489 | if (ret) | ||
490 | dev_err(&spi->dev, "can't request chipselect gpio %d\n", | ||
491 | spi->cs_gpio); | ||
492 | else | ||
493 | cdns_spi_data->gpio_requested = true; | ||
494 | } else { | ||
495 | if (gpio_is_valid(spi->cs_gpio)) { | ||
496 | int mode = ((spi->mode & SPI_CS_HIGH) ? | ||
497 | GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH); | ||
498 | |||
499 | ret = gpio_direction_output(spi->cs_gpio, mode); | ||
500 | if (ret) | ||
501 | dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n", | ||
502 | spi->cs_gpio, ret); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | return ret; | ||
507 | } | ||
508 | |||
509 | static void cdns_spi_cleanup(struct spi_device *spi) | ||
510 | { | ||
511 | struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); | ||
512 | |||
513 | if (cdns_spi_data) { | ||
514 | if (cdns_spi_data->gpio_requested) | ||
515 | gpio_free(spi->cs_gpio); | ||
516 | kfree(cdns_spi_data); | ||
517 | spi_set_ctldata(spi, NULL); | ||
518 | } | ||
519 | |||
520 | } | ||
521 | |||
459 | /** | 522 | /** |
460 | * cdns_spi_probe - Probe method for the SPI driver | 523 | * cdns_spi_probe - Probe method for the SPI driver |
461 | * @pdev: Pointer to the platform_device structure | 524 | * @pdev: Pointer to the platform_device structure |
@@ -555,6 +618,8 @@ static int cdns_spi_probe(struct platform_device *pdev) | |||
555 | master->transfer_one = cdns_transfer_one; | 618 | master->transfer_one = cdns_transfer_one; |
556 | master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware; | 619 | master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware; |
557 | master->set_cs = cdns_spi_chipselect; | 620 | master->set_cs = cdns_spi_chipselect; |
621 | master->setup = cdns_spi_setup; | ||
622 | master->cleanup = cdns_spi_cleanup; | ||
558 | master->auto_runtime_pm = true; | 623 | master->auto_runtime_pm = true; |
559 | master->mode_bits = SPI_CPOL | SPI_CPHA; | 624 | master->mode_bits = SPI_CPOL | SPI_CPHA; |
560 | 625 | ||