diff options
Diffstat (limited to 'drivers/spi/spi-fsl-spi.c')
-rw-r--r-- | drivers/spi/spi-fsl-spi.c | 193 |
1 files changed, 25 insertions, 168 deletions
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 1d9b33aa1a3b..4b80ace1d137 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -18,7 +18,7 @@ #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/fsl_devices.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/kernel.h> @@ -28,7 +28,6 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/of_gpio.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> @@ -481,32 +480,6 @@ static int fsl_spi_setup(struct spi_device *spi) return retval; } - if (mpc8xxx_spi->type == TYPE_GRLIB) { - if (gpio_is_valid(spi->cs_gpio)) { - int desel; - - retval = gpio_request(spi->cs_gpio, - dev_name(&spi->dev)); - if (retval) - return retval; - - desel = !(spi->mode & SPI_CS_HIGH); - retval = gpio_direction_output(spi->cs_gpio, desel); - if (retval) { - gpio_free(spi->cs_gpio); - return retval; - } - } else if (spi->cs_gpio != -ENOENT) { - if (spi->cs_gpio < 0) - return spi->cs_gpio; - return -EINVAL; - } - /* When spi->cs_gpio == -ENOENT, a hole in the phandle list - * indicates to use native chipselect if present, or allow for - * an always selected chip - */ - } - /* Initialize chipselect - might be active for SPI_CS_HIGH mode */ fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); @@ -515,12 +488,8 @@ static int fsl_spi_setup(struct spi_device *spi) static void fsl_spi_cleanup(struct spi_device *spi) { - struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); - if (mpc8xxx_spi->type == TYPE_GRLIB && gpio_is_valid(spi->cs_gpio)) - gpio_free(spi->cs_gpio); - kfree(cs); spi_set_ctldata(spi, NULL); } @@ -586,8 +555,8 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) u32 slvsel; u16 cs = spi->chip_select; - if (gpio_is_valid(spi->cs_gpio)) { - gpio_set_value(spi->cs_gpio, on); + if (spi->cs_gpiod) { + gpiod_set_value(spi->cs_gpiod, on); } else if (cs < mpc8xxx_spi->native_chipselects) { slvsel = mpc8xxx_spi_read_reg(®_base->slvsel); slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs)); @@ -718,139 +687,19 @@ err: static void fsl_spi_cs_control(struct spi_device *spi, bool on) { - struct device *dev = spi->dev.parent->parent; - struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); - struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); - u16 cs = spi->chip_select; - - if (cs < pinfo->ngpios) { - int gpio = pinfo->gpios[cs]; - bool alow = pinfo->alow_flags[cs]; - - gpio_set_value(gpio, on ^ alow); + if (spi->cs_gpiod) { + gpiod_set_value(spi->cs_gpiod, on); } else { - if (WARN_ON_ONCE(cs > pinfo->ngpios || !pinfo->immr_spi_cs)) + struct device *dev = spi->dev.parent->parent; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); + struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); + + if (WARN_ON_ONCE(!pinfo->immr_spi_cs)) return; iowrite32be(on ? SPI_BOOT_SEL_BIT : 0, pinfo->immr_spi_cs); } } -static int of_fsl_spi_get_chipselects(struct device *dev) -{ - struct device_node *np = dev->of_node; - struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); - struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); - bool spisel_boot = IS_ENABLED(CONFIG_FSL_SOC) && - of_property_read_bool(np, "fsl,spisel_boot"); - int ngpios; - int i = 0; - int ret; - - ngpios = of_gpio_count(np); - ngpios = max(ngpios, 0); - if (ngpios == 0 && !spisel_boot) { - /* - * SPI w/o chip-select line. One SPI device is still permitted - * though. - */ - pdata->max_chipselect = 1; - return 0; - } - - pinfo->ngpios = ngpios; - pinfo->gpios = kmalloc_array(ngpios, sizeof(*pinfo->gpios), - GFP_KERNEL); - if (!pinfo->gpios) - return -ENOMEM; - memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios)); - - pinfo->alow_flags = kcalloc(ngpios, sizeof(*pinfo->alow_flags), - GFP_KERNEL); - if (!pinfo->alow_flags) { - ret = -ENOMEM; - goto err_alloc_flags; - } - - for (; i < ngpios; i++) { - int gpio; - enum of_gpio_flags flags; - - gpio = of_get_gpio_flags(np, i, &flags); - if (!gpio_is_valid(gpio)) { - dev_err(dev, "invalid gpio #%d: %d\n", i, gpio); - ret = gpio; - goto err_loop; - } - - ret = gpio_request(gpio, dev_name(dev)); - if (ret) { - dev_err(dev, "can't request gpio #%d: %d\n", i, ret); - goto err_loop; - } - - pinfo->gpios[i] = gpio; - pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW; - - ret = gpio_direction_output(pinfo->gpios[i], - pinfo->alow_flags[i]); - if (ret) { - dev_err(dev, - "can't set output direction for gpio #%d: %d\n", - i, ret); - goto err_loop; - } - } - -#if IS_ENABLED(CONFIG_FSL_SOC) - if (spisel_boot) { - pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4); - if (!pinfo->immr_spi_cs) { - ret = -ENOMEM; - i = ngpios - 1; - goto err_loop; - } - } -#endif - - pdata->max_chipselect = ngpios + spisel_boot; - pdata->cs_control = fsl_spi_cs_control; - - return 0; - -err_loop: - while (i >= 0) { - if (gpio_is_valid(pinfo->gpios[i])) - gpio_free(pinfo->gpios[i]); - i--; - } - - kfree(pinfo->alow_flags); - pinfo->alow_flags = NULL; -err_alloc_flags: - kfree(pinfo->gpios); - pinfo->gpios = NULL; - return ret; -} - -static int of_fsl_spi_free_chipselects(struct device *dev) -{ - struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); - struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); - int i; - - if (!pinfo->gpios) - return 0; - - for (i = 0; i < pdata->max_chipselect; i++) { - if (gpio_is_valid(pinfo->gpios[i])) - gpio_free(pinfo->gpios[i]); - } - - kfree(pinfo->gpios); - kfree(pinfo->alow_flags); - return 0; -} - static int of_fsl_spi_probe(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; @@ -866,9 +715,21 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) type = fsl_spi_get_type(&ofdev->dev); if (type == TYPE_FSL) { - ret = of_fsl_spi_get_chipselects(dev); - if (ret) - goto err; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); +#if IS_ENABLED(CONFIG_FSL_SOC) + struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); + bool spisel_boot = of_property_read_bool(np, "fsl,spisel_boot"); + + if (spisel_boot) { + pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4); + if (!pinfo->immr_spi_cs) { + ret = -ENOMEM; + goto err; + } + } +#endif + + pdata->cs_control = fsl_spi_cs_control; } ret = of_address_to_resource(np, 0, &mem); @@ -891,8 +752,6 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) err: irq_dispose_mapping(irq); - if (type == TYPE_FSL) - of_fsl_spi_free_chipselects(dev); return ret; } @@ -902,8 +761,6 @@ static int of_fsl_spi_remove(struct platform_device *ofdev) struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); fsl_spi_cpm_free(mpc8xxx_spi); - if (mpc8xxx_spi->type == TYPE_FSL) - of_fsl_spi_free_chipselects(&ofdev->dev); return 0; } |