summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorJan Kundrát <jan.kundrat@cesnet.cz>2018-01-26 23:56:10 +0100
committerMark Brown <broonie@kernel.org>2018-02-14 16:26:49 +0000
commit544248623b95eefbe4bea5fa5c68ab0da495eaae (patch)
treed7cd94649c8fe1783587620e6f83fe7cdf72d3ee /drivers/spi
parent7928b2cbe55b2a410a0f5c1f154610059c57b1b2 (diff)
downloadlinux-544248623b95eefbe4bea5fa5c68ab0da495eaae.tar.bz2
spi: orion: Rework GPIO CS handling
- Claim the GPIO from the driver, not via DT bindings or through the platform code - Find an unused HW CS signal because Orion needs to drive one for each SPI transaction The spi-orion.c was the only driver which supported (or cared about) the CS GPIO, while it wasn't actually requesting it. This change means that the DT bindings should stop hogging the GPIO CS pins because it's now being handled by the driver. Signed-off-by: Jan Kundrát <jan.kundrat@cesnet.cz> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-orion.c47
1 files changed, 44 insertions, 3 deletions
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index deca63e82ff6..b341235d2947 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -96,6 +96,7 @@ struct orion_spi {
struct clk *clk;
struct clk *axi_clk;
const struct orion_spi_dev *devdata;
+ int unused_hw_gpio;
struct orion_direct_acc direct_access[ORION_NUM_CHIPSELECTS];
};
@@ -324,13 +325,13 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable)
struct orion_spi *orion_spi;
int cs;
+ orion_spi = spi_master_get_devdata(spi->master);
+
if (gpio_is_valid(spi->cs_gpio))
- cs = 0;
+ cs = orion_spi->unused_hw_gpio;
else
cs = spi->chip_select;
- orion_spi = spi_master_get_devdata(spi->master);
-
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK);
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG,
ORION_SPI_CS(cs));
@@ -498,6 +499,9 @@ static int orion_spi_transfer_one(struct spi_master *master,
static int orion_spi_setup(struct spi_device *spi)
{
+ if (gpio_is_valid(spi->cs_gpio)) {
+ gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
+ }
return orion_spi_setup_transfer(spi, NULL);
}
@@ -620,6 +624,7 @@ static int orion_spi_probe(struct platform_device *pdev)
spi = spi_master_get_devdata(master);
spi->master = master;
+ spi->unused_hw_gpio = -1;
of_id = of_match_device(orion_spi_of_match_table, &pdev->dev);
devdata = (of_id) ? of_id->data : &orion_spi_dev_data;
@@ -731,8 +736,44 @@ static int orion_spi_probe(struct platform_device *pdev)
if (status < 0)
goto out_rel_pm;
+ if (master->cs_gpios) {
+ int i;
+ for (i = 0; i < master->num_chipselect; ++i) {
+ char *gpio_name;
+
+ if (!gpio_is_valid(master->cs_gpios[i])) {
+ continue;
+ }
+
+ gpio_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "%s-CS%d", dev_name(&pdev->dev), i);
+ if (!gpio_name) {
+ status = -ENOMEM;
+ goto out_rel_master;
+ }
+
+ status = devm_gpio_request(&pdev->dev,
+ master->cs_gpios[i], gpio_name);
+ if (status) {
+ dev_err(&pdev->dev,
+ "Can't request GPIO for CS %d\n",
+ master->cs_gpios[i]);
+ goto out_rel_master;
+ }
+ if (spi->unused_hw_gpio == -1) {
+ dev_info(&pdev->dev,
+ "Selected unused HW CS#%d "
+ "for any GPIO CSes\n", i);
+ spi->unused_hw_gpio = i;
+ }
+ }
+ }
+
+
return status;
+out_rel_master:
+ spi_unregister_master(master);
out_rel_pm:
pm_runtime_disable(&pdev->dev);
out_rel_axi_clk: