diff options
author | Mark Brown <broonie@kernel.org> | 2019-09-15 05:32:06 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-09-15 05:32:06 -0400 |
commit | b769c5ba8aedc395ed04abe6db84a556d28beec1 (patch) | |
tree | dd00c955f899f65785d60c2b4673785c28054b30 /drivers/spi/spi-fsl-spi.c | |
parent | 262a2f33454fcecdc2032ca84d6fecdb08233468 (diff) | |
parent | fdeae8f5a2e5eb3fcc9c295bfb28503c3abd4d6e (diff) |
Merge branch 'spi-5.4' into spi-next
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 @@ | |||
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
20 | #include <linux/fsl_devices.h> | 20 | #include <linux/fsl_devices.h> |
21 | #include <linux/gpio.h> | 21 | #include <linux/gpio/consumer.h> |
22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/irq.h> | 23 | #include <linux/irq.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/of.h> | 28 | #include <linux/of.h> |
29 | #include <linux/of_address.h> | 29 | #include <linux/of_address.h> |
30 | #include <linux/of_irq.h> | 30 | #include <linux/of_irq.h> |
31 | #include <linux/of_gpio.h> | ||
32 | #include <linux/of_platform.h> | 31 | #include <linux/of_platform.h> |
33 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
34 | #include <linux/spi/spi.h> | 33 | #include <linux/spi/spi.h> |
@@ -481,32 +480,6 @@ static int fsl_spi_setup(struct spi_device *spi) | |||
481 | return retval; | 480 | return retval; |
482 | } | 481 | } |
483 | 482 | ||
484 | if (mpc8xxx_spi->type == TYPE_GRLIB) { | ||
485 | if (gpio_is_valid(spi->cs_gpio)) { | ||
486 | int desel; | ||
487 | |||
488 | retval = gpio_request(spi->cs_gpio, | ||
489 | dev_name(&spi->dev)); | ||
490 | if (retval) | ||
491 | return retval; | ||
492 | |||
493 | desel = !(spi->mode & SPI_CS_HIGH); | ||
494 | retval = gpio_direction_output(spi->cs_gpio, desel); | ||
495 | if (retval) { | ||
496 | gpio_free(spi->cs_gpio); | ||
497 | return retval; | ||
498 | } | ||
499 | } else if (spi->cs_gpio != -ENOENT) { | ||
500 | if (spi->cs_gpio < 0) | ||
501 | return spi->cs_gpio; | ||
502 | return -EINVAL; | ||
503 | } | ||
504 | /* When spi->cs_gpio == -ENOENT, a hole in the phandle list | ||
505 | * indicates to use native chipselect if present, or allow for | ||
506 | * an always selected chip | ||
507 | */ | ||
508 | } | ||
509 | |||
510 | /* Initialize chipselect - might be active for SPI_CS_HIGH mode */ | 483 | /* Initialize chipselect - might be active for SPI_CS_HIGH mode */ |
511 | fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); | 484 | fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); |
512 | 485 | ||
@@ -515,12 +488,8 @@ static int fsl_spi_setup(struct spi_device *spi) | |||
515 | 488 | ||
516 | static void fsl_spi_cleanup(struct spi_device *spi) | 489 | static void fsl_spi_cleanup(struct spi_device *spi) |
517 | { | 490 | { |
518 | struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); | ||
519 | struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); | 491 | struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); |
520 | 492 | ||
521 | if (mpc8xxx_spi->type == TYPE_GRLIB && gpio_is_valid(spi->cs_gpio)) | ||
522 | gpio_free(spi->cs_gpio); | ||
523 | |||
524 | kfree(cs); | 493 | kfree(cs); |
525 | spi_set_ctldata(spi, NULL); | 494 | spi_set_ctldata(spi, NULL); |
526 | } | 495 | } |
@@ -586,8 +555,8 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) | |||
586 | u32 slvsel; | 555 | u32 slvsel; |
587 | u16 cs = spi->chip_select; | 556 | u16 cs = spi->chip_select; |
588 | 557 | ||
589 | if (gpio_is_valid(spi->cs_gpio)) { | 558 | if (spi->cs_gpiod) { |
590 | gpio_set_value(spi->cs_gpio, on); | 559 | gpiod_set_value(spi->cs_gpiod, on); |
591 | } else if (cs < mpc8xxx_spi->native_chipselects) { | 560 | } else if (cs < mpc8xxx_spi->native_chipselects) { |
592 | slvsel = mpc8xxx_spi_read_reg(®_base->slvsel); | 561 | slvsel = mpc8xxx_spi_read_reg(®_base->slvsel); |
593 | slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs)); | 562 | slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs)); |
@@ -718,139 +687,19 @@ err: | |||
718 | 687 | ||
719 | static void fsl_spi_cs_control(struct spi_device *spi, bool on) | 688 | static void fsl_spi_cs_control(struct spi_device *spi, bool on) |
720 | { | 689 | { |
721 | struct device *dev = spi->dev.parent->parent; | 690 | if (spi->cs_gpiod) { |
722 | struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); | 691 | gpiod_set_value(spi->cs_gpiod, on); |
723 | struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); | ||
724 | u16 cs = spi->chip_select; | ||
725 | |||
726 | if (cs < pinfo->ngpios) { | ||
727 | int gpio = pinfo->gpios[cs]; | ||
728 | bool alow = pinfo->alow_flags[cs]; | ||
729 | |||
730 | gpio_set_value(gpio, on ^ alow); | ||
731 | } else { | 692 | } else { |
732 | if (WARN_ON_ONCE(cs > pinfo->ngpios || !pinfo->immr_spi_cs)) | 693 | struct device *dev = spi->dev.parent->parent; |
694 | struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); | ||
695 | struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); | ||
696 | |||
697 | if (WARN_ON_ONCE(!pinfo->immr_spi_cs)) | ||
733 | return; | 698 | return; |
734 | iowrite32be(on ? SPI_BOOT_SEL_BIT : 0, pinfo->immr_spi_cs); | 699 | iowrite32be(on ? SPI_BOOT_SEL_BIT : 0, pinfo->immr_spi_cs); |
735 | } | 700 | } |
736 | } | 701 | } |
737 | 702 | ||
738 | static int of_fsl_spi_get_chipselects(struct device *dev) | ||
739 | { | ||
740 | struct device_node *np = dev->of_node; | ||
741 | struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); | ||
742 | struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); | ||
743 | bool spisel_boot = IS_ENABLED(CONFIG_FSL_SOC) && | ||
744 | of_property_read_bool(np, "fsl,spisel_boot"); | ||
745 | int ngpios; | ||
746 | int i = 0; | ||
747 | int ret; | ||
748 | |||
749 | ngpios = of_gpio_count(np); | ||
750 | ngpios = max(ngpios, 0); | ||
751 | if (ngpios == 0 && !spisel_boot) { | ||
752 | /* | ||
753 | * SPI w/o chip-select line. One SPI device is still permitted | ||
754 | * though. | ||
755 | */ | ||
756 | pdata->max_chipselect = 1; | ||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | pinfo->ngpios = ngpios; | ||
761 | pinfo->gpios = kmalloc_array(ngpios, sizeof(*pinfo->gpios), | ||
762 | GFP_KERNEL); | ||
763 | if (!pinfo->gpios) | ||
764 | return -ENOMEM; | ||
765 | memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios)); | ||
766 | |||
767 | pinfo->alow_flags = kcalloc(ngpios, sizeof(*pinfo->alow_flags), | ||
768 | GFP_KERNEL); | ||
769 | if (!pinfo->alow_flags) { | ||
770 | ret = -ENOMEM; | ||
771 | goto err_alloc_flags; | ||
772 | } | ||
773 | |||
774 | for (; i < ngpios; i++) { | ||
775 | int gpio; | ||
776 | enum of_gpio_flags flags; | ||
777 | |||
778 | gpio = of_get_gpio_flags(np, i, &flags); | ||
779 | if (!gpio_is_valid(gpio)) { | ||
780 | dev_err(dev, "invalid gpio #%d: %d\n", i, gpio); | ||
781 | ret = gpio; | ||
782 | goto err_loop; | ||
783 | } | ||
784 | |||
785 | ret = gpio_request(gpio, dev_name(dev)); | ||
786 | if (ret) { | ||
787 | dev_err(dev, "can't request gpio #%d: %d\n", i, ret); | ||
788 | goto err_loop; | ||
789 | } | ||
790 | |||
791 | pinfo->gpios[i] = gpio; | ||
792 | pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW; | ||
793 | |||
794 | ret = gpio_direction_output(pinfo->gpios[i], | ||
795 | pinfo->alow_flags[i]); | ||
796 | if (ret) { | ||
797 | dev_err(dev, | ||
798 | "can't set output direction for gpio #%d: %d\n", | ||
799 | i, ret); | ||
800 | goto err_loop; | ||
801 | } | ||
802 | } | ||
803 | |||
804 | #if IS_ENABLED(CONFIG_FSL_SOC) | ||
805 | if (spisel_boot) { | ||
806 | pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4); | ||
807 | if (!pinfo->immr_spi_cs) { | ||
808 | ret = -ENOMEM; | ||
809 | i = ngpios - 1; | ||
810 | goto err_loop; | ||
811 | } | ||
812 | } | ||
813 | #endif | ||
814 | |||
815 | pdata->max_chipselect = ngpios + spisel_boot; | ||
816 | pdata->cs_control = fsl_spi_cs_control; | ||
817 | |||
818 | return 0; | ||
819 | |||
820 | err_loop: | ||
821 | while (i >= 0) { | ||
822 | if (gpio_is_valid(pinfo->gpios[i])) | ||
823 | gpio_free(pinfo->gpios[i]); | ||
824 | i--; | ||
825 | } | ||
826 | |||
827 | kfree(pinfo->alow_flags); | ||
828 | pinfo->alow_flags = NULL; | ||
829 | err_alloc_flags: | ||
830 | kfree(pinfo->gpios); | ||
831 | pinfo->gpios = NULL; | ||
832 | return ret; | ||
833 | } | ||
834 | |||
835 | static int of_fsl_spi_free_chipselects(struct device *dev) | ||
836 | { | ||
837 | struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); | ||
838 | struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); | ||
839 | int i; | ||
840 | |||
841 | if (!pinfo->gpios) | ||
842 | return 0; | ||
843 | |||
844 | for (i = 0; i < pdata->max_chipselect; i++) { | ||
845 | if (gpio_is_valid(pinfo->gpios[i])) | ||
846 | gpio_free(pinfo->gpios[i]); | ||
847 | } | ||
848 | |||
849 | kfree(pinfo->gpios); | ||
850 | kfree(pinfo->alow_flags); | ||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static int of_fsl_spi_probe(struct platform_device *ofdev) | 703 | static int of_fsl_spi_probe(struct platform_device *ofdev) |
855 | { | 704 | { |
856 | struct device *dev = &ofdev->dev; | 705 | struct device *dev = &ofdev->dev; |
@@ -866,9 +715,21 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) | |||
866 | 715 | ||
867 | type = fsl_spi_get_type(&ofdev->dev); | 716 | type = fsl_spi_get_type(&ofdev->dev); |
868 | if (type == TYPE_FSL) { | 717 | if (type == TYPE_FSL) { |
869 | ret = of_fsl_spi_get_chipselects(dev); | 718 | struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); |
870 | if (ret) | 719 | #if IS_ENABLED(CONFIG_FSL_SOC) |
871 | goto err; | 720 | struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); |
721 | bool spisel_boot = of_property_read_bool(np, "fsl,spisel_boot"); | ||
722 | |||
723 | if (spisel_boot) { | ||
724 | pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4); | ||
725 | if (!pinfo->immr_spi_cs) { | ||
726 | ret = -ENOMEM; | ||
727 | goto err; | ||
728 | } | ||
729 | } | ||
730 | #endif | ||
731 | |||
732 | pdata->cs_control = fsl_spi_cs_control; | ||
872 | } | 733 | } |
873 | 734 | ||
874 | ret = of_address_to_resource(np, 0, &mem); | 735 | ret = of_address_to_resource(np, 0, &mem); |
@@ -891,8 +752,6 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) | |||
891 | 752 | ||
892 | err: | 753 | err: |
893 | irq_dispose_mapping(irq); | 754 | irq_dispose_mapping(irq); |
894 | if (type == TYPE_FSL) | ||
895 | of_fsl_spi_free_chipselects(dev); | ||
896 | return ret; | 755 | return ret; |
897 | } | 756 | } |
898 | 757 | ||
@@ -902,8 +761,6 @@ static int of_fsl_spi_remove(struct platform_device *ofdev) | |||
902 | struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); | 761 | struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); |
903 | 762 | ||
904 | fsl_spi_cpm_free(mpc8xxx_spi); | 763 | fsl_spi_cpm_free(mpc8xxx_spi); |
905 | if (mpc8xxx_spi->type == TYPE_FSL) | ||
906 | of_fsl_spi_free_chipselects(&ofdev->dev); | ||
907 | return 0; | 764 | return 0; |
908 | } | 765 | } |
909 | 766 | ||