diff options
-rw-r--r-- | Documentation/devicetree/bindings/spi/spi-gpio.txt | 6 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/spi/spi-img-spfi.txt | 37 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/spi/spi-meson.txt | 22 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 15 | ||||
-rw-r--r-- | drivers/spi/Makefile | 2 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-dspi.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-espi.c | 59 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-lib.c | 59 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-lib.h | 10 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-spi.c | 17 | ||||
-rw-r--r-- | drivers/spi/spi-gpio.c | 37 | ||||
-rw-r--r-- | drivers/spi/spi-img-spfi.c | 746 | ||||
-rw-r--r-- | drivers/spi/spi-meson-spifc.c | 462 |
13 files changed, 1365 insertions, 110 deletions
diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.txt b/Documentation/devicetree/bindings/spi/spi-gpio.txt index 8a824be15754..a95603bcf6ff 100644 --- a/Documentation/devicetree/bindings/spi/spi-gpio.txt +++ b/Documentation/devicetree/bindings/spi/spi-gpio.txt | |||
@@ -8,8 +8,10 @@ Required properties: | |||
8 | - gpio-sck: GPIO spec for the SCK line to use | 8 | - gpio-sck: GPIO spec for the SCK line to use |
9 | - gpio-miso: GPIO spec for the MISO line to use | 9 | - gpio-miso: GPIO spec for the MISO line to use |
10 | - gpio-mosi: GPIO spec for the MOSI line to use | 10 | - gpio-mosi: GPIO spec for the MOSI line to use |
11 | - cs-gpios: GPIOs to use for chipselect lines | 11 | - cs-gpios: GPIOs to use for chipselect lines. |
12 | - num-chipselects: number of chipselect lines | 12 | Not needed if num-chipselects = <0>. |
13 | - num-chipselects: Number of chipselect lines. Should be <0> if a single device | ||
14 | with no chip select is connected. | ||
13 | 15 | ||
14 | Example: | 16 | Example: |
15 | 17 | ||
diff --git a/Documentation/devicetree/bindings/spi/spi-img-spfi.txt b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt new file mode 100644 index 000000000000..c7dd50fb8eb2 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt | |||
@@ -0,0 +1,37 @@ | |||
1 | IMG Synchronous Peripheral Flash Interface (SPFI) controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: Must be "img,spfi". | ||
5 | - reg: Must contain the base address and length of the SPFI registers. | ||
6 | - interrupts: Must contain the SPFI interrupt. | ||
7 | - clocks: Must contain an entry for each entry in clock-names. | ||
8 | See ../clock/clock-bindings.txt for details. | ||
9 | - clock-names: Must include the following entries: | ||
10 | - spfi: SPI operating clock | ||
11 | - sys: SPI system interface clock | ||
12 | - dmas: Must contain an entry for each entry in dma-names. | ||
13 | See ../dma/dma.txt for details. | ||
14 | - dma-names: Must include the following entries: | ||
15 | - rx | ||
16 | - tx | ||
17 | - #address-cells: Must be 1. | ||
18 | - #size-cells: Must be 0. | ||
19 | |||
20 | Optional properties: | ||
21 | - img,supports-quad-mode: Should be set if the interface supports quad mode | ||
22 | SPI transfers. | ||
23 | |||
24 | Example: | ||
25 | |||
26 | spi@18100f00 { | ||
27 | compatible = "img,spfi"; | ||
28 | reg = <0x18100f00 0x100>; | ||
29 | interrupts = <GIC_SHARED 22 IRQ_TYPE_LEVEL_HIGH>; | ||
30 | clocks = <&spi_clk>, <&system_clk>; | ||
31 | clock-names = "spfi", "sys"; | ||
32 | dmas = <&mdc 9 0xffffffff 0>, <&mdc 10 0xffffffff 0>; | ||
33 | dma-names = "rx", "tx"; | ||
34 | |||
35 | #address-cells = <1>; | ||
36 | #size-cells = <0>; | ||
37 | }; | ||
diff --git a/Documentation/devicetree/bindings/spi/spi-meson.txt b/Documentation/devicetree/bindings/spi/spi-meson.txt new file mode 100644 index 000000000000..bb52a86f3365 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-meson.txt | |||
@@ -0,0 +1,22 @@ | |||
1 | Amlogic Meson SPI controllers | ||
2 | |||
3 | * SPIFC (SPI Flash Controller) | ||
4 | |||
5 | The Meson SPIFC is a controller optimized for communication with SPI | ||
6 | NOR memories, without DMA support and a 64-byte unified transmit / | ||
7 | receive buffer. | ||
8 | |||
9 | Required properties: | ||
10 | - compatible: should be "amlogic,meson6-spifc" | ||
11 | - reg: physical base address and length of the controller registers | ||
12 | - clocks: phandle of the input clock for the baud rate generator | ||
13 | - #address-cells: should be 1 | ||
14 | - #size-cells: should be 0 | ||
15 | |||
16 | spi@c1108c80 { | ||
17 | compatible = "amlogic,meson6-spifc"; | ||
18 | reg = <0xc1108c80 0x80>; | ||
19 | clocks = <&clk81>; | ||
20 | #address-cells = <1>; | ||
21 | #size-cells = <0>; | ||
22 | }; | ||
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 84e7c9e6ccef..400c34468cad 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
@@ -225,6 +225,13 @@ config SPI_GPIO | |||
225 | GPIO operations, you should be able to leverage that for better | 225 | GPIO operations, you should be able to leverage that for better |
226 | speed with a custom version of this driver; see the source code. | 226 | speed with a custom version of this driver; see the source code. |
227 | 227 | ||
228 | config SPI_IMG_SPFI | ||
229 | tristate "IMG SPFI controller" | ||
230 | depends on MIPS || COMPILE_TEST | ||
231 | help | ||
232 | This enables support for the SPFI master controller found on | ||
233 | IMG SoCs. | ||
234 | |||
228 | config SPI_IMX | 235 | config SPI_IMX |
229 | tristate "Freescale i.MX SPI controllers" | 236 | tristate "Freescale i.MX SPI controllers" |
230 | depends on ARCH_MXC || COMPILE_TEST | 237 | depends on ARCH_MXC || COMPILE_TEST |
@@ -301,6 +308,14 @@ config SPI_FSL_ESPI | |||
301 | From MPC8536, 85xx platform uses the controller, and all P10xx, | 308 | From MPC8536, 85xx platform uses the controller, and all P10xx, |
302 | P20xx, P30xx,P40xx, P50xx uses this controller. | 309 | P20xx, P30xx,P40xx, P50xx uses this controller. |
303 | 310 | ||
311 | config SPI_MESON_SPIFC | ||
312 | tristate "Amlogic Meson SPIFC controller" | ||
313 | depends on ARCH_MESON || COMPILE_TEST | ||
314 | select REGMAP_MMIO | ||
315 | help | ||
316 | This enables master mode support for the SPIFC (SPI flash | ||
317 | controller) available in Amlogic Meson SoCs. | ||
318 | |||
304 | config SPI_OC_TINY | 319 | config SPI_OC_TINY |
305 | tristate "OpenCores tiny SPI" | 320 | tristate "OpenCores tiny SPI" |
306 | depends on GPIOLIB | 321 | depends on GPIOLIB |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 78f24ca36fcf..6b9d2ac629cc 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
@@ -40,8 +40,10 @@ obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o | |||
40 | obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o | 40 | obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o |
41 | obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o | 41 | obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o |
42 | obj-$(CONFIG_SPI_GPIO) += spi-gpio.o | 42 | obj-$(CONFIG_SPI_GPIO) += spi-gpio.o |
43 | obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o | ||
43 | obj-$(CONFIG_SPI_IMX) += spi-imx.o | 44 | obj-$(CONFIG_SPI_IMX) += spi-imx.o |
44 | obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o | 45 | obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o |
46 | obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o | ||
45 | obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o | 47 | obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o |
46 | obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o | 48 | obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o |
47 | obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o | 49 | obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o |
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 831ceb4a91f6..4cda994d3f40 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c | |||
@@ -438,7 +438,7 @@ static int dspi_resume(struct device *dev) | |||
438 | 438 | ||
439 | static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume); | 439 | static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume); |
440 | 440 | ||
441 | static struct regmap_config dspi_regmap_config = { | 441 | static const struct regmap_config dspi_regmap_config = { |
442 | .reg_bits = 32, | 442 | .reg_bits = 32, |
443 | .val_bits = 32, | 443 | .val_bits = 32, |
444 | .reg_stride = 4, | 444 | .reg_stride = 4, |
@@ -492,7 +492,6 @@ static int dspi_probe(struct platform_device *pdev) | |||
492 | goto out_master_put; | 492 | goto out_master_put; |
493 | } | 493 | } |
494 | 494 | ||
495 | dspi_regmap_config.lock_arg = dspi; | ||
496 | dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base, | 495 | dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base, |
497 | &dspi_regmap_config); | 496 | &dspi_regmap_config); |
498 | if (IS_ERR(dspi->regmap)) { | 497 | if (IS_ERR(dspi->regmap)) { |
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index a7f94b6a9e70..56cadf13519e 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c | |||
@@ -411,7 +411,8 @@ static void fsl_espi_rw_trans(struct spi_message *m, | |||
411 | kfree(local_buf); | 411 | kfree(local_buf); |
412 | } | 412 | } |
413 | 413 | ||
414 | static void fsl_espi_do_one_msg(struct spi_message *m) | 414 | static int fsl_espi_do_one_msg(struct spi_master *master, |
415 | struct spi_message *m) | ||
415 | { | 416 | { |
416 | struct spi_transfer *t; | 417 | struct spi_transfer *t; |
417 | u8 *rx_buf = NULL; | 418 | u8 *rx_buf = NULL; |
@@ -441,8 +442,8 @@ static void fsl_espi_do_one_msg(struct spi_message *m) | |||
441 | 442 | ||
442 | m->actual_length = espi_trans.actual_length; | 443 | m->actual_length = espi_trans.actual_length; |
443 | m->status = espi_trans.status; | 444 | m->status = espi_trans.status; |
444 | if (m->complete) | 445 | spi_finalize_current_message(master); |
445 | m->complete(m->context); | 446 | return 0; |
446 | } | 447 | } |
447 | 448 | ||
448 | static int fsl_espi_setup(struct spi_device *spi) | 449 | static int fsl_espi_setup(struct spi_device *spi) |
@@ -587,6 +588,38 @@ static void fsl_espi_remove(struct mpc8xxx_spi *mspi) | |||
587 | iounmap(mspi->reg_base); | 588 | iounmap(mspi->reg_base); |
588 | } | 589 | } |
589 | 590 | ||
591 | static int fsl_espi_suspend(struct spi_master *master) | ||
592 | { | ||
593 | struct mpc8xxx_spi *mpc8xxx_spi; | ||
594 | struct fsl_espi_reg *reg_base; | ||
595 | u32 regval; | ||
596 | |||
597 | mpc8xxx_spi = spi_master_get_devdata(master); | ||
598 | reg_base = mpc8xxx_spi->reg_base; | ||
599 | |||
600 | regval = mpc8xxx_spi_read_reg(®_base->mode); | ||
601 | regval &= ~SPMODE_ENABLE; | ||
602 | mpc8xxx_spi_write_reg(®_base->mode, regval); | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static int fsl_espi_resume(struct spi_master *master) | ||
608 | { | ||
609 | struct mpc8xxx_spi *mpc8xxx_spi; | ||
610 | struct fsl_espi_reg *reg_base; | ||
611 | u32 regval; | ||
612 | |||
613 | mpc8xxx_spi = spi_master_get_devdata(master); | ||
614 | reg_base = mpc8xxx_spi->reg_base; | ||
615 | |||
616 | regval = mpc8xxx_spi_read_reg(®_base->mode); | ||
617 | regval |= SPMODE_ENABLE; | ||
618 | mpc8xxx_spi_write_reg(®_base->mode, regval); | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
590 | static struct spi_master * fsl_espi_probe(struct device *dev, | 623 | static struct spi_master * fsl_espi_probe(struct device *dev, |
591 | struct resource *mem, unsigned int irq) | 624 | struct resource *mem, unsigned int irq) |
592 | { | 625 | { |
@@ -607,16 +640,16 @@ static struct spi_master * fsl_espi_probe(struct device *dev, | |||
607 | 640 | ||
608 | dev_set_drvdata(dev, master); | 641 | dev_set_drvdata(dev, master); |
609 | 642 | ||
610 | ret = mpc8xxx_spi_probe(dev, mem, irq); | 643 | mpc8xxx_spi_probe(dev, mem, irq); |
611 | if (ret) | ||
612 | goto err_probe; | ||
613 | 644 | ||
614 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); | 645 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); |
615 | master->setup = fsl_espi_setup; | 646 | master->setup = fsl_espi_setup; |
616 | master->cleanup = fsl_espi_cleanup; | 647 | master->cleanup = fsl_espi_cleanup; |
648 | master->transfer_one_message = fsl_espi_do_one_msg; | ||
649 | master->prepare_transfer_hardware = fsl_espi_resume; | ||
650 | master->unprepare_transfer_hardware = fsl_espi_suspend; | ||
617 | 651 | ||
618 | mpc8xxx_spi = spi_master_get_devdata(master); | 652 | mpc8xxx_spi = spi_master_get_devdata(master); |
619 | mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg; | ||
620 | mpc8xxx_spi->spi_remove = fsl_espi_remove; | 653 | mpc8xxx_spi->spi_remove = fsl_espi_remove; |
621 | 654 | ||
622 | mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); | 655 | mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); |
@@ -762,25 +795,15 @@ static int of_fsl_espi_remove(struct platform_device *dev) | |||
762 | static int of_fsl_espi_suspend(struct device *dev) | 795 | static int of_fsl_espi_suspend(struct device *dev) |
763 | { | 796 | { |
764 | struct spi_master *master = dev_get_drvdata(dev); | 797 | struct spi_master *master = dev_get_drvdata(dev); |
765 | struct mpc8xxx_spi *mpc8xxx_spi; | ||
766 | struct fsl_espi_reg *reg_base; | ||
767 | u32 regval; | ||
768 | int ret; | 798 | int ret; |
769 | 799 | ||
770 | mpc8xxx_spi = spi_master_get_devdata(master); | ||
771 | reg_base = mpc8xxx_spi->reg_base; | ||
772 | |||
773 | ret = spi_master_suspend(master); | 800 | ret = spi_master_suspend(master); |
774 | if (ret) { | 801 | if (ret) { |
775 | dev_warn(dev, "cannot suspend master\n"); | 802 | dev_warn(dev, "cannot suspend master\n"); |
776 | return ret; | 803 | return ret; |
777 | } | 804 | } |
778 | 805 | ||
779 | regval = mpc8xxx_spi_read_reg(®_base->mode); | 806 | return fsl_espi_suspend(master); |
780 | regval &= ~SPMODE_ENABLE; | ||
781 | mpc8xxx_spi_write_reg(®_base->mode, regval); | ||
782 | |||
783 | return 0; | ||
784 | } | 807 | } |
785 | 808 | ||
786 | static int of_fsl_espi_resume(struct device *dev) | 809 | static int of_fsl_espi_resume(struct device *dev) |
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index 5ddb5b098e4e..446b737e1532 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c | |||
@@ -61,44 +61,6 @@ struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata) | |||
61 | return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata); | 61 | return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata); |
62 | } | 62 | } |
63 | 63 | ||
64 | static void mpc8xxx_spi_work(struct work_struct *work) | ||
65 | { | ||
66 | struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi, | ||
67 | work); | ||
68 | |||
69 | spin_lock_irq(&mpc8xxx_spi->lock); | ||
70 | while (!list_empty(&mpc8xxx_spi->queue)) { | ||
71 | struct spi_message *m = container_of(mpc8xxx_spi->queue.next, | ||
72 | struct spi_message, queue); | ||
73 | |||
74 | list_del_init(&m->queue); | ||
75 | spin_unlock_irq(&mpc8xxx_spi->lock); | ||
76 | |||
77 | if (mpc8xxx_spi->spi_do_one_msg) | ||
78 | mpc8xxx_spi->spi_do_one_msg(m); | ||
79 | |||
80 | spin_lock_irq(&mpc8xxx_spi->lock); | ||
81 | } | ||
82 | spin_unlock_irq(&mpc8xxx_spi->lock); | ||
83 | } | ||
84 | |||
85 | int mpc8xxx_spi_transfer(struct spi_device *spi, | ||
86 | struct spi_message *m) | ||
87 | { | ||
88 | struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); | ||
89 | unsigned long flags; | ||
90 | |||
91 | m->actual_length = 0; | ||
92 | m->status = -EINPROGRESS; | ||
93 | |||
94 | spin_lock_irqsave(&mpc8xxx_spi->lock, flags); | ||
95 | list_add_tail(&m->queue, &mpc8xxx_spi->queue); | ||
96 | queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work); | ||
97 | spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | const char *mpc8xxx_spi_strmode(unsigned int flags) | 64 | const char *mpc8xxx_spi_strmode(unsigned int flags) |
103 | { | 65 | { |
104 | if (flags & SPI_QE_CPU_MODE) { | 66 | if (flags & SPI_QE_CPU_MODE) { |
@@ -114,13 +76,12 @@ const char *mpc8xxx_spi_strmode(unsigned int flags) | |||
114 | return "CPU"; | 76 | return "CPU"; |
115 | } | 77 | } |
116 | 78 | ||
117 | int mpc8xxx_spi_probe(struct device *dev, struct resource *mem, | 79 | void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, |
118 | unsigned int irq) | 80 | unsigned int irq) |
119 | { | 81 | { |
120 | struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); | 82 | struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); |
121 | struct spi_master *master; | 83 | struct spi_master *master; |
122 | struct mpc8xxx_spi *mpc8xxx_spi; | 84 | struct mpc8xxx_spi *mpc8xxx_spi; |
123 | int ret = 0; | ||
124 | 85 | ||
125 | master = dev_get_drvdata(dev); | 86 | master = dev_get_drvdata(dev); |
126 | 87 | ||
@@ -128,7 +89,6 @@ int mpc8xxx_spi_probe(struct device *dev, struct resource *mem, | |||
128 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | 89 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
129 | | SPI_LSB_FIRST | SPI_LOOP; | 90 | | SPI_LSB_FIRST | SPI_LOOP; |
130 | 91 | ||
131 | master->transfer = mpc8xxx_spi_transfer; | ||
132 | master->dev.of_node = dev->of_node; | 92 | master->dev.of_node = dev->of_node; |
133 | 93 | ||
134 | mpc8xxx_spi = spi_master_get_devdata(master); | 94 | mpc8xxx_spi = spi_master_get_devdata(master); |
@@ -147,22 +107,7 @@ int mpc8xxx_spi_probe(struct device *dev, struct resource *mem, | |||
147 | master->bus_num = pdata->bus_num; | 107 | master->bus_num = pdata->bus_num; |
148 | master->num_chipselect = pdata->max_chipselect; | 108 | master->num_chipselect = pdata->max_chipselect; |
149 | 109 | ||
150 | spin_lock_init(&mpc8xxx_spi->lock); | ||
151 | init_completion(&mpc8xxx_spi->done); | 110 | init_completion(&mpc8xxx_spi->done); |
152 | INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work); | ||
153 | INIT_LIST_HEAD(&mpc8xxx_spi->queue); | ||
154 | |||
155 | mpc8xxx_spi->workqueue = create_singlethread_workqueue( | ||
156 | dev_name(master->dev.parent)); | ||
157 | if (mpc8xxx_spi->workqueue == NULL) { | ||
158 | ret = -EBUSY; | ||
159 | goto err; | ||
160 | } | ||
161 | |||
162 | return 0; | ||
163 | |||
164 | err: | ||
165 | return ret; | ||
166 | } | 111 | } |
167 | 112 | ||
168 | int mpc8xxx_spi_remove(struct device *dev) | 113 | int mpc8xxx_spi_remove(struct device *dev) |
@@ -173,8 +118,6 @@ int mpc8xxx_spi_remove(struct device *dev) | |||
173 | master = dev_get_drvdata(dev); | 118 | master = dev_get_drvdata(dev); |
174 | mpc8xxx_spi = spi_master_get_devdata(master); | 119 | mpc8xxx_spi = spi_master_get_devdata(master); |
175 | 120 | ||
176 | flush_workqueue(mpc8xxx_spi->workqueue); | ||
177 | destroy_workqueue(mpc8xxx_spi->workqueue); | ||
178 | spi_unregister_master(master); | 121 | spi_unregister_master(master); |
179 | 122 | ||
180 | free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); | 123 | free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); |
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h index 2fcbfd01d109..b4ed04e8862f 100644 --- a/drivers/spi/spi-fsl-lib.h +++ b/drivers/spi/spi-fsl-lib.h | |||
@@ -55,7 +55,6 @@ struct mpc8xxx_spi { | |||
55 | u32(*get_tx) (struct mpc8xxx_spi *); | 55 | u32(*get_tx) (struct mpc8xxx_spi *); |
56 | 56 | ||
57 | /* hooks for different controller driver */ | 57 | /* hooks for different controller driver */ |
58 | void (*spi_do_one_msg) (struct spi_message *m); | ||
59 | void (*spi_remove) (struct mpc8xxx_spi *mspi); | 58 | void (*spi_remove) (struct mpc8xxx_spi *mspi); |
60 | 59 | ||
61 | unsigned int count; | 60 | unsigned int count; |
@@ -78,12 +77,6 @@ struct mpc8xxx_spi { | |||
78 | int bits_per_word, int msb_first); | 77 | int bits_per_word, int msb_first); |
79 | #endif | 78 | #endif |
80 | 79 | ||
81 | struct workqueue_struct *workqueue; | ||
82 | struct work_struct work; | ||
83 | |||
84 | struct list_head queue; | ||
85 | spinlock_t lock; | ||
86 | |||
87 | struct completion done; | 80 | struct completion done; |
88 | }; | 81 | }; |
89 | 82 | ||
@@ -123,9 +116,8 @@ extern struct mpc8xxx_spi_probe_info *to_of_pinfo( | |||
123 | struct fsl_spi_platform_data *pdata); | 116 | struct fsl_spi_platform_data *pdata); |
124 | extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi, | 117 | extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi, |
125 | struct spi_transfer *t, unsigned int len); | 118 | struct spi_transfer *t, unsigned int len); |
126 | extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m); | ||
127 | extern const char *mpc8xxx_spi_strmode(unsigned int flags); | 119 | extern const char *mpc8xxx_spi_strmode(unsigned int flags); |
128 | extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem, | 120 | extern void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, |
129 | unsigned int irq); | 121 | unsigned int irq); |
130 | extern int mpc8xxx_spi_remove(struct device *dev); | 122 | extern int mpc8xxx_spi_remove(struct device *dev); |
131 | extern int of_mpc8xxx_spi_probe(struct platform_device *ofdev); | 123 | extern int of_mpc8xxx_spi_probe(struct platform_device *ofdev); |
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index ed792880c9d6..3b159364c459 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c | |||
@@ -353,7 +353,8 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, | |||
353 | return mpc8xxx_spi->count; | 353 | return mpc8xxx_spi->count; |
354 | } | 354 | } |
355 | 355 | ||
356 | static void fsl_spi_do_one_msg(struct spi_message *m) | 356 | static int fsl_spi_do_one_msg(struct spi_master *master, |
357 | struct spi_message *m) | ||
357 | { | 358 | { |
358 | struct spi_device *spi = m->spi; | 359 | struct spi_device *spi = m->spi; |
359 | struct spi_transfer *t, *first; | 360 | struct spi_transfer *t, *first; |
@@ -367,10 +368,9 @@ static void fsl_spi_do_one_msg(struct spi_message *m) | |||
367 | list_for_each_entry(t, &m->transfers, transfer_list) { | 368 | list_for_each_entry(t, &m->transfers, transfer_list) { |
368 | if ((first->bits_per_word != t->bits_per_word) || | 369 | if ((first->bits_per_word != t->bits_per_word) || |
369 | (first->speed_hz != t->speed_hz)) { | 370 | (first->speed_hz != t->speed_hz)) { |
370 | status = -EINVAL; | ||
371 | dev_err(&spi->dev, | 371 | dev_err(&spi->dev, |
372 | "bits_per_word/speed_hz should be same for the same SPI transfer\n"); | 372 | "bits_per_word/speed_hz should be same for the same SPI transfer\n"); |
373 | return; | 373 | return -EINVAL; |
374 | } | 374 | } |
375 | } | 375 | } |
376 | 376 | ||
@@ -408,8 +408,7 @@ static void fsl_spi_do_one_msg(struct spi_message *m) | |||
408 | } | 408 | } |
409 | 409 | ||
410 | m->status = status; | 410 | m->status = status; |
411 | if (m->complete) | 411 | spi_finalize_current_message(master); |
412 | m->complete(m->context); | ||
413 | 412 | ||
414 | if (status || !cs_change) { | 413 | if (status || !cs_change) { |
415 | ndelay(nsecs); | 414 | ndelay(nsecs); |
@@ -417,6 +416,7 @@ static void fsl_spi_do_one_msg(struct spi_message *m) | |||
417 | } | 416 | } |
418 | 417 | ||
419 | fsl_spi_setup_transfer(spi, NULL); | 418 | fsl_spi_setup_transfer(spi, NULL); |
419 | return 0; | ||
420 | } | 420 | } |
421 | 421 | ||
422 | static int fsl_spi_setup(struct spi_device *spi) | 422 | static int fsl_spi_setup(struct spi_device *spi) |
@@ -624,15 +624,13 @@ static struct spi_master * fsl_spi_probe(struct device *dev, | |||
624 | 624 | ||
625 | dev_set_drvdata(dev, master); | 625 | dev_set_drvdata(dev, master); |
626 | 626 | ||
627 | ret = mpc8xxx_spi_probe(dev, mem, irq); | 627 | mpc8xxx_spi_probe(dev, mem, irq); |
628 | if (ret) | ||
629 | goto err_probe; | ||
630 | 628 | ||
631 | master->setup = fsl_spi_setup; | 629 | master->setup = fsl_spi_setup; |
632 | master->cleanup = fsl_spi_cleanup; | 630 | master->cleanup = fsl_spi_cleanup; |
631 | master->transfer_one_message = fsl_spi_do_one_msg; | ||
633 | 632 | ||
634 | mpc8xxx_spi = spi_master_get_devdata(master); | 633 | mpc8xxx_spi = spi_master_get_devdata(master); |
635 | mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg; | ||
636 | mpc8xxx_spi->spi_remove = fsl_spi_remove; | 634 | mpc8xxx_spi->spi_remove = fsl_spi_remove; |
637 | mpc8xxx_spi->max_bits_per_word = 32; | 635 | mpc8xxx_spi->max_bits_per_word = 32; |
638 | mpc8xxx_spi->type = fsl_spi_get_type(dev); | 636 | mpc8xxx_spi->type = fsl_spi_get_type(dev); |
@@ -704,7 +702,6 @@ free_irq: | |||
704 | err_ioremap: | 702 | err_ioremap: |
705 | fsl_spi_cpm_free(mpc8xxx_spi); | 703 | fsl_spi_cpm_free(mpc8xxx_spi); |
706 | err_cpm_init: | 704 | err_cpm_init: |
707 | err_probe: | ||
708 | spi_master_put(master); | 705 | spi_master_put(master); |
709 | err: | 706 | err: |
710 | return ERR_PTR(ret); | 707 | return ERR_PTR(ret); |
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 9f595535cf27..4b600d4f8548 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c | |||
@@ -48,7 +48,7 @@ struct spi_gpio { | |||
48 | struct spi_bitbang bitbang; | 48 | struct spi_bitbang bitbang; |
49 | struct spi_gpio_platform_data pdata; | 49 | struct spi_gpio_platform_data pdata; |
50 | struct platform_device *pdev; | 50 | struct platform_device *pdev; |
51 | int cs_gpios[0]; | 51 | unsigned long cs_gpios[0]; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | /*----------------------------------------------------------------------*/ | 54 | /*----------------------------------------------------------------------*/ |
@@ -220,7 +220,7 @@ static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi, | |||
220 | static void spi_gpio_chipselect(struct spi_device *spi, int is_active) | 220 | static void spi_gpio_chipselect(struct spi_device *spi, int is_active) |
221 | { | 221 | { |
222 | struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); | 222 | struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); |
223 | unsigned int cs = spi_gpio->cs_gpios[spi->chip_select]; | 223 | unsigned long cs = spi_gpio->cs_gpios[spi->chip_select]; |
224 | 224 | ||
225 | /* set initial clock polarity */ | 225 | /* set initial clock polarity */ |
226 | if (is_active) | 226 | if (is_active) |
@@ -234,7 +234,7 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active) | |||
234 | 234 | ||
235 | static int spi_gpio_setup(struct spi_device *spi) | 235 | static int spi_gpio_setup(struct spi_device *spi) |
236 | { | 236 | { |
237 | unsigned int cs; | 237 | unsigned long cs; |
238 | int status = 0; | 238 | int status = 0; |
239 | struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); | 239 | struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); |
240 | struct device_node *np = spi->master->dev.of_node; | 240 | struct device_node *np = spi->master->dev.of_node; |
@@ -249,7 +249,7 @@ static int spi_gpio_setup(struct spi_device *spi) | |||
249 | /* | 249 | /* |
250 | * ... otherwise, take it from spi->controller_data | 250 | * ... otherwise, take it from spi->controller_data |
251 | */ | 251 | */ |
252 | cs = (unsigned int)(uintptr_t) spi->controller_data; | 252 | cs = (uintptr_t) spi->controller_data; |
253 | } | 253 | } |
254 | 254 | ||
255 | if (!spi->controller_state) { | 255 | if (!spi->controller_state) { |
@@ -277,7 +277,7 @@ static int spi_gpio_setup(struct spi_device *spi) | |||
277 | static void spi_gpio_cleanup(struct spi_device *spi) | 277 | static void spi_gpio_cleanup(struct spi_device *spi) |
278 | { | 278 | { |
279 | struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); | 279 | struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); |
280 | unsigned int cs = spi_gpio->cs_gpios[spi->chip_select]; | 280 | unsigned long cs = spi_gpio->cs_gpios[spi->chip_select]; |
281 | 281 | ||
282 | if (cs != SPI_GPIO_NO_CHIPSELECT) | 282 | if (cs != SPI_GPIO_NO_CHIPSELECT) |
283 | gpio_free(cs); | 283 | gpio_free(cs); |
@@ -413,6 +413,7 @@ static int spi_gpio_probe(struct platform_device *pdev) | |||
413 | struct spi_gpio_platform_data *pdata; | 413 | struct spi_gpio_platform_data *pdata; |
414 | u16 master_flags = 0; | 414 | u16 master_flags = 0; |
415 | bool use_of = 0; | 415 | bool use_of = 0; |
416 | int num_devices; | ||
416 | 417 | ||
417 | status = spi_gpio_probe_dt(pdev); | 418 | status = spi_gpio_probe_dt(pdev); |
418 | if (status < 0) | 419 | if (status < 0) |
@@ -422,16 +423,21 @@ static int spi_gpio_probe(struct platform_device *pdev) | |||
422 | 423 | ||
423 | pdata = dev_get_platdata(&pdev->dev); | 424 | pdata = dev_get_platdata(&pdev->dev); |
424 | #ifdef GENERIC_BITBANG | 425 | #ifdef GENERIC_BITBANG |
425 | if (!pdata || !pdata->num_chipselect) | 426 | if (!pdata || (!use_of && !pdata->num_chipselect)) |
426 | return -ENODEV; | 427 | return -ENODEV; |
427 | #endif | 428 | #endif |
428 | 429 | ||
430 | if (use_of && !SPI_N_CHIPSEL) | ||
431 | num_devices = 1; | ||
432 | else | ||
433 | num_devices = SPI_N_CHIPSEL; | ||
434 | |||
429 | status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags); | 435 | status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags); |
430 | if (status < 0) | 436 | if (status < 0) |
431 | return status; | 437 | return status; |
432 | 438 | ||
433 | master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) + | 439 | master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) + |
434 | (sizeof(int) * SPI_N_CHIPSEL)); | 440 | (sizeof(unsigned long) * num_devices)); |
435 | if (!master) { | 441 | if (!master) { |
436 | status = -ENOMEM; | 442 | status = -ENOMEM; |
437 | goto gpio_free; | 443 | goto gpio_free; |
@@ -446,7 +452,7 @@ static int spi_gpio_probe(struct platform_device *pdev) | |||
446 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); | 452 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); |
447 | master->flags = master_flags; | 453 | master->flags = master_flags; |
448 | master->bus_num = pdev->id; | 454 | master->bus_num = pdev->id; |
449 | master->num_chipselect = SPI_N_CHIPSEL; | 455 | master->num_chipselect = num_devices; |
450 | master->setup = spi_gpio_setup; | 456 | master->setup = spi_gpio_setup; |
451 | master->cleanup = spi_gpio_cleanup; | 457 | master->cleanup = spi_gpio_cleanup; |
452 | #ifdef CONFIG_OF | 458 | #ifdef CONFIG_OF |
@@ -461,9 +467,18 @@ static int spi_gpio_probe(struct platform_device *pdev) | |||
461 | * property of the node. | 467 | * property of the node. |
462 | */ | 468 | */ |
463 | 469 | ||
464 | for (i = 0; i < SPI_N_CHIPSEL; i++) | 470 | if (!SPI_N_CHIPSEL) |
465 | spi_gpio->cs_gpios[i] = | 471 | spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT; |
466 | of_get_named_gpio(np, "cs-gpios", i); | 472 | else |
473 | for (i = 0; i < SPI_N_CHIPSEL; i++) { | ||
474 | status = of_get_named_gpio(np, "cs-gpios", i); | ||
475 | if (status < 0) { | ||
476 | dev_err(&pdev->dev, | ||
477 | "invalid cs-gpios property\n"); | ||
478 | goto gpio_free; | ||
479 | } | ||
480 | spi_gpio->cs_gpios[i] = status; | ||
481 | } | ||
467 | } | 482 | } |
468 | #endif | 483 | #endif |
469 | 484 | ||
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c new file mode 100644 index 000000000000..43781c9fe521 --- /dev/null +++ b/drivers/spi/spi-img-spfi.c | |||
@@ -0,0 +1,746 @@ | |||
1 | /* | ||
2 | * IMG SPFI controller driver | ||
3 | * | ||
4 | * Copyright (C) 2007,2008,2013 Imagination Technologies Ltd. | ||
5 | * Copyright (C) 2014 Google, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/dmaengine.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/pm_runtime.h> | ||
22 | #include <linux/scatterlist.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/spi/spi.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | |||
27 | #define SPFI_DEVICE_PARAMETER(x) (0x00 + 0x4 * (x)) | ||
28 | #define SPFI_DEVICE_PARAMETER_BITCLK_SHIFT 24 | ||
29 | #define SPFI_DEVICE_PARAMETER_BITCLK_MASK 0xff | ||
30 | #define SPFI_DEVICE_PARAMETER_CSSETUP_SHIFT 16 | ||
31 | #define SPFI_DEVICE_PARAMETER_CSSETUP_MASK 0xff | ||
32 | #define SPFI_DEVICE_PARAMETER_CSHOLD_SHIFT 8 | ||
33 | #define SPFI_DEVICE_PARAMETER_CSHOLD_MASK 0xff | ||
34 | #define SPFI_DEVICE_PARAMETER_CSDELAY_SHIFT 0 | ||
35 | #define SPFI_DEVICE_PARAMETER_CSDELAY_MASK 0xff | ||
36 | |||
37 | #define SPFI_CONTROL 0x14 | ||
38 | #define SPFI_CONTROL_CONTINUE BIT(12) | ||
39 | #define SPFI_CONTROL_SOFT_RESET BIT(11) | ||
40 | #define SPFI_CONTROL_SEND_DMA BIT(10) | ||
41 | #define SPFI_CONTROL_GET_DMA BIT(9) | ||
42 | #define SPFI_CONTROL_TMODE_SHIFT 5 | ||
43 | #define SPFI_CONTROL_TMODE_MASK 0x7 | ||
44 | #define SPFI_CONTROL_TMODE_SINGLE 0 | ||
45 | #define SPFI_CONTROL_TMODE_DUAL 1 | ||
46 | #define SPFI_CONTROL_TMODE_QUAD 2 | ||
47 | #define SPFI_CONTROL_SPFI_EN BIT(0) | ||
48 | |||
49 | #define SPFI_TRANSACTION 0x18 | ||
50 | #define SPFI_TRANSACTION_TSIZE_SHIFT 16 | ||
51 | #define SPFI_TRANSACTION_TSIZE_MASK 0xffff | ||
52 | |||
53 | #define SPFI_PORT_STATE 0x1c | ||
54 | #define SPFI_PORT_STATE_DEV_SEL_SHIFT 20 | ||
55 | #define SPFI_PORT_STATE_DEV_SEL_MASK 0x7 | ||
56 | #define SPFI_PORT_STATE_CK_POL(x) BIT(19 - (x)) | ||
57 | #define SPFI_PORT_STATE_CK_PHASE(x) BIT(14 - (x)) | ||
58 | |||
59 | #define SPFI_TX_32BIT_VALID_DATA 0x20 | ||
60 | #define SPFI_TX_8BIT_VALID_DATA 0x24 | ||
61 | #define SPFI_RX_32BIT_VALID_DATA 0x28 | ||
62 | #define SPFI_RX_8BIT_VALID_DATA 0x2c | ||
63 | |||
64 | #define SPFI_INTERRUPT_STATUS 0x30 | ||
65 | #define SPFI_INTERRUPT_ENABLE 0x34 | ||
66 | #define SPFI_INTERRUPT_CLEAR 0x38 | ||
67 | #define SPFI_INTERRUPT_IACCESS BIT(12) | ||
68 | #define SPFI_INTERRUPT_GDEX8BIT BIT(11) | ||
69 | #define SPFI_INTERRUPT_ALLDONETRIG BIT(9) | ||
70 | #define SPFI_INTERRUPT_GDFUL BIT(8) | ||
71 | #define SPFI_INTERRUPT_GDHF BIT(7) | ||
72 | #define SPFI_INTERRUPT_GDEX32BIT BIT(6) | ||
73 | #define SPFI_INTERRUPT_GDTRIG BIT(5) | ||
74 | #define SPFI_INTERRUPT_SDFUL BIT(3) | ||
75 | #define SPFI_INTERRUPT_SDHF BIT(2) | ||
76 | #define SPFI_INTERRUPT_SDE BIT(1) | ||
77 | #define SPFI_INTERRUPT_SDTRIG BIT(0) | ||
78 | |||
79 | /* | ||
80 | * There are four parallel FIFOs of 16 bytes each. The word buffer | ||
81 | * (*_32BIT_VALID_DATA) accesses all four FIFOs at once, resulting in an | ||
82 | * effective FIFO size of 64 bytes. The byte buffer (*_8BIT_VALID_DATA) | ||
83 | * accesses only a single FIFO, resulting in an effective FIFO size of | ||
84 | * 16 bytes. | ||
85 | */ | ||
86 | #define SPFI_32BIT_FIFO_SIZE 64 | ||
87 | #define SPFI_8BIT_FIFO_SIZE 16 | ||
88 | |||
89 | struct img_spfi { | ||
90 | struct device *dev; | ||
91 | struct spi_master *master; | ||
92 | spinlock_t lock; | ||
93 | |||
94 | void __iomem *regs; | ||
95 | phys_addr_t phys; | ||
96 | int irq; | ||
97 | struct clk *spfi_clk; | ||
98 | struct clk *sys_clk; | ||
99 | |||
100 | struct dma_chan *rx_ch; | ||
101 | struct dma_chan *tx_ch; | ||
102 | bool tx_dma_busy; | ||
103 | bool rx_dma_busy; | ||
104 | }; | ||
105 | |||
106 | static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) | ||
107 | { | ||
108 | return readl(spfi->regs + reg); | ||
109 | } | ||
110 | |||
111 | static inline void spfi_writel(struct img_spfi *spfi, u32 val, u32 reg) | ||
112 | { | ||
113 | writel(val, spfi->regs + reg); | ||
114 | } | ||
115 | |||
116 | static inline void spfi_start(struct img_spfi *spfi) | ||
117 | { | ||
118 | u32 val; | ||
119 | |||
120 | val = spfi_readl(spfi, SPFI_CONTROL); | ||
121 | val |= SPFI_CONTROL_SPFI_EN; | ||
122 | spfi_writel(spfi, val, SPFI_CONTROL); | ||
123 | } | ||
124 | |||
125 | static inline void spfi_stop(struct img_spfi *spfi) | ||
126 | { | ||
127 | u32 val; | ||
128 | |||
129 | val = spfi_readl(spfi, SPFI_CONTROL); | ||
130 | val &= ~SPFI_CONTROL_SPFI_EN; | ||
131 | spfi_writel(spfi, val, SPFI_CONTROL); | ||
132 | } | ||
133 | |||
134 | static inline void spfi_reset(struct img_spfi *spfi) | ||
135 | { | ||
136 | spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL); | ||
137 | udelay(1); | ||
138 | spfi_writel(spfi, 0, SPFI_CONTROL); | ||
139 | } | ||
140 | |||
141 | static void spfi_flush_tx_fifo(struct img_spfi *spfi) | ||
142 | { | ||
143 | unsigned long timeout = jiffies + msecs_to_jiffies(10); | ||
144 | |||
145 | spfi_writel(spfi, SPFI_INTERRUPT_SDE, SPFI_INTERRUPT_CLEAR); | ||
146 | while (time_before(jiffies, timeout)) { | ||
147 | if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & | ||
148 | SPFI_INTERRUPT_SDE) | ||
149 | return; | ||
150 | cpu_relax(); | ||
151 | } | ||
152 | |||
153 | dev_err(spfi->dev, "Timed out waiting for FIFO to drain\n"); | ||
154 | spfi_reset(spfi); | ||
155 | } | ||
156 | |||
157 | static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf, | ||
158 | unsigned int max) | ||
159 | { | ||
160 | unsigned int count = 0; | ||
161 | u32 status; | ||
162 | |||
163 | while (count < max) { | ||
164 | spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR); | ||
165 | status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); | ||
166 | if (status & SPFI_INTERRUPT_SDFUL) | ||
167 | break; | ||
168 | spfi_writel(spfi, buf[count / 4], SPFI_TX_32BIT_VALID_DATA); | ||
169 | count += 4; | ||
170 | } | ||
171 | |||
172 | return count; | ||
173 | } | ||
174 | |||
175 | static unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf, | ||
176 | unsigned int max) | ||
177 | { | ||
178 | unsigned int count = 0; | ||
179 | u32 status; | ||
180 | |||
181 | while (count < max) { | ||
182 | spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR); | ||
183 | status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); | ||
184 | if (status & SPFI_INTERRUPT_SDFUL) | ||
185 | break; | ||
186 | spfi_writel(spfi, buf[count], SPFI_TX_8BIT_VALID_DATA); | ||
187 | count++; | ||
188 | } | ||
189 | |||
190 | return count; | ||
191 | } | ||
192 | |||
193 | static unsigned int spfi_pio_read32(struct img_spfi *spfi, u32 *buf, | ||
194 | unsigned int max) | ||
195 | { | ||
196 | unsigned int count = 0; | ||
197 | u32 status; | ||
198 | |||
199 | while (count < max) { | ||
200 | spfi_writel(spfi, SPFI_INTERRUPT_GDEX32BIT, | ||
201 | SPFI_INTERRUPT_CLEAR); | ||
202 | status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); | ||
203 | if (!(status & SPFI_INTERRUPT_GDEX32BIT)) | ||
204 | break; | ||
205 | buf[count / 4] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA); | ||
206 | count += 4; | ||
207 | } | ||
208 | |||
209 | return count; | ||
210 | } | ||
211 | |||
212 | static unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf, | ||
213 | unsigned int max) | ||
214 | { | ||
215 | unsigned int count = 0; | ||
216 | u32 status; | ||
217 | |||
218 | while (count < max) { | ||
219 | spfi_writel(spfi, SPFI_INTERRUPT_GDEX8BIT, | ||
220 | SPFI_INTERRUPT_CLEAR); | ||
221 | status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); | ||
222 | if (!(status & SPFI_INTERRUPT_GDEX8BIT)) | ||
223 | break; | ||
224 | buf[count] = spfi_readl(spfi, SPFI_RX_8BIT_VALID_DATA); | ||
225 | count++; | ||
226 | } | ||
227 | |||
228 | return count; | ||
229 | } | ||
230 | |||
231 | static int img_spfi_start_pio(struct spi_master *master, | ||
232 | struct spi_device *spi, | ||
233 | struct spi_transfer *xfer) | ||
234 | { | ||
235 | struct img_spfi *spfi = spi_master_get_devdata(spi->master); | ||
236 | unsigned int tx_bytes = 0, rx_bytes = 0; | ||
237 | const void *tx_buf = xfer->tx_buf; | ||
238 | void *rx_buf = xfer->rx_buf; | ||
239 | unsigned long timeout; | ||
240 | |||
241 | if (tx_buf) | ||
242 | tx_bytes = xfer->len; | ||
243 | if (rx_buf) | ||
244 | rx_bytes = xfer->len; | ||
245 | |||
246 | spfi_start(spfi); | ||
247 | |||
248 | timeout = jiffies + | ||
249 | msecs_to_jiffies(xfer->len * 8 * 1000 / xfer->speed_hz + 100); | ||
250 | while ((tx_bytes > 0 || rx_bytes > 0) && | ||
251 | time_before(jiffies, timeout)) { | ||
252 | unsigned int tx_count, rx_count; | ||
253 | |||
254 | switch (xfer->bits_per_word) { | ||
255 | case 32: | ||
256 | tx_count = spfi_pio_write32(spfi, tx_buf, tx_bytes); | ||
257 | rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes); | ||
258 | break; | ||
259 | case 8: | ||
260 | default: | ||
261 | tx_count = spfi_pio_write8(spfi, tx_buf, tx_bytes); | ||
262 | rx_count = spfi_pio_read8(spfi, rx_buf, rx_bytes); | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | tx_buf += tx_count; | ||
267 | rx_buf += rx_count; | ||
268 | tx_bytes -= tx_count; | ||
269 | rx_bytes -= rx_count; | ||
270 | |||
271 | cpu_relax(); | ||
272 | } | ||
273 | |||
274 | if (rx_bytes > 0 || tx_bytes > 0) { | ||
275 | dev_err(spfi->dev, "PIO transfer timed out\n"); | ||
276 | spfi_reset(spfi); | ||
277 | return -ETIMEDOUT; | ||
278 | } | ||
279 | |||
280 | if (tx_buf) | ||
281 | spfi_flush_tx_fifo(spfi); | ||
282 | spfi_stop(spfi); | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static void img_spfi_dma_rx_cb(void *data) | ||
288 | { | ||
289 | struct img_spfi *spfi = data; | ||
290 | unsigned long flags; | ||
291 | |||
292 | spin_lock_irqsave(&spfi->lock, flags); | ||
293 | |||
294 | spfi->rx_dma_busy = false; | ||
295 | if (!spfi->tx_dma_busy) { | ||
296 | spfi_stop(spfi); | ||
297 | spi_finalize_current_transfer(spfi->master); | ||
298 | } | ||
299 | |||
300 | spin_unlock_irqrestore(&spfi->lock, flags); | ||
301 | } | ||
302 | |||
303 | static void img_spfi_dma_tx_cb(void *data) | ||
304 | { | ||
305 | struct img_spfi *spfi = data; | ||
306 | unsigned long flags; | ||
307 | |||
308 | spfi_flush_tx_fifo(spfi); | ||
309 | |||
310 | spin_lock_irqsave(&spfi->lock, flags); | ||
311 | |||
312 | spfi->tx_dma_busy = false; | ||
313 | if (!spfi->rx_dma_busy) { | ||
314 | spfi_stop(spfi); | ||
315 | spi_finalize_current_transfer(spfi->master); | ||
316 | } | ||
317 | |||
318 | spin_unlock_irqrestore(&spfi->lock, flags); | ||
319 | } | ||
320 | |||
321 | static int img_spfi_start_dma(struct spi_master *master, | ||
322 | struct spi_device *spi, | ||
323 | struct spi_transfer *xfer) | ||
324 | { | ||
325 | struct img_spfi *spfi = spi_master_get_devdata(spi->master); | ||
326 | struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL; | ||
327 | struct dma_slave_config rxconf, txconf; | ||
328 | |||
329 | spfi->rx_dma_busy = false; | ||
330 | spfi->tx_dma_busy = false; | ||
331 | |||
332 | if (xfer->rx_buf) { | ||
333 | rxconf.direction = DMA_DEV_TO_MEM; | ||
334 | switch (xfer->bits_per_word) { | ||
335 | case 32: | ||
336 | rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA; | ||
337 | rxconf.src_addr_width = 4; | ||
338 | rxconf.src_maxburst = 4; | ||
339 | break; | ||
340 | case 8: | ||
341 | default: | ||
342 | rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA; | ||
343 | rxconf.src_addr_width = 1; | ||
344 | rxconf.src_maxburst = 1; | ||
345 | } | ||
346 | dmaengine_slave_config(spfi->rx_ch, &rxconf); | ||
347 | |||
348 | rxdesc = dmaengine_prep_slave_sg(spfi->rx_ch, xfer->rx_sg.sgl, | ||
349 | xfer->rx_sg.nents, | ||
350 | DMA_DEV_TO_MEM, | ||
351 | DMA_PREP_INTERRUPT); | ||
352 | if (!rxdesc) | ||
353 | goto stop_dma; | ||
354 | |||
355 | rxdesc->callback = img_spfi_dma_rx_cb; | ||
356 | rxdesc->callback_param = spfi; | ||
357 | } | ||
358 | |||
359 | if (xfer->tx_buf) { | ||
360 | txconf.direction = DMA_MEM_TO_DEV; | ||
361 | switch (xfer->bits_per_word) { | ||
362 | case 32: | ||
363 | txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA; | ||
364 | txconf.dst_addr_width = 4; | ||
365 | txconf.dst_maxburst = 4; | ||
366 | break; | ||
367 | case 8: | ||
368 | default: | ||
369 | txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA; | ||
370 | txconf.dst_addr_width = 1; | ||
371 | txconf.dst_maxburst = 1; | ||
372 | break; | ||
373 | } | ||
374 | dmaengine_slave_config(spfi->tx_ch, &txconf); | ||
375 | |||
376 | txdesc = dmaengine_prep_slave_sg(spfi->tx_ch, xfer->tx_sg.sgl, | ||
377 | xfer->tx_sg.nents, | ||
378 | DMA_MEM_TO_DEV, | ||
379 | DMA_PREP_INTERRUPT); | ||
380 | if (!txdesc) | ||
381 | goto stop_dma; | ||
382 | |||
383 | txdesc->callback = img_spfi_dma_tx_cb; | ||
384 | txdesc->callback_param = spfi; | ||
385 | } | ||
386 | |||
387 | if (xfer->rx_buf) { | ||
388 | spfi->rx_dma_busy = true; | ||
389 | dmaengine_submit(rxdesc); | ||
390 | dma_async_issue_pending(spfi->rx_ch); | ||
391 | } | ||
392 | |||
393 | if (xfer->tx_buf) { | ||
394 | spfi->tx_dma_busy = true; | ||
395 | dmaengine_submit(txdesc); | ||
396 | dma_async_issue_pending(spfi->tx_ch); | ||
397 | } | ||
398 | |||
399 | spfi_start(spfi); | ||
400 | |||
401 | return 1; | ||
402 | |||
403 | stop_dma: | ||
404 | dmaengine_terminate_all(spfi->rx_ch); | ||
405 | dmaengine_terminate_all(spfi->tx_ch); | ||
406 | return -EIO; | ||
407 | } | ||
408 | |||
409 | static void img_spfi_config(struct spi_master *master, struct spi_device *spi, | ||
410 | struct spi_transfer *xfer) | ||
411 | { | ||
412 | struct img_spfi *spfi = spi_master_get_devdata(spi->master); | ||
413 | u32 val, div; | ||
414 | |||
415 | /* | ||
416 | * output = spfi_clk * (BITCLK / 512), where BITCLK must be a | ||
417 | * power of 2 up to 256 (where 255 == 256 since BITCLK is 8 bits) | ||
418 | */ | ||
419 | div = DIV_ROUND_UP(master->max_speed_hz, xfer->speed_hz); | ||
420 | div = clamp(512 / (1 << get_count_order(div)), 1, 255); | ||
421 | |||
422 | val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(spi->chip_select)); | ||
423 | val &= ~(SPFI_DEVICE_PARAMETER_BITCLK_MASK << | ||
424 | SPFI_DEVICE_PARAMETER_BITCLK_SHIFT); | ||
425 | val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT; | ||
426 | spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select)); | ||
427 | |||
428 | val = spfi_readl(spfi, SPFI_CONTROL); | ||
429 | val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA); | ||
430 | if (xfer->tx_buf) | ||
431 | val |= SPFI_CONTROL_SEND_DMA; | ||
432 | if (xfer->rx_buf) | ||
433 | val |= SPFI_CONTROL_GET_DMA; | ||
434 | val &= ~(SPFI_CONTROL_TMODE_MASK << SPFI_CONTROL_TMODE_SHIFT); | ||
435 | if (xfer->tx_nbits == SPI_NBITS_DUAL && | ||
436 | xfer->rx_nbits == SPI_NBITS_DUAL) | ||
437 | val |= SPFI_CONTROL_TMODE_DUAL << SPFI_CONTROL_TMODE_SHIFT; | ||
438 | else if (xfer->tx_nbits == SPI_NBITS_QUAD && | ||
439 | xfer->rx_nbits == SPI_NBITS_QUAD) | ||
440 | val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT; | ||
441 | val &= ~SPFI_CONTROL_CONTINUE; | ||
442 | if (!xfer->cs_change && !list_is_last(&xfer->transfer_list, | ||
443 | &master->cur_msg->transfers)) | ||
444 | val |= SPFI_CONTROL_CONTINUE; | ||
445 | spfi_writel(spfi, val, SPFI_CONTROL); | ||
446 | |||
447 | val = spfi_readl(spfi, SPFI_PORT_STATE); | ||
448 | if (spi->mode & SPI_CPHA) | ||
449 | val |= SPFI_PORT_STATE_CK_PHASE(spi->chip_select); | ||
450 | else | ||
451 | val &= ~SPFI_PORT_STATE_CK_PHASE(spi->chip_select); | ||
452 | if (spi->mode & SPI_CPOL) | ||
453 | val |= SPFI_PORT_STATE_CK_POL(spi->chip_select); | ||
454 | else | ||
455 | val &= ~SPFI_PORT_STATE_CK_POL(spi->chip_select); | ||
456 | spfi_writel(spfi, val, SPFI_PORT_STATE); | ||
457 | |||
458 | spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT, | ||
459 | SPFI_TRANSACTION); | ||
460 | } | ||
461 | |||
462 | static int img_spfi_transfer_one(struct spi_master *master, | ||
463 | struct spi_device *spi, | ||
464 | struct spi_transfer *xfer) | ||
465 | { | ||
466 | struct img_spfi *spfi = spi_master_get_devdata(spi->master); | ||
467 | bool dma_reset = false; | ||
468 | unsigned long flags; | ||
469 | int ret; | ||
470 | |||
471 | /* | ||
472 | * Stop all DMA and reset the controller if the previous transaction | ||
473 | * timed-out and never completed it's DMA. | ||
474 | */ | ||
475 | spin_lock_irqsave(&spfi->lock, flags); | ||
476 | if (spfi->tx_dma_busy || spfi->rx_dma_busy) { | ||
477 | dev_err(spfi->dev, "SPI DMA still busy\n"); | ||
478 | dma_reset = true; | ||
479 | } | ||
480 | spin_unlock_irqrestore(&spfi->lock, flags); | ||
481 | |||
482 | if (dma_reset) { | ||
483 | dmaengine_terminate_all(spfi->tx_ch); | ||
484 | dmaengine_terminate_all(spfi->rx_ch); | ||
485 | spfi_reset(spfi); | ||
486 | } | ||
487 | |||
488 | img_spfi_config(master, spi, xfer); | ||
489 | if (master->can_dma && master->can_dma(master, spi, xfer)) | ||
490 | ret = img_spfi_start_dma(master, spi, xfer); | ||
491 | else | ||
492 | ret = img_spfi_start_pio(master, spi, xfer); | ||
493 | |||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | static void img_spfi_set_cs(struct spi_device *spi, bool enable) | ||
498 | { | ||
499 | struct img_spfi *spfi = spi_master_get_devdata(spi->master); | ||
500 | u32 val; | ||
501 | |||
502 | val = spfi_readl(spfi, SPFI_PORT_STATE); | ||
503 | val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << SPFI_PORT_STATE_DEV_SEL_SHIFT); | ||
504 | val |= spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT; | ||
505 | spfi_writel(spfi, val, SPFI_PORT_STATE); | ||
506 | } | ||
507 | |||
508 | static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi, | ||
509 | struct spi_transfer *xfer) | ||
510 | { | ||
511 | if (xfer->bits_per_word == 8 && xfer->len > SPFI_8BIT_FIFO_SIZE) | ||
512 | return true; | ||
513 | if (xfer->bits_per_word == 32 && xfer->len > SPFI_32BIT_FIFO_SIZE) | ||
514 | return true; | ||
515 | return false; | ||
516 | } | ||
517 | |||
518 | static irqreturn_t img_spfi_irq(int irq, void *dev_id) | ||
519 | { | ||
520 | struct img_spfi *spfi = (struct img_spfi *)dev_id; | ||
521 | u32 status; | ||
522 | |||
523 | status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); | ||
524 | if (status & SPFI_INTERRUPT_IACCESS) { | ||
525 | spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_CLEAR); | ||
526 | dev_err(spfi->dev, "Illegal access interrupt"); | ||
527 | return IRQ_HANDLED; | ||
528 | } | ||
529 | |||
530 | return IRQ_NONE; | ||
531 | } | ||
532 | |||
533 | static int img_spfi_probe(struct platform_device *pdev) | ||
534 | { | ||
535 | struct spi_master *master; | ||
536 | struct img_spfi *spfi; | ||
537 | struct resource *res; | ||
538 | int ret; | ||
539 | |||
540 | master = spi_alloc_master(&pdev->dev, sizeof(*spfi)); | ||
541 | if (!master) | ||
542 | return -ENOMEM; | ||
543 | platform_set_drvdata(pdev, master); | ||
544 | |||
545 | spfi = spi_master_get_devdata(master); | ||
546 | spfi->dev = &pdev->dev; | ||
547 | spfi->master = master; | ||
548 | spin_lock_init(&spfi->lock); | ||
549 | |||
550 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
551 | spfi->regs = devm_ioremap_resource(spfi->dev, res); | ||
552 | if (IS_ERR(spfi->regs)) { | ||
553 | ret = PTR_ERR(spfi->regs); | ||
554 | goto put_spi; | ||
555 | } | ||
556 | spfi->phys = res->start; | ||
557 | |||
558 | spfi->irq = platform_get_irq(pdev, 0); | ||
559 | if (spfi->irq < 0) { | ||
560 | ret = spfi->irq; | ||
561 | goto put_spi; | ||
562 | } | ||
563 | ret = devm_request_irq(spfi->dev, spfi->irq, img_spfi_irq, | ||
564 | IRQ_TYPE_LEVEL_HIGH, dev_name(spfi->dev), spfi); | ||
565 | if (ret) | ||
566 | goto put_spi; | ||
567 | |||
568 | spfi->sys_clk = devm_clk_get(spfi->dev, "sys"); | ||
569 | if (IS_ERR(spfi->sys_clk)) { | ||
570 | ret = PTR_ERR(spfi->sys_clk); | ||
571 | goto put_spi; | ||
572 | } | ||
573 | spfi->spfi_clk = devm_clk_get(spfi->dev, "spfi"); | ||
574 | if (IS_ERR(spfi->spfi_clk)) { | ||
575 | ret = PTR_ERR(spfi->spfi_clk); | ||
576 | goto put_spi; | ||
577 | } | ||
578 | |||
579 | ret = clk_prepare_enable(spfi->sys_clk); | ||
580 | if (ret) | ||
581 | goto put_spi; | ||
582 | ret = clk_prepare_enable(spfi->spfi_clk); | ||
583 | if (ret) | ||
584 | goto disable_pclk; | ||
585 | |||
586 | spfi_reset(spfi); | ||
587 | /* | ||
588 | * Only enable the error (IACCESS) interrupt. In PIO mode we'll | ||
589 | * poll the status of the FIFOs. | ||
590 | */ | ||
591 | spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_ENABLE); | ||
592 | |||
593 | master->auto_runtime_pm = true; | ||
594 | master->bus_num = pdev->id; | ||
595 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL; | ||
596 | if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode")) | ||
597 | master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD; | ||
598 | master->num_chipselect = 5; | ||
599 | master->dev.of_node = pdev->dev.of_node; | ||
600 | master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8); | ||
601 | master->max_speed_hz = clk_get_rate(spfi->spfi_clk); | ||
602 | master->min_speed_hz = master->max_speed_hz / 512; | ||
603 | |||
604 | master->set_cs = img_spfi_set_cs; | ||
605 | master->transfer_one = img_spfi_transfer_one; | ||
606 | |||
607 | spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx"); | ||
608 | spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx"); | ||
609 | if (!spfi->tx_ch || !spfi->rx_ch) { | ||
610 | if (spfi->tx_ch) | ||
611 | dma_release_channel(spfi->tx_ch); | ||
612 | if (spfi->rx_ch) | ||
613 | dma_release_channel(spfi->rx_ch); | ||
614 | dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n"); | ||
615 | } else { | ||
616 | master->dma_tx = spfi->tx_ch; | ||
617 | master->dma_rx = spfi->rx_ch; | ||
618 | master->can_dma = img_spfi_can_dma; | ||
619 | } | ||
620 | |||
621 | pm_runtime_set_active(spfi->dev); | ||
622 | pm_runtime_enable(spfi->dev); | ||
623 | |||
624 | ret = devm_spi_register_master(spfi->dev, master); | ||
625 | if (ret) | ||
626 | goto disable_pm; | ||
627 | |||
628 | return 0; | ||
629 | |||
630 | disable_pm: | ||
631 | pm_runtime_disable(spfi->dev); | ||
632 | if (spfi->rx_ch) | ||
633 | dma_release_channel(spfi->rx_ch); | ||
634 | if (spfi->tx_ch) | ||
635 | dma_release_channel(spfi->tx_ch); | ||
636 | clk_disable_unprepare(spfi->spfi_clk); | ||
637 | disable_pclk: | ||
638 | clk_disable_unprepare(spfi->sys_clk); | ||
639 | put_spi: | ||
640 | spi_master_put(master); | ||
641 | |||
642 | return ret; | ||
643 | } | ||
644 | |||
645 | static int img_spfi_remove(struct platform_device *pdev) | ||
646 | { | ||
647 | struct spi_master *master = platform_get_drvdata(pdev); | ||
648 | struct img_spfi *spfi = spi_master_get_devdata(master); | ||
649 | |||
650 | if (spfi->tx_ch) | ||
651 | dma_release_channel(spfi->tx_ch); | ||
652 | if (spfi->rx_ch) | ||
653 | dma_release_channel(spfi->rx_ch); | ||
654 | |||
655 | pm_runtime_disable(spfi->dev); | ||
656 | if (!pm_runtime_status_suspended(spfi->dev)) { | ||
657 | clk_disable_unprepare(spfi->spfi_clk); | ||
658 | clk_disable_unprepare(spfi->sys_clk); | ||
659 | } | ||
660 | |||
661 | spi_master_put(master); | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | #ifdef CONFIG_PM_RUNTIME | ||
667 | static int img_spfi_runtime_suspend(struct device *dev) | ||
668 | { | ||
669 | struct spi_master *master = dev_get_drvdata(dev); | ||
670 | struct img_spfi *spfi = spi_master_get_devdata(master); | ||
671 | |||
672 | clk_disable_unprepare(spfi->spfi_clk); | ||
673 | clk_disable_unprepare(spfi->sys_clk); | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int img_spfi_runtime_resume(struct device *dev) | ||
679 | { | ||
680 | struct spi_master *master = dev_get_drvdata(dev); | ||
681 | struct img_spfi *spfi = spi_master_get_devdata(master); | ||
682 | int ret; | ||
683 | |||
684 | ret = clk_prepare_enable(spfi->sys_clk); | ||
685 | if (ret) | ||
686 | return ret; | ||
687 | ret = clk_prepare_enable(spfi->spfi_clk); | ||
688 | if (ret) { | ||
689 | clk_disable_unprepare(spfi->sys_clk); | ||
690 | return ret; | ||
691 | } | ||
692 | |||
693 | return 0; | ||
694 | } | ||
695 | #endif /* CONFIG_PM_RUNTIME */ | ||
696 | |||
697 | #ifdef CONFIG_PM_SLEEP | ||
698 | static int img_spfi_suspend(struct device *dev) | ||
699 | { | ||
700 | struct spi_master *master = dev_get_drvdata(dev); | ||
701 | |||
702 | return spi_master_suspend(master); | ||
703 | } | ||
704 | |||
705 | static int img_spfi_resume(struct device *dev) | ||
706 | { | ||
707 | struct spi_master *master = dev_get_drvdata(dev); | ||
708 | struct img_spfi *spfi = spi_master_get_devdata(master); | ||
709 | int ret; | ||
710 | |||
711 | ret = pm_runtime_get_sync(dev); | ||
712 | if (ret) | ||
713 | return ret; | ||
714 | spfi_reset(spfi); | ||
715 | pm_runtime_put(dev); | ||
716 | |||
717 | return spi_master_resume(master); | ||
718 | } | ||
719 | #endif /* CONFIG_PM_SLEEP */ | ||
720 | |||
721 | static const struct dev_pm_ops img_spfi_pm_ops = { | ||
722 | SET_RUNTIME_PM_OPS(img_spfi_runtime_suspend, img_spfi_runtime_resume, | ||
723 | NULL) | ||
724 | SET_SYSTEM_SLEEP_PM_OPS(img_spfi_suspend, img_spfi_resume) | ||
725 | }; | ||
726 | |||
727 | static const struct of_device_id img_spfi_of_match[] = { | ||
728 | { .compatible = "img,spfi", }, | ||
729 | { }, | ||
730 | }; | ||
731 | MODULE_DEVICE_TABLE(of, img_spfi_of_match); | ||
732 | |||
733 | static struct platform_driver img_spfi_driver = { | ||
734 | .driver = { | ||
735 | .name = "img-spfi", | ||
736 | .pm = &img_spfi_pm_ops, | ||
737 | .of_match_table = of_match_ptr(img_spfi_of_match), | ||
738 | }, | ||
739 | .probe = img_spfi_probe, | ||
740 | .remove = img_spfi_remove, | ||
741 | }; | ||
742 | module_platform_driver(img_spfi_driver); | ||
743 | |||
744 | MODULE_DESCRIPTION("IMG SPFI controller driver"); | ||
745 | MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); | ||
746 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c new file mode 100644 index 000000000000..0e48f8c2037d --- /dev/null +++ b/drivers/spi/spi-meson-spifc.c | |||
@@ -0,0 +1,462 @@ | |||
1 | /* | ||
2 | * Driver for Amlogic Meson SPI flash controller (SPIFC) | ||
3 | * | ||
4 | * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * You should have received a copy of the GNU General Public License | ||
11 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | #include <linux/regmap.h> | ||
24 | #include <linux/spi/spi.h> | ||
25 | #include <linux/types.h> | ||
26 | |||
27 | /* register map */ | ||
28 | #define REG_CMD 0x00 | ||
29 | #define REG_ADDR 0x04 | ||
30 | #define REG_CTRL 0x08 | ||
31 | #define REG_CTRL1 0x0c | ||
32 | #define REG_STATUS 0x10 | ||
33 | #define REG_CTRL2 0x14 | ||
34 | #define REG_CLOCK 0x18 | ||
35 | #define REG_USER 0x1c | ||
36 | #define REG_USER1 0x20 | ||
37 | #define REG_USER2 0x24 | ||
38 | #define REG_USER3 0x28 | ||
39 | #define REG_USER4 0x2c | ||
40 | #define REG_SLAVE 0x30 | ||
41 | #define REG_SLAVE1 0x34 | ||
42 | #define REG_SLAVE2 0x38 | ||
43 | #define REG_SLAVE3 0x3c | ||
44 | #define REG_C0 0x40 | ||
45 | #define REG_B8 0x60 | ||
46 | #define REG_MAX 0x7c | ||
47 | |||
48 | /* register fields */ | ||
49 | #define CMD_USER BIT(18) | ||
50 | #define CTRL_ENABLE_AHB BIT(17) | ||
51 | #define CLOCK_SOURCE BIT(31) | ||
52 | #define CLOCK_DIV_SHIFT 12 | ||
53 | #define CLOCK_DIV_MASK (0x3f << CLOCK_DIV_SHIFT) | ||
54 | #define CLOCK_CNT_HIGH_SHIFT 6 | ||
55 | #define CLOCK_CNT_HIGH_MASK (0x3f << CLOCK_CNT_HIGH_SHIFT) | ||
56 | #define CLOCK_CNT_LOW_SHIFT 0 | ||
57 | #define CLOCK_CNT_LOW_MASK (0x3f << CLOCK_CNT_LOW_SHIFT) | ||
58 | #define USER_DIN_EN_MS BIT(0) | ||
59 | #define USER_CMP_MODE BIT(2) | ||
60 | #define USER_UC_DOUT_SEL BIT(27) | ||
61 | #define USER_UC_DIN_SEL BIT(28) | ||
62 | #define USER_UC_MASK ((BIT(5) - 1) << 27) | ||
63 | #define USER1_BN_UC_DOUT_SHIFT 17 | ||
64 | #define USER1_BN_UC_DOUT_MASK (0xff << 16) | ||
65 | #define USER1_BN_UC_DIN_SHIFT 8 | ||
66 | #define USER1_BN_UC_DIN_MASK (0xff << 8) | ||
67 | #define USER4_CS_ACT BIT(30) | ||
68 | #define SLAVE_TRST_DONE BIT(4) | ||
69 | #define SLAVE_OP_MODE BIT(30) | ||
70 | #define SLAVE_SW_RST BIT(31) | ||
71 | |||
72 | #define SPIFC_BUFFER_SIZE 64 | ||
73 | |||
74 | /** | ||
75 | * struct meson_spifc | ||
76 | * @master: the SPI master | ||
77 | * @regmap: regmap for device registers | ||
78 | * @clk: input clock of the built-in baud rate generator | ||
79 | * @device: the device structure | ||
80 | */ | ||
81 | struct meson_spifc { | ||
82 | struct spi_master *master; | ||
83 | struct regmap *regmap; | ||
84 | struct clk *clk; | ||
85 | struct device *dev; | ||
86 | }; | ||
87 | |||
88 | static struct regmap_config spifc_regmap_config = { | ||
89 | .reg_bits = 32, | ||
90 | .val_bits = 32, | ||
91 | .reg_stride = 4, | ||
92 | .max_register = REG_MAX, | ||
93 | }; | ||
94 | |||
95 | /** | ||
96 | * meson_spifc_wait_ready() - wait for the current operation to terminate | ||
97 | * @spifc: the Meson SPI device | ||
98 | * Return: 0 on success, a negative value on error | ||
99 | */ | ||
100 | static int meson_spifc_wait_ready(struct meson_spifc *spifc) | ||
101 | { | ||
102 | unsigned long deadline = jiffies + msecs_to_jiffies(5); | ||
103 | u32 data; | ||
104 | |||
105 | do { | ||
106 | regmap_read(spifc->regmap, REG_SLAVE, &data); | ||
107 | if (data & SLAVE_TRST_DONE) | ||
108 | return 0; | ||
109 | cond_resched(); | ||
110 | } while (!time_after(jiffies, deadline)); | ||
111 | |||
112 | return -ETIMEDOUT; | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * meson_spifc_drain_buffer() - copy data from device buffer to memory | ||
117 | * @spifc: the Meson SPI device | ||
118 | * @buf: the destination buffer | ||
119 | * @len: number of bytes to copy | ||
120 | */ | ||
121 | static void meson_spifc_drain_buffer(struct meson_spifc *spifc, u8 *buf, | ||
122 | int len) | ||
123 | { | ||
124 | u32 data; | ||
125 | int i = 0; | ||
126 | |||
127 | while (i < len) { | ||
128 | regmap_read(spifc->regmap, REG_C0 + i, &data); | ||
129 | |||
130 | if (len - i >= 4) { | ||
131 | *((u32 *)buf) = data; | ||
132 | buf += 4; | ||
133 | } else { | ||
134 | memcpy(buf, &data, len - i); | ||
135 | break; | ||
136 | } | ||
137 | i += 4; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * meson_spifc_fill_buffer() - copy data from memory to device buffer | ||
143 | * @spifc: the Meson SPI device | ||
144 | * @buf: the source buffer | ||
145 | * @len: number of bytes to copy | ||
146 | */ | ||
147 | static void meson_spifc_fill_buffer(struct meson_spifc *spifc, const u8 *buf, | ||
148 | int len) | ||
149 | { | ||
150 | u32 data; | ||
151 | int i = 0; | ||
152 | |||
153 | while (i < len) { | ||
154 | if (len - i >= 4) | ||
155 | data = *(u32 *)buf; | ||
156 | else | ||
157 | memcpy(&data, buf, len - i); | ||
158 | |||
159 | regmap_write(spifc->regmap, REG_C0 + i, data); | ||
160 | |||
161 | buf += 4; | ||
162 | i += 4; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * meson_spifc_setup_speed() - program the clock divider | ||
168 | * @spifc: the Meson SPI device | ||
169 | * @speed: desired speed in Hz | ||
170 | */ | ||
171 | static void meson_spifc_setup_speed(struct meson_spifc *spifc, u32 speed) | ||
172 | { | ||
173 | unsigned long parent, value; | ||
174 | int n; | ||
175 | |||
176 | parent = clk_get_rate(spifc->clk); | ||
177 | n = max_t(int, parent / speed - 1, 1); | ||
178 | |||
179 | dev_dbg(spifc->dev, "parent %lu, speed %u, n %d\n", parent, | ||
180 | speed, n); | ||
181 | |||
182 | value = (n << CLOCK_DIV_SHIFT) & CLOCK_DIV_MASK; | ||
183 | value |= (n << CLOCK_CNT_LOW_SHIFT) & CLOCK_CNT_LOW_MASK; | ||
184 | value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) & | ||
185 | CLOCK_CNT_HIGH_MASK; | ||
186 | |||
187 | regmap_write(spifc->regmap, REG_CLOCK, value); | ||
188 | } | ||
189 | |||
190 | /** | ||
191 | * meson_spifc_txrx() - transfer a chunk of data | ||
192 | * @spifc: the Meson SPI device | ||
193 | * @xfer: the current SPI transfer | ||
194 | * @offset: offset of the data to transfer | ||
195 | * @len: length of the data to transfer | ||
196 | * @last_xfer: whether this is the last transfer of the message | ||
197 | * @last_chunk: whether this is the last chunk of the transfer | ||
198 | * Return: 0 on success, a negative value on error | ||
199 | */ | ||
200 | static int meson_spifc_txrx(struct meson_spifc *spifc, | ||
201 | struct spi_transfer *xfer, | ||
202 | int offset, int len, bool last_xfer, | ||
203 | bool last_chunk) | ||
204 | { | ||
205 | bool keep_cs = true; | ||
206 | int ret; | ||
207 | |||
208 | if (xfer->tx_buf) | ||
209 | meson_spifc_fill_buffer(spifc, xfer->tx_buf + offset, len); | ||
210 | |||
211 | /* enable DOUT stage */ | ||
212 | regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK, | ||
213 | USER_UC_DOUT_SEL); | ||
214 | regmap_write(spifc->regmap, REG_USER1, | ||
215 | (8 * len - 1) << USER1_BN_UC_DOUT_SHIFT); | ||
216 | |||
217 | /* enable data input during DOUT */ | ||
218 | regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS, | ||
219 | USER_DIN_EN_MS); | ||
220 | |||
221 | if (last_chunk) { | ||
222 | if (last_xfer) | ||
223 | keep_cs = xfer->cs_change; | ||
224 | else | ||
225 | keep_cs = !xfer->cs_change; | ||
226 | } | ||
227 | |||
228 | regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT, | ||
229 | keep_cs ? USER4_CS_ACT : 0); | ||
230 | |||
231 | /* clear transition done bit */ | ||
232 | regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0); | ||
233 | /* start transfer */ | ||
234 | regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER); | ||
235 | |||
236 | ret = meson_spifc_wait_ready(spifc); | ||
237 | |||
238 | if (!ret && xfer->rx_buf) | ||
239 | meson_spifc_drain_buffer(spifc, xfer->rx_buf + offset, len); | ||
240 | |||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * meson_spifc_transfer_one() - perform a single transfer | ||
246 | * @master: the SPI master | ||
247 | * @spi: the SPI device | ||
248 | * @xfer: the current SPI transfer | ||
249 | * Return: 0 on success, a negative value on error | ||
250 | */ | ||
251 | static int meson_spifc_transfer_one(struct spi_master *master, | ||
252 | struct spi_device *spi, | ||
253 | struct spi_transfer *xfer) | ||
254 | { | ||
255 | struct meson_spifc *spifc = spi_master_get_devdata(master); | ||
256 | int len, done = 0, ret = 0; | ||
257 | |||
258 | meson_spifc_setup_speed(spifc, xfer->speed_hz); | ||
259 | |||
260 | regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0); | ||
261 | |||
262 | while (done < xfer->len && !ret) { | ||
263 | len = min_t(int, xfer->len - done, SPIFC_BUFFER_SIZE); | ||
264 | ret = meson_spifc_txrx(spifc, xfer, done, len, | ||
265 | spi_transfer_is_last(master, xfer), | ||
266 | done + len >= xfer->len); | ||
267 | done += len; | ||
268 | } | ||
269 | |||
270 | regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, | ||
271 | CTRL_ENABLE_AHB); | ||
272 | |||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * meson_spifc_hw_init() - reset and initialize the SPI controller | ||
278 | * @spifc: the Meson SPI device | ||
279 | */ | ||
280 | static void meson_spifc_hw_init(struct meson_spifc *spifc) | ||
281 | { | ||
282 | /* reset device */ | ||
283 | regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST, | ||
284 | SLAVE_SW_RST); | ||
285 | /* disable compatible mode */ | ||
286 | regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0); | ||
287 | /* set master mode */ | ||
288 | regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0); | ||
289 | } | ||
290 | |||
291 | static int meson_spifc_probe(struct platform_device *pdev) | ||
292 | { | ||
293 | struct spi_master *master; | ||
294 | struct meson_spifc *spifc; | ||
295 | struct resource *res; | ||
296 | void __iomem *base; | ||
297 | unsigned int rate; | ||
298 | int ret = 0; | ||
299 | |||
300 | master = spi_alloc_master(&pdev->dev, sizeof(struct meson_spifc)); | ||
301 | if (!master) | ||
302 | return -ENOMEM; | ||
303 | |||
304 | platform_set_drvdata(pdev, master); | ||
305 | |||
306 | spifc = spi_master_get_devdata(master); | ||
307 | spifc->dev = &pdev->dev; | ||
308 | |||
309 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
310 | base = devm_ioremap_resource(spifc->dev, res); | ||
311 | if (IS_ERR(base)) { | ||
312 | ret = PTR_ERR(base); | ||
313 | goto out_err; | ||
314 | } | ||
315 | |||
316 | spifc->regmap = devm_regmap_init_mmio(spifc->dev, base, | ||
317 | &spifc_regmap_config); | ||
318 | if (IS_ERR(spifc->regmap)) { | ||
319 | ret = PTR_ERR(spifc->regmap); | ||
320 | goto out_err; | ||
321 | } | ||
322 | |||
323 | spifc->clk = devm_clk_get(spifc->dev, NULL); | ||
324 | if (IS_ERR(spifc->clk)) { | ||
325 | dev_err(spifc->dev, "missing clock\n"); | ||
326 | ret = PTR_ERR(spifc->clk); | ||
327 | goto out_err; | ||
328 | } | ||
329 | |||
330 | ret = clk_prepare_enable(spifc->clk); | ||
331 | if (ret) { | ||
332 | dev_err(spifc->dev, "can't prepare clock\n"); | ||
333 | goto out_err; | ||
334 | } | ||
335 | |||
336 | rate = clk_get_rate(spifc->clk); | ||
337 | |||
338 | master->num_chipselect = 1; | ||
339 | master->dev.of_node = pdev->dev.of_node; | ||
340 | master->bits_per_word_mask = SPI_BPW_MASK(8); | ||
341 | master->auto_runtime_pm = true; | ||
342 | master->transfer_one = meson_spifc_transfer_one; | ||
343 | master->min_speed_hz = rate >> 6; | ||
344 | master->max_speed_hz = rate >> 1; | ||
345 | |||
346 | meson_spifc_hw_init(spifc); | ||
347 | |||
348 | pm_runtime_set_active(spifc->dev); | ||
349 | pm_runtime_enable(spifc->dev); | ||
350 | |||
351 | ret = devm_spi_register_master(spifc->dev, master); | ||
352 | if (ret) { | ||
353 | dev_err(spifc->dev, "failed to register spi master\n"); | ||
354 | goto out_clk; | ||
355 | } | ||
356 | |||
357 | return 0; | ||
358 | out_clk: | ||
359 | clk_disable_unprepare(spifc->clk); | ||
360 | out_err: | ||
361 | spi_master_put(master); | ||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | static int meson_spifc_remove(struct platform_device *pdev) | ||
366 | { | ||
367 | struct spi_master *master = platform_get_drvdata(pdev); | ||
368 | struct meson_spifc *spifc = spi_master_get_devdata(master); | ||
369 | |||
370 | pm_runtime_get_sync(&pdev->dev); | ||
371 | clk_disable_unprepare(spifc->clk); | ||
372 | pm_runtime_disable(&pdev->dev); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | #ifdef CONFIG_PM_SLEEP | ||
378 | static int meson_spifc_suspend(struct device *dev) | ||
379 | { | ||
380 | struct spi_master *master = dev_get_drvdata(dev); | ||
381 | struct meson_spifc *spifc = spi_master_get_devdata(master); | ||
382 | int ret; | ||
383 | |||
384 | ret = spi_master_suspend(master); | ||
385 | if (ret) | ||
386 | return ret; | ||
387 | |||
388 | if (!pm_runtime_suspended(dev)) | ||
389 | clk_disable_unprepare(spifc->clk); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int meson_spifc_resume(struct device *dev) | ||
395 | { | ||
396 | struct spi_master *master = dev_get_drvdata(dev); | ||
397 | struct meson_spifc *spifc = spi_master_get_devdata(master); | ||
398 | int ret; | ||
399 | |||
400 | if (!pm_runtime_suspended(dev)) { | ||
401 | ret = clk_prepare_enable(spifc->clk); | ||
402 | if (ret) | ||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | meson_spifc_hw_init(spifc); | ||
407 | |||
408 | ret = spi_master_resume(master); | ||
409 | if (ret) | ||
410 | clk_disable_unprepare(spifc->clk); | ||
411 | |||
412 | return ret; | ||
413 | } | ||
414 | #endif /* CONFIG_PM_SLEEP */ | ||
415 | |||
416 | #ifdef CONFIG_PM_RUNTIME | ||
417 | static int meson_spifc_runtime_suspend(struct device *dev) | ||
418 | { | ||
419 | struct spi_master *master = dev_get_drvdata(dev); | ||
420 | struct meson_spifc *spifc = spi_master_get_devdata(master); | ||
421 | |||
422 | clk_disable_unprepare(spifc->clk); | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int meson_spifc_runtime_resume(struct device *dev) | ||
428 | { | ||
429 | struct spi_master *master = dev_get_drvdata(dev); | ||
430 | struct meson_spifc *spifc = spi_master_get_devdata(master); | ||
431 | |||
432 | return clk_prepare_enable(spifc->clk); | ||
433 | } | ||
434 | #endif /* CONFIG_PM_RUNTIME */ | ||
435 | |||
436 | static const struct dev_pm_ops meson_spifc_pm_ops = { | ||
437 | SET_SYSTEM_SLEEP_PM_OPS(meson_spifc_suspend, meson_spifc_resume) | ||
438 | SET_RUNTIME_PM_OPS(meson_spifc_runtime_suspend, | ||
439 | meson_spifc_runtime_resume, | ||
440 | NULL) | ||
441 | }; | ||
442 | |||
443 | static const struct of_device_id meson_spifc_dt_match[] = { | ||
444 | { .compatible = "amlogic,meson6-spifc", }, | ||
445 | { }, | ||
446 | }; | ||
447 | |||
448 | static struct platform_driver meson_spifc_driver = { | ||
449 | .probe = meson_spifc_probe, | ||
450 | .remove = meson_spifc_remove, | ||
451 | .driver = { | ||
452 | .name = "meson-spifc", | ||
453 | .of_match_table = of_match_ptr(meson_spifc_dt_match), | ||
454 | .pm = &meson_spifc_pm_ops, | ||
455 | }, | ||
456 | }; | ||
457 | |||
458 | module_platform_driver(meson_spifc_driver); | ||
459 | |||
460 | MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); | ||
461 | MODULE_DESCRIPTION("Amlogic Meson SPIFC driver"); | ||
462 | MODULE_LICENSE("GPL v2"); | ||