diff options
author | Anatolij Gustschin <agust@denx.de> | 2013-04-01 11:29:21 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-04-09 12:53:19 -0400 |
commit | 86e98743ec168b98eea3dfacc1e8b5ff442eb70d (patch) | |
tree | 2cf8bfed3e1eacfcfb957d2bb777f0415863da2d /drivers/spi | |
parent | ab300d18175aaae8e4c6f90c0b0577384721dea7 (diff) |
spi: spi-mpc512x-psc: add support for gpio chip selects
Currently the driver only uses one internal chip select.
Add support for gpio chip selects configured by cs-gpios
DT binding.
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-mpc512x-psc.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 3e490ee7f275..da60f268f74c 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/clk.h> | 28 | #include <linux/clk.h> |
29 | #include <linux/spi/spi.h> | 29 | #include <linux/spi/spi.h> |
30 | #include <linux/fsl_devices.h> | 30 | #include <linux/fsl_devices.h> |
31 | #include <linux/gpio.h> | ||
31 | #include <asm/mpc52xx_psc.h> | 32 | #include <asm/mpc52xx_psc.h> |
32 | 33 | ||
33 | struct mpc512x_psc_spi { | 34 | struct mpc512x_psc_spi { |
@@ -113,7 +114,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) | |||
113 | out_be32(&psc->ccr, ccr); | 114 | out_be32(&psc->ccr, ccr); |
114 | mps->bits_per_word = cs->bits_per_word; | 115 | mps->bits_per_word = cs->bits_per_word; |
115 | 116 | ||
116 | if (mps->cs_control) | 117 | if (mps->cs_control && gpio_is_valid(spi->cs_gpio)) |
117 | mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0); | 118 | mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0); |
118 | } | 119 | } |
119 | 120 | ||
@@ -121,7 +122,7 @@ static void mpc512x_psc_spi_deactivate_cs(struct spi_device *spi) | |||
121 | { | 122 | { |
122 | struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); | 123 | struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); |
123 | 124 | ||
124 | if (mps->cs_control) | 125 | if (mps->cs_control && gpio_is_valid(spi->cs_gpio)) |
125 | mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1); | 126 | mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1); |
126 | 127 | ||
127 | } | 128 | } |
@@ -278,6 +279,7 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi) | |||
278 | struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); | 279 | struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); |
279 | struct mpc512x_psc_spi_cs *cs = spi->controller_state; | 280 | struct mpc512x_psc_spi_cs *cs = spi->controller_state; |
280 | unsigned long flags; | 281 | unsigned long flags; |
282 | int ret; | ||
281 | 283 | ||
282 | if (spi->bits_per_word % 8) | 284 | if (spi->bits_per_word % 8) |
283 | return -EINVAL; | 285 | return -EINVAL; |
@@ -286,6 +288,19 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi) | |||
286 | cs = kzalloc(sizeof *cs, GFP_KERNEL); | 288 | cs = kzalloc(sizeof *cs, GFP_KERNEL); |
287 | if (!cs) | 289 | if (!cs) |
288 | return -ENOMEM; | 290 | return -ENOMEM; |
291 | |||
292 | if (gpio_is_valid(spi->cs_gpio)) { | ||
293 | ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); | ||
294 | if (ret) { | ||
295 | dev_err(&spi->dev, "can't get CS gpio: %d\n", | ||
296 | ret); | ||
297 | kfree(cs); | ||
298 | return ret; | ||
299 | } | ||
300 | gpio_direction_output(spi->cs_gpio, | ||
301 | spi->mode & SPI_CS_HIGH ? 0 : 1); | ||
302 | } | ||
303 | |||
289 | spi->controller_state = cs; | 304 | spi->controller_state = cs; |
290 | } | 305 | } |
291 | 306 | ||
@@ -319,6 +334,8 @@ static int mpc512x_psc_spi_transfer(struct spi_device *spi, | |||
319 | 334 | ||
320 | static void mpc512x_psc_spi_cleanup(struct spi_device *spi) | 335 | static void mpc512x_psc_spi_cleanup(struct spi_device *spi) |
321 | { | 336 | { |
337 | if (gpio_is_valid(spi->cs_gpio)) | ||
338 | gpio_free(spi->cs_gpio); | ||
322 | kfree(spi->controller_state); | 339 | kfree(spi->controller_state); |
323 | } | 340 | } |
324 | 341 | ||
@@ -405,6 +422,11 @@ static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id) | |||
405 | return IRQ_NONE; | 422 | return IRQ_NONE; |
406 | } | 423 | } |
407 | 424 | ||
425 | static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff) | ||
426 | { | ||
427 | gpio_set_value(spi->cs_gpio, onoff); | ||
428 | } | ||
429 | |||
408 | /* bus_num is used only for the case dev->platform_data == NULL */ | 430 | /* bus_num is used only for the case dev->platform_data == NULL */ |
409 | static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, | 431 | static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, |
410 | u32 size, unsigned int irq, | 432 | u32 size, unsigned int irq, |
@@ -425,12 +447,9 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, | |||
425 | mps->irq = irq; | 447 | mps->irq = irq; |
426 | 448 | ||
427 | if (pdata == NULL) { | 449 | if (pdata == NULL) { |
428 | dev_err(dev, "probe called without platform data, no " | 450 | mps->cs_control = mpc512x_spi_cs_control; |
429 | "cs_control function will be called\n"); | ||
430 | mps->cs_control = NULL; | ||
431 | mps->sysclk = 0; | 451 | mps->sysclk = 0; |
432 | master->bus_num = bus_num; | 452 | master->bus_num = bus_num; |
433 | master->num_chipselect = 255; | ||
434 | } else { | 453 | } else { |
435 | mps->cs_control = pdata->cs_control; | 454 | mps->cs_control = pdata->cs_control; |
436 | mps->sysclk = pdata->sysclk; | 455 | mps->sysclk = pdata->sysclk; |