Unified · Split
| @@ -0,0 +1,36 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-or-later) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/fsi/ibm,fsi2spi.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: IBM FSI-attached SPI controllers | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Eddie James <eajames@linux.ibm.com> | |
| 11 | + | |
| 12 | +description: | | |
| 13 | + This binding describes an FSI CFAM engine called the FSI2SPI. Therefore this | |
| 14 | + node will always be a child of an FSI CFAM node; see fsi.txt for details on | |
| 15 | + FSI slave and CFAM nodes. This FSI2SPI engine provides access to a number of | |
| 16 | + SPI controllers. | |
| 17 | + | |
| 18 | +properties: | |
| 19 | + compatible: | |
| 20 | + enum: | |
| 21 | + - ibm,fsi2spi | |
| 22 | + | |
| 23 | + reg: | |
| 24 | + items: | |
| 25 | + - description: FSI slave address | |
| 26 | + | |
| 27 | +required: | |
| 28 | + - compatible | |
| 29 | + - reg | |
| 30 | + | |
| 31 | +examples: | |
| 32 | + - | | |
| 33 | + fsi2spi@1c00 { | |
| 34 | + compatible = "ibm,fsi2spi"; | |
| 35 | + reg = <0x1c00 0x400>; | |
| 36 | + }; | |
| @@ -61,6 +61,7 @@ Regulator nodes are identified by their compatible: · 60 unmodified lines | ||
| 61 | 61 | "qcom,rpm-pm8901-regulators" |
| 62 | 62 | "qcom,rpm-pm8921-regulators" |
| 63 | 63 | "qcom,rpm-pm8018-regulators" |
| 64 | + "qcom,rpm-smb208-regulators" | |
| 64 | 65 | |
| 65 | 66 | - vdd_l0_l1_lvs-supply: |
| 66 | 67 | - vdd_l2_l11_l12-supply: |
| @@ -171,6 +172,9 @@ pm8018: · 104 unmodified lines | ||
| 171 | 172 | s1, s2, s3, s4, s5, , l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, |
| 172 | 173 | l12, l14, lvs1 |
| 173 | 174 | |
| 175 | +smb208: | |
| 176 | + s1a, s1b, s2a, s2b | |
| 177 | + | |
| 174 | 178 | The content of each sub-node is defined by the standard binding for regulators - |
| 175 | 179 | see regulator.txt - with additional custom properties described below: |
| 176 | 180 | |
| @@ -0,0 +1,78 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/regulator/mps,mp5416.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Monolithic Power System MP5416 PMIC | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Saravanan Sekar <sravanhome@gmail.com> | |
| 11 | + | |
| 12 | +properties: | |
| 13 | + $nodename: | |
| 14 | + pattern: "^pmic@[0-9a-f]{1,2}$" | |
| 15 | + compatible: | |
| 16 | + enum: | |
| 17 | + - mps,mp5416 | |
| 18 | + | |
| 19 | + reg: | |
| 20 | + maxItems: 1 | |
| 21 | + | |
| 22 | + regulators: | |
| 23 | + type: object | |
| 24 | + description: | | |
| 25 | + list of regulators provided by this controller, must be named | |
| 26 | + after their hardware counterparts BUCK[1-4] and LDO[1-4] | |
| 27 | + | |
| 28 | + patternProperties: | |
| 29 | + "^buck[1-4]$": | |
| 30 | + allOf: | |
| 31 | + - $ref: "regulator.yaml#" | |
| 32 | + type: object | |
| 33 | + | |
| 34 | + "^ldo[1-4]$": | |
| 35 | + allOf: | |
| 36 | + - $ref: "regulator.yaml#" | |
| 37 | + type: object | |
| 38 | + | |
| 39 | + additionalProperties: false | |
| 40 | + additionalProperties: false | |
| 41 | + | |
| 42 | +required: | |
| 43 | + - compatible | |
| 44 | + - reg | |
| 45 | + - regulators | |
| 46 | + | |
| 47 | +additionalProperties: false | |
| 48 | + | |
| 49 | +examples: | |
| 50 | + - | | |
| 51 | + i2c { | |
| 52 | + #address-cells = <1>; | |
| 53 | + #size-cells = <0>; | |
| 54 | + | |
| 55 | + pmic@69 { | |
| 56 | + compatible = "mps,mp5416"; | |
| 57 | + reg = <0x69>; | |
| 58 | + | |
| 59 | + regulators { | |
| 60 | + | |
| 61 | + buck1 { | |
| 62 | + regulator-name = "buck1"; | |
| 63 | + regulator-min-microvolt = <600000>; | |
| 64 | + regulator-max-microvolt = <2187500>; | |
| 65 | + regulator-min-microamp = <3800000>; | |
| 66 | + regulator-max-microamp = <6800000>; | |
| 67 | + regulator-boot-on; | |
| 68 | + }; | |
| 69 | + | |
| 70 | + ldo2 { | |
| 71 | + regulator-name = "ldo2"; | |
| 72 | + regulator-min-microvolt = <800000>; | |
| 73 | + regulator-max-microvolt = <3975000>; | |
| 74 | + }; | |
| 75 | + }; | |
| 76 | + }; | |
| 77 | + }; | |
| 78 | +... | |
| @@ -22,6 +22,7 @@ properties: · 21 unmodified lines | ||
| 22 | 22 | enum: |
| 23 | 23 | - amlogic,meson-gx-spicc # SPICC controller on Amlogic GX and compatible SoCs |
| 24 | 24 | - amlogic,meson-axg-spicc # SPICC controller on Amlogic AXG and compatible SoCs |
| 25 | + - amlogic,meson-g12a-spicc # SPICC controller on Amlogic G12A and compatible SoCs | |
| 25 | 26 | |
| 26 | 27 | interrupts: |
| 27 | 28 | maxItems: 1 |
| @@ -40,6 +41,27 @@ properties: · 12 unmodified lines | ||
| 40 | 41 | items: |
| 41 | 42 | - const: core |
| 42 | 43 | |
| 44 | +if: | |
| 45 | + properties: | |
| 46 | + compatible: | |
| 47 | + contains: | |
| 48 | + enum: | |
| 49 | + - amlogic,meson-g12a-spicc | |
| 50 | + | |
| 51 | +then: | |
| 52 | + properties: | |
| 53 | + clocks: | |
| 54 | + contains: | |
| 55 | + items: | |
| 56 | + - description: controller register bus clock | |
| 57 | + - description: baud rate generator and delay control clock | |
| 58 | + | |
| 59 | + clock-names: | |
| 60 | + minItems: 2 | |
| 61 | + items: | |
| 62 | + - const: core | |
| 63 | + - const: pclk | |
| 64 | + | |
| 43 | 65 | required: |
| 44 | 66 | - compatible |
| 45 | 67 | - reg |
| @@ -10,7 +10,10 @@ Required properties: · 9 unmodified lines | ||
| 10 | 10 | - "fsl,imx35-cspi" for SPI compatible with the one integrated on i.MX35 |
| 11 | 11 | - "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51 |
| 12 | 12 | - "fsl,imx53-ecspi" for SPI compatible with the one integrated on i.MX53 and later Soc |
| 13 | − - "fsl,imx8mq-ecspi" for SPI compatible with the one integrated on i.MX8M | |
| 13 | + - "fsl,imx8mq-ecspi" for SPI compatible with the one integrated on i.MX8MQ | |
| 14 | + - "fsl,imx8mm-ecspi" for SPI compatible with the one integrated on i.MX8MM | |
| 15 | + - "fsl,imx8mn-ecspi" for SPI compatible with the one integrated on i.MX8MN | |
| 16 | + - "fsl,imx8mp-ecspi" for SPI compatible with the one integrated on i.MX8MP | |
| 14 | 17 | - reg : Offset and length of the register set for the device |
| 15 | 18 | - interrupts : Should contain CSPI/eCSPI interrupt |
| 16 | 19 | - clocks : Clock specifiers for both ipg and per clocks. |
| @@ -0,0 +1,41 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/spi/qca,ar934x-spi.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Qualcomm Atheros AR934x/QCA95xx SoC SPI controller | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Chuanhong Guo <gch981213@gmail.com> | |
| 11 | + | |
| 12 | +allOf: | |
| 13 | + - $ref: spi-controller.yaml# | |
| 14 | + | |
| 15 | +properties: | |
| 16 | + compatible: | |
| 17 | + const: qca,ar934x-spi | |
| 18 | + | |
| 19 | + reg: | |
| 20 | + maxItems: 1 | |
| 21 | + | |
| 22 | + clocks: | |
| 23 | + maxItems: 1 | |
| 24 | + | |
| 25 | +required: | |
| 26 | + - compatible | |
| 27 | + - reg | |
| 28 | + - clocks | |
| 29 | + - '#address-cells' | |
| 30 | + - '#size-cells' | |
| 31 | + | |
| 32 | +examples: | |
| 33 | + - | | |
| 34 | + #include <dt-bindings/clock/ath79-clk.h> | |
| 35 | + spi: spi@1f000000 { | |
| 36 | + compatible = "qca,ar934x-spi"; | |
| 37 | + reg = <0x1f000000 0x1c>; | |
| 38 | + clocks = <&pll ATH79_CLK_AHB>; | |
| 39 | + #address-cells = <1>; | |
| 40 | + #size-cells = <0>; | |
| 41 | + }; | |
| @@ -52,6 +52,12 @@ properties: · 51 unmodified lines | ||
| 52 | 52 | description: |
| 53 | 53 | The SPI controller acts as a slave, instead of a master. |
| 54 | 54 | |
| 55 | +oneOf: | |
| 56 | + - required: | |
| 57 | + - "#address-cells" | |
| 58 | + - required: | |
| 59 | + - spi-slave | |
| 60 | + | |
| 55 | 61 | patternProperties: |
| 56 | 62 | "^slave$": |
| 57 | 63 | type: object |
| @@ -114,7 +120,7 @@ patternProperties: · 56 unmodified lines | ||
| 114 | 120 | - enum: [ 1, 2, 4, 8 ] |
| 115 | 121 | - default: 1 |
| 116 | 122 | description: |
| 117 | − Bus width to the SPI bus used for MISO. | |
| 123 | + Bus width to the SPI bus used for read transfers. | |
| 118 | 124 | |
| 119 | 125 | spi-rx-delay-us: |
| 120 | 126 | description: |
| @@ -126,7 +132,7 @@ patternProperties: · 5 unmodified lines | ||
| 126 | 132 | - enum: [ 1, 2, 4, 8 ] |
| 127 | 133 | - default: 1 |
| 128 | 134 | description: |
| 129 | − Bus width to the SPI bus used for MOSI. | |
| 135 | + Bus width to the SPI bus used for write transfers. | |
| 130 | 136 | |
| 131 | 137 | spi-tx-delay-us: |
| 132 | 138 | description: |
| @@ -1,12 +1,17 @@ | ||
| 1 | 1 | ARM Freescale DSPI controller |
| 2 | 2 | |
| 3 | 3 | Required properties: |
| 4 | −- compatible : "fsl,vf610-dspi", "fsl,ls1021a-v1.0-dspi", | |
| 5 | − "fsl,ls2085a-dspi" | |
| 6 | − or | |
| 7 | − "fsl,ls2080a-dspi" followed by "fsl,ls2085a-dspi" | |
| 8 | − "fsl,ls1012a-dspi" followed by "fsl,ls1021a-v1.0-dspi" | |
| 9 | − "fsl,ls1088a-dspi" followed by "fsl,ls1021a-v1.0-dspi" | |
| 4 | +- compatible : must be one of: | |
| 5 | + "fsl,vf610-dspi", | |
| 6 | + "fsl,ls1021a-v1.0-dspi", | |
| 7 | + "fsl,ls1012a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"), | |
| 8 | + "fsl,ls1028a-dspi", | |
| 9 | + "fsl,ls1043a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"), | |
| 10 | + "fsl,ls1046a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"), | |
| 11 | + "fsl,ls1088a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"), | |
| 12 | + "fsl,ls2080a-dspi" (optionally followed by "fsl,ls2085a-dspi"), | |
| 13 | + "fsl,ls2085a-dspi", | |
| 14 | + "fsl,lx2160a-dspi", | |
| 10 | 15 | - reg : Offset and length of the register set for the device |
| 11 | 16 | - interrupts : Should contain SPI controller interrupt |
| 12 | 17 | - clocks: from common clock binding: handle to dspi clock. |
| @@ -14,11 +19,11 @@ Required properties: · 1 unmodified line | ||
| 14 | 19 | - pinctrl-0: pin control group to be used for this controller. |
| 15 | 20 | - pinctrl-names: must contain a "default" entry. |
| 16 | 21 | - spi-num-chipselects : the number of the chipselect signals. |
| 17 | −- bus-num : the slave chip chipselect signal number. | |
| 18 | 22 | |
| 19 | 23 | Optional property: |
| 20 | 24 | - big-endian: If present the dspi device's registers are implemented |
| 21 | 25 | in big endian mode. |
| 26 | +- bus-num : the slave chip chipselect signal number. | |
| 22 | 27 | |
| 23 | 28 | Optional SPI slave node properties: |
| 24 | 29 | - fsl,spi-cs-sck-delay: a delay in nanoseconds between activating chip |
| @@ -1,4 +1,4 @@ | ||
| 1 | −* Serial NOR flash controller for MediaTek SoCs | |
| 1 | +* Serial NOR flash controller for MediaTek ARM SoCs | |
| 2 | 2 | |
| 3 | 3 | Required properties: |
| 4 | 4 | - compatible: For mt8173, compatible should be "mediatek,mt8173-nor", |
| @@ -13,6 +13,7 @@ Required properties: · 8 unmodified lines | ||
| 13 | 13 | "mediatek,mt7629-nor", "mediatek,mt8173-nor" |
| 14 | 14 | "mediatek,mt8173-nor" |
| 15 | 15 | - reg: physical base address and length of the controller's register |
| 16 | +- interrupts: Interrupt number used by the controller. | |
| 16 | 17 | - clocks: the phandle of the clocks needed by the nor controller |
| 17 | 18 | - clock-names: the names of the clocks |
| 18 | 19 | the clocks should be named "spi" and "sf". "spi" is used for spi bus, |
| @@ -22,20 +23,16 @@ Required properties: · 3 unmodified lines | ||
| 22 | 23 | - #address-cells: should be <1> |
| 23 | 24 | - #size-cells: should be <0> |
| 24 | 25 | |
| 25 | −The SPI flash must be a child of the nor_flash node and must have a | |
| 26 | −compatible property. Also see jedec,spi-nor.txt. | |
| 27 | − | |
| 28 | −Required properties: | |
| 29 | −- compatible: May include a device-specific string consisting of the manufacturer | |
| 30 | − and name of the chip. Must also include "jedec,spi-nor" for any | |
| 31 | − SPI NOR flash that can be identified by the JEDEC READ ID opcode (0x9F). | |
| 32 | −- reg : Chip-Select number | |
| 26 | +There should be only one spi slave device following generic spi bindings. | |
| 27 | +It's not recommended to use this controller for devices other than SPI NOR | |
| 28 | +flash due to limited transfer capability of this controller. | |
| 33 | 29 | |
| 34 | 30 | Example: |
| 35 | 31 | |
| 36 | 32 | nor_flash: spi@1100d000 { |
| 37 | 33 | compatible = "mediatek,mt8173-nor"; |
| 38 | 34 | reg = <0 0x1100d000 0 0xe0>; |
| 35 | + interrupts = <&spi_flash_irq>; | |
| 39 | 36 | clocks = <&pericfg CLK_PERI_SPI>, |
| 40 | 37 | <&topckgen CLK_TOP_SPINFI_IFR_SEL>; |
| 41 | 38 | clock-names = "spi", "sf"; |
| @@ -0,0 +1,89 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/spi/spi-mux.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Generic SPI Multiplexer | |
| 8 | + | |
| 9 | +description: | | |
| 10 | + This binding describes a SPI bus multiplexer to route the SPI chip select | |
| 11 | + signals. This can be used when you need more devices than the SPI controller | |
| 12 | + has chip selects available. An example setup is shown in ASCII art; the actual | |
| 13 | + setting of the multiplexer to a channel needs to be done by a specific SPI mux | |
| 14 | + driver. | |
| 15 | + | |
| 16 | + MOSI /--------------------------------+--------+--------+--------\ | |
| 17 | + MISO |/------------------------------+|-------+|-------+|-------\| | |
| 18 | + SCL ||/----------------------------+||------+||------+||------\|| | |
| 19 | + ||| ||| ||| ||| ||| | |
| 20 | + +------------+ ||| ||| ||| ||| | |
| 21 | + | SoC ||| | +-+++-+ +-+++-+ +-+++-+ +-+++-+ | |
| 22 | + | ||| | | dev | | dev | | dev | | dev | | |
| 23 | + | +--+++-+ | CS-X +------+\ +--+--+ +--+--+ +--+--+ +--+--+ | |
| 24 | + | | SPI +-|-------+ Mux |\\ CS-0 | | | | | |
| 25 | + | +------+ | +--+---+\\\-------/ CS-1 | | | | |
| 26 | + | | | \\\----------------/ CS-2 | | | |
| 27 | + | +------+ | | \\-------------------------/ CS-3 | | |
| 28 | + | | ? +-|----------/ \----------------------------------/ | |
| 29 | + | +------+ | | |
| 30 | + +------------+ | |
| 31 | + | |
| 32 | +allOf: | |
| 33 | + - $ref: "/schemas/spi/spi-controller.yaml#" | |
| 34 | + | |
| 35 | +maintainers: | |
| 36 | + - Chris Packham <chris.packham@alliedtelesis.co.nz> | |
| 37 | + | |
| 38 | +properties: | |
| 39 | + compatible: | |
| 40 | + const: spi-mux | |
| 41 | + | |
| 42 | + mux-controls: | |
| 43 | + maxItems: 1 | |
| 44 | + | |
| 45 | +required: | |
| 46 | + - compatible | |
| 47 | + - reg | |
| 48 | + - spi-max-frequency | |
| 49 | + - mux-controls | |
| 50 | + | |
| 51 | +examples: | |
| 52 | + - | | |
| 53 | + #include <dt-bindings/gpio/gpio.h> | |
| 54 | + mux: mux-controller { | |
| 55 | + compatible = "gpio-mux"; | |
| 56 | + #mux-control-cells = <0>; | |
| 57 | + | |
| 58 | + mux-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; | |
| 59 | + }; | |
| 60 | + | |
| 61 | + spi { | |
| 62 | + #address-cells = <1>; | |
| 63 | + #size-cells = <0>; | |
| 64 | + spi@0 { | |
| 65 | + compatible = "spi-mux"; | |
| 66 | + reg = <0>; | |
| 67 | + #address-cells = <1>; | |
| 68 | + #size-cells = <0>; | |
| 69 | + spi-max-frequency = <100000000>; | |
| 70 | + | |
| 71 | + mux-controls = <&mux>; | |
| 72 | + | |
| 73 | + spi-flash@0 { | |
| 74 | + compatible = "jedec,spi-nor"; | |
| 75 | + reg = <0>; | |
| 76 | + #address-cells = <1>; | |
| 77 | + #size-cells = <0>; | |
| 78 | + spi-max-frequency = <40000000>; | |
| 79 | + }; | |
| 80 | + | |
| 81 | + spi-device@1 { | |
| 82 | + compatible = "lineartechnology,ltc2488"; | |
| 83 | + reg = <1>; | |
| 84 | + #address-cells = <1>; | |
| 85 | + #size-cells = <0>; | |
| 86 | + spi-max-frequency = <10000000>; | |
| 87 | + }; | |
| 88 | + }; | |
| 89 | + }; | |
| @@ -2,6 +2,9 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | Required properties: |
| 4 | 4 | - compatible : Should be "nxp,lx2160a-fspi" |
| 5 | + "nxp,imx8qxp-fspi" | |
| 6 | + "nxp,imx8mm-fspi" | |
| 7 | + | |
| 5 | 8 | - reg : First contains the register location and length, |
| 6 | 9 | Second contains the memory mapping address and length |
| 7 | 10 | - reg-names : Should contain the resource reg names: |
| @@ -1,58 +0,0 @@ | ||
| 1 | −* Rockchip SPI Controller | |
| 2 | − | |
| 3 | −The Rockchip SPI controller is used to interface with various devices such as flash | |
| 4 | −and display controllers using the SPI communication interface. | |
| 5 | − | |
| 6 | −Required Properties: | |
| 7 | − | |
| 8 | −- compatible: should be one of the following. | |
| 9 | − "rockchip,rv1108-spi" for rv1108 SoCs. | |
| 10 | − "rockchip,px30-spi", "rockchip,rk3066-spi" for px30 SoCs. | |
| 11 | − "rockchip,rk3036-spi" for rk3036 SoCS. | |
| 12 | − "rockchip,rk3066-spi" for rk3066 SoCs. | |
| 13 | − "rockchip,rk3188-spi" for rk3188 SoCs. | |
| 14 | − "rockchip,rk3228-spi" for rk3228 SoCS. | |
| 15 | − "rockchip,rk3288-spi" for rk3288 SoCs. | |
| 16 | − "rockchip,rk3368-spi" for rk3368 SoCs. | |
| 17 | − "rockchip,rk3399-spi" for rk3399 SoCs. | |
| 18 | −- reg: physical base address of the controller and length of memory mapped | |
| 19 | − region. | |
| 20 | −- interrupts: The interrupt number to the cpu. The interrupt specifier format | |
| 21 | − depends on the interrupt controller. | |
| 22 | −- clocks: Must contain an entry for each entry in clock-names. | |
| 23 | −- clock-names: Shall be "spiclk" for the transfer-clock, and "apb_pclk" for | |
| 24 | − the peripheral clock. | |
| 25 | −- #address-cells: should be 1. | |
| 26 | −- #size-cells: should be 0. | |
| 27 | − | |
| 28 | −Optional Properties: | |
| 29 | − | |
| 30 | −- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, | |
| 31 | − Documentation/devicetree/bindings/dma/dma.txt | |
| 32 | −- dma-names: DMA request names should include "tx" and "rx" if present. | |
| 33 | −- rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling | |
| 34 | − Rx data (may need to be fine tuned for high capacitance lines). | |
| 35 | − No delay (0) by default. | |
| 36 | −- pinctrl-names: Names for the pin configuration(s); may be "default" or | |
| 37 | − "sleep", where the "sleep" configuration may describe the state | |
| 38 | − the pins should be in during system suspend. See also | |
| 39 | − pinctrl/pinctrl-bindings.txt. | |
| 40 | − | |
| 41 | − | |
| 42 | −Example: | |
| 43 | − | |
| 44 | − spi0: spi@ff110000 { | |
| 45 | − compatible = "rockchip,rk3066-spi"; | |
| 46 | − reg = <0xff110000 0x1000>; | |
| 47 | − dmas = <&pdma1 11>, <&pdma1 12>; | |
| 48 | − dma-names = "tx", "rx"; | |
| 49 | − rx-sample-delay-ns = <10>; | |
| 50 | − #address-cells = <1>; | |
| 51 | − #size-cells = <0>; | |
| 52 | − interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; | |
| 53 | − clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>; | |
| 54 | − clock-names = "spiclk", "apb_pclk"; | |
| 55 | − pinctrl-0 = <&spi1_pins>; | |
| 56 | − pinctrl-1 = <&spi1_sleep>; | |
| 57 | − pinctrl-names = "default", "sleep"; | |
| 58 | − }; | |
| @@ -0,0 +1,107 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/spi/spi-rockchip.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Rockchip SPI Controller | |
| 8 | + | |
| 9 | +description: | |
| 10 | + The Rockchip SPI controller is used to interface with various devices such | |
| 11 | + as flash and display controllers using the SPI communication interface. | |
| 12 | + | |
| 13 | +allOf: | |
| 14 | + - $ref: "spi-controller.yaml#" | |
| 15 | + | |
| 16 | +maintainers: | |
| 17 | + - Heiko Stuebner <heiko@sntech.de> | |
| 18 | + | |
| 19 | +# Everything else is described in the common file | |
| 20 | +properties: | |
| 21 | + compatible: | |
| 22 | + oneOf: | |
| 23 | + - const: rockchip,rk3036-spi | |
| 24 | + - const: rockchip,rk3066-spi | |
| 25 | + - const: rockchip,rk3228-spi | |
| 26 | + - const: rockchip,rv1108-spi | |
| 27 | + - items: | |
| 28 | + - enum: | |
| 29 | + - rockchip,px30-spi | |
| 30 | + - rockchip,rk3188-spi | |
| 31 | + - rockchip,rk3288-spi | |
| 32 | + - rockchip,rk3308-spi | |
| 33 | + - rockchip,rk3328-spi | |
| 34 | + - rockchip,rk3368-spi | |
| 35 | + - rockchip,rk3399-spi | |
| 36 | + - const: rockchip,rk3066-spi | |
| 37 | + | |
| 38 | + reg: | |
| 39 | + maxItems: 1 | |
| 40 | + | |
| 41 | + interrupts: | |
| 42 | + maxItems: 1 | |
| 43 | + | |
| 44 | + clocks: | |
| 45 | + items: | |
| 46 | + - description: transfer-clock | |
| 47 | + - description: peripheral clock | |
| 48 | + | |
| 49 | + clock-names: | |
| 50 | + items: | |
| 51 | + - const: spiclk | |
| 52 | + - const: apb_pclk | |
| 53 | + | |
| 54 | + dmas: | |
| 55 | + items: | |
| 56 | + - description: TX DMA Channel | |
| 57 | + - description: RX DMA Channel | |
| 58 | + | |
| 59 | + dma-names: | |
| 60 | + items: | |
| 61 | + - const: tx | |
| 62 | + - const: rx | |
| 63 | + | |
| 64 | + rx-sample-delay-ns: | |
| 65 | + default: 0 | |
| 66 | + description: | |
| 67 | + Nano seconds to delay after the SCLK edge before sampling Rx data | |
| 68 | + (may need to be fine tuned for high capacitance lines). | |
| 69 | + If not specified 0 will be used. | |
| 70 | + | |
| 71 | + pinctrl-names: | |
| 72 | + minItems: 1 | |
| 73 | + items: | |
| 74 | + - const: default | |
| 75 | + - const: sleep | |
| 76 | + description: | |
| 77 | + Names for the pin configuration(s); may be "default" or "sleep", | |
| 78 | + where the "sleep" configuration may describe the state | |
| 79 | + the pins should be in during system suspend. | |
| 80 | + | |
| 81 | +required: | |
| 82 | + - compatible | |
| 83 | + - reg | |
| 84 | + - interrupts | |
| 85 | + - clocks | |
| 86 | + - clock-names | |
| 87 | + | |
| 88 | +examples: | |
| 89 | + - | | |
| 90 | + #include <dt-bindings/clock/rk3188-cru-common.h> | |
| 91 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 92 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 93 | + spi0: spi@ff110000 { | |
| 94 | + compatible = "rockchip,rk3066-spi"; | |
| 95 | + reg = <0xff110000 0x1000>; | |
| 96 | + interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; | |
| 97 | + clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>; | |
| 98 | + clock-names = "spiclk", "apb_pclk"; | |
| 99 | + dmas = <&pdma1 11>, <&pdma1 12>; | |
| 100 | + dma-names = "tx", "rx"; | |
| 101 | + pinctrl-0 = <&spi1_pins>; | |
| 102 | + pinctrl-1 = <&spi1_sleep>; | |
| 103 | + pinctrl-names = "default", "sleep"; | |
| 104 | + rx-sample-delay-ns = <10>; | |
| 105 | + #address-cells = <1>; | |
| 106 | + #size-cells = <0>; | |
| 107 | + }; | |
| @@ -2276,6 +2276,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git · 2275 unmodified lines | ||
| 2276 | 2276 | S: Maintained |
| 2277 | 2277 | F: Documentation/devicetree/bindings/i2c/i2c-rk3x.txt |
| 2278 | 2278 | F: Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml |
| 2279 | +F: Documentation/devicetree/bindings/spi/spi-rockchip.yaml | |
| 2279 | 2280 | F: arch/arm/boot/dts/rk3* |
| 2280 | 2281 | F: arch/arm/boot/dts/rv1108* |
| 2281 | 2282 | F: arch/arm/mach-rockchip/ |
| @@ -6858,6 +6859,13 @@ S: Maintained · 4576 unmodified lines | ||
| 6858 | 6859 | F: drivers/i2c/busses/i2c-fsi.c |
| 6859 | 6860 | F: Documentation/devicetree/bindings/i2c/i2c-fsi.txt |
| 6860 | 6861 | |
| 6862 | +FSI-ATTACHED SPI DRIVER | |
| 6863 | +M: Eddie James <eajames@linux.ibm.com> | |
| 6864 | +L: linux-spi@vger.kernel.org | |
| 6865 | +S: Maintained | |
| 6866 | +F: drivers/spi/spi-fsi.c | |
| 6867 | +F: Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml | |
| 6868 | + | |
| 6861 | 6869 | FSNOTIFY: FILESYSTEM NOTIFICATION INFRASTRUCTURE |
| 6862 | 6870 | M: Jan Kara <jack@suse.cz> |
| 6863 | 6871 | R: Amir Goldstein <amir73il@gmail.com> |
| @@ -11256,7 +11264,8 @@ F: drivers/tty/mxser.* · 4392 unmodified lines | ||
| 11256 | 11264 | MONOLITHIC POWER SYSTEM PMIC DRIVER |
| 11257 | 11265 | M: Saravanan Sekar <sravanhome@gmail.com> |
| 11258 | 11266 | S: Maintained |
| 11259 | −F: Documentation/devicetree/bindings/regulator/mpq7920.yaml | |
| 11267 | +F: Documentation/devicetree/bindings/regulator/mps,mp*.yaml | |
| 11268 | +F: drivers/regulator/mp5416.c | |
| 11260 | 11269 | F: drivers/regulator/mpq7920.c |
| 11261 | 11270 | F: drivers/regulator/mpq7920.h |
| 11262 | 11271 | |
| @@ -52,14 +52,6 @@ config SPI_HISI_SFC · 51 unmodified lines | ||
| 52 | 52 | help |
| 53 | 53 | This enables support for HiSilicon FMC SPI-NOR flash controller. |
| 54 | 54 | |
| 55 | −config SPI_MTK_QUADSPI | |
| 56 | − tristate "MediaTek Quad SPI controller" | |
| 57 | − depends on HAS_IOMEM | |
| 58 | − help | |
| 59 | − This enables support for the Quad SPI controller in master mode. | |
| 60 | − This controller does not support generic SPI. It only supports | |
| 61 | − SPI NOR. | |
| 62 | − | |
| 63 | 55 | config SPI_NXP_SPIFI |
| 64 | 56 | tristate "NXP SPI Flash Interface (SPIFI)" |
| 65 | 57 | depends on OF && (ARCH_LPC18XX || COMPILE_TEST) |
| @@ -3,7 +3,6 @@ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o · 2 unmodified lines | ||
| 3 | 3 | obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o |
| 4 | 4 | obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o |
| 5 | 5 | obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o |
| 6 | −obj-$(CONFIG_SPI_MTK_QUADSPI) += mtk-quadspi.o | |
| 7 | 6 | obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o |
| 8 | 7 | obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o |
| 9 | 8 | obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o |
| @@ -1,565 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Copyright (c) 2015 MediaTek Inc. | |
| 4 | − * Author: Bayi Cheng <bayi.cheng@mediatek.com> | |
| 5 | − */ | |
| 6 | − | |
| 7 | −#include <linux/clk.h> | |
| 8 | −#include <linux/delay.h> | |
| 9 | −#include <linux/device.h> | |
| 10 | −#include <linux/init.h> | |
| 11 | −#include <linux/io.h> | |
| 12 | −#include <linux/iopoll.h> | |
| 13 | −#include <linux/ioport.h> | |
| 14 | −#include <linux/math64.h> | |
| 15 | −#include <linux/module.h> | |
| 16 | −#include <linux/mutex.h> | |
| 17 | −#include <linux/of.h> | |
| 18 | −#include <linux/of_device.h> | |
| 19 | −#include <linux/platform_device.h> | |
| 20 | −#include <linux/slab.h> | |
| 21 | −#include <linux/mtd/mtd.h> | |
| 22 | −#include <linux/mtd/partitions.h> | |
| 23 | −#include <linux/mtd/spi-nor.h> | |
| 24 | − | |
| 25 | −#define MTK_NOR_CMD_REG 0x00 | |
| 26 | −#define MTK_NOR_CNT_REG 0x04 | |
| 27 | −#define MTK_NOR_RDSR_REG 0x08 | |
| 28 | −#define MTK_NOR_RDATA_REG 0x0c | |
| 29 | −#define MTK_NOR_RADR0_REG 0x10 | |
| 30 | −#define MTK_NOR_RADR1_REG 0x14 | |
| 31 | −#define MTK_NOR_RADR2_REG 0x18 | |
| 32 | −#define MTK_NOR_WDATA_REG 0x1c | |
| 33 | −#define MTK_NOR_PRGDATA0_REG 0x20 | |
| 34 | −#define MTK_NOR_PRGDATA1_REG 0x24 | |
| 35 | −#define MTK_NOR_PRGDATA2_REG 0x28 | |
| 36 | −#define MTK_NOR_PRGDATA3_REG 0x2c | |
| 37 | −#define MTK_NOR_PRGDATA4_REG 0x30 | |
| 38 | −#define MTK_NOR_PRGDATA5_REG 0x34 | |
| 39 | −#define MTK_NOR_SHREG0_REG 0x38 | |
| 40 | −#define MTK_NOR_SHREG1_REG 0x3c | |
| 41 | −#define MTK_NOR_SHREG2_REG 0x40 | |
| 42 | −#define MTK_NOR_SHREG3_REG 0x44 | |
| 43 | −#define MTK_NOR_SHREG4_REG 0x48 | |
| 44 | −#define MTK_NOR_SHREG5_REG 0x4c | |
| 45 | −#define MTK_NOR_SHREG6_REG 0x50 | |
| 46 | −#define MTK_NOR_SHREG7_REG 0x54 | |
| 47 | −#define MTK_NOR_SHREG8_REG 0x58 | |
| 48 | −#define MTK_NOR_SHREG9_REG 0x5c | |
| 49 | −#define MTK_NOR_CFG1_REG 0x60 | |
| 50 | −#define MTK_NOR_CFG2_REG 0x64 | |
| 51 | −#define MTK_NOR_CFG3_REG 0x68 | |
| 52 | −#define MTK_NOR_STATUS0_REG 0x70 | |
| 53 | −#define MTK_NOR_STATUS1_REG 0x74 | |
| 54 | −#define MTK_NOR_STATUS2_REG 0x78 | |
| 55 | −#define MTK_NOR_STATUS3_REG 0x7c | |
| 56 | −#define MTK_NOR_FLHCFG_REG 0x84 | |
| 57 | −#define MTK_NOR_TIME_REG 0x94 | |
| 58 | −#define MTK_NOR_PP_DATA_REG 0x98 | |
| 59 | −#define MTK_NOR_PREBUF_STUS_REG 0x9c | |
| 60 | −#define MTK_NOR_DELSEL0_REG 0xa0 | |
| 61 | −#define MTK_NOR_DELSEL1_REG 0xa4 | |
| 62 | −#define MTK_NOR_INTRSTUS_REG 0xa8 | |
| 63 | −#define MTK_NOR_INTREN_REG 0xac | |
| 64 | −#define MTK_NOR_CHKSUM_CTL_REG 0xb8 | |
| 65 | −#define MTK_NOR_CHKSUM_REG 0xbc | |
| 66 | −#define MTK_NOR_CMD2_REG 0xc0 | |
| 67 | −#define MTK_NOR_WRPROT_REG 0xc4 | |
| 68 | −#define MTK_NOR_RADR3_REG 0xc8 | |
| 69 | −#define MTK_NOR_DUAL_REG 0xcc | |
| 70 | −#define MTK_NOR_DELSEL2_REG 0xd0 | |
| 71 | −#define MTK_NOR_DELSEL3_REG 0xd4 | |
| 72 | −#define MTK_NOR_DELSEL4_REG 0xd8 | |
| 73 | − | |
| 74 | −/* commands for mtk nor controller */ | |
| 75 | −#define MTK_NOR_READ_CMD 0x0 | |
| 76 | −#define MTK_NOR_RDSR_CMD 0x2 | |
| 77 | −#define MTK_NOR_PRG_CMD 0x4 | |
| 78 | −#define MTK_NOR_WR_CMD 0x10 | |
| 79 | −#define MTK_NOR_PIO_WR_CMD 0x90 | |
| 80 | −#define MTK_NOR_WRSR_CMD 0x20 | |
| 81 | −#define MTK_NOR_PIO_READ_CMD 0x81 | |
| 82 | −#define MTK_NOR_WR_BUF_ENABLE 0x1 | |
| 83 | −#define MTK_NOR_WR_BUF_DISABLE 0x0 | |
| 84 | −#define MTK_NOR_ENABLE_SF_CMD 0x30 | |
| 85 | −#define MTK_NOR_DUAD_ADDR_EN 0x8 | |
| 86 | −#define MTK_NOR_QUAD_READ_EN 0x4 | |
| 87 | −#define MTK_NOR_DUAL_ADDR_EN 0x2 | |
| 88 | −#define MTK_NOR_DUAL_READ_EN 0x1 | |
| 89 | −#define MTK_NOR_DUAL_DISABLE 0x0 | |
| 90 | −#define MTK_NOR_FAST_READ 0x1 | |
| 91 | − | |
| 92 | −#define SFLASH_WRBUF_SIZE 128 | |
| 93 | − | |
| 94 | −/* Can shift up to 48 bits (6 bytes) of TX/RX */ | |
| 95 | −#define MTK_NOR_MAX_RX_TX_SHIFT 6 | |
| 96 | −/* can shift up to 56 bits (7 bytes) transfer by MTK_NOR_PRG_CMD */ | |
| 97 | −#define MTK_NOR_MAX_SHIFT 7 | |
| 98 | −/* nor controller 4-byte address mode enable bit */ | |
| 99 | −#define MTK_NOR_4B_ADDR_EN BIT(4) | |
| 100 | − | |
| 101 | −/* Helpers for accessing the program data / shift data registers */ | |
| 102 | −#define MTK_NOR_PRG_REG(n) (MTK_NOR_PRGDATA0_REG + 4 * (n)) | |
| 103 | −#define MTK_NOR_SHREG(n) (MTK_NOR_SHREG0_REG + 4 * (n)) | |
| 104 | − | |
| 105 | −struct mtk_nor { | |
| 106 | − struct spi_nor nor; | |
| 107 | − struct device *dev; | |
| 108 | − void __iomem *base; /* nor flash base address */ | |
| 109 | − struct clk *spi_clk; | |
| 110 | − struct clk *nor_clk; | |
| 111 | −}; | |
| 112 | − | |
| 113 | −static void mtk_nor_set_read_mode(struct mtk_nor *mtk_nor) | |
| 114 | −{ | |
| 115 | − struct spi_nor *nor = &mtk_nor->nor; | |
| 116 | − | |
| 117 | − switch (nor->read_proto) { | |
| 118 | − case SNOR_PROTO_1_1_1: | |
| 119 | − writeb(nor->read_opcode, mtk_nor->base + | |
| 120 | − MTK_NOR_PRGDATA3_REG); | |
| 121 | − writeb(MTK_NOR_FAST_READ, mtk_nor->base + | |
| 122 | − MTK_NOR_CFG1_REG); | |
| 123 | − break; | |
| 124 | − case SNOR_PROTO_1_1_2: | |
| 125 | − writeb(nor->read_opcode, mtk_nor->base + | |
| 126 | − MTK_NOR_PRGDATA3_REG); | |
| 127 | − writeb(MTK_NOR_DUAL_READ_EN, mtk_nor->base + | |
| 128 | − MTK_NOR_DUAL_REG); | |
| 129 | − break; | |
| 130 | − case SNOR_PROTO_1_1_4: | |
| 131 | − writeb(nor->read_opcode, mtk_nor->base + | |
| 132 | − MTK_NOR_PRGDATA4_REG); | |
| 133 | − writeb(MTK_NOR_QUAD_READ_EN, mtk_nor->base + | |
| 134 | − MTK_NOR_DUAL_REG); | |
| 135 | − break; | |
| 136 | − default: | |
| 137 | − writeb(MTK_NOR_DUAL_DISABLE, mtk_nor->base + | |
| 138 | − MTK_NOR_DUAL_REG); | |
| 139 | − break; | |
| 140 | − } | |
| 141 | −} | |
| 142 | − | |
| 143 | −static int mtk_nor_execute_cmd(struct mtk_nor *mtk_nor, u8 cmdval) | |
| 144 | −{ | |
| 145 | − int reg; | |
| 146 | − u8 val = cmdval & 0x1f; | |
| 147 | − | |
| 148 | − writeb(cmdval, mtk_nor->base + MTK_NOR_CMD_REG); | |
| 149 | − return readl_poll_timeout(mtk_nor->base + MTK_NOR_CMD_REG, reg, | |
| 150 | − !(reg & val), 100, 10000); | |
| 151 | −} | |
| 152 | − | |
| 153 | −static int mtk_nor_do_tx_rx(struct mtk_nor *mtk_nor, u8 op, | |
| 154 | − const u8 *tx, size_t txlen, u8 *rx, size_t rxlen) | |
| 155 | −{ | |
| 156 | − size_t len = 1 + txlen + rxlen; | |
| 157 | − int i, ret, idx; | |
| 158 | − | |
| 159 | − if (len > MTK_NOR_MAX_SHIFT) | |
| 160 | − return -EINVAL; | |
| 161 | − | |
| 162 | − writeb(len * 8, mtk_nor->base + MTK_NOR_CNT_REG); | |
| 163 | − | |
| 164 | − /* start at PRGDATA5, go down to PRGDATA0 */ | |
| 165 | − idx = MTK_NOR_MAX_RX_TX_SHIFT - 1; | |
| 166 | − | |
| 167 | − /* opcode */ | |
| 168 | − writeb(op, mtk_nor->base + MTK_NOR_PRG_REG(idx)); | |
| 169 | − idx--; | |
| 170 | − | |
| 171 | − /* program TX data */ | |
| 172 | − for (i = 0; i < txlen; i++, idx--) | |
| 173 | − writeb(tx[i], mtk_nor->base + MTK_NOR_PRG_REG(idx)); | |
| 174 | − | |
| 175 | − /* clear out rest of TX registers */ | |
| 176 | − while (idx >= 0) { | |
| 177 | − writeb(0, mtk_nor->base + MTK_NOR_PRG_REG(idx)); | |
| 178 | − idx--; | |
| 179 | − } | |
| 180 | − | |
| 181 | − ret = mtk_nor_execute_cmd(mtk_nor, MTK_NOR_PRG_CMD); | |
| 182 | − if (ret) | |
| 183 | − return ret; | |
| 184 | − | |
| 185 | − /* restart at first RX byte */ | |
| 186 | − idx = rxlen - 1; | |
| 187 | − | |
| 188 | − /* read out RX data */ | |
| 189 | − for (i = 0; i < rxlen; i++, idx--) | |
| 190 | − rx[i] = readb(mtk_nor->base + MTK_NOR_SHREG(idx)); | |
| 191 | − | |
| 192 | − return 0; | |
| 193 | −} | |
| 194 | − | |
| 195 | −/* Do a WRSR (Write Status Register) command */ | |
| 196 | −static int mtk_nor_wr_sr(struct mtk_nor *mtk_nor, const u8 sr) | |
| 197 | −{ | |
| 198 | − writeb(sr, mtk_nor->base + MTK_NOR_PRGDATA5_REG); | |
| 199 | − writeb(8, mtk_nor->base + MTK_NOR_CNT_REG); | |
| 200 | − return mtk_nor_execute_cmd(mtk_nor, MTK_NOR_WRSR_CMD); | |
| 201 | −} | |
| 202 | − | |
| 203 | −static int mtk_nor_write_buffer_enable(struct mtk_nor *mtk_nor) | |
| 204 | −{ | |
| 205 | − u8 reg; | |
| 206 | − | |
| 207 | − /* the bit0 of MTK_NOR_CFG2_REG is pre-fetch buffer | |
| 208 | − * 0: pre-fetch buffer use for read | |
| 209 | − * 1: pre-fetch buffer use for page program | |
| 210 | − */ | |
| 211 | − writel(MTK_NOR_WR_BUF_ENABLE, mtk_nor->base + MTK_NOR_CFG2_REG); | |
| 212 | − return readb_poll_timeout(mtk_nor->base + MTK_NOR_CFG2_REG, reg, | |
| 213 | − 0x01 == (reg & 0x01), 100, 10000); | |
| 214 | −} | |
| 215 | − | |
| 216 | −static int mtk_nor_write_buffer_disable(struct mtk_nor *mtk_nor) | |
| 217 | −{ | |
| 218 | − u8 reg; | |
| 219 | − | |
| 220 | − writel(MTK_NOR_WR_BUF_DISABLE, mtk_nor->base + MTK_NOR_CFG2_REG); | |
| 221 | − return readb_poll_timeout(mtk_nor->base + MTK_NOR_CFG2_REG, reg, | |
| 222 | − MTK_NOR_WR_BUF_DISABLE == (reg & 0x1), 100, | |
| 223 | − 10000); | |
| 224 | −} | |
| 225 | − | |
| 226 | −static void mtk_nor_set_addr_width(struct mtk_nor *mtk_nor) | |
| 227 | −{ | |
| 228 | − u8 val; | |
| 229 | − struct spi_nor *nor = &mtk_nor->nor; | |
| 230 | − | |
| 231 | − val = readb(mtk_nor->base + MTK_NOR_DUAL_REG); | |
| 232 | − | |
| 233 | − switch (nor->addr_width) { | |
| 234 | − case 3: | |
| 235 | − val &= ~MTK_NOR_4B_ADDR_EN; | |
| 236 | − break; | |
| 237 | − case 4: | |
| 238 | − val |= MTK_NOR_4B_ADDR_EN; | |
| 239 | − break; | |
| 240 | − default: | |
| 241 | − dev_warn(mtk_nor->dev, "Unexpected address width %u.\n", | |
| 242 | − nor->addr_width); | |
| 243 | − break; | |
| 244 | − } | |
| 245 | − | |
| 246 | − writeb(val, mtk_nor->base + MTK_NOR_DUAL_REG); | |
| 247 | −} | |
| 248 | − | |
| 249 | −static void mtk_nor_set_addr(struct mtk_nor *mtk_nor, u32 addr) | |
| 250 | −{ | |
| 251 | − int i; | |
| 252 | − | |
| 253 | − mtk_nor_set_addr_width(mtk_nor); | |
| 254 | − | |
| 255 | − for (i = 0; i < 3; i++) { | |
| 256 | − writeb(addr & 0xff, mtk_nor->base + MTK_NOR_RADR0_REG + i * 4); | |
| 257 | − addr >>= 8; | |
| 258 | − } | |
| 259 | − /* Last register is non-contiguous */ | |
| 260 | − writeb(addr & 0xff, mtk_nor->base + MTK_NOR_RADR3_REG); | |
| 261 | −} | |
| 262 | − | |
| 263 | −static ssize_t mtk_nor_read(struct spi_nor *nor, loff_t from, size_t length, | |
| 264 | − u_char *buffer) | |
| 265 | −{ | |
| 266 | − int i, ret; | |
| 267 | − int addr = (int)from; | |
| 268 | − u8 *buf = (u8 *)buffer; | |
| 269 | − struct mtk_nor *mtk_nor = nor->priv; | |
| 270 | − | |
| 271 | − /* set mode for fast read mode ,dual mode or quad mode */ | |
| 272 | − mtk_nor_set_read_mode(mtk_nor); | |
| 273 | − mtk_nor_set_addr(mtk_nor, addr); | |
| 274 | − | |
| 275 | − for (i = 0; i < length; i++) { | |
| 276 | − ret = mtk_nor_execute_cmd(mtk_nor, MTK_NOR_PIO_READ_CMD); | |
| 277 | − if (ret < 0) | |
| 278 | − return ret; | |
| 279 | − buf[i] = readb(mtk_nor->base + MTK_NOR_RDATA_REG); | |
| 280 | − } | |
| 281 | − return length; | |
| 282 | −} | |
| 283 | − | |
| 284 | −static int mtk_nor_write_single_byte(struct mtk_nor *mtk_nor, | |
| 285 | − int addr, int length, u8 *data) | |
| 286 | −{ | |
| 287 | − int i, ret; | |
| 288 | − | |
| 289 | − mtk_nor_set_addr(mtk_nor, addr); | |
| 290 | − | |
| 291 | − for (i = 0; i < length; i++) { | |
| 292 | − writeb(*data++, mtk_nor->base + MTK_NOR_WDATA_REG); | |
| 293 | − ret = mtk_nor_execute_cmd(mtk_nor, MTK_NOR_PIO_WR_CMD); | |
| 294 | − if (ret < 0) | |
| 295 | − return ret; | |
| 296 | − } | |
| 297 | − return 0; | |
| 298 | −} | |
| 299 | − | |
| 300 | −static int mtk_nor_write_buffer(struct mtk_nor *mtk_nor, int addr, | |
| 301 | − const u8 *buf) | |
| 302 | −{ | |
| 303 | − int i, bufidx, data; | |
| 304 | − | |
| 305 | − mtk_nor_set_addr(mtk_nor, addr); | |
| 306 | − | |
| 307 | − bufidx = 0; | |
| 308 | − for (i = 0; i < SFLASH_WRBUF_SIZE; i += 4) { | |
| 309 | − data = buf[bufidx + 3]<<24 | buf[bufidx + 2]<<16 | | |
| 310 | − buf[bufidx + 1]<<8 | buf[bufidx]; | |
| 311 | − bufidx += 4; | |
| 312 | − writel(data, mtk_nor->base + MTK_NOR_PP_DATA_REG); | |
| 313 | − } | |
| 314 | − return mtk_nor_execute_cmd(mtk_nor, MTK_NOR_WR_CMD); | |
| 315 | −} | |
| 316 | − | |
| 317 | −static ssize_t mtk_nor_write(struct spi_nor *nor, loff_t to, size_t len, | |
| 318 | − const u_char *buf) | |
| 319 | −{ | |
| 320 | − int ret; | |
| 321 | − struct mtk_nor *mtk_nor = nor->priv; | |
| 322 | − size_t i; | |
| 323 | − | |
| 324 | − ret = mtk_nor_write_buffer_enable(mtk_nor); | |
| 325 | − if (ret < 0) { | |
| 326 | − dev_warn(mtk_nor->dev, "write buffer enable failed!\n"); | |
| 327 | − return ret; | |
| 328 | − } | |
| 329 | − | |
| 330 | − for (i = 0; i + SFLASH_WRBUF_SIZE <= len; i += SFLASH_WRBUF_SIZE) { | |
| 331 | − ret = mtk_nor_write_buffer(mtk_nor, to, buf); | |
| 332 | − if (ret < 0) { | |
| 333 | − dev_err(mtk_nor->dev, "write buffer failed!\n"); | |
| 334 | − return ret; | |
| 335 | − } | |
| 336 | − to += SFLASH_WRBUF_SIZE; | |
| 337 | − buf += SFLASH_WRBUF_SIZE; | |
| 338 | − } | |
| 339 | − ret = mtk_nor_write_buffer_disable(mtk_nor); | |
| 340 | − if (ret < 0) { | |
| 341 | − dev_warn(mtk_nor->dev, "write buffer disable failed!\n"); | |
| 342 | − return ret; | |
| 343 | − } | |
| 344 | − | |
| 345 | − if (i < len) { | |
| 346 | − ret = mtk_nor_write_single_byte(mtk_nor, to, | |
| 347 | − (int)(len - i), (u8 *)buf); | |
| 348 | − if (ret < 0) { | |
| 349 | − dev_err(mtk_nor->dev, "write single byte failed!\n"); | |
| 350 | − return ret; | |
| 351 | − } | |
| 352 | − } | |
| 353 | − | |
| 354 | − return len; | |
| 355 | −} | |
| 356 | − | |
| 357 | −static int mtk_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len) | |
| 358 | −{ | |
| 359 | − int ret; | |
| 360 | − struct mtk_nor *mtk_nor = nor->priv; | |
| 361 | − | |
| 362 | − switch (opcode) { | |
| 363 | − case SPINOR_OP_RDSR: | |
| 364 | − ret = mtk_nor_execute_cmd(mtk_nor, MTK_NOR_RDSR_CMD); | |
| 365 | − if (ret < 0) | |
| 366 | − return ret; | |
| 367 | − if (len == 1) | |
| 368 | − *buf = readb(mtk_nor->base + MTK_NOR_RDSR_REG); | |
| 369 | − else | |
| 370 | − dev_err(mtk_nor->dev, "len should be 1 for read status!\n"); | |
| 371 | − break; | |
| 372 | − default: | |
| 373 | − ret = mtk_nor_do_tx_rx(mtk_nor, opcode, NULL, 0, buf, len); | |
| 374 | − break; | |
| 375 | − } | |
| 376 | − return ret; | |
| 377 | −} | |
| 378 | − | |
| 379 | −static int mtk_nor_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, | |
| 380 | − size_t len) | |
| 381 | −{ | |
| 382 | − int ret; | |
| 383 | − struct mtk_nor *mtk_nor = nor->priv; | |
| 384 | − | |
| 385 | − switch (opcode) { | |
| 386 | − case SPINOR_OP_WRSR: | |
| 387 | − /* We only handle 1 byte */ | |
| 388 | − ret = mtk_nor_wr_sr(mtk_nor, *buf); | |
| 389 | − break; | |
| 390 | − default: | |
| 391 | − ret = mtk_nor_do_tx_rx(mtk_nor, opcode, buf, len, NULL, 0); | |
| 392 | − if (ret) | |
| 393 | − dev_warn(mtk_nor->dev, "write reg failure!\n"); | |
| 394 | − break; | |
| 395 | − } | |
| 396 | − return ret; | |
| 397 | −} | |
| 398 | − | |
| 399 | −static void mtk_nor_disable_clk(struct mtk_nor *mtk_nor) | |
| 400 | −{ | |
| 401 | − clk_disable_unprepare(mtk_nor->spi_clk); | |
| 402 | − clk_disable_unprepare(mtk_nor->nor_clk); | |
| 403 | −} | |
| 404 | − | |
| 405 | −static int mtk_nor_enable_clk(struct mtk_nor *mtk_nor) | |
| 406 | −{ | |
| 407 | − int ret; | |
| 408 | − | |
| 409 | − ret = clk_prepare_enable(mtk_nor->spi_clk); | |
| 410 | − if (ret) | |
| 411 | − return ret; | |
| 412 | − | |
| 413 | − ret = clk_prepare_enable(mtk_nor->nor_clk); | |
| 414 | − if (ret) { | |
| 415 | − clk_disable_unprepare(mtk_nor->spi_clk); | |
| 416 | − return ret; | |
| 417 | − } | |
| 418 | − | |
| 419 | − return 0; | |
| 420 | −} | |
| 421 | − | |
| 422 | −static const struct spi_nor_controller_ops mtk_controller_ops = { | |
| 423 | − .read_reg = mtk_nor_read_reg, | |
| 424 | − .write_reg = mtk_nor_write_reg, | |
| 425 | − .read = mtk_nor_read, | |
| 426 | − .write = mtk_nor_write, | |
| 427 | −}; | |
| 428 | − | |
| 429 | −static int mtk_nor_init(struct mtk_nor *mtk_nor, | |
| 430 | − struct device_node *flash_node) | |
| 431 | −{ | |
| 432 | − const struct spi_nor_hwcaps hwcaps = { | |
| 433 | − .mask = SNOR_HWCAPS_READ | | |
| 434 | − SNOR_HWCAPS_READ_FAST | | |
| 435 | − SNOR_HWCAPS_READ_1_1_2 | | |
| 436 | − SNOR_HWCAPS_PP, | |
| 437 | − }; | |
| 438 | − int ret; | |
| 439 | − struct spi_nor *nor; | |
| 440 | − | |
| 441 | − /* initialize controller to accept commands */ | |
| 442 | − writel(MTK_NOR_ENABLE_SF_CMD, mtk_nor->base + MTK_NOR_WRPROT_REG); | |
| 443 | − | |
| 444 | − nor = &mtk_nor->nor; | |
| 445 | − nor->dev = mtk_nor->dev; | |
| 446 | − nor->priv = mtk_nor; | |
| 447 | − spi_nor_set_flash_node(nor, flash_node); | |
| 448 | − nor->controller_ops = &mtk_controller_ops; | |
| 449 | − | |
| 450 | − nor->mtd.name = "mtk_nor"; | |
| 451 | − /* initialized with NULL */ | |
| 452 | − ret = spi_nor_scan(nor, NULL, &hwcaps); | |
| 453 | − if (ret) | |
| 454 | − return ret; | |
| 455 | − | |
| 456 | − return mtd_device_register(&nor->mtd, NULL, 0); | |
| 457 | −} | |
| 458 | − | |
| 459 | −static int mtk_nor_drv_probe(struct platform_device *pdev) | |
| 460 | −{ | |
| 461 | − struct device_node *flash_np; | |
| 462 | − struct resource *res; | |
| 463 | − int ret; | |
| 464 | − struct mtk_nor *mtk_nor; | |
| 465 | − | |
| 466 | − if (!pdev->dev.of_node) { | |
| 467 | − dev_err(&pdev->dev, "No DT found\n"); | |
| 468 | − return -EINVAL; | |
| 469 | − } | |
| 470 | − | |
| 471 | − mtk_nor = devm_kzalloc(&pdev->dev, sizeof(*mtk_nor), GFP_KERNEL); | |
| 472 | − if (!mtk_nor) | |
| 473 | − return -ENOMEM; | |
| 474 | − platform_set_drvdata(pdev, mtk_nor); | |
| 475 | − | |
| 476 | − res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 477 | − mtk_nor->base = devm_ioremap_resource(&pdev->dev, res); | |
| 478 | − if (IS_ERR(mtk_nor->base)) | |
| 479 | − return PTR_ERR(mtk_nor->base); | |
| 480 | − | |
| 481 | − mtk_nor->spi_clk = devm_clk_get(&pdev->dev, "spi"); | |
| 482 | − if (IS_ERR(mtk_nor->spi_clk)) | |
| 483 | − return PTR_ERR(mtk_nor->spi_clk); | |
| 484 | − | |
| 485 | − mtk_nor->nor_clk = devm_clk_get(&pdev->dev, "sf"); | |
| 486 | − if (IS_ERR(mtk_nor->nor_clk)) | |
| 487 | − return PTR_ERR(mtk_nor->nor_clk); | |
| 488 | − | |
| 489 | − mtk_nor->dev = &pdev->dev; | |
| 490 | − | |
| 491 | − ret = mtk_nor_enable_clk(mtk_nor); | |
| 492 | − if (ret) | |
| 493 | − return ret; | |
| 494 | − | |
| 495 | − /* only support one attached flash */ | |
| 496 | − flash_np = of_get_next_available_child(pdev->dev.of_node, NULL); | |
| 497 | − if (!flash_np) { | |
| 498 | − dev_err(&pdev->dev, "no SPI flash device to configure\n"); | |
| 499 | − ret = -ENODEV; | |
| 500 | − goto nor_free; | |
| 501 | − } | |
| 502 | − ret = mtk_nor_init(mtk_nor, flash_np); | |
| 503 | − | |
| 504 | −nor_free: | |
| 505 | − if (ret) | |
| 506 | − mtk_nor_disable_clk(mtk_nor); | |
| 507 | − | |
| 508 | − return ret; | |
| 509 | −} | |
| 510 | − | |
| 511 | −static int mtk_nor_drv_remove(struct platform_device *pdev) | |
| 512 | −{ | |
| 513 | − struct mtk_nor *mtk_nor = platform_get_drvdata(pdev); | |
| 514 | − | |
| 515 | − mtk_nor_disable_clk(mtk_nor); | |
| 516 | − | |
| 517 | − return 0; | |
| 518 | −} | |
| 519 | − | |
| 520 | −#ifdef CONFIG_PM_SLEEP | |
| 521 | −static int mtk_nor_suspend(struct device *dev) | |
| 522 | −{ | |
| 523 | − struct mtk_nor *mtk_nor = dev_get_drvdata(dev); | |
| 524 | − | |
| 525 | − mtk_nor_disable_clk(mtk_nor); | |
| 526 | − | |
| 527 | − return 0; | |
| 528 | −} | |
| 529 | − | |
| 530 | −static int mtk_nor_resume(struct device *dev) | |
| 531 | −{ | |
| 532 | − struct mtk_nor *mtk_nor = dev_get_drvdata(dev); | |
| 533 | − | |
| 534 | − return mtk_nor_enable_clk(mtk_nor); | |
| 535 | −} | |
| 536 | − | |
| 537 | −static const struct dev_pm_ops mtk_nor_dev_pm_ops = { | |
| 538 | − .suspend = mtk_nor_suspend, | |
| 539 | − .resume = mtk_nor_resume, | |
| 540 | −}; | |
| 541 | − | |
| 542 | −#define MTK_NOR_DEV_PM_OPS (&mtk_nor_dev_pm_ops) | |
| 543 | −#else | |
| 544 | −#define MTK_NOR_DEV_PM_OPS NULL | |
| 545 | −#endif | |
| 546 | − | |
| 547 | −static const struct of_device_id mtk_nor_of_ids[] = { | |
| 548 | − { .compatible = "mediatek,mt8173-nor"}, | |
| 549 | − { /* sentinel */ } | |
| 550 | −}; | |
| 551 | −MODULE_DEVICE_TABLE(of, mtk_nor_of_ids); | |
| 552 | − | |
| 553 | −static struct platform_driver mtk_nor_driver = { | |
| 554 | − .probe = mtk_nor_drv_probe, | |
| 555 | − .remove = mtk_nor_drv_remove, | |
| 556 | − .driver = { | |
| 557 | − .name = "mtk-nor", | |
| 558 | − .pm = MTK_NOR_DEV_PM_OPS, | |
| 559 | − .of_match_table = mtk_nor_of_ids, | |
| 560 | − }, | |
| 561 | −}; | |
| 562 | − | |
| 563 | −module_platform_driver(mtk_nor_driver); | |
| 564 | −MODULE_LICENSE("GPL v2"); | |
| 565 | −MODULE_DESCRIPTION("MediaTek SPI NOR Flash Driver"); | |
| @@ -107,6 +107,7 @@ config REGULATOR_AD5398 · 106 unmodified lines | ||
| 107 | 107 | |
| 108 | 108 | config REGULATOR_ANATOP |
| 109 | 109 | tristate "Freescale i.MX on-chip ANATOP LDO regulators" |
| 110 | + depends on ARCH_MXC || COMPILE_TEST | |
| 110 | 111 | depends on MFD_SYSCON |
| 111 | 112 | help |
| 112 | 113 | Say y here to support Freescale i.MX on-chip ANATOP LDOs |
| @@ -613,6 +614,16 @@ config REGULATOR_MCP16502 · 500 unmodified lines | ||
| 613 | 614 | through the regulator interface. In addition it enables |
| 614 | 615 | suspend-to-ram/standby transition. |
| 615 | 616 | |
| 617 | +config REGULATOR_MP5416 | |
| 618 | + tristate "Monolithic MP5416 PMIC" | |
| 619 | + depends on I2C && OF | |
| 620 | + select REGMAP_I2C | |
| 621 | + help | |
| 622 | + Say y here to support the MP5416 PMIC. This will enable supports | |
| 623 | + the software controllable 4 buck and 4 LDO regulators. | |
| 624 | + Say M here if you want to include support for the regulator as a | |
| 625 | + module. | |
| 626 | + | |
| 616 | 627 | config REGULATOR_MP8859 |
| 617 | 628 | tristate "MPS MP8859 regulator driver" |
| 618 | 629 | depends on I2C |
| @@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o · 77 unmodified lines | ||
| 78 | 78 | obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o |
| 79 | 79 | obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o |
| 80 | 80 | obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o |
| 81 | +obj-$(CONFIG_REGULATOR_MP5416) += mp5416.o | |
| 81 | 82 | obj-$(CONFIG_REGULATOR_MP8859) += mp8859.o |
| 82 | 83 | obj-$(CONFIG_REGULATOR_MPQ7920) += mpq7920.o |
| 83 | 84 | obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o |
| @@ -305,9 +305,13 @@ static int anatop_regulator_probe(struct platform_device *pdev) · 304 unmodified lines | ||
| 305 | 305 | /* register regulator */ |
| 306 | 306 | rdev = devm_regulator_register(dev, rdesc, &config); |
| 307 | 307 | if (IS_ERR(rdev)) { |
| 308 | − dev_err(dev, "failed to register %s\n", | |
| 309 | − rdesc->name); | |
| 310 | − return PTR_ERR(rdev); | |
| 308 | + ret = PTR_ERR(rdev); | |
| 309 | + if (ret == -EPROBE_DEFER) | |
| 310 | + dev_dbg(dev, "failed to register %s, deferring...\n", | |
| 311 | + rdesc->name); | |
| 312 | + else | |
| 313 | + dev_err(dev, "failed to register %s\n", rdesc->name); | |
| 314 | + return ret; | |
| 311 | 315 | } |
| 312 | 316 | |
| 313 | 317 | platform_set_drvdata(pdev, rdev); |
| @@ -381,8 +381,7 @@ static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp) · 380 unmodified lines | ||
| 381 | 381 | mask = AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE_MASK | |
| 382 | 382 | AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN_MASK; |
| 383 | 383 | enable = (ramp > 0) ? |
| 384 | − AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN : | |
| 385 | − !AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN; | |
| 384 | + AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN : 0; | |
| 386 | 385 | break; |
| 387 | 386 | } |
| 388 | 387 | |
| @@ -393,8 +392,7 @@ static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp) · 4 unmodified lines | ||
| 393 | 392 | mask = AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE_MASK | |
| 394 | 393 | AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN_MASK; |
| 395 | 394 | enable = (ramp > 0) ? |
| 396 | − AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN : | |
| 397 | − !AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN; | |
| 395 | + AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN : 0; | |
| 398 | 396 | break; |
| 399 | 397 | } |
| 400 | 398 | |
| @@ -73,7 +73,7 @@ struct da9062_regulators { · 72 unmodified lines | ||
| 73 | 73 | int irq_ldo_lim; |
| 74 | 74 | unsigned n_regulators; |
| 75 | 75 | /* Array size to be defined during init. Keep at end. */ |
| 76 | − struct da9062_regulator regulator[0]; | |
| 76 | + struct da9062_regulator regulator[]; | |
| 77 | 77 | }; |
| 78 | 78 | |
| 79 | 79 | /* Regulator operations */ |
| @@ -66,7 +66,7 @@ struct da9063_regulator_data { · 65 unmodified lines | ||
| 66 | 66 | }; |
| 67 | 67 | |
| 68 | 68 | struct da9063_regulators_pdata { |
| 69 | − unsigned n_regulators; | |
| 69 | + unsigned int n_regulators; | |
| 70 | 70 | struct da9063_regulator_data *regulator_data; |
| 71 | 71 | }; |
| 72 | 72 | |
| @@ -131,7 +131,7 @@ struct da9063_regulator_info { · 58 unmodified lines | ||
| 131 | 131 | /* Defines asignment of regulators info table to chip model */ |
| 132 | 132 | struct da9063_dev_model { |
| 133 | 133 | const struct da9063_regulator_info *regulator_info; |
| 134 | − unsigned n_regulators; | |
| 134 | + unsigned int n_regulators; | |
| 135 | 135 | enum da9063_type type; |
| 136 | 136 | }; |
| 137 | 137 | |
| @@ -150,9 +150,9 @@ struct da9063_regulator { · 12 unmodified lines | ||
| 150 | 150 | |
| 151 | 151 | /* Encapsulates all information for the regulators driver */ |
| 152 | 152 | struct da9063_regulators { |
| 153 | − unsigned n_regulators; | |
| 153 | + unsigned int n_regulators; | |
| 154 | 154 | /* Array size to be defined during init. Keep at end. */ |
| 155 | − struct da9063_regulator regulator[0]; | |
| 155 | + struct da9063_regulator regulator[]; | |
| 156 | 156 | }; |
| 157 | 157 | |
| 158 | 158 | /* BUCK modes for DA9063 */ |
| @@ -165,38 +165,46 @@ enum { · 6 unmodified lines | ||
| 165 | 165 | |
| 166 | 166 | /* Regulator operations */ |
| 167 | 167 | |
| 168 | −/* Current limits array (in uA) for BCORE1, BCORE2, BPRO. | |
| 169 | − Entry indexes corresponds to register values. */ | |
| 168 | +/* | |
| 169 | + * Current limits array (in uA) for BCORE1, BCORE2, BPRO. | |
| 170 | + * Entry indexes corresponds to register values. | |
| 171 | + */ | |
| 170 | 172 | static const unsigned int da9063_buck_a_limits[] = { |
| 171 | 173 | 500000, 600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, |
| 172 | 174 | 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000 |
| 173 | 175 | }; |
| 174 | 176 | |
| 175 | −/* Current limits array (in uA) for BMEM, BIO, BPERI. | |
| 176 | − Entry indexes corresponds to register values. */ | |
| 177 | +/* | |
| 178 | + * Current limits array (in uA) for BMEM, BIO, BPERI. | |
| 179 | + * Entry indexes corresponds to register values. | |
| 180 | + */ | |
| 177 | 181 | static const unsigned int da9063_buck_b_limits[] = { |
| 178 | 182 | 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000, |
| 179 | 183 | 2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000 |
| 180 | 184 | }; |
| 181 | 185 | |
| 182 | −/* Current limits array (in uA) for merged BCORE1 and BCORE2. | |
| 183 | − Entry indexes corresponds to register values. */ | |
| 186 | +/* | |
| 187 | + * Current limits array (in uA) for merged BCORE1 and BCORE2. | |
| 188 | + * Entry indexes corresponds to register values. | |
| 189 | + */ | |
| 184 | 190 | static const unsigned int da9063_bcores_merged_limits[] = { |
| 185 | 191 | 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2200000, 2400000, |
| 186 | 192 | 2600000, 2800000, 3000000, 3200000, 3400000, 3600000, 3800000, 4000000 |
| 187 | 193 | }; |
| 188 | 194 | |
| 189 | −/* Current limits array (in uA) for merged BMEM and BIO. | |
| 190 | − Entry indexes corresponds to register values. */ | |
| 195 | +/* | |
| 196 | + * Current limits array (in uA) for merged BMEM and BIO. | |
| 197 | + * Entry indexes corresponds to register values. | |
| 198 | + */ | |
| 191 | 199 | static const unsigned int da9063_bmem_bio_merged_limits[] = { |
| 192 | 200 | 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, |
| 193 | 201 | 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000 |
| 194 | 202 | }; |
| 195 | 203 | |
| 196 | −static int da9063_buck_set_mode(struct regulator_dev *rdev, unsigned mode) | |
| 204 | +static int da9063_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) | |
| 197 | 205 | { |
| 198 | 206 | struct da9063_regulator *regl = rdev_get_drvdata(rdev); |
| 199 | − unsigned val; | |
| 207 | + unsigned int val; | |
| 200 | 208 | |
| 201 | 209 | switch (mode) { |
| 202 | 210 | case REGULATOR_MODE_FAST: |
| @@ -221,7 +229,7 @@ static int da9063_buck_set_mode(struct regulator_dev *rdev, unsigned mode) · 18 unmodified lines | ||
| 221 | 229 | * There are 3 modes to map to: FAST, NORMAL, and STANDBY. |
| 222 | 230 | */ |
| 223 | 231 | |
| 224 | −static unsigned da9063_buck_get_mode(struct regulator_dev *rdev) | |
| 232 | +static unsigned int da9063_buck_get_mode(struct regulator_dev *rdev) | |
| 225 | 233 | { |
| 226 | 234 | struct da9063_regulator *regl = rdev_get_drvdata(rdev); |
| 227 | 235 | struct regmap_field *field; |
| @@ -271,10 +279,10 @@ static unsigned da9063_buck_get_mode(struct regulator_dev *rdev) · 43 unmodified lines | ||
| 271 | 279 | * There are 2 modes to map to: NORMAL and STANDBY (sleep) for each state. |
| 272 | 280 | */ |
| 273 | 281 | |
| 274 | −static int da9063_ldo_set_mode(struct regulator_dev *rdev, unsigned mode) | |
| 282 | +static int da9063_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) | |
| 275 | 283 | { |
| 276 | 284 | struct da9063_regulator *regl = rdev_get_drvdata(rdev); |
| 277 | − unsigned val; | |
| 285 | + unsigned int val; | |
| 278 | 286 | |
| 279 | 287 | switch (mode) { |
| 280 | 288 | case REGULATOR_MODE_NORMAL: |
| @@ -290,7 +298,7 @@ static int da9063_ldo_set_mode(struct regulator_dev *rdev, unsigned mode) · 9 unmodified lines | ||
| 290 | 298 | return regmap_field_write(regl->sleep, val); |
| 291 | 299 | } |
| 292 | 300 | |
| 293 | −static unsigned da9063_ldo_get_mode(struct regulator_dev *rdev) | |
| 301 | +static unsigned int da9063_ldo_get_mode(struct regulator_dev *rdev) | |
| 294 | 302 | { |
| 295 | 303 | struct da9063_regulator *regl = rdev_get_drvdata(rdev); |
| 296 | 304 | struct regmap_field *field; |
| @@ -383,7 +391,8 @@ static int da9063_suspend_disable(struct regulator_dev *rdev) · 86 unmodified lines | ||
| 383 | 391 | return regmap_field_write(regl->suspend, 0); |
| 384 | 392 | } |
| 385 | 393 | |
| 386 | −static int da9063_buck_set_suspend_mode(struct regulator_dev *rdev, unsigned mode) | |
| 394 | +static int da9063_buck_set_suspend_mode(struct regulator_dev *rdev, | |
| 395 | + unsigned int mode) | |
| 387 | 396 | { |
| 388 | 397 | struct da9063_regulator *regl = rdev_get_drvdata(rdev); |
| 389 | 398 | int val; |
| @@ -405,10 +414,11 @@ static int da9063_buck_set_suspend_mode(struct regulator_dev *rdev, unsigned mod · 15 unmodified lines | ||
| 405 | 414 | return regmap_field_write(regl->mode, val); |
| 406 | 415 | } |
| 407 | 416 | |
| 408 | −static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev, unsigned mode) | |
| 417 | +static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev, | |
| 418 | + unsigned int mode) | |
| 409 | 419 | { |
| 410 | 420 | struct da9063_regulator *regl = rdev_get_drvdata(rdev); |
| 411 | − unsigned val; | |
| 421 | + unsigned int val; | |
| 412 | 422 | |
| 413 | 423 | switch (mode) { |
| 414 | 424 | case REGULATOR_MODE_NORMAL: |
| @@ -593,7 +603,7 @@ static irqreturn_t da9063_ldo_lim_event(int irq, void *data) · 178 unmodified lines | ||
| 593 | 603 | struct da9063_regulators *regulators = data; |
| 594 | 604 | struct da9063 *hw = regulators->regulator[0].hw; |
| 595 | 605 | struct da9063_regulator *regl; |
| 596 | − int bits, i , ret; | |
| 606 | + int bits, i, ret; | |
| 597 | 607 | |
| 598 | 608 | ret = regmap_read(hw->regmap, DA9063_REG_STATUS_D, &bits); |
| 599 | 609 | if (ret < 0) |
| @@ -605,10 +615,10 @@ static irqreturn_t da9063_ldo_lim_event(int irq, void *data) · 5 unmodified lines | ||
| 605 | 615 | continue; |
| 606 | 616 | |
| 607 | 617 | if (BIT(regl->info->oc_event.lsb) & bits) { |
| 608 | − regulator_lock(regl->rdev); | |
| 618 | + regulator_lock(regl->rdev); | |
| 609 | 619 | regulator_notifier_call_chain(regl->rdev, |
| 610 | 620 | REGULATOR_EVENT_OVER_CURRENT, NULL); |
| 611 | − regulator_unlock(regl->rdev); | |
| 621 | + regulator_unlock(regl->rdev); | |
| 612 | 622 | } |
| 613 | 623 | } |
| 614 | 624 | |
| @@ -833,7 +843,7 @@ static int da9063_regulator_probe(struct platform_device *pdev) · 218 unmodified lines | ||
| 833 | 843 | |
| 834 | 844 | if (regl->info->suspend_sleep.reg) { |
| 835 | 845 | regl->suspend_sleep = devm_regmap_field_alloc(&pdev->dev, |
| 836 | − da9063->regmap, regl->info->suspend_sleep); | |
| 846 | + da9063->regmap, regl->info->suspend_sleep); | |
| 837 | 847 | if (IS_ERR(regl->suspend_sleep)) |
| 838 | 848 | return PTR_ERR(regl->suspend_sleep); |
| 839 | 849 | } |
| @@ -867,12 +877,10 @@ static int da9063_regulator_probe(struct platform_device *pdev) · 27 unmodified lines | ||
| 867 | 877 | NULL, da9063_ldo_lim_event, |
| 868 | 878 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
| 869 | 879 | "LDO_LIM", regulators); |
| 870 | − if (ret) { | |
| 880 | + if (ret) | |
| 871 | 881 | dev_err(&pdev->dev, "Failed to request LDO_LIM IRQ.\n"); |
| 872 | − return ret; | |
| 873 | − } | |
| 874 | 882 | |
| 875 | − return 0; | |
| 883 | + return ret; | |
| 876 | 884 | } |
| 877 | 885 | |
| 878 | 886 | static struct platform_driver da9063_regulator_driver = { |
| @@ -0,0 +1,245 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | +// | |
| 3 | +// mp5416.c - regulator driver for mps mp5416 | |
| 4 | +// | |
| 5 | +// Copyright 2020 Monolithic Power Systems, Inc | |
| 6 | +// | |
| 7 | +// Author: Saravanan Sekar <sravanhome@gmail.com> | |
| 8 | + | |
| 9 | +#include <linux/kernel.h> | |
| 10 | +#include <linux/module.h> | |
| 11 | +#include <linux/init.h> | |
| 12 | +#include <linux/err.h> | |
| 13 | +#include <linux/platform_device.h> | |
| 14 | +#include <linux/regmap.h> | |
| 15 | +#include <linux/regulator/driver.h> | |
| 16 | +#include <linux/i2c.h> | |
| 17 | + | |
| 18 | +#define MP5416_REG_CTL0 0x00 | |
| 19 | +#define MP5416_REG_CTL1 0x01 | |
| 20 | +#define MP5416_REG_CTL2 0x02 | |
| 21 | +#define MP5416_REG_ILIM 0x03 | |
| 22 | +#define MP5416_REG_BUCK1 0x04 | |
| 23 | +#define MP5416_REG_BUCK2 0x05 | |
| 24 | +#define MP5416_REG_BUCK3 0x06 | |
| 25 | +#define MP5416_REG_BUCK4 0x07 | |
| 26 | +#define MP5416_REG_LDO1 0x08 | |
| 27 | +#define MP5416_REG_LDO2 0x09 | |
| 28 | +#define MP5416_REG_LDO3 0x0a | |
| 29 | +#define MP5416_REG_LDO4 0x0b | |
| 30 | + | |
| 31 | +#define MP5416_REGULATOR_EN BIT(7) | |
| 32 | +#define MP5416_MASK_VSET 0x7f | |
| 33 | +#define MP5416_MASK_BUCK1_ILIM 0xc0 | |
| 34 | +#define MP5416_MASK_BUCK2_ILIM 0x0c | |
| 35 | +#define MP5416_MASK_BUCK3_ILIM 0x30 | |
| 36 | +#define MP5416_MASK_BUCK4_ILIM 0x03 | |
| 37 | +#define MP5416_MASK_DVS_SLEWRATE 0xc0 | |
| 38 | + | |
| 39 | +/* values in uV */ | |
| 40 | +#define MP5416_VOLT1_MIN 600000 | |
| 41 | +#define MP5416_VOLT1_MAX 2187500 | |
| 42 | +#define MP5416_VOLT1_STEP 12500 | |
| 43 | +#define MP5416_VOLT2_MIN 800000 | |
| 44 | +#define MP5416_VOLT2_MAX 3975000 | |
| 45 | +#define MP5416_VOLT2_STEP 25000 | |
| 46 | + | |
| 47 | +#define MP5416_VOLT1_RANGE \ | |
| 48 | + ((MP5416_VOLT1_MAX - MP5416_VOLT1_MIN)/MP5416_VOLT1_STEP + 1) | |
| 49 | +#define MP5416_VOLT2_RANGE \ | |
| 50 | + ((MP5416_VOLT2_MAX - MP5416_VOLT2_MIN)/MP5416_VOLT2_STEP + 1) | |
| 51 | + | |
| 52 | +#define MP5416BUCK(_name, _id, _ilim, _dreg, _dval, _vsel) \ | |
| 53 | + [MP5416_BUCK ## _id] = { \ | |
| 54 | + .id = MP5416_BUCK ## _id, \ | |
| 55 | + .name = _name, \ | |
| 56 | + .of_match = _name, \ | |
| 57 | + .regulators_node = "regulators", \ | |
| 58 | + .ops = &mp5416_buck_ops, \ | |
| 59 | + .min_uV = MP5416_VOLT ##_vsel## _MIN, \ | |
| 60 | + .uV_step = MP5416_VOLT ##_vsel## _STEP, \ | |
| 61 | + .n_voltages = MP5416_VOLT ##_vsel## _RANGE, \ | |
| 62 | + .curr_table = _ilim, \ | |
| 63 | + .n_current_limits = ARRAY_SIZE(_ilim), \ | |
| 64 | + .csel_reg = MP5416_REG_ILIM, \ | |
| 65 | + .csel_mask = MP5416_MASK_BUCK ## _id ##_ILIM, \ | |
| 66 | + .vsel_reg = MP5416_REG_BUCK ## _id, \ | |
| 67 | + .vsel_mask = MP5416_MASK_VSET, \ | |
| 68 | + .enable_reg = MP5416_REG_BUCK ## _id, \ | |
| 69 | + .enable_mask = MP5416_REGULATOR_EN, \ | |
| 70 | + .active_discharge_on = _dval, \ | |
| 71 | + .active_discharge_reg = _dreg, \ | |
| 72 | + .active_discharge_mask = _dval, \ | |
| 73 | + .owner = THIS_MODULE, \ | |
| 74 | + } | |
| 75 | + | |
| 76 | +#define MP5416LDO(_name, _id, _dval) \ | |
| 77 | + [MP5416_LDO ## _id] = { \ | |
| 78 | + .id = MP5416_LDO ## _id, \ | |
| 79 | + .name = _name, \ | |
| 80 | + .of_match = _name, \ | |
| 81 | + .regulators_node = "regulators", \ | |
| 82 | + .ops = &mp5416_ldo_ops, \ | |
| 83 | + .min_uV = MP5416_VOLT2_MIN, \ | |
| 84 | + .uV_step = MP5416_VOLT2_STEP, \ | |
| 85 | + .n_voltages = MP5416_VOLT2_RANGE, \ | |
| 86 | + .vsel_reg = MP5416_REG_LDO ##_id, \ | |
| 87 | + .vsel_mask = MP5416_MASK_VSET, \ | |
| 88 | + .enable_reg = MP5416_REG_LDO ##_id, \ | |
| 89 | + .enable_mask = MP5416_REGULATOR_EN, \ | |
| 90 | + .active_discharge_on = _dval, \ | |
| 91 | + .active_discharge_reg = MP5416_REG_CTL2, \ | |
| 92 | + .active_discharge_mask = _dval, \ | |
| 93 | + .owner = THIS_MODULE, \ | |
| 94 | + } | |
| 95 | + | |
| 96 | +enum mp5416_regulators { | |
| 97 | + MP5416_BUCK1, | |
| 98 | + MP5416_BUCK2, | |
| 99 | + MP5416_BUCK3, | |
| 100 | + MP5416_BUCK4, | |
| 101 | + MP5416_LDO1, | |
| 102 | + MP5416_LDO2, | |
| 103 | + MP5416_LDO3, | |
| 104 | + MP5416_LDO4, | |
| 105 | + MP5416_MAX_REGULATORS, | |
| 106 | +}; | |
| 107 | + | |
| 108 | +static const struct regmap_config mp5416_regmap_config = { | |
| 109 | + .reg_bits = 8, | |
| 110 | + .val_bits = 8, | |
| 111 | + .max_register = 0x0d, | |
| 112 | +}; | |
| 113 | + | |
| 114 | +/* Current limits array (in uA) | |
| 115 | + * ILIM1 & ILIM3 | |
| 116 | + */ | |
| 117 | +static const unsigned int mp5416_I_limits1[] = { | |
| 118 | + 3800000, 4600000, 5600000, 6800000 | |
| 119 | +}; | |
| 120 | + | |
| 121 | +/* ILIM2 & ILIM4 */ | |
| 122 | +static const unsigned int mp5416_I_limits2[] = { | |
| 123 | + 2200000, 3200000, 4200000, 5200000 | |
| 124 | +}; | |
| 125 | + | |
| 126 | +static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay); | |
| 127 | + | |
| 128 | +static const struct regulator_ops mp5416_ldo_ops = { | |
| 129 | + .enable = regulator_enable_regmap, | |
| 130 | + .disable = regulator_disable_regmap, | |
| 131 | + .is_enabled = regulator_is_enabled_regmap, | |
| 132 | + .list_voltage = regulator_list_voltage_linear, | |
| 133 | + .map_voltage = regulator_map_voltage_linear, | |
| 134 | + .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
| 135 | + .set_voltage_sel = regulator_set_voltage_sel_regmap, | |
| 136 | + .set_active_discharge = regulator_set_active_discharge_regmap, | |
| 137 | +}; | |
| 138 | + | |
| 139 | +static const struct regulator_ops mp5416_buck_ops = { | |
| 140 | + .enable = regulator_enable_regmap, | |
| 141 | + .disable = regulator_disable_regmap, | |
| 142 | + .is_enabled = regulator_is_enabled_regmap, | |
| 143 | + .list_voltage = regulator_list_voltage_linear, | |
| 144 | + .map_voltage = regulator_map_voltage_linear, | |
| 145 | + .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
| 146 | + .set_voltage_sel = regulator_set_voltage_sel_regmap, | |
| 147 | + .set_active_discharge = regulator_set_active_discharge_regmap, | |
| 148 | + .get_current_limit = regulator_get_current_limit_regmap, | |
| 149 | + .set_current_limit = regulator_set_current_limit_regmap, | |
| 150 | + .set_ramp_delay = mp5416_set_ramp_delay, | |
| 151 | +}; | |
| 152 | + | |
| 153 | +static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = { | |
| 154 | + MP5416BUCK("buck1", 1, mp5416_I_limits1, MP5416_REG_CTL1, BIT(0), 1), | |
| 155 | + MP5416BUCK("buck2", 2, mp5416_I_limits2, MP5416_REG_CTL1, BIT(1), 2), | |
| 156 | + MP5416BUCK("buck3", 3, mp5416_I_limits1, MP5416_REG_CTL1, BIT(2), 1), | |
| 157 | + MP5416BUCK("buck4", 4, mp5416_I_limits2, MP5416_REG_CTL2, BIT(5), 2), | |
| 158 | + MP5416LDO("ldo1", 1, BIT(4)), | |
| 159 | + MP5416LDO("ldo2", 2, BIT(3)), | |
| 160 | + MP5416LDO("ldo3", 3, BIT(2)), | |
| 161 | + MP5416LDO("ldo4", 4, BIT(1)), | |
| 162 | +}; | |
| 163 | + | |
| 164 | +/* | |
| 165 | + * DVS ramp rate BUCK1 to BUCK4 | |
| 166 | + * 00: 32mV/us | |
| 167 | + * 01: 16mV/us | |
| 168 | + * 10: 8mV/us | |
| 169 | + * 11: 4mV/us | |
| 170 | + */ | |
| 171 | +static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) | |
| 172 | +{ | |
| 173 | + unsigned int ramp_val; | |
| 174 | + | |
| 175 | + if (ramp_delay > 32000 || ramp_delay < 0) | |
| 176 | + return -EINVAL; | |
| 177 | + | |
| 178 | + if (ramp_delay <= 4000) | |
| 179 | + ramp_val = 3; | |
| 180 | + else if (ramp_delay <= 8000) | |
| 181 | + ramp_val = 2; | |
| 182 | + else if (ramp_delay <= 16000) | |
| 183 | + ramp_val = 1; | |
| 184 | + else | |
| 185 | + ramp_val = 0; | |
| 186 | + | |
| 187 | + return regmap_update_bits(rdev->regmap, MP5416_REG_CTL2, | |
| 188 | + MP5416_MASK_DVS_SLEWRATE, ramp_val << 6); | |
| 189 | +} | |
| 190 | + | |
| 191 | +static int mp5416_i2c_probe(struct i2c_client *client) | |
| 192 | +{ | |
| 193 | + struct device *dev = &client->dev; | |
| 194 | + struct regulator_config config = { NULL, }; | |
| 195 | + struct regulator_dev *rdev; | |
| 196 | + struct regmap *regmap; | |
| 197 | + int i; | |
| 198 | + | |
| 199 | + regmap = devm_regmap_init_i2c(client, &mp5416_regmap_config); | |
| 200 | + if (IS_ERR(regmap)) { | |
| 201 | + dev_err(dev, "Failed to allocate regmap!\n"); | |
| 202 | + return PTR_ERR(regmap); | |
| 203 | + } | |
| 204 | + | |
| 205 | + config.dev = dev; | |
| 206 | + config.regmap = regmap; | |
| 207 | + | |
| 208 | + for (i = 0; i < MP5416_MAX_REGULATORS; i++) { | |
| 209 | + rdev = devm_regulator_register(dev, | |
| 210 | + &mp5416_regulators_desc[i], | |
| 211 | + &config); | |
| 212 | + if (IS_ERR(rdev)) { | |
| 213 | + dev_err(dev, "Failed to register regulator!\n"); | |
| 214 | + return PTR_ERR(rdev); | |
| 215 | + } | |
| 216 | + } | |
| 217 | + | |
| 218 | + return 0; | |
| 219 | +} | |
| 220 | + | |
| 221 | +static const struct of_device_id mp5416_of_match[] = { | |
| 222 | + { .compatible = "mps,mp5416" }, | |
| 223 | + {}, | |
| 224 | +}; | |
| 225 | +MODULE_DEVICE_TABLE(of, mp5416_of_match); | |
| 226 | + | |
| 227 | +static const struct i2c_device_id mp5416_id[] = { | |
| 228 | + { "mp5416", }, | |
| 229 | + { }, | |
| 230 | +}; | |
| 231 | +MODULE_DEVICE_TABLE(i2c, mp5416_id); | |
| 232 | + | |
| 233 | +static struct i2c_driver mp5416_regulator_driver = { | |
| 234 | + .driver = { | |
| 235 | + .name = "mp5416", | |
| 236 | + .of_match_table = of_match_ptr(mp5416_of_match), | |
| 237 | + }, | |
| 238 | + .probe_new = mp5416_i2c_probe, | |
| 239 | + .id_table = mp5416_id, | |
| 240 | +}; | |
| 241 | +module_i2c_driver(mp5416_regulator_driver); | |
| 242 | + | |
| 243 | +MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>"); | |
| 244 | +MODULE_DESCRIPTION("MP5416 PMIC regulator driver"); | |
| 245 | +MODULE_LICENSE("GPL"); | |
| @@ -95,6 +95,7 @@ static const struct regulator_desc mp8859_regulators[] = { · 94 unmodified lines | ||
| 95 | 95 | .id = 0, |
| 96 | 96 | .type = REGULATOR_VOLTAGE, |
| 97 | 97 | .name = "mp8859_dcdc", |
| 98 | + .supply_name = "vin", | |
| 98 | 99 | .of_match = of_match_ptr("mp8859_dcdc"), |
| 99 | 100 | .n_voltages = VOL_MAX_IDX + 1, |
| 100 | 101 | .linear_ranges = mp8859_dcdc_ranges, |
| @@ -354,7 +354,11 @@ static int pwm_regulator_probe(struct platform_device *pdev) · 353 unmodified lines | ||
| 354 | 354 | drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); |
| 355 | 355 | if (IS_ERR(drvdata->pwm)) { |
| 356 | 356 | ret = PTR_ERR(drvdata->pwm); |
| 357 | − dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret); | |
| 357 | + if (ret == -EPROBE_DEFER) | |
| 358 | + dev_dbg(&pdev->dev, | |
| 359 | + "Failed to get PWM, deferring probe\n"); | |
| 360 | + else | |
| 361 | + dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret); | |
| 358 | 362 | return ret; |
| 359 | 363 | } |
| 360 | 364 | |
| @@ -925,12 +925,21 @@ static const struct rpm_regulator_data rpm_pm8921_regulators[] = { · 924 unmodified lines | ||
| 925 | 925 | { } |
| 926 | 926 | }; |
| 927 | 927 | |
| 928 | +static const struct rpm_regulator_data rpm_smb208_regulators[] = { | |
| 929 | + { "s1a", QCOM_RPM_SMB208_S1a, &smb208_smps, "vin_s1a" }, | |
| 930 | + { "s1b", QCOM_RPM_SMB208_S1b, &smb208_smps, "vin_s1b" }, | |
| 931 | + { "s2a", QCOM_RPM_SMB208_S2a, &smb208_smps, "vin_s2a" }, | |
| 932 | + { "s2b", QCOM_RPM_SMB208_S2b, &smb208_smps, "vin_s2b" }, | |
| 933 | + { } | |
| 934 | +}; | |
| 935 | + | |
| 928 | 936 | static const struct of_device_id rpm_of_match[] = { |
| 929 | 937 | { .compatible = "qcom,rpm-pm8018-regulators", |
| 930 | 938 | .data = &rpm_pm8018_regulators }, |
| 931 | 939 | { .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators }, |
| 932 | 940 | { .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators }, |
| 933 | 941 | { .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators }, |
| 942 | + { .compatible = "qcom,rpm-smb208-regulators", .data = &rpm_smb208_regulators }, | |
| 934 | 943 | { } |
| 935 | 944 | }; |
| 936 | 945 | MODULE_DEVICE_TABLE(of, rpm_of_match); |
| @@ -62,6 +62,13 @@ config SPI_ALTERA · 61 unmodified lines | ||
| 62 | 62 | help |
| 63 | 63 | This is the driver for the Altera SPI Controller. |
| 64 | 64 | |
| 65 | +config SPI_AR934X | |
| 66 | + tristate "Qualcomm Atheros AR934X/QCA95XX SPI controller driver" | |
| 67 | + depends on ATH79 || COMPILE_TEST | |
| 68 | + help | |
| 69 | + This enables support for the SPI controller present on the | |
| 70 | + Qualcomm Atheros AR934X/QCA95XX SoCs. | |
| 71 | + | |
| 65 | 72 | config SPI_ATH79 |
| 66 | 73 | tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver" |
| 67 | 74 | depends on ATH79 || COMPILE_TEST |
| @@ -264,6 +271,13 @@ config SPI_FALCON · 196 unmodified lines | ||
| 264 | 271 | has only been tested with m25p80 type chips. The hardware has no |
| 265 | 272 | support for other types of SPI peripherals. |
| 266 | 273 | |
| 274 | +config SPI_FSI | |
| 275 | + tristate "FSI SPI driver" | |
| 276 | + depends on FSI | |
| 277 | + help | |
| 278 | + This enables support for the driver for FSI bus attached SPI | |
| 279 | + controllers. | |
| 280 | + | |
| 267 | 281 | config SPI_FSL_LPSPI |
| 268 | 282 | tristate "Freescale i.MX LPSPI controller" |
| 269 | 283 | depends on ARCH_MXC || COMPILE_TEST |
| @@ -285,7 +299,6 @@ config SPI_HISI_SFC_V3XX · 15 unmodified lines | ||
| 285 | 299 | tristate "HiSilicon SPI-NOR Flash Controller for Hi16XX chipsets" |
| 286 | 300 | depends on (ARM64 && ACPI) || COMPILE_TEST |
| 287 | 301 | depends on HAS_IOMEM |
| 288 | − select CONFIG_MTD_SPI_NOR | |
| 289 | 302 | help |
| 290 | 303 | This enables support for HiSilicon v3xx SPI-NOR flash controller |
| 291 | 304 | found in hi16xx chipsets. |
| @@ -415,6 +428,7 @@ config SPI_FSL_ESPI · 123 unmodified lines | ||
| 415 | 428 | |
| 416 | 429 | config SPI_MESON_SPICC |
| 417 | 430 | tristate "Amlogic Meson SPICC controller" |
| 431 | + depends on COMMON_CLK | |
| 418 | 432 | depends on ARCH_MESON || COMPILE_TEST |
| 419 | 433 | help |
| 420 | 434 | This enables master mode support for the SPICC (SPI communication |
| @@ -443,6 +457,16 @@ config SPI_MT7621 · 22 unmodified lines | ||
| 443 | 457 | help |
| 444 | 458 | This selects a driver for the MediaTek MT7621 SPI Controller. |
| 445 | 459 | |
| 460 | +config SPI_MTK_NOR | |
| 461 | + tristate "MediaTek SPI NOR controller" | |
| 462 | + depends on ARCH_MEDIATEK || COMPILE_TEST | |
| 463 | + help | |
| 464 | + This enables support for SPI NOR controller found on MediaTek | |
| 465 | + ARM SoCs. This is a controller specifically for SPI-NOR flash. | |
| 466 | + It can perform generic SPI transfers up to 6 bytes via generic | |
| 467 | + SPI interface as well as several SPI-NOR specific instructions | |
| 468 | + via SPI MEM interface. | |
| 469 | + | |
| 446 | 470 | config SPI_NPCM_FIU |
| 447 | 471 | tristate "Nuvoton NPCM FLASH Interface Unit" |
| 448 | 472 | depends on ARCH_NPCM || COMPILE_TEST |
| @@ -890,6 +914,17 @@ config SPI_ZYNQMP_GQSPI · 441 unmodified lines | ||
| 890 | 914 | # Add new SPI master controllers in alphabetical order above this line |
| 891 | 915 | # |
| 892 | 916 | |
| 917 | +comment "SPI Multiplexer support" | |
| 918 | + | |
| 919 | +config SPI_MUX | |
| 920 | + tristate "SPI multiplexer support" | |
| 921 | + select MULTIPLEXER | |
| 922 | + help | |
| 923 | + This adds support for SPI multiplexers. Each SPI mux will be | |
| 924 | + accessible as a SPI controller, the devices behind the mux will appear | |
| 925 | + to be chip selects on this controller. It is still necessary to | |
| 926 | + select one or more specific mux-controller drivers. | |
| 927 | + | |
| 893 | 928 | # |
| 894 | 929 | # There are lots of SPI device types, with sensors and memory |
| 895 | 930 | # being probably the most widely used ones. |
| @@ -9,11 +9,13 @@ ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG · 8 unmodified lines | ||
| 9 | 9 | # config declarations into driver model code |
| 10 | 10 | obj-$(CONFIG_SPI_MASTER) += spi.o |
| 11 | 11 | obj-$(CONFIG_SPI_MEM) += spi-mem.o |
| 12 | +obj-$(CONFIG_SPI_MUX) += spi-mux.o | |
| 12 | 13 | obj-$(CONFIG_SPI_SPIDEV) += spidev.o |
| 13 | 14 | obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o |
| 14 | 15 | |
| 15 | 16 | # SPI master controller drivers (bus) |
| 16 | 17 | obj-$(CONFIG_SPI_ALTERA) += spi-altera.o |
| 18 | +obj-$(CONFIG_SPI_AR934X) += spi-ar934x.o | |
| 17 | 19 | obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o |
| 18 | 20 | obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o |
| 19 | 21 | obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o |
| @@ -40,6 +42,7 @@ spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o · 20 unmodified lines | ||
| 40 | 42 | obj-$(CONFIG_SPI_EFM32) += spi-efm32.o |
| 41 | 43 | obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o |
| 42 | 44 | obj-$(CONFIG_SPI_FALCON) += spi-falcon.o |
| 45 | +obj-$(CONFIG_SPI_FSI) += spi-fsi.o | |
| 43 | 46 | obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o |
| 44 | 47 | obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o |
| 45 | 48 | obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o |
| @@ -62,6 +65,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o · 16 unmodified lines | ||
| 62 | 65 | obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o |
| 63 | 66 | obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o |
| 64 | 67 | obj-$(CONFIG_SPI_MT7621) += spi-mt7621.o |
| 68 | +obj-$(CONFIG_SPI_MTK_NOR) += spi-mtk-nor.o | |
| 65 | 69 | obj-$(CONFIG_SPI_MXIC) += spi-mxic.o |
| 66 | 70 | obj-$(CONFIG_SPI_MXS) += spi-mxs.o |
| 67 | 71 | obj-$(CONFIG_SPI_NPCM_FIU) += spi-npcm-fiu.o |
| @@ -173,6 +173,81 @@ static const struct atmel_qspi_mode atmel_qspi_modes[] = { · 172 unmodified lines | ||
| 173 | 173 | { 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD }, |
| 174 | 174 | }; |
| 175 | 175 | |
| 176 | +#ifdef VERBOSE_DEBUG | |
| 177 | +static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz) | |
| 178 | +{ | |
| 179 | + switch (offset) { | |
| 180 | + case QSPI_CR: | |
| 181 | + return "CR"; | |
| 182 | + case QSPI_MR: | |
| 183 | + return "MR"; | |
| 184 | + case QSPI_RD: | |
| 185 | + return "MR"; | |
| 186 | + case QSPI_TD: | |
| 187 | + return "TD"; | |
| 188 | + case QSPI_SR: | |
| 189 | + return "SR"; | |
| 190 | + case QSPI_IER: | |
| 191 | + return "IER"; | |
| 192 | + case QSPI_IDR: | |
| 193 | + return "IDR"; | |
| 194 | + case QSPI_IMR: | |
| 195 | + return "IMR"; | |
| 196 | + case QSPI_SCR: | |
| 197 | + return "SCR"; | |
| 198 | + case QSPI_IAR: | |
| 199 | + return "IAR"; | |
| 200 | + case QSPI_ICR: | |
| 201 | + return "ICR/WICR"; | |
| 202 | + case QSPI_IFR: | |
| 203 | + return "IFR"; | |
| 204 | + case QSPI_RICR: | |
| 205 | + return "RICR"; | |
| 206 | + case QSPI_SMR: | |
| 207 | + return "SMR"; | |
| 208 | + case QSPI_SKR: | |
| 209 | + return "SKR"; | |
| 210 | + case QSPI_WPMR: | |
| 211 | + return "WPMR"; | |
| 212 | + case QSPI_WPSR: | |
| 213 | + return "WPSR"; | |
| 214 | + case QSPI_VERSION: | |
| 215 | + return "VERSION"; | |
| 216 | + default: | |
| 217 | + snprintf(tmp, sz, "0x%02x", offset); | |
| 218 | + break; | |
| 219 | + } | |
| 220 | + | |
| 221 | + return tmp; | |
| 222 | +} | |
| 223 | +#endif /* VERBOSE_DEBUG */ | |
| 224 | + | |
| 225 | +static u32 atmel_qspi_read(struct atmel_qspi *aq, u32 offset) | |
| 226 | +{ | |
| 227 | + u32 value = readl_relaxed(aq->regs + offset); | |
| 228 | + | |
| 229 | +#ifdef VERBOSE_DEBUG | |
| 230 | + char tmp[8]; | |
| 231 | + | |
| 232 | + dev_vdbg(&aq->pdev->dev, "read 0x%08x from %s\n", value, | |
| 233 | + atmel_qspi_reg_name(offset, tmp, sizeof(tmp))); | |
| 234 | +#endif /* VERBOSE_DEBUG */ | |
| 235 | + | |
| 236 | + return value; | |
| 237 | +} | |
| 238 | + | |
| 239 | +static void atmel_qspi_write(u32 value, struct atmel_qspi *aq, u32 offset) | |
| 240 | +{ | |
| 241 | +#ifdef VERBOSE_DEBUG | |
| 242 | + char tmp[8]; | |
| 243 | + | |
| 244 | + dev_vdbg(&aq->pdev->dev, "write 0x%08x into %s\n", value, | |
| 245 | + atmel_qspi_reg_name(offset, tmp, sizeof(tmp))); | |
| 246 | +#endif /* VERBOSE_DEBUG */ | |
| 247 | + | |
| 248 | + writel_relaxed(value, aq->regs + offset); | |
| 249 | +} | |
| 250 | + | |
| 176 | 251 | static inline bool atmel_qspi_is_compatible(const struct spi_mem_op *op, |
| 177 | 252 | const struct atmel_qspi_mode *mode) |
| 178 | 253 | { |
| @@ -293,32 +368,32 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq, · 114 unmodified lines | ||
| 293 | 368 | * Serial Memory Mode (SMM). |
| 294 | 369 | */ |
| 295 | 370 | if (aq->mr != QSPI_MR_SMM) { |
| 296 | − writel_relaxed(QSPI_MR_SMM, aq->regs + QSPI_MR); | |
| 371 | + atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR); | |
| 297 | 372 | aq->mr = QSPI_MR_SMM; |
| 298 | 373 | } |
| 299 | 374 | |
| 300 | 375 | /* Clear pending interrupts */ |
| 301 | − (void)readl_relaxed(aq->regs + QSPI_SR); | |
| 376 | + (void)atmel_qspi_read(aq, QSPI_SR); | |
| 302 | 377 | |
| 303 | 378 | if (aq->caps->has_ricr) { |
| 304 | 379 | if (!op->addr.nbytes && op->data.dir == SPI_MEM_DATA_IN) |
| 305 | 380 | ifr |= QSPI_IFR_APBTFRTYP_READ; |
| 306 | 381 | |
| 307 | 382 | /* Set QSPI Instruction Frame registers */ |
| 308 | − writel_relaxed(iar, aq->regs + QSPI_IAR); | |
| 383 | + atmel_qspi_write(iar, aq, QSPI_IAR); | |
| 309 | 384 | if (op->data.dir == SPI_MEM_DATA_IN) |
| 310 | − writel_relaxed(icr, aq->regs + QSPI_RICR); | |
| 385 | + atmel_qspi_write(icr, aq, QSPI_RICR); | |
| 311 | 386 | else |
| 312 | − writel_relaxed(icr, aq->regs + QSPI_WICR); | |
| 313 | − writel_relaxed(ifr, aq->regs + QSPI_IFR); | |
| 387 | + atmel_qspi_write(icr, aq, QSPI_WICR); | |
| 388 | + atmel_qspi_write(ifr, aq, QSPI_IFR); | |
| 314 | 389 | } else { |
| 315 | 390 | if (op->data.dir == SPI_MEM_DATA_OUT) |
| 316 | 391 | ifr |= QSPI_IFR_SAMA5D2_WRITE_TRSFR; |
| 317 | 392 | |
| 318 | 393 | /* Set QSPI Instruction Frame registers */ |
| 319 | − writel_relaxed(iar, aq->regs + QSPI_IAR); | |
| 320 | − writel_relaxed(icr, aq->regs + QSPI_ICR); | |
| 321 | − writel_relaxed(ifr, aq->regs + QSPI_IFR); | |
| 394 | + atmel_qspi_write(iar, aq, QSPI_IAR); | |
| 395 | + atmel_qspi_write(icr, aq, QSPI_ICR); | |
| 396 | + atmel_qspi_write(ifr, aq, QSPI_IFR); | |
| 322 | 397 | } |
| 323 | 398 | |
| 324 | 399 | return 0; |
| @@ -345,7 +420,7 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) · 20 unmodified lines | ||
| 345 | 420 | /* Skip to the final steps if there is no data */ |
| 346 | 421 | if (op->data.nbytes) { |
| 347 | 422 | /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */ |
| 348 | − (void)readl_relaxed(aq->regs + QSPI_IFR); | |
| 423 | + (void)atmel_qspi_read(aq, QSPI_IFR); | |
| 349 | 424 | |
| 350 | 425 | /* Send/Receive data */ |
| 351 | 426 | if (op->data.dir == SPI_MEM_DATA_IN) |
| @@ -356,22 +431,22 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) · 4 unmodified lines | ||
| 356 | 431 | op->data.nbytes); |
| 357 | 432 | |
| 358 | 433 | /* Release the chip-select */ |
| 359 | − writel_relaxed(QSPI_CR_LASTXFER, aq->regs + QSPI_CR); | |
| 434 | + atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR); | |
| 360 | 435 | } |
| 361 | 436 | |
| 362 | 437 | /* Poll INSTRuction End status */ |
| 363 | − sr = readl_relaxed(aq->regs + QSPI_SR); | |
| 438 | + sr = atmel_qspi_read(aq, QSPI_SR); | |
| 364 | 439 | if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED) |
| 365 | 440 | return err; |
| 366 | 441 | |
| 367 | 442 | /* Wait for INSTRuction End interrupt */ |
| 368 | 443 | reinit_completion(&aq->cmd_completion); |
| 369 | 444 | aq->pending = sr & QSPI_SR_CMD_COMPLETED; |
| 370 | − writel_relaxed(QSPI_SR_CMD_COMPLETED, aq->regs + QSPI_IER); | |
| 445 | + atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IER); | |
| 371 | 446 | if (!wait_for_completion_timeout(&aq->cmd_completion, |
| 372 | 447 | msecs_to_jiffies(1000))) |
| 373 | 448 | err = -ETIMEDOUT; |
| 374 | − writel_relaxed(QSPI_SR_CMD_COMPLETED, aq->regs + QSPI_IDR); | |
| 449 | + atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IDR); | |
| 375 | 450 | |
| 376 | 451 | return err; |
| 377 | 452 | } |
| @@ -410,7 +485,7 @@ static int atmel_qspi_setup(struct spi_device *spi) · 32 unmodified lines | ||
| 410 | 485 | scbr--; |
| 411 | 486 | |
| 412 | 487 | aq->scr = QSPI_SCR_SCBR(scbr); |
| 413 | − writel_relaxed(aq->scr, aq->regs + QSPI_SCR); | |
| 488 | + atmel_qspi_write(aq->scr, aq, QSPI_SCR); | |
| 414 | 489 | |
| 415 | 490 | return 0; |
| 416 | 491 | } |
| @@ -418,14 +493,14 @@ static int atmel_qspi_setup(struct spi_device *spi) · 1 unmodified line | ||
| 418 | 493 | static void atmel_qspi_init(struct atmel_qspi *aq) |
| 419 | 494 | { |
| 420 | 495 | /* Reset the QSPI controller */ |
| 421 | − writel_relaxed(QSPI_CR_SWRST, aq->regs + QSPI_CR); | |
| 496 | + atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR); | |
| 422 | 497 | |
| 423 | 498 | /* Set the QSPI controller by default in Serial Memory Mode */ |
| 424 | − writel_relaxed(QSPI_MR_SMM, aq->regs + QSPI_MR); | |
| 499 | + atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR); | |
| 425 | 500 | aq->mr = QSPI_MR_SMM; |
| 426 | 501 | |
| 427 | 502 | /* Enable the QSPI controller */ |
| 428 | − writel_relaxed(QSPI_CR_QSPIEN, aq->regs + QSPI_CR); | |
| 503 | + atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR); | |
| 429 | 504 | } |
| 430 | 505 | |
| 431 | 506 | static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id) |
| @@ -433,8 +508,8 @@ static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id) · 1 unmodified line | ||
| 433 | 508 | struct atmel_qspi *aq = dev_id; |
| 434 | 509 | u32 status, mask, pending; |
| 435 | 510 | |
| 436 | − status = readl_relaxed(aq->regs + QSPI_SR); | |
| 437 | − mask = readl_relaxed(aq->regs + QSPI_IMR); | |
| 511 | + status = atmel_qspi_read(aq, QSPI_SR); | |
| 512 | + mask = atmel_qspi_read(aq, QSPI_IMR); | |
| 438 | 513 | pending = status & mask; |
| 439 | 514 | |
| 440 | 515 | if (!pending) |
| @@ -569,7 +644,7 @@ static int atmel_qspi_remove(struct platform_device *pdev) · 128 unmodified lines | ||
| 569 | 644 | struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); |
| 570 | 645 | |
| 571 | 646 | spi_unregister_controller(ctrl); |
| 572 | − writel_relaxed(QSPI_CR_QSPIDIS, aq->regs + QSPI_CR); | |
| 647 | + atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR); | |
| 573 | 648 | clk_disable_unprepare(aq->qspick); |
| 574 | 649 | clk_disable_unprepare(aq->pclk); |
| 575 | 650 | return 0; |
| @@ -596,7 +671,7 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev) · 20 unmodified lines | ||
| 596 | 671 | |
| 597 | 672 | atmel_qspi_init(aq); |
| 598 | 673 | |
| 599 | − writel_relaxed(aq->scr, aq->regs + QSPI_SCR); | |
| 674 | + atmel_qspi_write(aq->scr, aq, QSPI_SCR); | |
| 600 | 675 | |
| 601 | 676 | return 0; |
| 602 | 677 | } |
| @@ -0,0 +1,235 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +// | |
| 3 | +// SPI controller driver for Qualcomm Atheros AR934x/QCA95xx SoCs | |
| 4 | +// | |
| 5 | +// Copyright (C) 2020 Chuanhong Guo <gch981213@gmail.com> | |
| 6 | +// | |
| 7 | +// Based on spi-mt7621.c: | |
| 8 | +// Copyright (C) 2011 Sergiy <piratfm@gmail.com> | |
| 9 | +// Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> | |
| 10 | +// Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name> | |
| 11 | + | |
| 12 | +#include <linux/clk.h> | |
| 13 | +#include <linux/io.h> | |
| 14 | +#include <linux/iopoll.h> | |
| 15 | +#include <linux/kernel.h> | |
| 16 | +#include <linux/module.h> | |
| 17 | +#include <linux/of_device.h> | |
| 18 | +#include <linux/spi/spi.h> | |
| 19 | + | |
| 20 | +#define DRIVER_NAME "spi-ar934x" | |
| 21 | + | |
| 22 | +#define AR934X_SPI_REG_FS 0x00 | |
| 23 | +#define AR934X_SPI_ENABLE BIT(0) | |
| 24 | + | |
| 25 | +#define AR934X_SPI_REG_IOC 0x08 | |
| 26 | +#define AR934X_SPI_IOC_INITVAL 0x70000 | |
| 27 | + | |
| 28 | +#define AR934X_SPI_REG_CTRL 0x04 | |
| 29 | +#define AR934X_SPI_CLK_MASK GENMASK(5, 0) | |
| 30 | + | |
| 31 | +#define AR934X_SPI_DATAOUT 0x10 | |
| 32 | + | |
| 33 | +#define AR934X_SPI_REG_SHIFT_CTRL 0x14 | |
| 34 | +#define AR934X_SPI_SHIFT_EN BIT(31) | |
| 35 | +#define AR934X_SPI_SHIFT_CS(n) BIT(28 + (n)) | |
| 36 | +#define AR934X_SPI_SHIFT_TERM 26 | |
| 37 | +#define AR934X_SPI_SHIFT_VAL(cs, term, count) \ | |
| 38 | + (AR934X_SPI_SHIFT_EN | AR934X_SPI_SHIFT_CS(cs) | \ | |
| 39 | + (term) << AR934X_SPI_SHIFT_TERM | (count)) | |
| 40 | + | |
| 41 | +#define AR934X_SPI_DATAIN 0x18 | |
| 42 | + | |
| 43 | +struct ar934x_spi { | |
| 44 | + struct spi_controller *ctlr; | |
| 45 | + void __iomem *base; | |
| 46 | + struct clk *clk; | |
| 47 | + unsigned int clk_freq; | |
| 48 | +}; | |
| 49 | + | |
| 50 | +static inline int ar934x_spi_clk_div(struct ar934x_spi *sp, unsigned int freq) | |
| 51 | +{ | |
| 52 | + int div = DIV_ROUND_UP(sp->clk_freq, freq * 2) - 1; | |
| 53 | + | |
| 54 | + if (div < 0) | |
| 55 | + return 0; | |
| 56 | + else if (div > AR934X_SPI_CLK_MASK) | |
| 57 | + return -EINVAL; | |
| 58 | + else | |
| 59 | + return div; | |
| 60 | +} | |
| 61 | + | |
| 62 | +static int ar934x_spi_setup(struct spi_device *spi) | |
| 63 | +{ | |
| 64 | + struct ar934x_spi *sp = spi_controller_get_devdata(spi->master); | |
| 65 | + | |
| 66 | + if ((spi->max_speed_hz == 0) || | |
| 67 | + (spi->max_speed_hz > (sp->clk_freq / 2))) { | |
| 68 | + spi->max_speed_hz = sp->clk_freq / 2; | |
| 69 | + } else if (spi->max_speed_hz < (sp->clk_freq / 128)) { | |
| 70 | + dev_err(&spi->dev, "spi clock is too low\n"); | |
| 71 | + return -EINVAL; | |
| 72 | + } | |
| 73 | + | |
| 74 | + return 0; | |
| 75 | +} | |
| 76 | + | |
| 77 | +static int ar934x_spi_transfer_one_message(struct spi_controller *master, | |
| 78 | + struct spi_message *m) | |
| 79 | +{ | |
| 80 | + struct ar934x_spi *sp = spi_controller_get_devdata(master); | |
| 81 | + struct spi_transfer *t = NULL; | |
| 82 | + struct spi_device *spi = m->spi; | |
| 83 | + unsigned long trx_done, trx_cur; | |
| 84 | + int stat = 0; | |
| 85 | + u8 term = 0; | |
| 86 | + int div, i; | |
| 87 | + u32 reg; | |
| 88 | + const u8 *tx_buf; | |
| 89 | + u8 *buf; | |
| 90 | + | |
| 91 | + m->actual_length = 0; | |
| 92 | + list_for_each_entry(t, &m->transfers, transfer_list) { | |
| 93 | + if (t->speed_hz) | |
| 94 | + div = ar934x_spi_clk_div(sp, t->speed_hz); | |
| 95 | + else | |
| 96 | + div = ar934x_spi_clk_div(sp, spi->max_speed_hz); | |
| 97 | + if (div < 0) { | |
| 98 | + stat = -EIO; | |
| 99 | + goto msg_done; | |
| 100 | + } | |
| 101 | + | |
| 102 | + reg = ioread32(sp->base + AR934X_SPI_REG_CTRL); | |
| 103 | + reg &= ~AR934X_SPI_CLK_MASK; | |
| 104 | + reg |= div; | |
| 105 | + iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL); | |
| 106 | + iowrite32(0, sp->base + AR934X_SPI_DATAOUT); | |
| 107 | + | |
| 108 | + for (trx_done = 0; trx_done < t->len; trx_done += 4) { | |
| 109 | + trx_cur = t->len - trx_done; | |
| 110 | + if (trx_cur > 4) | |
| 111 | + trx_cur = 4; | |
| 112 | + else if (list_is_last(&t->transfer_list, &m->transfers)) | |
| 113 | + term = 1; | |
| 114 | + | |
| 115 | + if (t->tx_buf) { | |
| 116 | + tx_buf = t->tx_buf + trx_done; | |
| 117 | + reg = tx_buf[0]; | |
| 118 | + for (i = 1; i < trx_cur; i++) | |
| 119 | + reg = reg << 8 | tx_buf[i]; | |
| 120 | + iowrite32(reg, sp->base + AR934X_SPI_DATAOUT); | |
| 121 | + } | |
| 122 | + | |
| 123 | + reg = AR934X_SPI_SHIFT_VAL(spi->chip_select, term, | |
| 124 | + trx_cur * 8); | |
| 125 | + iowrite32(reg, sp->base + AR934X_SPI_REG_SHIFT_CTRL); | |
| 126 | + stat = readl_poll_timeout( | |
| 127 | + sp->base + AR934X_SPI_REG_SHIFT_CTRL, reg, | |
| 128 | + !(reg & AR934X_SPI_SHIFT_EN), 0, 5); | |
| 129 | + if (stat < 0) | |
| 130 | + goto msg_done; | |
| 131 | + | |
| 132 | + if (t->rx_buf) { | |
| 133 | + reg = ioread32(sp->base + AR934X_SPI_DATAIN); | |
| 134 | + buf = t->rx_buf + trx_done; | |
| 135 | + for (i = 0; i < trx_cur; i++) { | |
| 136 | + buf[trx_cur - i - 1] = reg & 0xff; | |
| 137 | + reg >>= 8; | |
| 138 | + } | |
| 139 | + } | |
| 140 | + } | |
| 141 | + m->actual_length += t->len; | |
| 142 | + } | |
| 143 | + | |
| 144 | +msg_done: | |
| 145 | + m->status = stat; | |
| 146 | + spi_finalize_current_message(master); | |
| 147 | + | |
| 148 | + return 0; | |
| 149 | +} | |
| 150 | + | |
| 151 | +static const struct of_device_id ar934x_spi_match[] = { | |
| 152 | + { .compatible = "qca,ar934x-spi" }, | |
| 153 | + {}, | |
| 154 | +}; | |
| 155 | +MODULE_DEVICE_TABLE(of, ar934x_spi_match); | |
| 156 | + | |
| 157 | +static int ar934x_spi_probe(struct platform_device *pdev) | |
| 158 | +{ | |
| 159 | + struct spi_controller *ctlr; | |
| 160 | + struct ar934x_spi *sp; | |
| 161 | + void __iomem *base; | |
| 162 | + struct clk *clk; | |
| 163 | + int ret; | |
| 164 | + | |
| 165 | + base = devm_platform_ioremap_resource(pdev, 0); | |
| 166 | + if (IS_ERR(base)) | |
| 167 | + return PTR_ERR(base); | |
| 168 | + | |
| 169 | + clk = devm_clk_get(&pdev->dev, NULL); | |
| 170 | + if (IS_ERR(clk)) { | |
| 171 | + dev_err(&pdev->dev, "failed to get clock\n"); | |
| 172 | + return PTR_ERR(clk); | |
| 173 | + } | |
| 174 | + | |
| 175 | + ret = clk_prepare_enable(clk); | |
| 176 | + if (ret) | |
| 177 | + return ret; | |
| 178 | + | |
| 179 | + ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp)); | |
| 180 | + if (!ctlr) { | |
| 181 | + dev_info(&pdev->dev, "failed to allocate spi controller\n"); | |
| 182 | + return -ENOMEM; | |
| 183 | + } | |
| 184 | + | |
| 185 | + /* disable flash mapping and expose spi controller registers */ | |
| 186 | + iowrite32(AR934X_SPI_ENABLE, base + AR934X_SPI_REG_FS); | |
| 187 | + /* restore pins to default state: CSn=1 DO=CLK=0 */ | |
| 188 | + iowrite32(AR934X_SPI_IOC_INITVAL, base + AR934X_SPI_REG_IOC); | |
| 189 | + | |
| 190 | + ctlr->mode_bits = SPI_LSB_FIRST; | |
| 191 | + ctlr->setup = ar934x_spi_setup; | |
| 192 | + ctlr->transfer_one_message = ar934x_spi_transfer_one_message; | |
| 193 | + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); | |
| 194 | + ctlr->dev.of_node = pdev->dev.of_node; | |
| 195 | + ctlr->num_chipselect = 3; | |
| 196 | + | |
| 197 | + dev_set_drvdata(&pdev->dev, ctlr); | |
| 198 | + | |
| 199 | + sp = spi_controller_get_devdata(ctlr); | |
| 200 | + sp->base = base; | |
| 201 | + sp->clk = clk; | |
| 202 | + sp->clk_freq = clk_get_rate(clk); | |
| 203 | + sp->ctlr = ctlr; | |
| 204 | + | |
| 205 | + return devm_spi_register_controller(&pdev->dev, ctlr); | |
| 206 | +} | |
| 207 | + | |
| 208 | +static int ar934x_spi_remove(struct platform_device *pdev) | |
| 209 | +{ | |
| 210 | + struct spi_controller *ctlr; | |
| 211 | + struct ar934x_spi *sp; | |
| 212 | + | |
| 213 | + ctlr = dev_get_drvdata(&pdev->dev); | |
| 214 | + sp = spi_controller_get_devdata(ctlr); | |
| 215 | + | |
| 216 | + clk_disable_unprepare(sp->clk); | |
| 217 | + | |
| 218 | + return 0; | |
| 219 | +} | |
| 220 | + | |
| 221 | +static struct platform_driver ar934x_spi_driver = { | |
| 222 | + .driver = { | |
| 223 | + .name = DRIVER_NAME, | |
| 224 | + .of_match_table = ar934x_spi_match, | |
| 225 | + }, | |
| 226 | + .probe = ar934x_spi_probe, | |
| 227 | + .remove = ar934x_spi_remove, | |
| 228 | +}; | |
| 229 | + | |
| 230 | +module_platform_driver(ar934x_spi_driver); | |
| 231 | + | |
| 232 | +MODULE_DESCRIPTION("SPI controller driver for Qualcomm Atheros AR934x/QCA95xx"); | |
| 233 | +MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>"); | |
| 234 | +MODULE_LICENSE("GPL v2"); | |
| 235 | +MODULE_ALIAS("platform:" DRIVER_NAME); | |
| @@ -6,14 +6,13 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <linux/io.h> |
| 7 | 7 | #include <linux/spi/spi.h> |
| 8 | 8 | #include <linux/spi/spi_bitbang.h> |
| 9 | −#include <linux/gpio.h> | |
| 10 | 9 | #include <linux/interrupt.h> |
| 11 | 10 | #include <linux/platform_device.h> |
| 12 | 11 | #include <linux/clk.h> |
| 13 | 12 | #include <linux/err.h> |
| 14 | 13 | #include <linux/module.h> |
| 15 | −#include <linux/of_gpio.h> | |
| 16 | 14 | #include <linux/platform_data/efm32-spi.h> |
| 15 | +#include <linux/of.h> | |
| 17 | 16 | |
| 18 | 17 | #define DRIVER_NAME "efm32-spi" |
| 19 | 18 | |
| @@ -82,9 +81,6 @@ struct efm32_spi_ddata { · 62 unmodified lines | ||
| 82 | 81 | const u8 *tx_buf; |
| 83 | 82 | u8 *rx_buf; |
| 84 | 83 | unsigned tx_len, rx_len; |
| 85 | − | |
| 86 | − /* chip selects */ | |
| 87 | − unsigned csgpio[]; | |
| 88 | 84 | }; |
| 89 | 85 | |
| 90 | 86 | #define ddata_to_dev(ddata) (&(ddata->bitbang.master->dev)) |
| @@ -102,14 +98,6 @@ static u32 efm32_spi_read32(struct efm32_spi_ddata *ddata, unsigned offset) · 11 unmodified lines | ||
| 102 | 98 | return readl_relaxed(ddata->base + offset); |
| 103 | 99 | } |
| 104 | 100 | |
| 105 | −static void efm32_spi_chipselect(struct spi_device *spi, int is_on) | |
| 106 | −{ | |
| 107 | − struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master); | |
| 108 | − int value = !(spi->mode & SPI_CS_HIGH) == !(is_on == BITBANG_CS_ACTIVE); | |
| 109 | − | |
| 110 | − gpio_set_value(ddata->csgpio[spi->chip_select], value); | |
| 111 | −} | |
| 112 | − | |
| 113 | 101 | static int efm32_spi_setup_transfer(struct spi_device *spi, |
| 114 | 102 | struct spi_transfer *t) |
| 115 | 103 | { |
| @@ -320,17 +308,11 @@ static int efm32_spi_probe(struct platform_device *pdev) · 204 unmodified lines | ||
| 320 | 308 | int ret; |
| 321 | 309 | struct spi_master *master; |
| 322 | 310 | struct device_node *np = pdev->dev.of_node; |
| 323 | − int num_cs, i; | |
| 324 | 311 | |
| 325 | 312 | if (!np) |
| 326 | 313 | return -EINVAL; |
| 327 | 314 | |
| 328 | − num_cs = of_gpio_named_count(np, "cs-gpios"); | |
| 329 | − if (num_cs < 0) | |
| 330 | − return num_cs; | |
| 331 | − | |
| 332 | − master = spi_alloc_master(&pdev->dev, | |
| 333 | − sizeof(*ddata) + num_cs * sizeof(unsigned)); | |
| 315 | + master = spi_alloc_master(&pdev->dev, sizeof(*ddata)); | |
| 334 | 316 | if (!master) { |
| 335 | 317 | dev_dbg(&pdev->dev, |
| 336 | 318 | "failed to allocate spi master controller\n"); |
| @@ -340,14 +322,13 @@ static int efm32_spi_probe(struct platform_device *pdev) · 3 unmodified lines | ||
| 340 | 322 | |
| 341 | 323 | master->dev.of_node = pdev->dev.of_node; |
| 342 | 324 | |
| 343 | − master->num_chipselect = num_cs; | |
| 344 | 325 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; |
| 345 | 326 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); |
| 327 | + master->use_gpio_descriptors = true; | |
| 346 | 328 | |
| 347 | 329 | ddata = spi_master_get_devdata(master); |
| 348 | 330 | |
| 349 | 331 | ddata->bitbang.master = master; |
| 350 | − ddata->bitbang.chipselect = efm32_spi_chipselect; | |
| 351 | 332 | ddata->bitbang.setup_transfer = efm32_spi_setup_transfer; |
| 352 | 333 | ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs; |
| 353 | 334 | |
| @@ -361,25 +342,6 @@ static int efm32_spi_probe(struct platform_device *pdev) · 7 unmodified lines | ||
| 361 | 342 | goto err; |
| 362 | 343 | } |
| 363 | 344 | |
| 364 | − for (i = 0; i < num_cs; ++i) { | |
| 365 | − ret = of_get_named_gpio(np, "cs-gpios", i); | |
| 366 | − if (ret < 0) { | |
| 367 | − dev_err(&pdev->dev, "failed to get csgpio#%u (%d)\n", | |
| 368 | − i, ret); | |
| 369 | − goto err; | |
| 370 | − } | |
| 371 | − ddata->csgpio[i] = ret; | |
| 372 | − dev_dbg(&pdev->dev, "csgpio#%u = %u\n", i, ddata->csgpio[i]); | |
| 373 | − ret = devm_gpio_request_one(&pdev->dev, ddata->csgpio[i], | |
| 374 | − GPIOF_OUT_INIT_LOW, DRIVER_NAME); | |
| 375 | − if (ret < 0) { | |
| 376 | − dev_err(&pdev->dev, | |
| 377 | − "failed to configure csgpio#%u (%d)\n", | |
| 378 | − i, ret); | |
| 379 | − goto err; | |
| 380 | − } | |
| 381 | − } | |
| 382 | − | |
| 383 | 345 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 384 | 346 | if (!res) { |
| 385 | 347 | ret = -ENODEV; |
| @@ -0,0 +1,558 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | +// Copyright (C) IBM Corporation 2020 | |
| 3 | + | |
| 4 | +#include <linux/bitfield.h> | |
| 5 | +#include <linux/bits.h> | |
| 6 | +#include <linux/fsi.h> | |
| 7 | +#include <linux/jiffies.h> | |
| 8 | +#include <linux/kernel.h> | |
| 9 | +#include <linux/module.h> | |
| 10 | +#include <linux/of.h> | |
| 11 | +#include <linux/spi/spi.h> | |
| 12 | + | |
| 13 | +#define FSI_ENGID_SPI 0x23 | |
| 14 | +#define FSI_MBOX_ROOT_CTRL_8 0x2860 | |
| 15 | + | |
| 16 | +#define FSI2SPI_DATA0 0x00 | |
| 17 | +#define FSI2SPI_DATA1 0x04 | |
| 18 | +#define FSI2SPI_CMD 0x08 | |
| 19 | +#define FSI2SPI_CMD_WRITE BIT(31) | |
| 20 | +#define FSI2SPI_RESET 0x18 | |
| 21 | +#define FSI2SPI_STATUS 0x1c | |
| 22 | +#define FSI2SPI_STATUS_ANY_ERROR BIT(31) | |
| 23 | +#define FSI2SPI_IRQ 0x20 | |
| 24 | + | |
| 25 | +#define SPI_FSI_BASE 0x70000 | |
| 26 | +#define SPI_FSI_INIT_TIMEOUT_MS 1000 | |
| 27 | +#define SPI_FSI_MAX_TRANSFER_SIZE 2048 | |
| 28 | + | |
| 29 | +#define SPI_FSI_ERROR 0x0 | |
| 30 | +#define SPI_FSI_COUNTER_CFG 0x1 | |
| 31 | +#define SPI_FSI_COUNTER_CFG_LOOPS(x) (((u64)(x) & 0xffULL) << 32) | |
| 32 | +#define SPI_FSI_CFG1 0x2 | |
| 33 | +#define SPI_FSI_CLOCK_CFG 0x3 | |
| 34 | +#define SPI_FSI_CLOCK_CFG_MM_ENABLE BIT_ULL(32) | |
| 35 | +#define SPI_FSI_CLOCK_CFG_ECC_DISABLE (BIT_ULL(35) | BIT_ULL(33)) | |
| 36 | +#define SPI_FSI_CLOCK_CFG_RESET1 (BIT_ULL(36) | BIT_ULL(38)) | |
| 37 | +#define SPI_FSI_CLOCK_CFG_RESET2 (BIT_ULL(37) | BIT_ULL(39)) | |
| 38 | +#define SPI_FSI_CLOCK_CFG_MODE (BIT_ULL(41) | BIT_ULL(42)) | |
| 39 | +#define SPI_FSI_CLOCK_CFG_SCK_RECV_DEL GENMASK_ULL(51, 44) | |
| 40 | +#define SPI_FSI_CLOCK_CFG_SCK_NO_DEL BIT_ULL(51) | |
| 41 | +#define SPI_FSI_CLOCK_CFG_SCK_DIV GENMASK_ULL(63, 52) | |
| 42 | +#define SPI_FSI_MMAP 0x4 | |
| 43 | +#define SPI_FSI_DATA_TX 0x5 | |
| 44 | +#define SPI_FSI_DATA_RX 0x6 | |
| 45 | +#define SPI_FSI_SEQUENCE 0x7 | |
| 46 | +#define SPI_FSI_SEQUENCE_STOP 0x00 | |
| 47 | +#define SPI_FSI_SEQUENCE_SEL_SLAVE(x) (0x10 | ((x) & 0xf)) | |
| 48 | +#define SPI_FSI_SEQUENCE_SHIFT_OUT(x) (0x30 | ((x) & 0xf)) | |
| 49 | +#define SPI_FSI_SEQUENCE_SHIFT_IN(x) (0x40 | ((x) & 0xf)) | |
| 50 | +#define SPI_FSI_SEQUENCE_COPY_DATA_TX 0xc0 | |
| 51 | +#define SPI_FSI_SEQUENCE_BRANCH(x) (0xe0 | ((x) & 0xf)) | |
| 52 | +#define SPI_FSI_STATUS 0x8 | |
| 53 | +#define SPI_FSI_STATUS_ERROR \ | |
| 54 | + (GENMASK_ULL(31, 21) | GENMASK_ULL(15, 12)) | |
| 55 | +#define SPI_FSI_STATUS_SEQ_STATE GENMASK_ULL(55, 48) | |
| 56 | +#define SPI_FSI_STATUS_SEQ_STATE_IDLE BIT_ULL(48) | |
| 57 | +#define SPI_FSI_STATUS_TDR_UNDERRUN BIT_ULL(57) | |
| 58 | +#define SPI_FSI_STATUS_TDR_OVERRUN BIT_ULL(58) | |
| 59 | +#define SPI_FSI_STATUS_TDR_FULL BIT_ULL(59) | |
| 60 | +#define SPI_FSI_STATUS_RDR_UNDERRUN BIT_ULL(61) | |
| 61 | +#define SPI_FSI_STATUS_RDR_OVERRUN BIT_ULL(62) | |
| 62 | +#define SPI_FSI_STATUS_RDR_FULL BIT_ULL(63) | |
| 63 | +#define SPI_FSI_STATUS_ANY_ERROR \ | |
| 64 | + (SPI_FSI_STATUS_ERROR | SPI_FSI_STATUS_TDR_UNDERRUN | \ | |
| 65 | + SPI_FSI_STATUS_TDR_OVERRUN | SPI_FSI_STATUS_RDR_UNDERRUN | \ | |
| 66 | + SPI_FSI_STATUS_RDR_OVERRUN) | |
| 67 | +#define SPI_FSI_PORT_CTRL 0x9 | |
| 68 | + | |
| 69 | +struct fsi_spi { | |
| 70 | + struct device *dev; /* SPI controller device */ | |
| 71 | + struct fsi_device *fsi; /* FSI2SPI CFAM engine device */ | |
| 72 | + u32 base; | |
| 73 | +}; | |
| 74 | + | |
| 75 | +struct fsi_spi_sequence { | |
| 76 | + int bit; | |
| 77 | + u64 data; | |
| 78 | +}; | |
| 79 | + | |
| 80 | +static int fsi_spi_check_status(struct fsi_spi *ctx) | |
| 81 | +{ | |
| 82 | + int rc; | |
| 83 | + u32 sts; | |
| 84 | + __be32 sts_be; | |
| 85 | + | |
| 86 | + rc = fsi_device_read(ctx->fsi, FSI2SPI_STATUS, &sts_be, | |
| 87 | + sizeof(sts_be)); | |
| 88 | + if (rc) | |
| 89 | + return rc; | |
| 90 | + | |
| 91 | + sts = be32_to_cpu(sts_be); | |
| 92 | + if (sts & FSI2SPI_STATUS_ANY_ERROR) { | |
| 93 | + dev_err(ctx->dev, "Error with FSI2SPI interface: %08x.\n", sts); | |
| 94 | + return -EIO; | |
| 95 | + } | |
| 96 | + | |
| 97 | + return 0; | |
| 98 | +} | |
| 99 | + | |
| 100 | +static int fsi_spi_read_reg(struct fsi_spi *ctx, u32 offset, u64 *value) | |
| 101 | +{ | |
| 102 | + int rc; | |
| 103 | + __be32 cmd_be; | |
| 104 | + __be32 data_be; | |
| 105 | + u32 cmd = offset + ctx->base; | |
| 106 | + | |
| 107 | + *value = 0ULL; | |
| 108 | + | |
| 109 | + if (cmd & FSI2SPI_CMD_WRITE) | |
| 110 | + return -EINVAL; | |
| 111 | + | |
| 112 | + cmd_be = cpu_to_be32(cmd); | |
| 113 | + rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be)); | |
| 114 | + if (rc) | |
| 115 | + return rc; | |
| 116 | + | |
| 117 | + rc = fsi_spi_check_status(ctx); | |
| 118 | + if (rc) | |
| 119 | + return rc; | |
| 120 | + | |
| 121 | + rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA0, &data_be, | |
| 122 | + sizeof(data_be)); | |
| 123 | + if (rc) | |
| 124 | + return rc; | |
| 125 | + | |
| 126 | + *value |= (u64)be32_to_cpu(data_be) << 32; | |
| 127 | + | |
| 128 | + rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA1, &data_be, | |
| 129 | + sizeof(data_be)); | |
| 130 | + if (rc) | |
| 131 | + return rc; | |
| 132 | + | |
| 133 | + *value |= (u64)be32_to_cpu(data_be); | |
| 134 | + dev_dbg(ctx->dev, "Read %02x[%016llx].\n", offset, *value); | |
| 135 | + | |
| 136 | + return 0; | |
| 137 | +} | |
| 138 | + | |
| 139 | +static int fsi_spi_write_reg(struct fsi_spi *ctx, u32 offset, u64 value) | |
| 140 | +{ | |
| 141 | + int rc; | |
| 142 | + __be32 cmd_be; | |
| 143 | + __be32 data_be; | |
| 144 | + u32 cmd = offset + ctx->base; | |
| 145 | + | |
| 146 | + if (cmd & FSI2SPI_CMD_WRITE) | |
| 147 | + return -EINVAL; | |
| 148 | + | |
| 149 | + dev_dbg(ctx->dev, "Write %02x[%016llx].\n", offset, value); | |
| 150 | + | |
| 151 | + data_be = cpu_to_be32(upper_32_bits(value)); | |
| 152 | + rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA0, &data_be, | |
| 153 | + sizeof(data_be)); | |
| 154 | + if (rc) | |
| 155 | + return rc; | |
| 156 | + | |
| 157 | + data_be = cpu_to_be32(lower_32_bits(value)); | |
| 158 | + rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA1, &data_be, | |
| 159 | + sizeof(data_be)); | |
| 160 | + if (rc) | |
| 161 | + return rc; | |
| 162 | + | |
| 163 | + cmd_be = cpu_to_be32(cmd | FSI2SPI_CMD_WRITE); | |
| 164 | + rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be)); | |
| 165 | + if (rc) | |
| 166 | + return rc; | |
| 167 | + | |
| 168 | + return fsi_spi_check_status(ctx); | |
| 169 | +} | |
| 170 | + | |
| 171 | +static int fsi_spi_data_in(u64 in, u8 *rx, int len) | |
| 172 | +{ | |
| 173 | + int i; | |
| 174 | + int num_bytes = min(len, 8); | |
| 175 | + | |
| 176 | + for (i = 0; i < num_bytes; ++i) | |
| 177 | + rx[i] = (u8)(in >> (8 * ((num_bytes - 1) - i))); | |
| 178 | + | |
| 179 | + return num_bytes; | |
| 180 | +} | |
| 181 | + | |
| 182 | +static int fsi_spi_data_out(u64 *out, const u8 *tx, int len) | |
| 183 | +{ | |
| 184 | + int i; | |
| 185 | + int num_bytes = min(len, 8); | |
| 186 | + u8 *out_bytes = (u8 *)out; | |
| 187 | + | |
| 188 | + /* Unused bytes of the tx data should be 0. */ | |
| 189 | + *out = 0ULL; | |
| 190 | + | |
| 191 | + for (i = 0; i < num_bytes; ++i) | |
| 192 | + out_bytes[8 - (i + 1)] = tx[i]; | |
| 193 | + | |
| 194 | + return num_bytes; | |
| 195 | +} | |
| 196 | + | |
| 197 | +static int fsi_spi_reset(struct fsi_spi *ctx) | |
| 198 | +{ | |
| 199 | + int rc; | |
| 200 | + | |
| 201 | + dev_dbg(ctx->dev, "Resetting SPI controller.\n"); | |
| 202 | + | |
| 203 | + rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, | |
| 204 | + SPI_FSI_CLOCK_CFG_RESET1); | |
| 205 | + if (rc) | |
| 206 | + return rc; | |
| 207 | + | |
| 208 | + return fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, | |
| 209 | + SPI_FSI_CLOCK_CFG_RESET2); | |
| 210 | +} | |
| 211 | + | |
| 212 | +static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) | |
| 213 | +{ | |
| 214 | + /* | |
| 215 | + * Add the next byte of instruction to the 8-byte sequence register. | |
| 216 | + * Then decrement the counter so that the next instruction will go in | |
| 217 | + * the right place. Return the number of "slots" left in the sequence | |
| 218 | + * register. | |
| 219 | + */ | |
| 220 | + seq->data |= (u64)val << seq->bit; | |
| 221 | + seq->bit -= 8; | |
| 222 | + | |
| 223 | + return ((64 - seq->bit) / 8) - 2; | |
| 224 | +} | |
| 225 | + | |
| 226 | +static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq) | |
| 227 | +{ | |
| 228 | + seq->bit = 56; | |
| 229 | + seq->data = 0ULL; | |
| 230 | +} | |
| 231 | + | |
| 232 | +static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, | |
| 233 | + struct fsi_spi_sequence *seq, | |
| 234 | + struct spi_transfer *transfer) | |
| 235 | +{ | |
| 236 | + int loops; | |
| 237 | + int idx; | |
| 238 | + int rc; | |
| 239 | + u8 len = min(transfer->len, 8U); | |
| 240 | + u8 rem = transfer->len % len; | |
| 241 | + | |
| 242 | + loops = transfer->len / len; | |
| 243 | + | |
| 244 | + if (transfer->tx_buf) { | |
| 245 | + idx = fsi_spi_sequence_add(seq, | |
| 246 | + SPI_FSI_SEQUENCE_SHIFT_OUT(len)); | |
| 247 | + if (rem) | |
| 248 | + rem = SPI_FSI_SEQUENCE_SHIFT_OUT(rem); | |
| 249 | + } else if (transfer->rx_buf) { | |
| 250 | + idx = fsi_spi_sequence_add(seq, | |
| 251 | + SPI_FSI_SEQUENCE_SHIFT_IN(len)); | |
| 252 | + if (rem) | |
| 253 | + rem = SPI_FSI_SEQUENCE_SHIFT_IN(rem); | |
| 254 | + } else { | |
| 255 | + return -EINVAL; | |
| 256 | + } | |
| 257 | + | |
| 258 | + if (loops > 1) { | |
| 259 | + fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); | |
| 260 | + | |
| 261 | + if (rem) | |
| 262 | + fsi_spi_sequence_add(seq, rem); | |
| 263 | + | |
| 264 | + rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, | |
| 265 | + SPI_FSI_COUNTER_CFG_LOOPS(loops - 1)); | |
| 266 | + if (rc) | |
| 267 | + return rc; | |
| 268 | + } | |
| 269 | + | |
| 270 | + return 0; | |
| 271 | +} | |
| 272 | + | |
| 273 | +static int fsi_spi_transfer_data(struct fsi_spi *ctx, | |
| 274 | + struct spi_transfer *transfer) | |
| 275 | +{ | |
| 276 | + int rc = 0; | |
| 277 | + u64 status = 0ULL; | |
| 278 | + | |
| 279 | + if (transfer->tx_buf) { | |
| 280 | + int nb; | |
| 281 | + int sent = 0; | |
| 282 | + u64 out = 0ULL; | |
| 283 | + const u8 *tx = transfer->tx_buf; | |
| 284 | + | |
| 285 | + while (transfer->len > sent) { | |
| 286 | + nb = fsi_spi_data_out(&out, &tx[sent], | |
| 287 | + (int)transfer->len - sent); | |
| 288 | + | |
| 289 | + rc = fsi_spi_write_reg(ctx, SPI_FSI_DATA_TX, out); | |
| 290 | + if (rc) | |
| 291 | + return rc; | |
| 292 | + | |
| 293 | + do { | |
| 294 | + rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, | |
| 295 | + &status); | |
| 296 | + if (rc) | |
| 297 | + return rc; | |
| 298 | + | |
| 299 | + if (status & SPI_FSI_STATUS_ANY_ERROR) { | |
| 300 | + rc = fsi_spi_reset(ctx); | |
| 301 | + if (rc) | |
| 302 | + return rc; | |
| 303 | + | |
| 304 | + return -EREMOTEIO; | |
| 305 | + } | |
| 306 | + } while (status & SPI_FSI_STATUS_TDR_FULL); | |
| 307 | + | |
| 308 | + sent += nb; | |
| 309 | + } | |
| 310 | + } else if (transfer->rx_buf) { | |
| 311 | + int recv = 0; | |
| 312 | + u64 in = 0ULL; | |
| 313 | + u8 *rx = transfer->rx_buf; | |
| 314 | + | |
| 315 | + while (transfer->len > recv) { | |
| 316 | + do { | |
| 317 | + rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, | |
| 318 | + &status); | |
| 319 | + if (rc) | |
| 320 | + return rc; | |
| 321 | + | |
| 322 | + if (status & SPI_FSI_STATUS_ANY_ERROR) { | |
| 323 | + rc = fsi_spi_reset(ctx); | |
| 324 | + if (rc) | |
| 325 | + return rc; | |
| 326 | + | |
| 327 | + return -EREMOTEIO; | |
| 328 | + } | |
| 329 | + } while (!(status & SPI_FSI_STATUS_RDR_FULL)); | |
| 330 | + | |
| 331 | + rc = fsi_spi_read_reg(ctx, SPI_FSI_DATA_RX, &in); | |
| 332 | + if (rc) | |
| 333 | + return rc; | |
| 334 | + | |
| 335 | + recv += fsi_spi_data_in(in, &rx[recv], | |
| 336 | + (int)transfer->len - recv); | |
| 337 | + } | |
| 338 | + } | |
| 339 | + | |
| 340 | + return 0; | |
| 341 | +} | |
| 342 | + | |
| 343 | +static int fsi_spi_transfer_init(struct fsi_spi *ctx) | |
| 344 | +{ | |
| 345 | + int rc; | |
| 346 | + bool reset = false; | |
| 347 | + unsigned long end; | |
| 348 | + u64 seq_state; | |
| 349 | + u64 clock_cfg = 0ULL; | |
| 350 | + u64 status = 0ULL; | |
| 351 | + u64 wanted_clock_cfg = SPI_FSI_CLOCK_CFG_ECC_DISABLE | | |
| 352 | + SPI_FSI_CLOCK_CFG_SCK_NO_DEL | | |
| 353 | + FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 4); | |
| 354 | + | |
| 355 | + end = jiffies + msecs_to_jiffies(SPI_FSI_INIT_TIMEOUT_MS); | |
| 356 | + do { | |
| 357 | + if (time_after(jiffies, end)) | |
| 358 | + return -ETIMEDOUT; | |
| 359 | + | |
| 360 | + rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, &status); | |
| 361 | + if (rc) | |
| 362 | + return rc; | |
| 363 | + | |
| 364 | + seq_state = status & SPI_FSI_STATUS_SEQ_STATE; | |
| 365 | + | |
| 366 | + if (status & (SPI_FSI_STATUS_ANY_ERROR | | |
| 367 | + SPI_FSI_STATUS_TDR_FULL | | |
| 368 | + SPI_FSI_STATUS_RDR_FULL)) { | |
| 369 | + if (reset) | |
| 370 | + return -EIO; | |
| 371 | + | |
| 372 | + rc = fsi_spi_reset(ctx); | |
| 373 | + if (rc) | |
| 374 | + return rc; | |
| 375 | + | |
| 376 | + reset = true; | |
| 377 | + continue; | |
| 378 | + } | |
| 379 | + } while (seq_state && (seq_state != SPI_FSI_STATUS_SEQ_STATE_IDLE)); | |
| 380 | + | |
| 381 | + rc = fsi_spi_read_reg(ctx, SPI_FSI_CLOCK_CFG, &clock_cfg); | |
| 382 | + if (rc) | |
| 383 | + return rc; | |
| 384 | + | |
| 385 | + if ((clock_cfg & (SPI_FSI_CLOCK_CFG_MM_ENABLE | | |
| 386 | + SPI_FSI_CLOCK_CFG_ECC_DISABLE | | |
| 387 | + SPI_FSI_CLOCK_CFG_MODE | | |
| 388 | + SPI_FSI_CLOCK_CFG_SCK_RECV_DEL | | |
| 389 | + SPI_FSI_CLOCK_CFG_SCK_DIV)) != wanted_clock_cfg) | |
| 390 | + rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, | |
| 391 | + wanted_clock_cfg); | |
| 392 | + | |
| 393 | + return rc; | |
| 394 | +} | |
| 395 | + | |
| 396 | +static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, | |
| 397 | + struct spi_message *mesg) | |
| 398 | +{ | |
| 399 | + int rc = 0; | |
| 400 | + u8 seq_slave = SPI_FSI_SEQUENCE_SEL_SLAVE(mesg->spi->chip_select + 1); | |
| 401 | + struct spi_transfer *transfer; | |
| 402 | + struct fsi_spi *ctx = spi_controller_get_devdata(ctlr); | |
| 403 | + | |
| 404 | + list_for_each_entry(transfer, &mesg->transfers, transfer_list) { | |
| 405 | + struct fsi_spi_sequence seq; | |
| 406 | + struct spi_transfer *next = NULL; | |
| 407 | + | |
| 408 | + /* Sequencer must do shift out (tx) first. */ | |
| 409 | + if (!transfer->tx_buf || | |
| 410 | + transfer->len > SPI_FSI_MAX_TRANSFER_SIZE) { | |
| 411 | + rc = -EINVAL; | |
| 412 | + goto error; | |
| 413 | + } | |
| 414 | + | |
| 415 | + dev_dbg(ctx->dev, "Start tx of %d bytes.\n", transfer->len); | |
| 416 | + | |
| 417 | + rc = fsi_spi_transfer_init(ctx); | |
| 418 | + if (rc < 0) | |
| 419 | + goto error; | |
| 420 | + | |
| 421 | + fsi_spi_sequence_init(&seq); | |
| 422 | + fsi_spi_sequence_add(&seq, seq_slave); | |
| 423 | + | |
| 424 | + rc = fsi_spi_sequence_transfer(ctx, &seq, transfer); | |
| 425 | + if (rc) | |
| 426 | + goto error; | |
| 427 | + | |
| 428 | + if (!list_is_last(&transfer->transfer_list, | |
| 429 | + &mesg->transfers)) { | |
| 430 | + next = list_next_entry(transfer, transfer_list); | |
| 431 | + | |
| 432 | + /* Sequencer can only do shift in (rx) after tx. */ | |
| 433 | + if (next->rx_buf) { | |
| 434 | + if (next->len > SPI_FSI_MAX_TRANSFER_SIZE) { | |
| 435 | + rc = -EINVAL; | |
| 436 | + goto error; | |
| 437 | + } | |
| 438 | + | |
| 439 | + dev_dbg(ctx->dev, "Sequence rx of %d bytes.\n", | |
| 440 | + next->len); | |
| 441 | + | |
| 442 | + rc = fsi_spi_sequence_transfer(ctx, &seq, | |
| 443 | + next); | |
| 444 | + if (rc) | |
| 445 | + goto error; | |
| 446 | + } else { | |
| 447 | + next = NULL; | |
| 448 | + } | |
| 449 | + } | |
| 450 | + | |
| 451 | + fsi_spi_sequence_add(&seq, SPI_FSI_SEQUENCE_SEL_SLAVE(0)); | |
| 452 | + | |
| 453 | + rc = fsi_spi_write_reg(ctx, SPI_FSI_SEQUENCE, seq.data); | |
| 454 | + if (rc) | |
| 455 | + goto error; | |
| 456 | + | |
| 457 | + rc = fsi_spi_transfer_data(ctx, transfer); | |
| 458 | + if (rc) | |
| 459 | + goto error; | |
| 460 | + | |
| 461 | + if (next) { | |
| 462 | + rc = fsi_spi_transfer_data(ctx, next); | |
| 463 | + if (rc) | |
| 464 | + goto error; | |
| 465 | + | |
| 466 | + transfer = next; | |
| 467 | + } | |
| 468 | + } | |
| 469 | + | |
| 470 | +error: | |
| 471 | + mesg->status = rc; | |
| 472 | + spi_finalize_current_message(ctlr); | |
| 473 | + | |
| 474 | + return rc; | |
| 475 | +} | |
| 476 | + | |
| 477 | +static size_t fsi_spi_max_transfer_size(struct spi_device *spi) | |
| 478 | +{ | |
| 479 | + return SPI_FSI_MAX_TRANSFER_SIZE; | |
| 480 | +} | |
| 481 | + | |
| 482 | +static int fsi_spi_probe(struct device *dev) | |
| 483 | +{ | |
| 484 | + int rc; | |
| 485 | + u32 root_ctrl_8; | |
| 486 | + struct device_node *np; | |
| 487 | + int num_controllers_registered = 0; | |
| 488 | + struct fsi_device *fsi = to_fsi_dev(dev); | |
| 489 | + | |
| 490 | + /* | |
| 491 | + * Check the SPI mux before attempting to probe. If the mux isn't set | |
| 492 | + * then the SPI controllers can't access their slave devices. | |
| 493 | + */ | |
| 494 | + rc = fsi_slave_read(fsi->slave, FSI_MBOX_ROOT_CTRL_8, &root_ctrl_8, | |
| 495 | + sizeof(root_ctrl_8)); | |
| 496 | + if (rc) | |
| 497 | + return rc; | |
| 498 | + | |
| 499 | + if (!root_ctrl_8) { | |
| 500 | + dev_dbg(dev, "SPI mux not set, aborting probe.\n"); | |
| 501 | + return -ENODEV; | |
| 502 | + } | |
| 503 | + | |
| 504 | + for_each_available_child_of_node(dev->of_node, np) { | |
| 505 | + u32 base; | |
| 506 | + struct fsi_spi *ctx; | |
| 507 | + struct spi_controller *ctlr; | |
| 508 | + | |
| 509 | + if (of_property_read_u32(np, "reg", &base)) | |
| 510 | + continue; | |
| 511 | + | |
| 512 | + ctlr = spi_alloc_master(dev, sizeof(*ctx)); | |
| 513 | + if (!ctlr) | |
| 514 | + break; | |
| 515 | + | |
| 516 | + ctlr->dev.of_node = np; | |
| 517 | + ctlr->num_chipselect = of_get_available_child_count(np) ?: 1; | |
| 518 | + ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX; | |
| 519 | + ctlr->max_transfer_size = fsi_spi_max_transfer_size; | |
| 520 | + ctlr->transfer_one_message = fsi_spi_transfer_one_message; | |
| 521 | + | |
| 522 | + ctx = spi_controller_get_devdata(ctlr); | |
| 523 | + ctx->dev = &ctlr->dev; | |
| 524 | + ctx->fsi = fsi; | |
| 525 | + ctx->base = base + SPI_FSI_BASE; | |
| 526 | + | |
| 527 | + rc = devm_spi_register_controller(dev, ctlr); | |
| 528 | + if (rc) | |
| 529 | + spi_controller_put(ctlr); | |
| 530 | + else | |
| 531 | + num_controllers_registered++; | |
| 532 | + } | |
| 533 | + | |
| 534 | + if (!num_controllers_registered) | |
| 535 | + return -ENODEV; | |
| 536 | + | |
| 537 | + return 0; | |
| 538 | +} | |
| 539 | + | |
| 540 | +static const struct fsi_device_id fsi_spi_ids[] = { | |
| 541 | + { FSI_ENGID_SPI, FSI_VERSION_ANY }, | |
| 542 | + { } | |
| 543 | +}; | |
| 544 | +MODULE_DEVICE_TABLE(fsi, fsi_spi_ids); | |
| 545 | + | |
| 546 | +static struct fsi_driver fsi_spi_driver = { | |
| 547 | + .id_table = fsi_spi_ids, | |
| 548 | + .drv = { | |
| 549 | + .name = "spi-fsi", | |
| 550 | + .bus = &fsi_bus_type, | |
| 551 | + .probe = fsi_spi_probe, | |
| 552 | + }, | |
| 553 | +}; | |
| 554 | +module_fsi_driver(fsi_spi_driver); | |
| 555 | + | |
| 556 | +MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>"); | |
| 557 | +MODULE_DESCRIPTION("FSI attached SPI controller"); | |
| 558 | +MODULE_LICENSE("GPL"); | |
| @@ -20,16 +20,9 @@ · 19 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | #define DRIVER_NAME "fsl-dspi" |
| 22 | 22 | |
| 23 | −#ifdef CONFIG_M5441x | |
| 24 | −#define DSPI_FIFO_SIZE 16 | |
| 25 | −#else | |
| 26 | −#define DSPI_FIFO_SIZE 4 | |
| 27 | −#endif | |
| 28 | −#define DSPI_DMA_BUFSIZE (DSPI_FIFO_SIZE * 1024) | |
| 29 | − | |
| 30 | 23 | #define SPI_MCR 0x00 |
| 31 | 24 | #define SPI_MCR_MASTER BIT(31) |
| 32 | −#define SPI_MCR_PCSIS (0x3F << 16) | |
| 25 | +#define SPI_MCR_PCSIS(x) ((x) << 16) | |
| 33 | 26 | #define SPI_MCR_CLR_TXF BIT(11) |
| 34 | 27 | #define SPI_MCR_CLR_RXF BIT(10) |
| 35 | 28 | #define SPI_MCR_XSPI BIT(3) |
| @@ -79,6 +72,7 @@ · 43 unmodified lines | ||
| 79 | 72 | #define SPI_RSER 0x30 |
| 80 | 73 | #define SPI_RSER_TCFQE BIT(31) |
| 81 | 74 | #define SPI_RSER_EOQFE BIT(28) |
| 75 | +#define SPI_RSER_CMDTCFE BIT(23) | |
| 82 | 76 | |
| 83 | 77 | #define SPI_PUSHR 0x34 |
| 84 | 78 | #define SPI_PUSHR_CMD_CONT BIT(15) |
| @@ -109,57 +103,95 @@ · 24 unmodified lines | ||
| 109 | 103 | #define SPI_FRAME_BITS(bits) SPI_CTAR_FMSZ((bits) - 1) |
| 110 | 104 | #define SPI_FRAME_EBITS(bits) SPI_CTARE_FMSZE(((bits) - 1) >> 4) |
| 111 | 105 | |
| 112 | −/* Register offsets for regmap_pushr */ | |
| 113 | −#define PUSHR_CMD 0x0 | |
| 114 | −#define PUSHR_TX 0x2 | |
| 115 | − | |
| 116 | 106 | #define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000) |
| 117 | 107 | |
| 118 | 108 | struct chip_data { |
| 119 | 109 | u32 ctar_val; |
| 120 | − u16 void_write_data; | |
| 121 | 110 | }; |
| 122 | 111 | |
| 123 | 112 | enum dspi_trans_mode { |
| 124 | 113 | DSPI_EOQ_MODE = 0, |
| 125 | − DSPI_TCFQ_MODE, | |
| 114 | + DSPI_XSPI_MODE, | |
| 126 | 115 | DSPI_DMA_MODE, |
| 127 | 116 | }; |
| 128 | 117 | |
| 129 | 118 | struct fsl_dspi_devtype_data { |
| 130 | 119 | enum dspi_trans_mode trans_mode; |
| 131 | 120 | u8 max_clock_factor; |
| 132 | − bool ptp_sts_supported; | |
| 133 | − bool xspi_mode; | |
| 134 | −}; | |
| 135 | − | |
| 136 | −static const struct fsl_dspi_devtype_data vf610_data = { | |
| 137 | − .trans_mode = DSPI_DMA_MODE, | |
| 138 | − .max_clock_factor = 2, | |
| 139 | −}; | |
| 140 | − | |
| 141 | −static const struct fsl_dspi_devtype_data ls1021a_v1_data = { | |
| 142 | − .trans_mode = DSPI_TCFQ_MODE, | |
| 143 | − .max_clock_factor = 8, | |
| 144 | − .ptp_sts_supported = true, | |
| 145 | − .xspi_mode = true, | |
| 121 | + int fifo_size; | |
| 146 | 122 | }; |
| 147 | 123 | |
| 148 | −static const struct fsl_dspi_devtype_data ls2085a_data = { | |
| 149 | − .trans_mode = DSPI_TCFQ_MODE, | |
| 150 | − .max_clock_factor = 8, | |
| 151 | − .ptp_sts_supported = true, | |
| 124 | +enum { | |
| 125 | + LS1021A, | |
| 126 | + LS1012A, | |
| 127 | + LS1028A, | |
| 128 | + LS1043A, | |
| 129 | + LS1046A, | |
| 130 | + LS2080A, | |
| 131 | + LS2085A, | |
| 132 | + LX2160A, | |
| 133 | + MCF5441X, | |
| 134 | + VF610, | |
| 152 | 135 | }; |
| 153 | 136 | |
| 154 | −static const struct fsl_dspi_devtype_data coldfire_data = { | |
| 155 | − .trans_mode = DSPI_EOQ_MODE, | |
| 156 | − .max_clock_factor = 8, | |
| 137 | +static const struct fsl_dspi_devtype_data devtype_data[] = { | |
| 138 | + [VF610] = { | |
| 139 | + .trans_mode = DSPI_DMA_MODE, | |
| 140 | + .max_clock_factor = 2, | |
| 141 | + .fifo_size = 4, | |
| 142 | + }, | |
| 143 | + [LS1021A] = { | |
| 144 | + /* Has A-011218 DMA erratum */ | |
| 145 | + .trans_mode = DSPI_XSPI_MODE, | |
| 146 | + .max_clock_factor = 8, | |
| 147 | + .fifo_size = 4, | |
| 148 | + }, | |
| 149 | + [LS1012A] = { | |
| 150 | + /* Has A-011218 DMA erratum */ | |
| 151 | + .trans_mode = DSPI_XSPI_MODE, | |
| 152 | + .max_clock_factor = 8, | |
| 153 | + .fifo_size = 16, | |
| 154 | + }, | |
| 155 | + [LS1028A] = { | |
| 156 | + .trans_mode = DSPI_XSPI_MODE, | |
| 157 | + .max_clock_factor = 8, | |
| 158 | + .fifo_size = 4, | |
| 159 | + }, | |
| 160 | + [LS1043A] = { | |
| 161 | + /* Has A-011218 DMA erratum */ | |
| 162 | + .trans_mode = DSPI_XSPI_MODE, | |
| 163 | + .max_clock_factor = 8, | |
| 164 | + .fifo_size = 16, | |
| 165 | + }, | |
| 166 | + [LS1046A] = { | |
| 167 | + /* Has A-011218 DMA erratum */ | |
| 168 | + .trans_mode = DSPI_XSPI_MODE, | |
| 169 | + .max_clock_factor = 8, | |
| 170 | + .fifo_size = 16, | |
| 171 | + }, | |
| 172 | + [LS2080A] = { | |
| 173 | + .trans_mode = DSPI_DMA_MODE, | |
| 174 | + .max_clock_factor = 8, | |
| 175 | + .fifo_size = 4, | |
| 176 | + }, | |
| 177 | + [LS2085A] = { | |
| 178 | + .trans_mode = DSPI_DMA_MODE, | |
| 179 | + .max_clock_factor = 8, | |
| 180 | + .fifo_size = 4, | |
| 181 | + }, | |
| 182 | + [LX2160A] = { | |
| 183 | + .trans_mode = DSPI_DMA_MODE, | |
| 184 | + .max_clock_factor = 8, | |
| 185 | + .fifo_size = 4, | |
| 186 | + }, | |
| 187 | + [MCF5441X] = { | |
| 188 | + .trans_mode = DSPI_EOQ_MODE, | |
| 189 | + .max_clock_factor = 8, | |
| 190 | + .fifo_size = 16, | |
| 191 | + }, | |
| 157 | 192 | }; |
| 158 | 193 | |
| 159 | 194 | struct fsl_dspi_dma { |
| 160 | − /* Length of transfer in words of DSPI_FIFO_SIZE */ | |
| 161 | − u32 curr_xfer_len; | |
| 162 | − | |
| 163 | 195 | u32 *tx_dma_buf; |
| 164 | 196 | struct dma_chan *chan_tx; |
| 165 | 197 | dma_addr_t tx_dma_phys; |
| @@ -189,36 +221,99 @@ struct fsl_dspi { · 23 unmodified lines | ||
| 189 | 221 | size_t len; |
| 190 | 222 | const void *tx; |
| 191 | 223 | void *rx; |
| 192 | − void *rx_end; | |
| 193 | − u16 void_write_data; | |
| 194 | 224 | u16 tx_cmd; |
| 195 | − u8 bits_per_word; | |
| 196 | − u8 bytes_per_word; | |
| 197 | 225 | const struct fsl_dspi_devtype_data *devtype_data; |
| 198 | 226 | |
| 199 | − wait_queue_head_t waitq; | |
| 200 | − u32 waitflags; | |
| 227 | + struct completion xfer_done; | |
| 201 | 228 | |
| 202 | 229 | struct fsl_dspi_dma *dma; |
| 230 | + | |
| 231 | + int oper_word_size; | |
| 232 | + int oper_bits_per_word; | |
| 233 | + | |
| 234 | + int words_in_flight; | |
| 235 | + | |
| 236 | + /* | |
| 237 | + * Offsets for CMD and TXDATA within SPI_PUSHR when accessed | |
| 238 | + * individually (in XSPI mode) | |
| 239 | + */ | |
| 240 | + int pushr_cmd; | |
| 241 | + int pushr_tx; | |
| 242 | + | |
| 243 | + void (*host_to_dev)(struct fsl_dspi *dspi, u32 *txdata); | |
| 244 | + void (*dev_to_host)(struct fsl_dspi *dspi, u32 rxdata); | |
| 203 | 245 | }; |
| 204 | 246 | |
| 247 | +static void dspi_native_host_to_dev(struct fsl_dspi *dspi, u32 *txdata) | |
| 248 | +{ | |
| 249 | + memcpy(txdata, dspi->tx, dspi->oper_word_size); | |
| 250 | + dspi->tx += dspi->oper_word_size; | |
| 251 | +} | |
| 252 | + | |
| 253 | +static void dspi_native_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) | |
| 254 | +{ | |
| 255 | + memcpy(dspi->rx, &rxdata, dspi->oper_word_size); | |
| 256 | + dspi->rx += dspi->oper_word_size; | |
| 257 | +} | |
| 258 | + | |
| 259 | +static void dspi_8on32_host_to_dev(struct fsl_dspi *dspi, u32 *txdata) | |
| 260 | +{ | |
| 261 | + *txdata = cpu_to_be32(*(u32 *)dspi->tx); | |
| 262 | + dspi->tx += sizeof(u32); | |
| 263 | +} | |
| 264 | + | |
| 265 | +static void dspi_8on32_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) | |
| 266 | +{ | |
| 267 | + *(u32 *)dspi->rx = be32_to_cpu(rxdata); | |
| 268 | + dspi->rx += sizeof(u32); | |
| 269 | +} | |
| 270 | + | |
| 271 | +static void dspi_8on16_host_to_dev(struct fsl_dspi *dspi, u32 *txdata) | |
| 272 | +{ | |
| 273 | + *txdata = cpu_to_be16(*(u16 *)dspi->tx); | |
| 274 | + dspi->tx += sizeof(u16); | |
| 275 | +} | |
| 276 | + | |
| 277 | +static void dspi_8on16_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) | |
| 278 | +{ | |
| 279 | + *(u16 *)dspi->rx = be16_to_cpu(rxdata); | |
| 280 | + dspi->rx += sizeof(u16); | |
| 281 | +} | |
| 282 | + | |
| 283 | +static void dspi_16on32_host_to_dev(struct fsl_dspi *dspi, u32 *txdata) | |
| 284 | +{ | |
| 285 | + u16 hi = *(u16 *)dspi->tx; | |
| 286 | + u16 lo = *(u16 *)(dspi->tx + 2); | |
| 287 | + | |
| 288 | + *txdata = (u32)hi << 16 | lo; | |
| 289 | + dspi->tx += sizeof(u32); | |
| 290 | +} | |
| 291 | + | |
| 292 | +static void dspi_16on32_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) | |
| 293 | +{ | |
| 294 | + u16 hi = rxdata & 0xffff; | |
| 295 | + u16 lo = rxdata >> 16; | |
| 296 | + | |
| 297 | + *(u16 *)dspi->rx = lo; | |
| 298 | + *(u16 *)(dspi->rx + 2) = hi; | |
| 299 | + dspi->rx += sizeof(u32); | |
| 300 | +} | |
| 301 | + | |
| 302 | +/* | |
| 303 | + * Pop one word from the TX buffer for pushing into the | |
| 304 | + * PUSHR register (TX FIFO) | |
| 305 | + */ | |
| 205 | 306 | static u32 dspi_pop_tx(struct fsl_dspi *dspi) |
| 206 | 307 | { |
| 207 | 308 | u32 txdata = 0; |
| 208 | 309 | |
| 209 | − if (dspi->tx) { | |
| 210 | − if (dspi->bytes_per_word == 1) | |
| 211 | − txdata = *(u8 *)dspi->tx; | |
| 212 | − else if (dspi->bytes_per_word == 2) | |
| 213 | − txdata = *(u16 *)dspi->tx; | |
| 214 | − else /* dspi->bytes_per_word == 4 */ | |
| 215 | − txdata = *(u32 *)dspi->tx; | |
| 216 | − dspi->tx += dspi->bytes_per_word; | |
| 217 | − } | |
| 218 | − dspi->len -= dspi->bytes_per_word; | |
| 310 | + if (dspi->tx) | |
| 311 | + dspi->host_to_dev(dspi, &txdata); | |
| 312 | + dspi->len -= dspi->oper_word_size; | |
| 219 | 313 | return txdata; |
| 220 | 314 | } |
| 221 | 315 | |
| 316 | +/* Prepare one TX FIFO entry (txdata plus cmd) */ | |
| 222 | 317 | static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi) |
| 223 | 318 | { |
| 224 | 319 | u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi); |
| @@ -231,21 +326,12 @@ static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi) · 6 unmodified lines | ||
| 231 | 326 | return cmd << 16 | data; |
| 232 | 327 | } |
| 233 | 328 | |
| 329 | +/* Push one word to the RX buffer from the POPR register (RX FIFO) */ | |
| 234 | 330 | static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata) |
| 235 | 331 | { |
| 236 | 332 | if (!dspi->rx) |
| 237 | 333 | return; |
| 238 | − | |
| 239 | − /* Mask off undefined bits */ | |
| 240 | − rxdata &= (1 << dspi->bits_per_word) - 1; | |
| 241 | − | |
| 242 | − if (dspi->bytes_per_word == 1) | |
| 243 | − *(u8 *)dspi->rx = rxdata; | |
| 244 | − else if (dspi->bytes_per_word == 2) | |
| 245 | − *(u16 *)dspi->rx = rxdata; | |
| 246 | − else /* dspi->bytes_per_word == 4 */ | |
| 247 | − *(u32 *)dspi->rx = rxdata; | |
| 248 | − dspi->rx += dspi->bytes_per_word; | |
| 334 | + dspi->dev_to_host(dspi, rxdata); | |
| 249 | 335 | } |
| 250 | 336 | |
| 251 | 337 | static void dspi_tx_dma_callback(void *arg) |
| @@ -263,7 +349,7 @@ static void dspi_rx_dma_callback(void *arg) · 11 unmodified lines | ||
| 263 | 349 | int i; |
| 264 | 350 | |
| 265 | 351 | if (dspi->rx) { |
| 266 | − for (i = 0; i < dma->curr_xfer_len; i++) | |
| 352 | + for (i = 0; i < dspi->words_in_flight; i++) | |
| 267 | 353 | dspi_push_rx(dspi, dspi->dma->rx_dma_buf[i]); |
| 268 | 354 | } |
| 269 | 355 | |
| @@ -277,12 +363,12 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi) · 7 unmodified lines | ||
| 277 | 363 | int time_left; |
| 278 | 364 | int i; |
| 279 | 365 | |
| 280 | − for (i = 0; i < dma->curr_xfer_len; i++) | |
| 366 | + for (i = 0; i < dspi->words_in_flight; i++) | |
| 281 | 367 | dspi->dma->tx_dma_buf[i] = dspi_pop_tx_pushr(dspi); |
| 282 | 368 | |
| 283 | 369 | dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx, |
| 284 | 370 | dma->tx_dma_phys, |
| 285 | − dma->curr_xfer_len * | |
| 371 | + dspi->words_in_flight * | |
| 286 | 372 | DMA_SLAVE_BUSWIDTH_4_BYTES, |
| 287 | 373 | DMA_MEM_TO_DEV, |
| 288 | 374 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
| @@ -300,7 +386,7 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi) · 11 unmodified lines | ||
| 300 | 386 | |
| 301 | 387 | dma->rx_desc = dmaengine_prep_slave_single(dma->chan_rx, |
| 302 | 388 | dma->rx_dma_phys, |
| 303 | − dma->curr_xfer_len * | |
| 389 | + dspi->words_in_flight * | |
| 304 | 390 | DMA_SLAVE_BUSWIDTH_4_BYTES, |
| 305 | 391 | DMA_DEV_TO_MEM, |
| 306 | 392 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
| @@ -348,45 +434,42 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi) · 41 unmodified lines | ||
| 348 | 434 | return 0; |
| 349 | 435 | } |
| 350 | 436 | |
| 437 | +static void dspi_setup_accel(struct fsl_dspi *dspi); | |
| 438 | + | |
| 351 | 439 | static int dspi_dma_xfer(struct fsl_dspi *dspi) |
| 352 | 440 | { |
| 353 | 441 | struct spi_message *message = dspi->cur_msg; |
| 354 | 442 | struct device *dev = &dspi->pdev->dev; |
| 355 | − struct fsl_dspi_dma *dma = dspi->dma; | |
| 356 | − int curr_remaining_bytes; | |
| 357 | − int bytes_per_buffer; | |
| 358 | 443 | int ret = 0; |
| 359 | 444 | |
| 360 | − curr_remaining_bytes = dspi->len; | |
| 361 | − bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE; | |
| 362 | − while (curr_remaining_bytes) { | |
| 363 | − /* Check if current transfer fits the DMA buffer */ | |
| 364 | − dma->curr_xfer_len = curr_remaining_bytes | |
| 365 | − / dspi->bytes_per_word; | |
| 366 | − if (dma->curr_xfer_len > bytes_per_buffer) | |
| 367 | − dma->curr_xfer_len = bytes_per_buffer; | |
| 445 | + /* | |
| 446 | + * dspi->len gets decremented by dspi_pop_tx_pushr in | |
| 447 | + * dspi_next_xfer_dma_submit | |
| 448 | + */ | |
| 449 | + while (dspi->len) { | |
| 450 | + /* Figure out operational bits-per-word for this chunk */ | |
| 451 | + dspi_setup_accel(dspi); | |
| 452 | + | |
| 453 | + dspi->words_in_flight = dspi->len / dspi->oper_word_size; | |
| 454 | + if (dspi->words_in_flight > dspi->devtype_data->fifo_size) | |
| 455 | + dspi->words_in_flight = dspi->devtype_data->fifo_size; | |
| 456 | + | |
| 457 | + message->actual_length += dspi->words_in_flight * | |
| 458 | + dspi->oper_word_size; | |
| 368 | 459 | |
| 369 | 460 | ret = dspi_next_xfer_dma_submit(dspi); |
| 370 | 461 | if (ret) { |
| 371 | 462 | dev_err(dev, "DMA transfer failed\n"); |
| 372 | − goto exit; | |
| 373 | − | |
| 374 | − } else { | |
| 375 | − const int len = | |
| 376 | − dma->curr_xfer_len * dspi->bytes_per_word; | |
| 377 | − curr_remaining_bytes -= len; | |
| 378 | − message->actual_length += len; | |
| 379 | − if (curr_remaining_bytes < 0) | |
| 380 | − curr_remaining_bytes = 0; | |
| 463 | + break; | |
| 381 | 464 | } |
| 382 | 465 | } |
| 383 | 466 | |
| 384 | −exit: | |
| 385 | 467 | return ret; |
| 386 | 468 | } |
| 387 | 469 | |
| 388 | 470 | static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr) |
| 389 | 471 | { |
| 472 | + int dma_bufsize = dspi->devtype_data->fifo_size * 2; | |
| 390 | 473 | struct device *dev = &dspi->pdev->dev; |
| 391 | 474 | struct dma_slave_config cfg; |
| 392 | 475 | struct fsl_dspi_dma *dma; |
| @@ -410,15 +493,17 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr) · 17 unmodified lines | ||
| 410 | 493 | goto err_tx_channel; |
| 411 | 494 | } |
| 412 | 495 | |
| 413 | − dma->tx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE, | |
| 414 | − &dma->tx_dma_phys, GFP_KERNEL); | |
| 496 | + dma->tx_dma_buf = dma_alloc_coherent(dma->chan_tx->device->dev, | |
| 497 | + dma_bufsize, &dma->tx_dma_phys, | |
| 498 | + GFP_KERNEL); | |
| 415 | 499 | if (!dma->tx_dma_buf) { |
| 416 | 500 | ret = -ENOMEM; |
| 417 | 501 | goto err_tx_dma_buf; |
| 418 | 502 | } |
| 419 | 503 | |
| 420 | − dma->rx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE, | |
| 421 | − &dma->rx_dma_phys, GFP_KERNEL); | |
| 504 | + dma->rx_dma_buf = dma_alloc_coherent(dma->chan_rx->device->dev, | |
| 505 | + dma_bufsize, &dma->rx_dma_phys, | |
| 506 | + GFP_KERNEL); | |
| 422 | 507 | if (!dma->rx_dma_buf) { |
| 423 | 508 | ret = -ENOMEM; |
| 424 | 509 | goto err_rx_dma_buf; |
| @@ -454,11 +539,11 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr) · 29 unmodified lines | ||
| 454 | 539 | return 0; |
| 455 | 540 | |
| 456 | 541 | err_slave_config: |
| 457 | − dma_free_coherent(dev, DSPI_DMA_BUFSIZE, | |
| 458 | − dma->rx_dma_buf, dma->rx_dma_phys); | |
| 542 | + dma_free_coherent(dma->chan_rx->device->dev, | |
| 543 | + dma_bufsize, dma->rx_dma_buf, dma->rx_dma_phys); | |
| 459 | 544 | err_rx_dma_buf: |
| 460 | − dma_free_coherent(dev, DSPI_DMA_BUFSIZE, | |
| 461 | − dma->tx_dma_buf, dma->tx_dma_phys); | |
| 545 | + dma_free_coherent(dma->chan_tx->device->dev, | |
| 546 | + dma_bufsize, dma->tx_dma_buf, dma->tx_dma_phys); | |
| 462 | 547 | err_tx_dma_buf: |
| 463 | 548 | dma_release_channel(dma->chan_tx); |
| 464 | 549 | err_tx_channel: |
| @@ -472,21 +557,21 @@ err_tx_channel: · 7 unmodified lines | ||
| 472 | 557 | |
| 473 | 558 | static void dspi_release_dma(struct fsl_dspi *dspi) |
| 474 | 559 | { |
| 560 | + int dma_bufsize = dspi->devtype_data->fifo_size * 2; | |
| 475 | 561 | struct fsl_dspi_dma *dma = dspi->dma; |
| 476 | − struct device *dev = &dspi->pdev->dev; | |
| 477 | 562 | |
| 478 | 563 | if (!dma) |
| 479 | 564 | return; |
| 480 | 565 | |
| 481 | 566 | if (dma->chan_tx) { |
| 482 | − dma_unmap_single(dev, dma->tx_dma_phys, | |
| 483 | − DSPI_DMA_BUFSIZE, DMA_TO_DEVICE); | |
| 567 | + dma_unmap_single(dma->chan_tx->device->dev, dma->tx_dma_phys, | |
| 568 | + dma_bufsize, DMA_TO_DEVICE); | |
| 484 | 569 | dma_release_channel(dma->chan_tx); |
| 485 | 570 | } |
| 486 | 571 | |
| 487 | 572 | if (dma->chan_rx) { |
| 488 | − dma_unmap_single(dev, dma->rx_dma_phys, | |
| 489 | − DSPI_DMA_BUFSIZE, DMA_FROM_DEVICE); | |
| 573 | + dma_unmap_single(dma->chan_rx->device->dev, dma->rx_dma_phys, | |
| 574 | + dma_bufsize, DMA_FROM_DEVICE); | |
| 490 | 575 | dma_release_channel(dma->chan_rx); |
| 491 | 576 | } |
| 492 | 577 | } |
| @@ -562,124 +647,220 @@ static void ns_delay_scale(char *psc, char *sc, int delay_ns, · 69 unmodified lines | ||
| 562 | 647 | } |
| 563 | 648 | } |
| 564 | 649 | |
| 565 | −static void fifo_write(struct fsl_dspi *dspi) | |
| 650 | +static void dspi_pushr_write(struct fsl_dspi *dspi) | |
| 566 | 651 | { |
| 567 | 652 | regmap_write(dspi->regmap, SPI_PUSHR, dspi_pop_tx_pushr(dspi)); |
| 568 | 653 | } |
| 569 | 654 | |
| 570 | −static void cmd_fifo_write(struct fsl_dspi *dspi) | |
| 655 | +static void dspi_pushr_cmd_write(struct fsl_dspi *dspi, u16 cmd) | |
| 571 | 656 | { |
| 572 | − u16 cmd = dspi->tx_cmd; | |
| 573 | − | |
| 574 | − if (dspi->len > 0) | |
| 657 | + /* | |
| 658 | + * The only time when the PCS doesn't need continuation after this word | |
| 659 | + * is when it's last. We need to look ahead, because we actually call | |
| 660 | + * dspi_pop_tx (the function that decrements dspi->len) _after_ | |
| 661 | + * dspi_pushr_cmd_write with XSPI mode. As for how much in advance? One | |
| 662 | + * word is enough. If there's more to transmit than that, | |
| 663 | + * dspi_xspi_write will know to split the FIFO writes in 2, and | |
| 664 | + * generate a new PUSHR command with the final word that will have PCS | |
| 665 | + * deasserted (not continued) here. | |
| 666 | + */ | |
| 667 | + if (dspi->len > dspi->oper_word_size) | |
| 575 | 668 | cmd |= SPI_PUSHR_CMD_CONT; |
| 576 | − regmap_write(dspi->regmap_pushr, PUSHR_CMD, cmd); | |
| 669 | + regmap_write(dspi->regmap_pushr, dspi->pushr_cmd, cmd); | |
| 577 | 670 | } |
| 578 | 671 | |
| 579 | −static void tx_fifo_write(struct fsl_dspi *dspi, u16 txdata) | |
| 672 | +static void dspi_pushr_txdata_write(struct fsl_dspi *dspi, u16 txdata) | |
| 580 | 673 | { |
| 581 | − regmap_write(dspi->regmap_pushr, PUSHR_TX, txdata); | |
| 674 | + regmap_write(dspi->regmap_pushr, dspi->pushr_tx, txdata); | |
| 582 | 675 | } |
| 583 | 676 | |
| 584 | −static void dspi_tcfq_write(struct fsl_dspi *dspi) | |
| 677 | +static void dspi_xspi_fifo_write(struct fsl_dspi *dspi, int num_words) | |
| 585 | 678 | { |
| 586 | − /* Clear transfer count */ | |
| 587 | − dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT; | |
| 679 | + int num_bytes = num_words * dspi->oper_word_size; | |
| 680 | + u16 tx_cmd = dspi->tx_cmd; | |
| 588 | 681 | |
| 589 | − if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) { | |
| 590 | − /* Write the CMD FIFO entry first, and then the two | |
| 591 | − * corresponding TX FIFO entries. | |
| 592 | − */ | |
| 593 | − u32 data = dspi_pop_tx(dspi); | |
| 682 | + /* | |
| 683 | + * If the PCS needs to de-assert (i.e. we're at the end of the buffer | |
| 684 | + * and cs_change does not want the PCS to stay on), then we need a new | |
| 685 | + * PUSHR command, since this one (for the body of the buffer) | |
| 686 | + * necessarily has the CONT bit set. | |
| 687 | + * So send one word less during this go, to force a split and a command | |
| 688 | + * with a single word next time, when CONT will be unset. | |
| 689 | + */ | |
| 690 | + if (!(dspi->tx_cmd & SPI_PUSHR_CMD_CONT) && num_bytes == dspi->len) | |
| 691 | + tx_cmd |= SPI_PUSHR_CMD_EOQ; | |
| 594 | 692 | |
| 595 | − cmd_fifo_write(dspi); | |
| 596 | − tx_fifo_write(dspi, data & 0xFFFF); | |
| 597 | − tx_fifo_write(dspi, data >> 16); | |
| 598 | − } else { | |
| 599 | − /* Write one entry to both TX FIFO and CMD FIFO | |
| 600 | − * simultaneously. | |
| 601 | − */ | |
| 602 | − fifo_write(dspi); | |
| 603 | − } | |
| 604 | −} | |
| 693 | + /* Update CTARE */ | |
| 694 | + regmap_write(dspi->regmap, SPI_CTARE(0), | |
| 695 | + SPI_FRAME_EBITS(dspi->oper_bits_per_word) | | |
| 696 | + SPI_CTARE_DTCP(num_words)); | |
| 605 | 697 | |
| 606 | −static u32 fifo_read(struct fsl_dspi *dspi) | |
| 607 | −{ | |
| 608 | − u32 rxdata = 0; | |
| 698 | + /* | |
| 699 | + * Write the CMD FIFO entry first, and then the two | |
| 700 | + * corresponding TX FIFO entries (or one...). | |
| 701 | + */ | |
| 702 | + dspi_pushr_cmd_write(dspi, tx_cmd); | |
| 609 | 703 | |
| 610 | − regmap_read(dspi->regmap, SPI_POPR, &rxdata); | |
| 611 | − return rxdata; | |
| 612 | −} | |
| 704 | + /* Fill TX FIFO with as many transfers as possible */ | |
| 705 | + while (num_words--) { | |
| 706 | + u32 data = dspi_pop_tx(dspi); | |
| 613 | 707 | |
| 614 | −static void dspi_tcfq_read(struct fsl_dspi *dspi) | |
| 615 | −{ | |
| 616 | − dspi_push_rx(dspi, fifo_read(dspi)); | |
| 708 | + dspi_pushr_txdata_write(dspi, data & 0xFFFF); | |
| 709 | + if (dspi->oper_bits_per_word > 16) | |
| 710 | + dspi_pushr_txdata_write(dspi, data >> 16); | |
| 711 | + } | |
| 617 | 712 | } |
| 618 | 713 | |
| 619 | −static void dspi_eoq_write(struct fsl_dspi *dspi) | |
| 714 | +static void dspi_eoq_fifo_write(struct fsl_dspi *dspi, int num_words) | |
| 620 | 715 | { |
| 621 | − int fifo_size = DSPI_FIFO_SIZE; | |
| 622 | 716 | u16 xfer_cmd = dspi->tx_cmd; |
| 623 | 717 | |
| 624 | 718 | /* Fill TX FIFO with as many transfers as possible */ |
| 625 | − while (dspi->len && fifo_size--) { | |
| 719 | + while (num_words--) { | |
| 626 | 720 | dspi->tx_cmd = xfer_cmd; |
| 627 | 721 | /* Request EOQF for last transfer in FIFO */ |
| 628 | − if (dspi->len == dspi->bytes_per_word || fifo_size == 0) | |
| 722 | + if (num_words == 0) | |
| 629 | 723 | dspi->tx_cmd |= SPI_PUSHR_CMD_EOQ; |
| 630 | − /* Clear transfer count for first transfer in FIFO */ | |
| 631 | − if (fifo_size == (DSPI_FIFO_SIZE - 1)) | |
| 632 | − dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT; | |
| 633 | 724 | /* Write combined TX FIFO and CMD FIFO entry */ |
| 634 | − fifo_write(dspi); | |
| 725 | + dspi_pushr_write(dspi); | |
| 635 | 726 | } |
| 636 | 727 | } |
| 637 | 728 | |
| 638 | −static void dspi_eoq_read(struct fsl_dspi *dspi) | |
| 729 | +static u32 dspi_popr_read(struct fsl_dspi *dspi) | |
| 639 | 730 | { |
| 640 | − int fifo_size = DSPI_FIFO_SIZE; | |
| 731 | + u32 rxdata = 0; | |
| 732 | + | |
| 733 | + regmap_read(dspi->regmap, SPI_POPR, &rxdata); | |
| 734 | + return rxdata; | |
| 735 | +} | |
| 736 | + | |
| 737 | +static void dspi_fifo_read(struct fsl_dspi *dspi) | |
| 738 | +{ | |
| 739 | + int num_fifo_entries = dspi->words_in_flight; | |
| 641 | 740 | |
| 642 | 741 | /* Read one FIFO entry and push to rx buffer */ |
| 643 | − while ((dspi->rx < dspi->rx_end) && fifo_size--) | |
| 644 | − dspi_push_rx(dspi, fifo_read(dspi)); | |
| 742 | + while (num_fifo_entries--) | |
| 743 | + dspi_push_rx(dspi, dspi_popr_read(dspi)); | |
| 645 | 744 | } |
| 646 | 745 | |
| 647 | −static int dspi_rxtx(struct fsl_dspi *dspi) | |
| 746 | +static void dspi_setup_accel(struct fsl_dspi *dspi) | |
| 648 | 747 | { |
| 748 | + struct spi_transfer *xfer = dspi->cur_transfer; | |
| 749 | + bool odd = !!(dspi->len & 1); | |
| 750 | + | |
| 751 | + /* No accel for frames not multiple of 8 bits at the moment */ | |
| 752 | + if (xfer->bits_per_word % 8) | |
| 753 | + goto no_accel; | |
| 754 | + | |
| 755 | + if (!odd && dspi->len <= dspi->devtype_data->fifo_size * 2) { | |
| 756 | + dspi->oper_bits_per_word = 16; | |
| 757 | + } else if (odd && dspi->len <= dspi->devtype_data->fifo_size) { | |
| 758 | + dspi->oper_bits_per_word = 8; | |
| 759 | + } else { | |
| 760 | + /* Start off with maximum supported by hardware */ | |
| 761 | + if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE) | |
| 762 | + dspi->oper_bits_per_word = 32; | |
| 763 | + else | |
| 764 | + dspi->oper_bits_per_word = 16; | |
| 765 | + | |
| 766 | + /* | |
| 767 | + * And go down only if the buffer can't be sent with | |
| 768 | + * words this big | |
| 769 | + */ | |
| 770 | + do { | |
| 771 | + if (dspi->len >= DIV_ROUND_UP(dspi->oper_bits_per_word, 8)) | |
| 772 | + break; | |
| 773 | + | |
| 774 | + dspi->oper_bits_per_word /= 2; | |
| 775 | + } while (dspi->oper_bits_per_word > 8); | |
| 776 | + } | |
| 777 | + | |
| 778 | + if (xfer->bits_per_word == 8 && dspi->oper_bits_per_word == 32) { | |
| 779 | + dspi->dev_to_host = dspi_8on32_dev_to_host; | |
| 780 | + dspi->host_to_dev = dspi_8on32_host_to_dev; | |
| 781 | + } else if (xfer->bits_per_word == 8 && dspi->oper_bits_per_word == 16) { | |
| 782 | + dspi->dev_to_host = dspi_8on16_dev_to_host; | |
| 783 | + dspi->host_to_dev = dspi_8on16_host_to_dev; | |
| 784 | + } else if (xfer->bits_per_word == 16 && dspi->oper_bits_per_word == 32) { | |
| 785 | + dspi->dev_to_host = dspi_16on32_dev_to_host; | |
| 786 | + dspi->host_to_dev = dspi_16on32_host_to_dev; | |
| 787 | + } else { | |
| 788 | +no_accel: | |
| 789 | + dspi->dev_to_host = dspi_native_dev_to_host; | |
| 790 | + dspi->host_to_dev = dspi_native_host_to_dev; | |
| 791 | + dspi->oper_bits_per_word = xfer->bits_per_word; | |
| 792 | + } | |
| 793 | + | |
| 794 | + dspi->oper_word_size = DIV_ROUND_UP(dspi->oper_bits_per_word, 8); | |
| 795 | + | |
| 796 | + /* | |
| 797 | + * Update CTAR here (code is common for EOQ, XSPI and DMA modes). | |
| 798 | + * We will update CTARE in the portion specific to XSPI, when we | |
| 799 | + * also know the preload value (DTCP). | |
| 800 | + */ | |
| 801 | + regmap_write(dspi->regmap, SPI_CTAR(0), | |
| 802 | + dspi->cur_chip->ctar_val | | |
| 803 | + SPI_FRAME_BITS(dspi->oper_bits_per_word)); | |
| 804 | +} | |
| 805 | + | |
| 806 | +static void dspi_fifo_write(struct fsl_dspi *dspi) | |
| 807 | +{ | |
| 808 | + int num_fifo_entries = dspi->devtype_data->fifo_size; | |
| 809 | + struct spi_transfer *xfer = dspi->cur_transfer; | |
| 649 | 810 | struct spi_message *msg = dspi->cur_msg; |
| 650 | − enum dspi_trans_mode trans_mode; | |
| 651 | − u16 spi_tcnt; | |
| 652 | − u32 spi_tcr; | |
| 811 | + int num_words, num_bytes; | |
| 653 | 812 | |
| 654 | − spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer, | |
| 655 | − dspi->progress, !dspi->irq); | |
| 813 | + dspi_setup_accel(dspi); | |
| 814 | + | |
| 815 | + /* In XSPI mode each 32-bit word occupies 2 TX FIFO entries */ | |
| 816 | + if (dspi->oper_word_size == 4) | |
| 817 | + num_fifo_entries /= 2; | |
| 656 | 818 | |
| 657 | − /* Get transfer counter (in number of SPI transfers). It was | |
| 658 | − * reset to 0 when transfer(s) were started. | |
| 819 | + /* | |
| 820 | + * Integer division intentionally trims off odd (or non-multiple of 4) | |
| 821 | + * numbers of bytes at the end of the buffer, which will be sent next | |
| 822 | + * time using a smaller oper_word_size. | |
| 659 | 823 | */ |
| 660 | − regmap_read(dspi->regmap, SPI_TCR, &spi_tcr); | |
| 661 | − spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr); | |
| 824 | + num_words = dspi->len / dspi->oper_word_size; | |
| 825 | + if (num_words > num_fifo_entries) | |
| 826 | + num_words = num_fifo_entries; | |
| 827 | + | |
| 662 | 828 | /* Update total number of bytes that were transferred */ |
| 663 | − msg->actual_length += spi_tcnt * dspi->bytes_per_word; | |
| 664 | − dspi->progress += spi_tcnt; | |
| 829 | + num_bytes = num_words * dspi->oper_word_size; | |
| 830 | + msg->actual_length += num_bytes; | |
| 831 | + dspi->progress += num_bytes / DIV_ROUND_UP(xfer->bits_per_word, 8); | |
| 665 | 832 | |
| 666 | − trans_mode = dspi->devtype_data->trans_mode; | |
| 667 | − if (trans_mode == DSPI_EOQ_MODE) | |
| 668 | − dspi_eoq_read(dspi); | |
| 669 | − else if (trans_mode == DSPI_TCFQ_MODE) | |
| 670 | − dspi_tcfq_read(dspi); | |
| 833 | + /* | |
| 834 | + * Update shared variable for use in the next interrupt (both in | |
| 835 | + * dspi_fifo_read and in dspi_fifo_write). | |
| 836 | + */ | |
| 837 | + dspi->words_in_flight = num_words; | |
| 838 | + | |
| 839 | + spi_take_timestamp_pre(dspi->ctlr, xfer, dspi->progress, !dspi->irq); | |
| 840 | + | |
| 841 | + if (dspi->devtype_data->trans_mode == DSPI_EOQ_MODE) | |
| 842 | + dspi_eoq_fifo_write(dspi, num_words); | |
| 843 | + else | |
| 844 | + dspi_xspi_fifo_write(dspi, num_words); | |
| 845 | + /* | |
| 846 | + * Everything after this point is in a potential race with the next | |
| 847 | + * interrupt, so we must never use dspi->words_in_flight again since it | |
| 848 | + * might already be modified by the next dspi_fifo_write. | |
| 849 | + */ | |
| 850 | + | |
| 851 | + spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer, | |
| 852 | + dspi->progress, !dspi->irq); | |
| 853 | +} | |
| 854 | + | |
| 855 | +static int dspi_rxtx(struct fsl_dspi *dspi) | |
| 856 | +{ | |
| 857 | + dspi_fifo_read(dspi); | |
| 671 | 858 | |
| 672 | 859 | if (!dspi->len) |
| 673 | 860 | /* Success! */ |
| 674 | 861 | return 0; |
| 675 | 862 | |
| 676 | − spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, | |
| 677 | − dspi->progress, !dspi->irq); | |
| 678 | − | |
| 679 | − if (trans_mode == DSPI_EOQ_MODE) | |
| 680 | − dspi_eoq_write(dspi); | |
| 681 | − else if (trans_mode == DSPI_TCFQ_MODE) | |
| 682 | − dspi_tcfq_write(dspi); | |
| 863 | + dspi_fifo_write(dspi); | |
| 683 | 864 | |
| 684 | 865 | return -EINPROGRESS; |
| 685 | 866 | } |
| @@ -693,7 +874,7 @@ static int dspi_poll(struct fsl_dspi *dspi) · 7 unmodified lines | ||
| 693 | 874 | regmap_read(dspi->regmap, SPI_SR, &spi_sr); |
| 694 | 875 | regmap_write(dspi->regmap, SPI_SR, spi_sr); |
| 695 | 876 | |
| 696 | − if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)) | |
| 877 | + if (spi_sr & (SPI_SR_EOQF | SPI_SR_CMDTCF)) | |
| 697 | 878 | break; |
| 698 | 879 | } while (--tries); |
| 699 | 880 | |
| @@ -711,13 +892,11 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id) · 11 unmodified lines | ||
| 711 | 892 | regmap_read(dspi->regmap, SPI_SR, &spi_sr); |
| 712 | 893 | regmap_write(dspi->regmap, SPI_SR, spi_sr); |
| 713 | 894 | |
| 714 | − if (!(spi_sr & SPI_SR_EOQF)) | |
| 895 | + if (!(spi_sr & (SPI_SR_EOQF | SPI_SR_CMDTCF))) | |
| 715 | 896 | return IRQ_NONE; |
| 716 | 897 | |
| 717 | − if (dspi_rxtx(dspi) == 0) { | |
| 718 | − dspi->waitflags = 1; | |
| 719 | − wake_up_interruptible(&dspi->waitq); | |
| 720 | − } | |
| 898 | + if (dspi_rxtx(dspi) == 0) | |
| 899 | + complete(&dspi->xfer_done); | |
| 721 | 900 | |
| 722 | 901 | return IRQ_HANDLED; |
| 723 | 902 | } |
| @@ -727,7 +906,6 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, · 3 unmodified lines | ||
| 727 | 906 | { |
| 728 | 907 | struct fsl_dspi *dspi = spi_controller_get_devdata(ctlr); |
| 729 | 908 | struct spi_device *spi = message->spi; |
| 730 | − enum dspi_trans_mode trans_mode; | |
| 731 | 909 | struct spi_transfer *transfer; |
| 732 | 910 | int status = 0; |
| 733 | 911 | |
| @@ -757,76 +935,38 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, · 23 unmodified lines | ||
| 757 | 935 | dspi->tx_cmd |= SPI_PUSHR_CMD_CONT; |
| 758 | 936 | } |
| 759 | 937 | |
| 760 | − dspi->void_write_data = dspi->cur_chip->void_write_data; | |
| 761 | − | |
| 762 | 938 | dspi->tx = transfer->tx_buf; |
| 763 | 939 | dspi->rx = transfer->rx_buf; |
| 764 | − dspi->rx_end = dspi->rx + transfer->len; | |
| 765 | 940 | dspi->len = transfer->len; |
| 766 | 941 | dspi->progress = 0; |
| 767 | − /* Validated transfer specific frame size (defaults applied) */ | |
| 768 | − dspi->bits_per_word = transfer->bits_per_word; | |
| 769 | − if (transfer->bits_per_word <= 8) | |
| 770 | − dspi->bytes_per_word = 1; | |
| 771 | − else if (transfer->bits_per_word <= 16) | |
| 772 | − dspi->bytes_per_word = 2; | |
| 773 | − else | |
| 774 | − dspi->bytes_per_word = 4; | |
| 775 | 942 | |
| 776 | 943 | regmap_update_bits(dspi->regmap, SPI_MCR, |
| 777 | 944 | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF, |
| 778 | 945 | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF); |
| 779 | − regmap_write(dspi->regmap, SPI_CTAR(0), | |
| 780 | − dspi->cur_chip->ctar_val | | |
| 781 | − SPI_FRAME_BITS(transfer->bits_per_word)); | |
| 782 | − if (dspi->devtype_data->xspi_mode) | |
| 783 | − regmap_write(dspi->regmap, SPI_CTARE(0), | |
| 784 | − SPI_FRAME_EBITS(transfer->bits_per_word) | | |
| 785 | − SPI_CTARE_DTCP(1)); | |
| 786 | 946 | |
| 787 | 947 | spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, |
| 788 | 948 | dspi->progress, !dspi->irq); |
| 789 | 949 | |
| 790 | − trans_mode = dspi->devtype_data->trans_mode; | |
| 791 | − switch (trans_mode) { | |
| 792 | − case DSPI_EOQ_MODE: | |
| 793 | − regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); | |
| 794 | − dspi_eoq_write(dspi); | |
| 795 | − break; | |
| 796 | − case DSPI_TCFQ_MODE: | |
| 797 | − regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE); | |
| 798 | − dspi_tcfq_write(dspi); | |
| 799 | − break; | |
| 800 | − case DSPI_DMA_MODE: | |
| 801 | − regmap_write(dspi->regmap, SPI_RSER, | |
| 802 | − SPI_RSER_TFFFE | SPI_RSER_TFFFD | | |
| 803 | − SPI_RSER_RFDFE | SPI_RSER_RFDFD); | |
| 950 | + if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) { | |
| 804 | 951 | status = dspi_dma_xfer(dspi); |
| 805 | − break; | |
| 806 | − default: | |
| 807 | − dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n", | |
| 808 | − trans_mode); | |
| 809 | − status = -EINVAL; | |
| 810 | − goto out; | |
| 811 | − } | |
| 812 | − | |
| 813 | − if (!dspi->irq) { | |
| 814 | − do { | |
| 815 | − status = dspi_poll(dspi); | |
| 816 | − } while (status == -EINPROGRESS); | |
| 817 | − } else if (trans_mode != DSPI_DMA_MODE) { | |
| 818 | − status = wait_event_interruptible(dspi->waitq, | |
| 819 | − dspi->waitflags); | |
| 820 | − dspi->waitflags = 0; | |
| 952 | + } else { | |
| 953 | + dspi_fifo_write(dspi); | |
| 954 | + | |
| 955 | + if (dspi->irq) { | |
| 956 | + wait_for_completion(&dspi->xfer_done); | |
| 957 | + reinit_completion(&dspi->xfer_done); | |
| 958 | + } else { | |
| 959 | + do { | |
| 960 | + status = dspi_poll(dspi); | |
| 961 | + } while (status == -EINPROGRESS); | |
| 962 | + } | |
| 821 | 963 | } |
| 822 | 964 | if (status) |
| 823 | − dev_err(&dspi->pdev->dev, | |
| 824 | − "Waiting for transfer to complete failed!\n"); | |
| 965 | + break; | |
| 825 | 966 | |
| 826 | 967 | spi_transfer_delay_exec(transfer); |
| 827 | 968 | } |
| 828 | 969 | |
| 829 | −out: | |
| 830 | 970 | message->status = status; |
| 831 | 971 | spi_finalize_current_message(ctlr); |
| 832 | 972 | |
| @@ -864,8 +1004,6 @@ static int dspi_setup(struct spi_device *spi) · 31 unmodified lines | ||
| 864 | 1004 | sck_cs_delay = pdata->sck_cs_delay; |
| 865 | 1005 | } |
| 866 | 1006 | |
| 867 | − chip->void_write_data = 0; | |
| 868 | − | |
| 869 | 1007 | clkrate = clk_get_rate(dspi->clk); |
| 870 | 1008 | hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate); |
| 871 | 1009 | |
| @@ -909,9 +1047,34 @@ static void dspi_cleanup(struct spi_device *spi) · 37 unmodified lines | ||
| 909 | 1047 | } |
| 910 | 1048 | |
| 911 | 1049 | static const struct of_device_id fsl_dspi_dt_ids[] = { |
| 912 | − { .compatible = "fsl,vf610-dspi", .data = &vf610_data, }, | |
| 913 | − { .compatible = "fsl,ls1021a-v1.0-dspi", .data = &ls1021a_v1_data, }, | |
| 914 | − { .compatible = "fsl,ls2085a-dspi", .data = &ls2085a_data, }, | |
| 1050 | + { | |
| 1051 | + .compatible = "fsl,vf610-dspi", | |
| 1052 | + .data = &devtype_data[VF610], | |
| 1053 | + }, { | |
| 1054 | + .compatible = "fsl,ls1021a-v1.0-dspi", | |
| 1055 | + .data = &devtype_data[LS1021A], | |
| 1056 | + }, { | |
| 1057 | + .compatible = "fsl,ls1012a-dspi", | |
| 1058 | + .data = &devtype_data[LS1012A], | |
| 1059 | + }, { | |
| 1060 | + .compatible = "fsl,ls1028a-dspi", | |
| 1061 | + .data = &devtype_data[LS1028A], | |
| 1062 | + }, { | |
| 1063 | + .compatible = "fsl,ls1043a-dspi", | |
| 1064 | + .data = &devtype_data[LS1043A], | |
| 1065 | + }, { | |
| 1066 | + .compatible = "fsl,ls1046a-dspi", | |
| 1067 | + .data = &devtype_data[LS1046A], | |
| 1068 | + }, { | |
| 1069 | + .compatible = "fsl,ls2080a-dspi", | |
| 1070 | + .data = &devtype_data[LS2080A], | |
| 1071 | + }, { | |
| 1072 | + .compatible = "fsl,ls2085a-dspi", | |
| 1073 | + .data = &devtype_data[LS2085A], | |
| 1074 | + }, { | |
| 1075 | + .compatible = "fsl,lx2160a-dspi", | |
| 1076 | + .data = &devtype_data[LX2160A], | |
| 1077 | + }, | |
| 915 | 1078 | { /* sentinel */ } |
| 916 | 1079 | }; |
| 917 | 1080 | MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids); |
| @@ -997,20 +1160,40 @@ static const struct regmap_config dspi_xspi_regmap_config[] = { · 79 unmodified lines | ||
| 997 | 1160 | }, |
| 998 | 1161 | }; |
| 999 | 1162 | |
| 1000 | −static void dspi_init(struct fsl_dspi *dspi) | |
| 1163 | +static int dspi_init(struct fsl_dspi *dspi) | |
| 1001 | 1164 | { |
| 1002 | − unsigned int mcr = SPI_MCR_PCSIS; | |
| 1165 | + unsigned int mcr; | |
| 1166 | + | |
| 1167 | + /* Set idle states for all chip select signals to high */ | |
| 1168 | + mcr = SPI_MCR_PCSIS(GENMASK(dspi->ctlr->num_chipselect - 1, 0)); | |
| 1003 | 1169 | |
| 1004 | − if (dspi->devtype_data->xspi_mode) | |
| 1170 | + if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE) | |
| 1005 | 1171 | mcr |= SPI_MCR_XSPI; |
| 1006 | 1172 | if (!spi_controller_is_slave(dspi->ctlr)) |
| 1007 | 1173 | mcr |= SPI_MCR_MASTER; |
| 1008 | 1174 | |
| 1009 | 1175 | regmap_write(dspi->regmap, SPI_MCR, mcr); |
| 1010 | 1176 | regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR); |
| 1011 | − if (dspi->devtype_data->xspi_mode) | |
| 1012 | − regmap_write(dspi->regmap, SPI_CTARE(0), | |
| 1013 | − SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1)); | |
| 1177 | + | |
| 1178 | + switch (dspi->devtype_data->trans_mode) { | |
| 1179 | + case DSPI_EOQ_MODE: | |
| 1180 | + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); | |
| 1181 | + break; | |
| 1182 | + case DSPI_XSPI_MODE: | |
| 1183 | + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_CMDTCFE); | |
| 1184 | + break; | |
| 1185 | + case DSPI_DMA_MODE: | |
| 1186 | + regmap_write(dspi->regmap, SPI_RSER, | |
| 1187 | + SPI_RSER_TFFFE | SPI_RSER_TFFFD | | |
| 1188 | + SPI_RSER_RFDFE | SPI_RSER_RFDFD); | |
| 1189 | + break; | |
| 1190 | + default: | |
| 1191 | + dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n", | |
| 1192 | + dspi->devtype_data->trans_mode); | |
| 1193 | + return -EINVAL; | |
| 1194 | + } | |
| 1195 | + | |
| 1196 | + return 0; | |
| 1014 | 1197 | } |
| 1015 | 1198 | |
| 1016 | 1199 | static int dspi_slave_abort(struct spi_master *master) |
| @@ -1021,8 +1204,10 @@ static int dspi_slave_abort(struct spi_master *master) · 4 unmodified lines | ||
| 1021 | 1204 | * Terminate all pending DMA transactions for the SPI working |
| 1022 | 1205 | * in SLAVE mode. |
| 1023 | 1206 | */ |
| 1024 | − dmaengine_terminate_sync(dspi->dma->chan_rx); | |
| 1025 | − dmaengine_terminate_sync(dspi->dma->chan_tx); | |
| 1207 | + if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) { | |
| 1208 | + dmaengine_terminate_sync(dspi->dma->chan_rx); | |
| 1209 | + dmaengine_terminate_sync(dspi->dma->chan_tx); | |
| 1210 | + } | |
| 1026 | 1211 | |
| 1027 | 1212 | /* Clear the internal DSPI RX and TX FIFO buffers */ |
| 1028 | 1213 | regmap_update_bits(dspi->regmap, SPI_MCR, |
| @@ -1032,16 +1217,33 @@ static int dspi_slave_abort(struct spi_master *master) · 3 unmodified lines | ||
| 1032 | 1217 | return 0; |
| 1033 | 1218 | } |
| 1034 | 1219 | |
| 1220 | +/* | |
| 1221 | + * EOQ mode will inevitably deassert its PCS signal on last word in a queue | |
| 1222 | + * (hardware limitation), so we need to inform the spi_device that larger | |
| 1223 | + * buffers than the FIFO size are going to have the chip select randomly | |
| 1224 | + * toggling, so it has a chance to adapt its message sizes. | |
| 1225 | + */ | |
| 1226 | +static size_t dspi_max_message_size(struct spi_device *spi) | |
| 1227 | +{ | |
| 1228 | + struct fsl_dspi *dspi = spi_controller_get_devdata(spi->controller); | |
| 1229 | + | |
| 1230 | + if (dspi->devtype_data->trans_mode == DSPI_EOQ_MODE) | |
| 1231 | + return dspi->devtype_data->fifo_size; | |
| 1232 | + | |
| 1233 | + return SIZE_MAX; | |
| 1234 | +} | |
| 1235 | + | |
| 1035 | 1236 | static int dspi_probe(struct platform_device *pdev) |
| 1036 | 1237 | { |
| 1037 | 1238 | struct device_node *np = pdev->dev.of_node; |
| 1038 | 1239 | const struct regmap_config *regmap_config; |
| 1039 | 1240 | struct fsl_dspi_platform_data *pdata; |
| 1040 | 1241 | struct spi_controller *ctlr; |
| 1041 | − int ret, cs_num, bus_num; | |
| 1242 | + int ret, cs_num, bus_num = -1; | |
| 1042 | 1243 | struct fsl_dspi *dspi; |
| 1043 | 1244 | struct resource *res; |
| 1044 | 1245 | void __iomem *base; |
| 1246 | + bool big_endian; | |
| 1045 | 1247 | |
| 1046 | 1248 | ctlr = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi)); |
| 1047 | 1249 | if (!ctlr) |
| @@ -1053,6 +1255,7 @@ static int dspi_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 1053 | 1255 | |
| 1054 | 1256 | ctlr->setup = dspi_setup; |
| 1055 | 1257 | ctlr->transfer_one_message = dspi_transfer_one_message; |
| 1258 | + ctlr->max_message_size = dspi_max_message_size; | |
| 1056 | 1259 | ctlr->dev.of_node = pdev->dev.of_node; |
| 1057 | 1260 | |
| 1058 | 1261 | ctlr->cleanup = dspi_cleanup; |
| @@ -1064,7 +1267,9 @@ static int dspi_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 1064 | 1267 | ctlr->num_chipselect = pdata->cs_num; |
| 1065 | 1268 | ctlr->bus_num = pdata->bus_num; |
| 1066 | 1269 | |
| 1067 | − dspi->devtype_data = &coldfire_data; | |
| 1270 | + /* Only Coldfire uses platform data */ | |
| 1271 | + dspi->devtype_data = &devtype_data[MCF5441X]; | |
| 1272 | + big_endian = true; | |
| 1068 | 1273 | } else { |
| 1069 | 1274 | |
| 1070 | 1275 | ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num); |
| @@ -1074,11 +1279,7 @@ static int dspi_probe(struct platform_device *pdev) · 3 unmodified lines | ||
| 1074 | 1279 | } |
| 1075 | 1280 | ctlr->num_chipselect = cs_num; |
| 1076 | 1281 | |
| 1077 | − ret = of_property_read_u32(np, "bus-num", &bus_num); | |
| 1078 | − if (ret < 0) { | |
| 1079 | − dev_err(&pdev->dev, "can't get bus-num\n"); | |
| 1080 | − goto out_ctlr_put; | |
| 1081 | − } | |
| 1282 | + of_property_read_u32(np, "bus-num", &bus_num); | |
| 1082 | 1283 | ctlr->bus_num = bus_num; |
| 1083 | 1284 | |
| 1084 | 1285 | if (of_property_read_bool(np, "spi-slave")) |
| @@ -1090,9 +1291,18 @@ static int dspi_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 1090 | 1291 | ret = -EFAULT; |
| 1091 | 1292 | goto out_ctlr_put; |
| 1092 | 1293 | } |
| 1294 | + | |
| 1295 | + big_endian = of_device_is_big_endian(np); | |
| 1296 | + } | |
| 1297 | + if (big_endian) { | |
| 1298 | + dspi->pushr_cmd = 0; | |
| 1299 | + dspi->pushr_tx = 2; | |
| 1300 | + } else { | |
| 1301 | + dspi->pushr_cmd = 2; | |
| 1302 | + dspi->pushr_tx = 0; | |
| 1093 | 1303 | } |
| 1094 | 1304 | |
| 1095 | − if (dspi->devtype_data->xspi_mode) | |
| 1305 | + if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE) | |
| 1096 | 1306 | ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); |
| 1097 | 1307 | else |
| 1098 | 1308 | ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); |
| @@ -1104,7 +1314,7 @@ static int dspi_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 1104 | 1314 | goto out_ctlr_put; |
| 1105 | 1315 | } |
| 1106 | 1316 | |
| 1107 | − if (dspi->devtype_data->xspi_mode) | |
| 1317 | + if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE) | |
| 1108 | 1318 | regmap_config = &dspi_xspi_regmap_config[0]; |
| 1109 | 1319 | else |
| 1110 | 1320 | regmap_config = &dspi_regmap_config; |
| @@ -1116,7 +1326,7 @@ static int dspi_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 1116 | 1326 | goto out_ctlr_put; |
| 1117 | 1327 | } |
| 1118 | 1328 | |
| 1119 | − if (dspi->devtype_data->xspi_mode) { | |
| 1329 | + if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE) { | |
| 1120 | 1330 | dspi->regmap_pushr = devm_regmap_init_mmio( |
| 1121 | 1331 | &pdev->dev, base + SPI_PUSHR, |
| 1122 | 1332 | &dspi_xspi_regmap_config[1]); |
| @@ -1139,10 +1349,9 @@ static int dspi_probe(struct platform_device *pdev) · 16 unmodified lines | ||
| 1139 | 1349 | if (ret) |
| 1140 | 1350 | goto out_ctlr_put; |
| 1141 | 1351 | |
| 1142 | − dspi_init(dspi); | |
| 1143 | − | |
| 1144 | − if (dspi->devtype_data->trans_mode == DSPI_TCFQ_MODE) | |
| 1145 | − goto poll_mode; | |
| 1352 | + ret = dspi_init(dspi); | |
| 1353 | + if (ret) | |
| 1354 | + goto out_clk_put; | |
| 1146 | 1355 | |
| 1147 | 1356 | dspi->irq = platform_get_irq(pdev, 0); |
| 1148 | 1357 | if (dspi->irq <= 0) { |
| @@ -1159,7 +1368,7 @@ static int dspi_probe(struct platform_device *pdev) · 10 unmodified lines | ||
| 1159 | 1368 | goto out_clk_put; |
| 1160 | 1369 | } |
| 1161 | 1370 | |
| 1162 | − init_waitqueue_head(&dspi->waitq); | |
| 1371 | + init_completion(&dspi->xfer_done); | |
| 1163 | 1372 | |
| 1164 | 1373 | poll_mode: |
| 1165 | 1374 | |
| @@ -1174,7 +1383,8 @@ poll_mode: · 8 unmodified lines | ||
| 1174 | 1383 | ctlr->max_speed_hz = |
| 1175 | 1384 | clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor; |
| 1176 | 1385 | |
| 1177 | − ctlr->ptp_sts_supported = dspi->devtype_data->ptp_sts_supported; | |
| 1386 | + if (dspi->devtype_data->trans_mode != DSPI_DMA_MODE) | |
| 1387 | + ctlr->ptp_sts_supported = true; | |
| 1178 | 1388 | |
| 1179 | 1389 | platform_set_drvdata(pdev, ctlr); |
| 1180 | 1390 | |
| @@ -86,8 +86,6 @@ · 85 unmodified lines | ||
| 86 | 86 | #define TCR_RXMSK BIT(19) |
| 87 | 87 | #define TCR_TXMSK BIT(18) |
| 88 | 88 | |
| 89 | −static int clkdivs[] = {1, 2, 4, 8, 16, 32, 64, 128}; | |
| 90 | − | |
| 91 | 89 | struct lpspi_config { |
| 92 | 90 | u8 bpw; |
| 93 | 91 | u8 chip_select; |
| @@ -125,7 +123,7 @@ struct fsl_lpspi_data { · 31 unmodified lines | ||
| 125 | 123 | struct completion dma_rx_completion; |
| 126 | 124 | struct completion dma_tx_completion; |
| 127 | 125 | |
| 128 | − int chipselect[0]; | |
| 126 | + int chipselect[]; | |
| 129 | 127 | }; |
| 130 | 128 | |
| 131 | 129 | static const struct of_device_id fsl_lpspi_dt_ids[] = { |
| @@ -331,15 +329,14 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) · 199 unmodified lines | ||
| 331 | 329 | } |
| 332 | 330 | |
| 333 | 331 | for (prescale = 0; prescale < 8; prescale++) { |
| 334 | − scldiv = perclk_rate / | |
| 335 | − (clkdivs[prescale] * config.speed_hz) - 2; | |
| 332 | + scldiv = perclk_rate / config.speed_hz / (1 << prescale) - 2; | |
| 336 | 333 | if (scldiv < 256) { |
| 337 | 334 | fsl_lpspi->config.prescale = prescale; |
| 338 | 335 | break; |
| 339 | 336 | } |
| 340 | 337 | } |
| 341 | 338 | |
| 342 | − if (prescale == 8 && scldiv >= 256) | |
| 339 | + if (scldiv >= 256) | |
| 343 | 340 | return -EINVAL; |
| 344 | 341 | |
| 345 | 342 | writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16), |
| @@ -6,7 +6,6 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <linux/io.h> |
| 7 | 7 | #include <linux/log2.h> |
| 8 | 8 | #include <linux/module.h> |
| 9 | −#include <linux/of.h> | |
| 10 | 9 | #include <linux/platform_device.h> |
| 11 | 10 | #include <linux/pm_runtime.h> |
| 12 | 11 | #include <linux/qcom-geni-se.h> |
| @@ -536,6 +535,7 @@ static int spi_geni_probe(struct platform_device *pdev) · 523 unmodified lines | ||
| 536 | 535 | struct spi_geni_master *mas; |
| 537 | 536 | void __iomem *base; |
| 538 | 537 | struct clk *clk; |
| 538 | + struct device *dev = &pdev->dev; | |
| 539 | 539 | |
| 540 | 540 | irq = platform_get_irq(pdev, 0); |
| 541 | 541 | if (irq < 0) |
| @@ -545,28 +545,25 @@ static int spi_geni_probe(struct platform_device *pdev) · 3 unmodified lines | ||
| 545 | 545 | if (IS_ERR(base)) |
| 546 | 546 | return PTR_ERR(base); |
| 547 | 547 | |
| 548 | − clk = devm_clk_get(&pdev->dev, "se"); | |
| 549 | − if (IS_ERR(clk)) { | |
| 550 | − dev_err(&pdev->dev, "Err getting SE Core clk %ld\n", | |
| 551 | − PTR_ERR(clk)); | |
| 548 | + clk = devm_clk_get(dev, "se"); | |
| 549 | + if (IS_ERR(clk)) | |
| 552 | 550 | return PTR_ERR(clk); |
| 553 | − } | |
| 554 | 551 | |
| 555 | − spi = spi_alloc_master(&pdev->dev, sizeof(*mas)); | |
| 552 | + spi = spi_alloc_master(dev, sizeof(*mas)); | |
| 556 | 553 | if (!spi) |
| 557 | 554 | return -ENOMEM; |
| 558 | 555 | |
| 559 | 556 | platform_set_drvdata(pdev, spi); |
| 560 | 557 | mas = spi_master_get_devdata(spi); |
| 561 | 558 | mas->irq = irq; |
| 562 | − mas->dev = &pdev->dev; | |
| 563 | − mas->se.dev = &pdev->dev; | |
| 564 | − mas->se.wrapper = dev_get_drvdata(pdev->dev.parent); | |
| 559 | + mas->dev = dev; | |
| 560 | + mas->se.dev = dev; | |
| 561 | + mas->se.wrapper = dev_get_drvdata(dev->parent); | |
| 565 | 562 | mas->se.base = base; |
| 566 | 563 | mas->se.clk = clk; |
| 567 | 564 | |
| 568 | 565 | spi->bus_num = -1; |
| 569 | − spi->dev.of_node = pdev->dev.of_node; | |
| 566 | + spi->dev.of_node = dev->of_node; | |
| 570 | 567 | spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; |
| 571 | 568 | spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); |
| 572 | 569 | spi->num_chipselect = 4; |
| @@ -579,14 +576,13 @@ static int spi_geni_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 579 | 576 | |
| 580 | 577 | init_completion(&mas->xfer_done); |
| 581 | 578 | spin_lock_init(&mas->lock); |
| 582 | − pm_runtime_enable(&pdev->dev); | |
| 579 | + pm_runtime_enable(dev); | |
| 583 | 580 | |
| 584 | 581 | ret = spi_geni_init(mas); |
| 585 | 582 | if (ret) |
| 586 | 583 | goto spi_geni_probe_runtime_disable; |
| 587 | 584 | |
| 588 | − ret = request_irq(mas->irq, geni_spi_isr, | |
| 589 | − IRQF_TRIGGER_HIGH, "spi_geni", spi); | |
| 585 | + ret = request_irq(mas->irq, geni_spi_isr, 0, dev_name(dev), spi); | |
| 590 | 586 | if (ret) |
| 591 | 587 | goto spi_geni_probe_runtime_disable; |
| 592 | 588 | |
| @@ -598,7 +594,7 @@ static int spi_geni_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 598 | 594 | spi_geni_probe_free_irq: |
| 599 | 595 | free_irq(mas->irq, spi); |
| 600 | 596 | spi_geni_probe_runtime_disable: |
| 601 | − pm_runtime_disable(&pdev->dev); | |
| 597 | + pm_runtime_disable(dev); | |
| 602 | 598 | spi_master_put(spi); |
| 603 | 599 | return ret; |
| 604 | 600 | } |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | #include <linux/acpi.h> |
| 9 | 9 | #include <linux/bitops.h> |
| 10 | +#include <linux/dmi.h> | |
| 10 | 11 | #include <linux/iopoll.h> |
| 11 | 12 | #include <linux/module.h> |
| 12 | 13 | #include <linux/platform_device.h> |
| @@ -17,6 +18,12 @@ · 4 unmodified lines | ||
| 17 | 18 | #define HISI_SFC_V3XX_VERSION (0x1f8) |
| 18 | 19 | |
| 19 | 20 | #define HISI_SFC_V3XX_CMD_CFG (0x300) |
| 21 | +#define HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT (1 << 17) | |
| 22 | +#define HISI_SFC_V3XX_CMD_CFG_DUAL_IO (2 << 17) | |
| 23 | +#define HISI_SFC_V3XX_CMD_CFG_FULL_DIO (3 << 17) | |
| 24 | +#define HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT (5 << 17) | |
| 25 | +#define HISI_SFC_V3XX_CMD_CFG_QUAD_IO (6 << 17) | |
| 26 | +#define HISI_SFC_V3XX_CMD_CFG_FULL_QIO (7 << 17) | |
| 20 | 27 | #define HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF 9 |
| 21 | 28 | #define HISI_SFC_V3XX_CMD_CFG_RW_MSK BIT(8) |
| 22 | 29 | #define HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK BIT(7) |
| @@ -161,6 +168,43 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host, · 138 unmodified lines | ||
| 161 | 168 | if (op->addr.nbytes) |
| 162 | 169 | config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK; |
| 163 | 170 | |
| 171 | + switch (op->data.buswidth) { | |
| 172 | + case 0 ... 1: | |
| 173 | + break; | |
| 174 | + case 2: | |
| 175 | + if (op->addr.buswidth <= 1) { | |
| 176 | + config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT; | |
| 177 | + } else if (op->addr.buswidth == 2) { | |
| 178 | + if (op->cmd.buswidth <= 1) { | |
| 179 | + config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IO; | |
| 180 | + } else if (op->cmd.buswidth == 2) { | |
| 181 | + config |= HISI_SFC_V3XX_CMD_CFG_FULL_DIO; | |
| 182 | + } else { | |
| 183 | + return -EIO; | |
| 184 | + } | |
| 185 | + } else { | |
| 186 | + return -EIO; | |
| 187 | + } | |
| 188 | + break; | |
| 189 | + case 4: | |
| 190 | + if (op->addr.buswidth <= 1) { | |
| 191 | + config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT; | |
| 192 | + } else if (op->addr.buswidth == 4) { | |
| 193 | + if (op->cmd.buswidth <= 1) { | |
| 194 | + config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IO; | |
| 195 | + } else if (op->cmd.buswidth == 4) { | |
| 196 | + config |= HISI_SFC_V3XX_CMD_CFG_FULL_QIO; | |
| 197 | + } else { | |
| 198 | + return -EIO; | |
| 199 | + } | |
| 200 | + } else { | |
| 201 | + return -EIO; | |
| 202 | + } | |
| 203 | + break; | |
| 204 | + default: | |
| 205 | + return -EOPNOTSUPP; | |
| 206 | + } | |
| 207 | + | |
| 164 | 208 | if (op->data.dir != SPI_MEM_NO_DATA) { |
| 165 | 209 | config |= (len - 1) << HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF; |
| 166 | 210 | config |= HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK; |
| @@ -207,6 +251,44 @@ static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = { · 40 unmodified lines | ||
| 207 | 251 | .exec_op = hisi_sfc_v3xx_exec_op, |
| 208 | 252 | }; |
| 209 | 253 | |
| 254 | +static int hisi_sfc_v3xx_buswidth_override_bits; | |
| 255 | + | |
| 256 | +/* | |
| 257 | + * ACPI FW does not allow us to currently set the device buswidth, so quirk it | |
| 258 | + * depending on the board. | |
| 259 | + */ | |
| 260 | +static int __init hisi_sfc_v3xx_dmi_quirk(const struct dmi_system_id *d) | |
| 261 | +{ | |
| 262 | + hisi_sfc_v3xx_buswidth_override_bits = SPI_RX_QUAD | SPI_TX_QUAD; | |
| 263 | + | |
| 264 | + return 0; | |
| 265 | +} | |
| 266 | + | |
| 267 | +static const struct dmi_system_id hisi_sfc_v3xx_dmi_quirk_table[] = { | |
| 268 | + { | |
| 269 | + .callback = hisi_sfc_v3xx_dmi_quirk, | |
| 270 | + .matches = { | |
| 271 | + DMI_MATCH(DMI_SYS_VENDOR, "Huawei"), | |
| 272 | + DMI_MATCH(DMI_PRODUCT_NAME, "D06"), | |
| 273 | + }, | |
| 274 | + }, | |
| 275 | + { | |
| 276 | + .callback = hisi_sfc_v3xx_dmi_quirk, | |
| 277 | + .matches = { | |
| 278 | + DMI_MATCH(DMI_SYS_VENDOR, "Huawei"), | |
| 279 | + DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 2280 V2"), | |
| 280 | + }, | |
| 281 | + }, | |
| 282 | + { | |
| 283 | + .callback = hisi_sfc_v3xx_dmi_quirk, | |
| 284 | + .matches = { | |
| 285 | + DMI_MATCH(DMI_SYS_VENDOR, "Huawei"), | |
| 286 | + DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 200 (Model 2280)"), | |
| 287 | + }, | |
| 288 | + }, | |
| 289 | + {} | |
| 290 | +}; | |
| 291 | + | |
| 210 | 292 | static int hisi_sfc_v3xx_probe(struct platform_device *pdev) |
| 211 | 293 | { |
| 212 | 294 | struct device *dev = &pdev->dev; |
| @@ -222,6 +304,8 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev) · 9 unmodified lines | ||
| 222 | 304 | ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | |
| 223 | 305 | SPI_TX_DUAL | SPI_TX_QUAD; |
| 224 | 306 | |
| 307 | + ctlr->buswidth_override_bits = hisi_sfc_v3xx_buswidth_override_bits; | |
| 308 | + | |
| 225 | 309 | host = spi_controller_get_devdata(ctlr); |
| 226 | 310 | host->dev = dev; |
| 227 | 311 | |
| @@ -277,7 +361,20 @@ static struct platform_driver hisi_sfc_v3xx_spi_driver = { · 49 unmodified lines | ||
| 277 | 361 | .probe = hisi_sfc_v3xx_probe, |
| 278 | 362 | }; |
| 279 | 363 | |
| 280 | −module_platform_driver(hisi_sfc_v3xx_spi_driver); | |
| 364 | +static int __init hisi_sfc_v3xx_spi_init(void) | |
| 365 | +{ | |
| 366 | + dmi_check_system(hisi_sfc_v3xx_dmi_quirk_table); | |
| 367 | + | |
| 368 | + return platform_driver_register(&hisi_sfc_v3xx_spi_driver); | |
| 369 | +} | |
| 370 | + | |
| 371 | +static void __exit hisi_sfc_v3xx_spi_exit(void) | |
| 372 | +{ | |
| 373 | + platform_driver_unregister(&hisi_sfc_v3xx_spi_driver); | |
| 374 | +} | |
| 375 | + | |
| 376 | +module_init(hisi_sfc_v3xx_spi_init); | |
| 377 | +module_exit(hisi_sfc_v3xx_spi_exit); | |
| 281 | 378 | |
| 282 | 379 | MODULE_LICENSE("GPL"); |
| 283 | 380 | MODULE_AUTHOR("John Garry <john.garry@huawei.com>"); |
| @@ -418,12 +418,13 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) · 417 unmodified lines | ||
| 418 | 418 | struct spi_controller *ctlr = mem->spi->controller; |
| 419 | 419 | size_t len; |
| 420 | 420 | |
| 421 | − len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; | |
| 422 | − | |
| 423 | 421 | if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size) |
| 424 | 422 | return ctlr->mem_ops->adjust_op_size(mem, op); |
| 425 | 423 | |
| 426 | 424 | if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) { |
| 425 | + len = sizeof(op->cmd.opcode) + op->addr.nbytes + | |
| 426 | + op->dummy.nbytes; | |
| 427 | + | |
| 427 | 428 | if (len > spi_max_transfer_size(mem->spi)) |
| 428 | 429 | return -EINVAL; |
| 429 | 430 | |
| @@ -487,7 +488,7 @@ static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc, · 57 unmodified lines | ||
| 487 | 488 | * This function is creating a direct mapping descriptor which can then be used |
| 488 | 489 | * to access the memory using spi_mem_dirmap_read() or spi_mem_dirmap_write(). |
| 489 | 490 | * If the SPI controller driver does not support direct mapping, this function |
| 490 | − * fallback to an implementation using spi_mem_exec_op(), so that the caller | |
| 491 | + * falls back to an implementation using spi_mem_exec_op(), so that the caller | |
| 491 | 492 | * doesn't have to bother implementing a fallback on his own. |
| 492 | 493 | * |
| 493 | 494 | * Return: a valid pointer in case of success, and ERR_PTR() otherwise. |
| @@ -9,11 +9,13 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | #include <linux/bitfield.h> |
| 11 | 11 | #include <linux/clk.h> |
| 12 | +#include <linux/clk-provider.h> | |
| 12 | 13 | #include <linux/device.h> |
| 13 | 14 | #include <linux/io.h> |
| 14 | 15 | #include <linux/kernel.h> |
| 15 | 16 | #include <linux/module.h> |
| 16 | 17 | #include <linux/of.h> |
| 18 | +#include <linux/of_device.h> | |
| 17 | 19 | #include <linux/platform_device.h> |
| 18 | 20 | #include <linux/spi/spi.h> |
| 19 | 21 | #include <linux/types.h> |
| @@ -33,7 +35,6 @@ · 13 unmodified lines | ||
| 33 | 35 | * to have a CS go down over the full transfer |
| 34 | 36 | */ |
| 35 | 37 | |
| 36 | −#define SPICC_MAX_FREQ 30000000 | |
| 37 | 38 | #define SPICC_MAX_BURST 128 |
| 38 | 39 | |
| 39 | 40 | /* Register Map */ |
| @@ -105,7 +106,21 @@ · 65 unmodified lines | ||
| 105 | 106 | #define SPICC_SWAP_RO BIT(14) /* RX FIFO Data Swap Read-Only */ |
| 106 | 107 | #define SPICC_SWAP_W1 BIT(15) /* RX FIFO Data Swap Write-Only */ |
| 107 | 108 | #define SPICC_DLYCTL_RO_MASK GENMASK(20, 15) /* Delay Control Read-Only */ |
| 108 | −#define SPICC_DLYCTL_W1_MASK GENMASK(21, 16) /* Delay Control Write-Only */ | |
| 109 | +#define SPICC_MO_DELAY_MASK GENMASK(17, 16) /* Master Output Delay */ | |
| 110 | +#define SPICC_MO_NO_DELAY 0 | |
| 111 | +#define SPICC_MO_DELAY_1_CYCLE 1 | |
| 112 | +#define SPICC_MO_DELAY_2_CYCLE 2 | |
| 113 | +#define SPICC_MO_DELAY_3_CYCLE 3 | |
| 114 | +#define SPICC_MI_DELAY_MASK GENMASK(19, 18) /* Master Input Delay */ | |
| 115 | +#define SPICC_MI_NO_DELAY 0 | |
| 116 | +#define SPICC_MI_DELAY_1_CYCLE 1 | |
| 117 | +#define SPICC_MI_DELAY_2_CYCLE 2 | |
| 118 | +#define SPICC_MI_DELAY_3_CYCLE 3 | |
| 119 | +#define SPICC_MI_CAP_DELAY_MASK GENMASK(21, 20) /* Master Capture Delay */ | |
| 120 | +#define SPICC_CAP_AHEAD_2_CYCLE 0 | |
| 121 | +#define SPICC_CAP_AHEAD_1_CYCLE 1 | |
| 122 | +#define SPICC_CAP_NO_DELAY 2 | |
| 123 | +#define SPICC_CAP_DELAY_1_CYCLE 3 | |
| 109 | 124 | #define SPICC_FIFORST_RO_MASK GENMASK(22, 21) /* FIFO Softreset Read-Only */ |
| 110 | 125 | #define SPICC_FIFORST_W1_MASK GENMASK(23, 22) /* FIFO Softreset Write-Only */ |
| 111 | 126 | |
| @@ -113,31 +128,59 @@ · 1 unmodified line | ||
| 113 | 128 | |
| 114 | 129 | #define SPICC_DWADDR 0x24 /* Write Address of DMA */ |
| 115 | 130 | |
| 131 | +#define SPICC_ENH_CTL0 0x38 /* Enhanced Feature */ | |
| 132 | +#define SPICC_ENH_CLK_CS_DELAY_MASK GENMASK(15, 0) | |
| 133 | +#define SPICC_ENH_DATARATE_MASK GENMASK(23, 16) | |
| 134 | +#define SPICC_ENH_DATARATE_EN BIT(24) | |
| 135 | +#define SPICC_ENH_MOSI_OEN BIT(25) | |
| 136 | +#define SPICC_ENH_CLK_OEN BIT(26) | |
| 137 | +#define SPICC_ENH_CS_OEN BIT(27) | |
| 138 | +#define SPICC_ENH_CLK_CS_DELAY_EN BIT(28) | |
| 139 | +#define SPICC_ENH_MAIN_CLK_AO BIT(29) | |
| 140 | + | |
| 116 | 141 | #define writel_bits_relaxed(mask, val, addr) \ |
| 117 | 142 | writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr) |
| 118 | 143 | |
| 119 | −#define SPICC_BURST_MAX 16 | |
| 120 | −#define SPICC_FIFO_HALF 10 | |
| 144 | +struct meson_spicc_data { | |
| 145 | + unsigned int max_speed_hz; | |
| 146 | + unsigned int min_speed_hz; | |
| 147 | + unsigned int fifo_size; | |
| 148 | + bool has_oen; | |
| 149 | + bool has_enhance_clk_div; | |
| 150 | + bool has_pclk; | |
| 151 | +}; | |
| 121 | 152 | |
| 122 | 153 | struct meson_spicc_device { |
| 123 | 154 | struct spi_master *master; |
| 124 | 155 | struct platform_device *pdev; |
| 125 | 156 | void __iomem *base; |
| 126 | 157 | struct clk *core; |
| 158 | + struct clk *pclk; | |
| 159 | + struct clk *clk; | |
| 127 | 160 | struct spi_message *message; |
| 128 | 161 | struct spi_transfer *xfer; |
| 162 | + const struct meson_spicc_data *data; | |
| 129 | 163 | u8 *tx_buf; |
| 130 | 164 | u8 *rx_buf; |
| 131 | 165 | unsigned int bytes_per_word; |
| 132 | 166 | unsigned long tx_remain; |
| 133 | − unsigned long txb_remain; | |
| 134 | 167 | unsigned long rx_remain; |
| 135 | − unsigned long rxb_remain; | |
| 136 | 168 | unsigned long xfer_remain; |
| 137 | − bool is_burst_end; | |
| 138 | − bool is_last_burst; | |
| 139 | 169 | }; |
| 140 | 170 | |
| 171 | +static void meson_spicc_oen_enable(struct meson_spicc_device *spicc) | |
| 172 | +{ | |
| 173 | + u32 conf; | |
| 174 | + | |
| 175 | + if (!spicc->data->has_oen) | |
| 176 | + return; | |
| 177 | + | |
| 178 | + conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0) | | |
| 179 | + SPICC_ENH_MOSI_OEN | SPICC_ENH_CLK_OEN | SPICC_ENH_CS_OEN; | |
| 180 | + | |
| 181 | + writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0); | |
| 182 | +} | |
| 183 | + | |
| 141 | 184 | static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc) |
| 142 | 185 | { |
| 143 | 186 | return !!FIELD_GET(SPICC_TF, |
| @@ -146,7 +189,7 @@ static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc) · 2 unmodified lines | ||
| 146 | 189 | |
| 147 | 190 | static inline bool meson_spicc_rxready(struct meson_spicc_device *spicc) |
| 148 | 191 | { |
| 149 | − return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF_EN, | |
| 192 | + return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF, | |
| 150 | 193 | readl_relaxed(spicc->base + SPICC_STATREG)); |
| 151 | 194 | } |
| 152 | 195 | |
| @@ -201,34 +244,22 @@ static inline void meson_spicc_tx(struct meson_spicc_device *spicc) · 48 unmodified lines | ||
| 201 | 244 | spicc->base + SPICC_TXDATA); |
| 202 | 245 | } |
| 203 | 246 | |
| 204 | −static inline u32 meson_spicc_setup_rx_irq(struct meson_spicc_device *spicc, | |
| 205 | − u32 irq_ctrl) | |
| 247 | +static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc) | |
| 206 | 248 | { |
| 207 | − if (spicc->rx_remain > SPICC_FIFO_HALF) | |
| 208 | − irq_ctrl |= SPICC_RH_EN; | |
| 209 | − else | |
| 210 | − irq_ctrl |= SPICC_RR_EN; | |
| 211 | − | |
| 212 | − return irq_ctrl; | |
| 213 | −} | |
| 214 | 249 | |
| 215 | −static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc, | |
| 216 | − unsigned int burst_len) | |
| 217 | −{ | |
| 250 | + unsigned int burst_len = min_t(unsigned int, | |
| 251 | + spicc->xfer_remain / | |
| 252 | + spicc->bytes_per_word, | |
| 253 | + spicc->data->fifo_size); | |
| 218 | 254 | /* Setup Xfer variables */ |
| 219 | 255 | spicc->tx_remain = burst_len; |
| 220 | 256 | spicc->rx_remain = burst_len; |
| 221 | 257 | spicc->xfer_remain -= burst_len * spicc->bytes_per_word; |
| 222 | − spicc->is_burst_end = false; | |
| 223 | − if (burst_len < SPICC_BURST_MAX || !spicc->xfer_remain) | |
| 224 | − spicc->is_last_burst = true; | |
| 225 | − else | |
| 226 | − spicc->is_last_burst = false; | |
| 227 | 258 | |
| 228 | 259 | /* Setup burst length */ |
| 229 | 260 | writel_bits_relaxed(SPICC_BURSTLENGTH_MASK, |
| 230 | 261 | FIELD_PREP(SPICC_BURSTLENGTH_MASK, |
| 231 | − burst_len), | |
| 262 | + burst_len - 1), | |
| 232 | 263 | spicc->base + SPICC_CONREG); |
| 233 | 264 | |
| 234 | 265 | /* Fill TX FIFO */ |
| @@ -238,97 +269,71 @@ static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc, · 3 unmodified lines | ||
| 238 | 269 | static irqreturn_t meson_spicc_irq(int irq, void *data) |
| 239 | 270 | { |
| 240 | 271 | struct meson_spicc_device *spicc = (void *) data; |
| 241 | − u32 ctrl = readl_relaxed(spicc->base + SPICC_INTREG); | |
| 242 | − u32 stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl; | |
| 243 | 272 | |
| 244 | − ctrl &= ~(SPICC_RH_EN | SPICC_RR_EN); | |
| 273 | + writel_bits_relaxed(SPICC_TC, SPICC_TC, spicc->base + SPICC_STATREG); | |
| 245 | 274 | |
| 246 | 275 | /* Empty RX FIFO */ |
| 247 | 276 | meson_spicc_rx(spicc); |
| 248 | 277 | |
| 249 | − /* Enable TC interrupt since we transferred everything */ | |
| 250 | − if (!spicc->tx_remain && !spicc->rx_remain) { | |
| 251 | − spicc->is_burst_end = true; | |
| 252 | − | |
| 253 | − /* Enable TC interrupt */ | |
| 254 | − ctrl |= SPICC_TC_EN; | |
| 278 | + if (!spicc->xfer_remain) { | |
| 279 | + /* Disable all IRQs */ | |
| 280 | + writel(0, spicc->base + SPICC_INTREG); | |
| 255 | 281 | |
| 256 | − /* Reload IRQ status */ | |
| 257 | − stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl; | |
| 258 | − } | |
| 259 | − | |
| 260 | − /* Check transfer complete */ | |
| 261 | − if ((stat & SPICC_TC) && spicc->is_burst_end) { | |
| 262 | − unsigned int burst_len; | |
| 263 | − | |
| 264 | − /* Clear TC bit */ | |
| 265 | − writel_relaxed(SPICC_TC, spicc->base + SPICC_STATREG); | |
| 266 | − | |
| 267 | − /* Disable TC interrupt */ | |
| 268 | − ctrl &= ~SPICC_TC_EN; | |
| 269 | − | |
| 270 | − if (spicc->is_last_burst) { | |
| 271 | − /* Disable all IRQs */ | |
| 272 | − writel(0, spicc->base + SPICC_INTREG); | |
| 273 | − | |
| 274 | − spi_finalize_current_transfer(spicc->master); | |
| 275 | − | |
| 276 | − return IRQ_HANDLED; | |
| 277 | − } | |
| 278 | − | |
| 279 | − burst_len = min_t(unsigned int, | |
| 280 | − spicc->xfer_remain / spicc->bytes_per_word, | |
| 281 | − SPICC_BURST_MAX); | |
| 282 | + spi_finalize_current_transfer(spicc->master); | |
| 282 | 283 | |
| 283 | − /* Setup burst */ | |
| 284 | − meson_spicc_setup_burst(spicc, burst_len); | |
| 285 | − | |
| 286 | − /* Restart burst */ | |
| 287 | − writel_bits_relaxed(SPICC_XCH, SPICC_XCH, | |
| 288 | − spicc->base + SPICC_CONREG); | |
| 284 | + return IRQ_HANDLED; | |
| 289 | 285 | } |
| 290 | 286 | |
| 291 | − /* Setup RX interrupt trigger */ | |
| 292 | − ctrl = meson_spicc_setup_rx_irq(spicc, ctrl); | |
| 287 | + /* Setup burst */ | |
| 288 | + meson_spicc_setup_burst(spicc); | |
| 293 | 289 | |
| 294 | − /* Reconfigure interrupts */ | |
| 295 | − writel(ctrl, spicc->base + SPICC_INTREG); | |
| 290 | + /* Start burst */ | |
| 291 | + writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG); | |
| 296 | 292 | |
| 297 | 293 | return IRQ_HANDLED; |
| 298 | 294 | } |
| 299 | 295 | |
| 300 | −static u32 meson_spicc_setup_speed(struct meson_spicc_device *spicc, u32 conf, | |
| 301 | − u32 speed) | |
| 296 | +static void meson_spicc_auto_io_delay(struct meson_spicc_device *spicc) | |
| 302 | 297 | { |
| 303 | − unsigned long parent, value; | |
| 304 | − unsigned int i, div; | |
| 305 | − | |
| 306 | − parent = clk_get_rate(spicc->core); | |
| 307 | − | |
| 308 | − /* Find closest inferior/equal possible speed */ | |
| 309 | − for (i = 0 ; i < 7 ; ++i) { | |
| 310 | − /* 2^(data_rate+2) */ | |
| 311 | − value = parent >> (i + 2); | |
| 312 | − | |
| 313 | − if (value <= speed) | |
| 314 | − break; | |
| 298 | + u32 div, hz; | |
| 299 | + u32 mi_delay, cap_delay; | |
| 300 | + u32 conf; | |
| 301 | + | |
| 302 | + if (spicc->data->has_enhance_clk_div) { | |
| 303 | + div = FIELD_GET(SPICC_ENH_DATARATE_MASK, | |
| 304 | + readl_relaxed(spicc->base + SPICC_ENH_CTL0)); | |
| 305 | + div++; | |
| 306 | + div <<= 1; | |
| 307 | + } else { | |
| 308 | + div = FIELD_GET(SPICC_DATARATE_MASK, | |
| 309 | + readl_relaxed(spicc->base + SPICC_CONREG)); | |
| 310 | + div += 2; | |
| 311 | + div = 1 << div; | |
| 315 | 312 | } |
| 316 | 313 | |
| 317 | − /* If provided speed it lower than max divider, use max divider */ | |
| 318 | − if (i > 7) { | |
| 319 | − div = 7; | |
| 320 | − dev_warn_once(&spicc->pdev->dev, "unable to get close to speed %u\n", | |
| 321 | − speed); | |
| 322 | − } else | |
| 323 | − div = i; | |
| 324 | − | |
| 325 | − dev_dbg(&spicc->pdev->dev, "parent %lu, speed %u -> %lu (%u)\n", | |
| 326 | − parent, speed, value, div); | |
| 327 | − | |
| 328 | − conf &= ~SPICC_DATARATE_MASK; | |
| 329 | − conf |= FIELD_PREP(SPICC_DATARATE_MASK, div); | |
| 330 | − | |
| 331 | − return conf; | |
| 314 | + mi_delay = SPICC_MI_NO_DELAY; | |
| 315 | + cap_delay = SPICC_CAP_AHEAD_2_CYCLE; | |
| 316 | + hz = clk_get_rate(spicc->clk); | |
| 317 | + | |
| 318 | + if (hz >= 100000000) | |
| 319 | + cap_delay = SPICC_CAP_DELAY_1_CYCLE; | |
| 320 | + else if (hz >= 80000000) | |
| 321 | + cap_delay = SPICC_CAP_NO_DELAY; | |
| 322 | + else if (hz >= 40000000) | |
| 323 | + cap_delay = SPICC_CAP_AHEAD_1_CYCLE; | |
| 324 | + else if (div >= 16) | |
| 325 | + mi_delay = SPICC_MI_DELAY_3_CYCLE; | |
| 326 | + else if (div >= 8) | |
| 327 | + mi_delay = SPICC_MI_DELAY_2_CYCLE; | |
| 328 | + else if (div >= 6) | |
| 329 | + mi_delay = SPICC_MI_DELAY_1_CYCLE; | |
| 330 | + | |
| 331 | + conf = readl_relaxed(spicc->base + SPICC_TESTREG); | |
| 332 | + conf &= ~(SPICC_MO_DELAY_MASK | SPICC_MI_DELAY_MASK | |
| 333 | + | SPICC_MI_CAP_DELAY_MASK); | |
| 334 | + conf |= FIELD_PREP(SPICC_MI_DELAY_MASK, mi_delay); | |
| 335 | + conf |= FIELD_PREP(SPICC_MI_CAP_DELAY_MASK, cap_delay); | |
| 336 | + writel_relaxed(conf, spicc->base + SPICC_TESTREG); | |
| 332 | 337 | } |
| 333 | 338 | |
| 334 | 339 | static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, |
| @@ -339,9 +344,6 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, · 4 unmodified lines | ||
| 339 | 344 | /* Read original configuration */ |
| 340 | 345 | conf = conf_orig = readl_relaxed(spicc->base + SPICC_CONREG); |
| 341 | 346 | |
| 342 | − /* Select closest divider */ | |
| 343 | − conf = meson_spicc_setup_speed(spicc, conf, xfer->speed_hz); | |
| 344 | − | |
| 345 | 347 | /* Setup word width */ |
| 346 | 348 | conf &= ~SPICC_BITLENGTH_MASK; |
| 347 | 349 | conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, |
| @@ -350,6 +352,32 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, · 2 unmodified lines | ||
| 350 | 352 | /* Ignore if unchanged */ |
| 351 | 353 | if (conf != conf_orig) |
| 352 | 354 | writel_relaxed(conf, spicc->base + SPICC_CONREG); |
| 355 | + | |
| 356 | + clk_set_rate(spicc->clk, xfer->speed_hz); | |
| 357 | + | |
| 358 | + meson_spicc_auto_io_delay(spicc); | |
| 359 | + | |
| 360 | + writel_relaxed(0, spicc->base + SPICC_DMAREG); | |
| 361 | +} | |
| 362 | + | |
| 363 | +static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc) | |
| 364 | +{ | |
| 365 | + u32 data; | |
| 366 | + | |
| 367 | + if (spicc->data->has_oen) | |
| 368 | + writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, | |
| 369 | + SPICC_ENH_MAIN_CLK_AO, | |
| 370 | + spicc->base + SPICC_ENH_CTL0); | |
| 371 | + | |
| 372 | + writel_bits_relaxed(SPICC_FIFORST_W1_MASK, SPICC_FIFORST_W1_MASK, | |
| 373 | + spicc->base + SPICC_TESTREG); | |
| 374 | + | |
| 375 | + while (meson_spicc_rxready(spicc)) | |
| 376 | + data = readl_relaxed(spicc->base + SPICC_RXDATA); | |
| 377 | + | |
| 378 | + if (spicc->data->has_oen) | |
| 379 | + writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, 0, | |
| 380 | + spicc->base + SPICC_ENH_CTL0); | |
| 353 | 381 | } |
| 354 | 382 | |
| 355 | 383 | static int meson_spicc_transfer_one(struct spi_master *master, |
| @@ -357,8 +385,6 @@ static int meson_spicc_transfer_one(struct spi_master *master, · 1 unmodified line | ||
| 357 | 385 | struct spi_transfer *xfer) |
| 358 | 386 | { |
| 359 | 387 | struct meson_spicc_device *spicc = spi_master_get_devdata(master); |
| 360 | − unsigned int burst_len; | |
| 361 | − u32 irq = 0; | |
| 362 | 388 | |
| 363 | 389 | /* Store current transfer */ |
| 364 | 390 | spicc->xfer = xfer; |
| @@ -372,22 +398,22 @@ static int meson_spicc_transfer_one(struct spi_master *master, · 7 unmodified lines | ||
| 372 | 398 | spicc->bytes_per_word = |
| 373 | 399 | DIV_ROUND_UP(spicc->xfer->bits_per_word, 8); |
| 374 | 400 | |
| 401 | + if (xfer->len % spicc->bytes_per_word) | |
| 402 | + return -EINVAL; | |
| 403 | + | |
| 375 | 404 | /* Setup transfer parameters */ |
| 376 | 405 | meson_spicc_setup_xfer(spicc, xfer); |
| 377 | 406 | |
| 378 | − burst_len = min_t(unsigned int, | |
| 379 | − spicc->xfer_remain / spicc->bytes_per_word, | |
| 380 | − SPICC_BURST_MAX); | |
| 407 | + meson_spicc_reset_fifo(spicc); | |
| 381 | 408 | |
| 382 | − meson_spicc_setup_burst(spicc, burst_len); | |
| 383 | − | |
| 384 | − irq = meson_spicc_setup_rx_irq(spicc, irq); | |
| 409 | + /* Setup burst */ | |
| 410 | + meson_spicc_setup_burst(spicc); | |
| 385 | 411 | |
| 386 | 412 | /* Start burst */ |
| 387 | 413 | writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG); |
| 388 | 414 | |
| 389 | 415 | /* Enable interrupts */ |
| 390 | − writel_relaxed(irq, spicc->base + SPICC_INTREG); | |
| 416 | + writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG); | |
| 391 | 417 | |
| 392 | 418 | return 1; |
| 393 | 419 | } |
| @@ -444,7 +470,7 @@ static int meson_spicc_prepare_message(struct spi_master *master, · 50 unmodified lines | ||
| 444 | 470 | /* Setup no wait cycles by default */ |
| 445 | 471 | writel_relaxed(0, spicc->base + SPICC_PERIODREG); |
| 446 | 472 | |
| 447 | − writel_bits_relaxed(BIT(24), BIT(24), spicc->base + SPICC_TESTREG); | |
| 473 | + writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG); | |
| 448 | 474 | |
| 449 | 475 | return 0; |
| 450 | 476 | } |
| @@ -456,9 +482,6 @@ static int meson_spicc_unprepare_transfer(struct spi_master *master) · 5 unmodified lines | ||
| 456 | 482 | /* Disable all IRQs */ |
| 457 | 483 | writel(0, spicc->base + SPICC_INTREG); |
| 458 | 484 | |
| 459 | − /* Disable controller */ | |
| 460 | − writel_bits_relaxed(SPICC_ENABLE, 0, spicc->base + SPICC_CONREG); | |
| 461 | − | |
| 462 | 485 | device_reset_optional(&spicc->pdev->dev); |
| 463 | 486 | |
| 464 | 487 | return 0; |
| @@ -477,11 +500,167 @@ static void meson_spicc_cleanup(struct spi_device *spi) · 12 unmodified lines | ||
| 477 | 500 | spi->controller_state = NULL; |
| 478 | 501 | } |
| 479 | 502 | |
| 503 | +/* | |
| 504 | + * The Clock Mux | |
| 505 | + * x-----------------x x------------x x------\ | |
| 506 | + * |---| pow2 fixed div |---| pow2 div |----| | | |
| 507 | + * | x-----------------x x------------x | | | |
| 508 | + * src ---| | mux |-- out | |
| 509 | + * | x-----------------x x------------x | | | |
| 510 | + * |---| enh fixed div |---| enh div |0---| | | |
| 511 | + * x-----------------x x------------x x------/ | |
| 512 | + * | |
| 513 | + * Clk path for GX series: | |
| 514 | + * src -> pow2 fixed div -> pow2 div -> out | |
| 515 | + * | |
| 516 | + * Clk path for AXG series: | |
| 517 | + * src -> pow2 fixed div -> pow2 div -> mux -> out | |
| 518 | + * src -> enh fixed div -> enh div -> mux -> out | |
| 519 | + * | |
| 520 | + * Clk path for G12A series: | |
| 521 | + * pclk -> pow2 fixed div -> pow2 div -> mux -> out | |
| 522 | + * pclk -> enh fixed div -> enh div -> mux -> out | |
| 523 | + */ | |
| 524 | + | |
| 525 | +static int meson_spicc_clk_init(struct meson_spicc_device *spicc) | |
| 526 | +{ | |
| 527 | + struct device *dev = &spicc->pdev->dev; | |
| 528 | + struct clk_fixed_factor *pow2_fixed_div, *enh_fixed_div; | |
| 529 | + struct clk_divider *pow2_div, *enh_div; | |
| 530 | + struct clk_mux *mux; | |
| 531 | + struct clk_init_data init; | |
| 532 | + struct clk *clk; | |
| 533 | + struct clk_parent_data parent_data[2]; | |
| 534 | + char name[64]; | |
| 535 | + | |
| 536 | + memset(&init, 0, sizeof(init)); | |
| 537 | + memset(&parent_data, 0, sizeof(parent_data)); | |
| 538 | + | |
| 539 | + init.parent_data = parent_data; | |
| 540 | + | |
| 541 | + /* algorithm for pow2 div: rate = freq / 4 / (2 ^ N) */ | |
| 542 | + | |
| 543 | + pow2_fixed_div = devm_kzalloc(dev, sizeof(*pow2_fixed_div), GFP_KERNEL); | |
| 544 | + if (!pow2_fixed_div) | |
| 545 | + return -ENOMEM; | |
| 546 | + | |
| 547 | + snprintf(name, sizeof(name), "%s#pow2_fixed_div", dev_name(dev)); | |
| 548 | + init.name = name; | |
| 549 | + init.ops = &clk_fixed_factor_ops; | |
| 550 | + init.flags = 0; | |
| 551 | + if (spicc->data->has_pclk) | |
| 552 | + parent_data[0].hw = __clk_get_hw(spicc->pclk); | |
| 553 | + else | |
| 554 | + parent_data[0].hw = __clk_get_hw(spicc->core); | |
| 555 | + init.num_parents = 1; | |
| 556 | + | |
| 557 | + pow2_fixed_div->mult = 1, | |
| 558 | + pow2_fixed_div->div = 4, | |
| 559 | + pow2_fixed_div->hw.init = &init; | |
| 560 | + | |
| 561 | + clk = devm_clk_register(dev, &pow2_fixed_div->hw); | |
| 562 | + if (WARN_ON(IS_ERR(clk))) | |
| 563 | + return PTR_ERR(clk); | |
| 564 | + | |
| 565 | + pow2_div = devm_kzalloc(dev, sizeof(*pow2_div), GFP_KERNEL); | |
| 566 | + if (!pow2_div) | |
| 567 | + return -ENOMEM; | |
| 568 | + | |
| 569 | + snprintf(name, sizeof(name), "%s#pow2_div", dev_name(dev)); | |
| 570 | + init.name = name; | |
| 571 | + init.ops = &clk_divider_ops; | |
| 572 | + init.flags = CLK_SET_RATE_PARENT; | |
| 573 | + parent_data[0].hw = &pow2_fixed_div->hw; | |
| 574 | + init.num_parents = 1; | |
| 575 | + | |
| 576 | + pow2_div->shift = 16, | |
| 577 | + pow2_div->width = 3, | |
| 578 | + pow2_div->flags = CLK_DIVIDER_POWER_OF_TWO, | |
| 579 | + pow2_div->reg = spicc->base + SPICC_CONREG; | |
| 580 | + pow2_div->hw.init = &init; | |
| 581 | + | |
| 582 | + clk = devm_clk_register(dev, &pow2_div->hw); | |
| 583 | + if (WARN_ON(IS_ERR(clk))) | |
| 584 | + return PTR_ERR(clk); | |
| 585 | + | |
| 586 | + if (!spicc->data->has_enhance_clk_div) { | |
| 587 | + spicc->clk = clk; | |
| 588 | + return 0; | |
| 589 | + } | |
| 590 | + | |
| 591 | + /* algorithm for enh div: rate = freq / 2 / (N + 1) */ | |
| 592 | + | |
| 593 | + enh_fixed_div = devm_kzalloc(dev, sizeof(*enh_fixed_div), GFP_KERNEL); | |
| 594 | + if (!enh_fixed_div) | |
| 595 | + return -ENOMEM; | |
| 596 | + | |
| 597 | + snprintf(name, sizeof(name), "%s#enh_fixed_div", dev_name(dev)); | |
| 598 | + init.name = name; | |
| 599 | + init.ops = &clk_fixed_factor_ops; | |
| 600 | + init.flags = 0; | |
| 601 | + if (spicc->data->has_pclk) | |
| 602 | + parent_data[0].hw = __clk_get_hw(spicc->pclk); | |
| 603 | + else | |
| 604 | + parent_data[0].hw = __clk_get_hw(spicc->core); | |
| 605 | + init.num_parents = 1; | |
| 606 | + | |
| 607 | + enh_fixed_div->mult = 1, | |
| 608 | + enh_fixed_div->div = 2, | |
| 609 | + enh_fixed_div->hw.init = &init; | |
| 610 | + | |
| 611 | + clk = devm_clk_register(dev, &enh_fixed_div->hw); | |
| 612 | + if (WARN_ON(IS_ERR(clk))) | |
| 613 | + return PTR_ERR(clk); | |
| 614 | + | |
| 615 | + enh_div = devm_kzalloc(dev, sizeof(*enh_div), GFP_KERNEL); | |
| 616 | + if (!enh_div) | |
| 617 | + return -ENOMEM; | |
| 618 | + | |
| 619 | + snprintf(name, sizeof(name), "%s#enh_div", dev_name(dev)); | |
| 620 | + init.name = name; | |
| 621 | + init.ops = &clk_divider_ops; | |
| 622 | + init.flags = CLK_SET_RATE_PARENT; | |
| 623 | + parent_data[0].hw = &enh_fixed_div->hw; | |
| 624 | + init.num_parents = 1; | |
| 625 | + | |
| 626 | + enh_div->shift = 16, | |
| 627 | + enh_div->width = 8, | |
| 628 | + enh_div->reg = spicc->base + SPICC_ENH_CTL0; | |
| 629 | + enh_div->hw.init = &init; | |
| 630 | + | |
| 631 | + clk = devm_clk_register(dev, &enh_div->hw); | |
| 632 | + if (WARN_ON(IS_ERR(clk))) | |
| 633 | + return PTR_ERR(clk); | |
| 634 | + | |
| 635 | + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); | |
| 636 | + if (!mux) | |
| 637 | + return -ENOMEM; | |
| 638 | + | |
| 639 | + snprintf(name, sizeof(name), "%s#sel", dev_name(dev)); | |
| 640 | + init.name = name; | |
| 641 | + init.ops = &clk_mux_ops; | |
| 642 | + parent_data[0].hw = &pow2_div->hw; | |
| 643 | + parent_data[1].hw = &enh_div->hw; | |
| 644 | + init.num_parents = 2; | |
| 645 | + init.flags = CLK_SET_RATE_PARENT; | |
| 646 | + | |
| 647 | + mux->mask = 0x1, | |
| 648 | + mux->shift = 24, | |
| 649 | + mux->reg = spicc->base + SPICC_ENH_CTL0; | |
| 650 | + mux->hw.init = &init; | |
| 651 | + | |
| 652 | + spicc->clk = devm_clk_register(dev, &mux->hw); | |
| 653 | + if (WARN_ON(IS_ERR(spicc->clk))) | |
| 654 | + return PTR_ERR(spicc->clk); | |
| 655 | + | |
| 656 | + return 0; | |
| 657 | +} | |
| 658 | + | |
| 480 | 659 | static int meson_spicc_probe(struct platform_device *pdev) |
| 481 | 660 | { |
| 482 | 661 | struct spi_master *master; |
| 483 | 662 | struct meson_spicc_device *spicc; |
| 484 | − int ret, irq, rate; | |
| 663 | + int ret, irq; | |
| 485 | 664 | |
| 486 | 665 | master = spi_alloc_master(&pdev->dev, sizeof(*spicc)); |
| 487 | 666 | if (!master) { |
| @@ -491,6 +670,13 @@ static int meson_spicc_probe(struct platform_device *pdev) · 3 unmodified lines | ||
| 491 | 670 | spicc = spi_master_get_devdata(master); |
| 492 | 671 | spicc->master = master; |
| 493 | 672 | |
| 673 | + spicc->data = of_device_get_match_data(&pdev->dev); | |
| 674 | + if (!spicc->data) { | |
| 675 | + dev_err(&pdev->dev, "failed to get match data\n"); | |
| 676 | + ret = -EINVAL; | |
| 677 | + goto out_master; | |
| 678 | + } | |
| 679 | + | |
| 494 | 680 | spicc->pdev = pdev; |
| 495 | 681 | platform_set_drvdata(pdev, spicc); |
| 496 | 682 | |
| @@ -501,6 +687,10 @@ static int meson_spicc_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 501 | 687 | goto out_master; |
| 502 | 688 | } |
| 503 | 689 | |
| 690 | + /* Set master mode and enable controller */ | |
| 691 | + writel_relaxed(SPICC_ENABLE | SPICC_MODE_MASTER, | |
| 692 | + spicc->base + SPICC_CONREG); | |
| 693 | + | |
| 504 | 694 | /* Disable all IRQs */ |
| 505 | 695 | writel_relaxed(0, spicc->base + SPICC_INTREG); |
| 506 | 696 | |
| @@ -519,12 +709,26 @@ static int meson_spicc_probe(struct platform_device *pdev) · 12 unmodified lines | ||
| 519 | 709 | goto out_master; |
| 520 | 710 | } |
| 521 | 711 | |
| 712 | + if (spicc->data->has_pclk) { | |
| 713 | + spicc->pclk = devm_clk_get(&pdev->dev, "pclk"); | |
| 714 | + if (IS_ERR(spicc->pclk)) { | |
| 715 | + dev_err(&pdev->dev, "pclk clock request failed\n"); | |
| 716 | + ret = PTR_ERR(spicc->pclk); | |
| 717 | + goto out_master; | |
| 718 | + } | |
| 719 | + } | |
| 720 | + | |
| 522 | 721 | ret = clk_prepare_enable(spicc->core); |
| 523 | 722 | if (ret) { |
| 524 | 723 | dev_err(&pdev->dev, "core clock enable failed\n"); |
| 525 | 724 | goto out_master; |
| 526 | 725 | } |
| 527 | − rate = clk_get_rate(spicc->core); | |
| 726 | + | |
| 727 | + ret = clk_prepare_enable(spicc->pclk); | |
| 728 | + if (ret) { | |
| 729 | + dev_err(&pdev->dev, "pclk clock enable failed\n"); | |
| 730 | + goto out_master; | |
| 731 | + } | |
| 528 | 732 | |
| 529 | 733 | device_reset_optional(&pdev->dev); |
| 530 | 734 | |
| @@ -536,7 +740,8 @@ static int meson_spicc_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 536 | 740 | SPI_BPW_MASK(16) | |
| 537 | 741 | SPI_BPW_MASK(8); |
| 538 | 742 | master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX); |
| 539 | − master->min_speed_hz = rate >> 9; | |
| 743 | + master->min_speed_hz = spicc->data->min_speed_hz; | |
| 744 | + master->max_speed_hz = spicc->data->max_speed_hz; | |
| 540 | 745 | master->setup = meson_spicc_setup; |
| 541 | 746 | master->cleanup = meson_spicc_cleanup; |
| 542 | 747 | master->prepare_message = meson_spicc_prepare_message; |
| @@ -544,11 +749,13 @@ static int meson_spicc_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 544 | 749 | master->transfer_one = meson_spicc_transfer_one; |
| 545 | 750 | master->use_gpio_descriptors = true; |
| 546 | 751 | |
| 547 | − /* Setup max rate according to the Meson GX datasheet */ | |
| 548 | − if ((rate >> 2) > SPICC_MAX_FREQ) | |
| 549 | − master->max_speed_hz = SPICC_MAX_FREQ; | |
| 550 | − else | |
| 551 | − master->max_speed_hz = rate >> 2; | |
| 752 | + meson_spicc_oen_enable(spicc); | |
| 753 | + | |
| 754 | + ret = meson_spicc_clk_init(spicc); | |
| 755 | + if (ret) { | |
| 756 | + dev_err(&pdev->dev, "clock registration failed\n"); | |
| 757 | + goto out_master; | |
| 758 | + } | |
| 552 | 759 | |
| 553 | 760 | ret = devm_spi_register_master(&pdev->dev, master); |
| 554 | 761 | if (ret) { |
| @@ -560,6 +767,7 @@ static int meson_spicc_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 560 | 767 | |
| 561 | 768 | out_clk: |
| 562 | 769 | clk_disable_unprepare(spicc->core); |
| 770 | + clk_disable_unprepare(spicc->pclk); | |
| 563 | 771 | |
| 564 | 772 | out_master: |
| 565 | 773 | spi_master_put(master); |
| @@ -575,13 +783,47 @@ static int meson_spicc_remove(struct platform_device *pdev) · 9 unmodified lines | ||
| 575 | 783 | writel(0, spicc->base + SPICC_CONREG); |
| 576 | 784 | |
| 577 | 785 | clk_disable_unprepare(spicc->core); |
| 786 | + clk_disable_unprepare(spicc->pclk); | |
| 578 | 787 | |
| 579 | 788 | return 0; |
| 580 | 789 | } |
| 581 | 790 | |
| 791 | +static const struct meson_spicc_data meson_spicc_gx_data = { | |
| 792 | + .max_speed_hz = 30000000, | |
| 793 | + .min_speed_hz = 325000, | |
| 794 | + .fifo_size = 16, | |
| 795 | +}; | |
| 796 | + | |
| 797 | +static const struct meson_spicc_data meson_spicc_axg_data = { | |
| 798 | + .max_speed_hz = 80000000, | |
| 799 | + .min_speed_hz = 325000, | |
| 800 | + .fifo_size = 16, | |
| 801 | + .has_oen = true, | |
| 802 | + .has_enhance_clk_div = true, | |
| 803 | +}; | |
| 804 | + | |
| 805 | +static const struct meson_spicc_data meson_spicc_g12a_data = { | |
| 806 | + .max_speed_hz = 166666666, | |
| 807 | + .min_speed_hz = 50000, | |
| 808 | + .fifo_size = 15, | |
| 809 | + .has_oen = true, | |
| 810 | + .has_enhance_clk_div = true, | |
| 811 | + .has_pclk = true, | |
| 812 | +}; | |
| 813 | + | |
| 582 | 814 | static const struct of_device_id meson_spicc_of_match[] = { |
| 583 | − { .compatible = "amlogic,meson-gx-spicc", }, | |
| 584 | − { .compatible = "amlogic,meson-axg-spicc", }, | |
| 815 | + { | |
| 816 | + .compatible = "amlogic,meson-gx-spicc", | |
| 817 | + .data = &meson_spicc_gx_data, | |
| 818 | + }, | |
| 819 | + { | |
| 820 | + .compatible = "amlogic,meson-axg-spicc", | |
| 821 | + .data = &meson_spicc_axg_data, | |
| 822 | + }, | |
| 823 | + { | |
| 824 | + .compatible = "amlogic,meson-g12a-spicc", | |
| 825 | + .data = &meson_spicc_g12a_data, | |
| 826 | + }, | |
| 585 | 827 | { /* sentinel */ } |
| 586 | 828 | }; |
| 587 | 829 | MODULE_DEVICE_TABLE(of, meson_spicc_of_match); |
| @@ -0,0 +1,689 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +// | |
| 3 | +// Mediatek SPI NOR controller driver | |
| 4 | +// | |
| 5 | +// Copyright (C) 2020 Chuanhong Guo <gch981213@gmail.com> | |
| 6 | + | |
| 7 | +#include <linux/bits.h> | |
| 8 | +#include <linux/clk.h> | |
| 9 | +#include <linux/completion.h> | |
| 10 | +#include <linux/dma-mapping.h> | |
| 11 | +#include <linux/interrupt.h> | |
| 12 | +#include <linux/io.h> | |
| 13 | +#include <linux/iopoll.h> | |
| 14 | +#include <linux/kernel.h> | |
| 15 | +#include <linux/module.h> | |
| 16 | +#include <linux/of_device.h> | |
| 17 | +#include <linux/spi/spi.h> | |
| 18 | +#include <linux/spi/spi-mem.h> | |
| 19 | +#include <linux/string.h> | |
| 20 | + | |
| 21 | +#define DRIVER_NAME "mtk-spi-nor" | |
| 22 | + | |
| 23 | +#define MTK_NOR_REG_CMD 0x00 | |
| 24 | +#define MTK_NOR_CMD_WRITE BIT(4) | |
| 25 | +#define MTK_NOR_CMD_PROGRAM BIT(2) | |
| 26 | +#define MTK_NOR_CMD_READ BIT(0) | |
| 27 | +#define MTK_NOR_CMD_MASK GENMASK(5, 0) | |
| 28 | + | |
| 29 | +#define MTK_NOR_REG_PRG_CNT 0x04 | |
| 30 | +#define MTK_NOR_REG_RDATA 0x0c | |
| 31 | + | |
| 32 | +#define MTK_NOR_REG_RADR0 0x10 | |
| 33 | +#define MTK_NOR_REG_RADR(n) (MTK_NOR_REG_RADR0 + 4 * (n)) | |
| 34 | +#define MTK_NOR_REG_RADR3 0xc8 | |
| 35 | + | |
| 36 | +#define MTK_NOR_REG_WDATA 0x1c | |
| 37 | + | |
| 38 | +#define MTK_NOR_REG_PRGDATA0 0x20 | |
| 39 | +#define MTK_NOR_REG_PRGDATA(n) (MTK_NOR_REG_PRGDATA0 + 4 * (n)) | |
| 40 | +#define MTK_NOR_REG_PRGDATA_MAX 5 | |
| 41 | + | |
| 42 | +#define MTK_NOR_REG_SHIFT0 0x38 | |
| 43 | +#define MTK_NOR_REG_SHIFT(n) (MTK_NOR_REG_SHIFT0 + 4 * (n)) | |
| 44 | +#define MTK_NOR_REG_SHIFT_MAX 9 | |
| 45 | + | |
| 46 | +#define MTK_NOR_REG_CFG1 0x60 | |
| 47 | +#define MTK_NOR_FAST_READ BIT(0) | |
| 48 | + | |
| 49 | +#define MTK_NOR_REG_CFG2 0x64 | |
| 50 | +#define MTK_NOR_WR_CUSTOM_OP_EN BIT(4) | |
| 51 | +#define MTK_NOR_WR_BUF_EN BIT(0) | |
| 52 | + | |
| 53 | +#define MTK_NOR_REG_PP_DATA 0x98 | |
| 54 | + | |
| 55 | +#define MTK_NOR_REG_IRQ_STAT 0xa8 | |
| 56 | +#define MTK_NOR_REG_IRQ_EN 0xac | |
| 57 | +#define MTK_NOR_IRQ_DMA BIT(7) | |
| 58 | +#define MTK_NOR_IRQ_MASK GENMASK(7, 0) | |
| 59 | + | |
| 60 | +#define MTK_NOR_REG_CFG3 0xb4 | |
| 61 | +#define MTK_NOR_DISABLE_WREN BIT(7) | |
| 62 | +#define MTK_NOR_DISABLE_SR_POLL BIT(5) | |
| 63 | + | |
| 64 | +#define MTK_NOR_REG_WP 0xc4 | |
| 65 | +#define MTK_NOR_ENABLE_SF_CMD 0x30 | |
| 66 | + | |
| 67 | +#define MTK_NOR_REG_BUSCFG 0xcc | |
| 68 | +#define MTK_NOR_4B_ADDR BIT(4) | |
| 69 | +#define MTK_NOR_QUAD_ADDR BIT(3) | |
| 70 | +#define MTK_NOR_QUAD_READ BIT(2) | |
| 71 | +#define MTK_NOR_DUAL_ADDR BIT(1) | |
| 72 | +#define MTK_NOR_DUAL_READ BIT(0) | |
| 73 | +#define MTK_NOR_BUS_MODE_MASK GENMASK(4, 0) | |
| 74 | + | |
| 75 | +#define MTK_NOR_REG_DMA_CTL 0x718 | |
| 76 | +#define MTK_NOR_DMA_START BIT(0) | |
| 77 | + | |
| 78 | +#define MTK_NOR_REG_DMA_FADR 0x71c | |
| 79 | +#define MTK_NOR_REG_DMA_DADR 0x720 | |
| 80 | +#define MTK_NOR_REG_DMA_END_DADR 0x724 | |
| 81 | + | |
| 82 | +#define MTK_NOR_PRG_MAX_SIZE 6 | |
| 83 | +// Reading DMA src/dst addresses have to be 16-byte aligned | |
| 84 | +#define MTK_NOR_DMA_ALIGN 16 | |
| 85 | +#define MTK_NOR_DMA_ALIGN_MASK (MTK_NOR_DMA_ALIGN - 1) | |
| 86 | +// and we allocate a bounce buffer if destination address isn't aligned. | |
| 87 | +#define MTK_NOR_BOUNCE_BUF_SIZE PAGE_SIZE | |
| 88 | + | |
| 89 | +// Buffered page program can do one 128-byte transfer | |
| 90 | +#define MTK_NOR_PP_SIZE 128 | |
| 91 | + | |
| 92 | +#define CLK_TO_US(sp, clkcnt) ((clkcnt) * 1000000 / sp->spi_freq) | |
| 93 | + | |
| 94 | +struct mtk_nor { | |
| 95 | + struct spi_controller *ctlr; | |
| 96 | + struct device *dev; | |
| 97 | + void __iomem *base; | |
| 98 | + u8 *buffer; | |
| 99 | + struct clk *spi_clk; | |
| 100 | + struct clk *ctlr_clk; | |
| 101 | + unsigned int spi_freq; | |
| 102 | + bool wbuf_en; | |
| 103 | + bool has_irq; | |
| 104 | + struct completion op_done; | |
| 105 | +}; | |
| 106 | + | |
| 107 | +static inline void mtk_nor_rmw(struct mtk_nor *sp, u32 reg, u32 set, u32 clr) | |
| 108 | +{ | |
| 109 | + u32 val = readl(sp->base + reg); | |
| 110 | + | |
| 111 | + val &= ~clr; | |
| 112 | + val |= set; | |
| 113 | + writel(val, sp->base + reg); | |
| 114 | +} | |
| 115 | + | |
| 116 | +static inline int mtk_nor_cmd_exec(struct mtk_nor *sp, u32 cmd, ulong clk) | |
| 117 | +{ | |
| 118 | + ulong delay = CLK_TO_US(sp, clk); | |
| 119 | + u32 reg; | |
| 120 | + int ret; | |
| 121 | + | |
| 122 | + writel(cmd, sp->base + MTK_NOR_REG_CMD); | |
| 123 | + ret = readl_poll_timeout(sp->base + MTK_NOR_REG_CMD, reg, !(reg & cmd), | |
| 124 | + delay / 3, (delay + 1) * 200); | |
| 125 | + if (ret < 0) | |
| 126 | + dev_err(sp->dev, "command %u timeout.\n", cmd); | |
| 127 | + return ret; | |
| 128 | +} | |
| 129 | + | |
| 130 | +static void mtk_nor_set_addr(struct mtk_nor *sp, const struct spi_mem_op *op) | |
| 131 | +{ | |
| 132 | + u32 addr = op->addr.val; | |
| 133 | + int i; | |
| 134 | + | |
| 135 | + for (i = 0; i < 3; i++) { | |
| 136 | + writeb(addr & 0xff, sp->base + MTK_NOR_REG_RADR(i)); | |
| 137 | + addr >>= 8; | |
| 138 | + } | |
| 139 | + if (op->addr.nbytes == 4) { | |
| 140 | + writeb(addr & 0xff, sp->base + MTK_NOR_REG_RADR3); | |
| 141 | + mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, MTK_NOR_4B_ADDR, 0); | |
| 142 | + } else { | |
| 143 | + mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, 0, MTK_NOR_4B_ADDR); | |
| 144 | + } | |
| 145 | +} | |
| 146 | + | |
| 147 | +static bool mtk_nor_match_read(const struct spi_mem_op *op) | |
| 148 | +{ | |
| 149 | + int dummy = 0; | |
| 150 | + | |
| 151 | + if (op->dummy.buswidth) | |
| 152 | + dummy = op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth; | |
| 153 | + | |
| 154 | + if ((op->data.buswidth == 2) || (op->data.buswidth == 4)) { | |
| 155 | + if (op->addr.buswidth == 1) | |
| 156 | + return dummy == 8; | |
| 157 | + else if (op->addr.buswidth == 2) | |
| 158 | + return dummy == 4; | |
| 159 | + else if (op->addr.buswidth == 4) | |
| 160 | + return dummy == 6; | |
| 161 | + } else if ((op->addr.buswidth == 1) && (op->data.buswidth == 1)) { | |
| 162 | + if (op->cmd.opcode == 0x03) | |
| 163 | + return dummy == 0; | |
| 164 | + else if (op->cmd.opcode == 0x0b) | |
| 165 | + return dummy == 8; | |
| 166 | + } | |
| 167 | + return false; | |
| 168 | +} | |
| 169 | + | |
| 170 | +static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) | |
| 171 | +{ | |
| 172 | + size_t len; | |
| 173 | + | |
| 174 | + if (!op->data.nbytes) | |
| 175 | + return 0; | |
| 176 | + | |
| 177 | + if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) { | |
| 178 | + if ((op->data.dir == SPI_MEM_DATA_IN) && | |
| 179 | + mtk_nor_match_read(op)) { | |
| 180 | + if ((op->addr.val & MTK_NOR_DMA_ALIGN_MASK) || | |
| 181 | + (op->data.nbytes < MTK_NOR_DMA_ALIGN)) | |
| 182 | + op->data.nbytes = 1; | |
| 183 | + else if (!((ulong)(op->data.buf.in) & | |
| 184 | + MTK_NOR_DMA_ALIGN_MASK)) | |
| 185 | + op->data.nbytes &= ~MTK_NOR_DMA_ALIGN_MASK; | |
| 186 | + else if (op->data.nbytes > MTK_NOR_BOUNCE_BUF_SIZE) | |
| 187 | + op->data.nbytes = MTK_NOR_BOUNCE_BUF_SIZE; | |
| 188 | + return 0; | |
| 189 | + } else if (op->data.dir == SPI_MEM_DATA_OUT) { | |
| 190 | + if (op->data.nbytes >= MTK_NOR_PP_SIZE) | |
| 191 | + op->data.nbytes = MTK_NOR_PP_SIZE; | |
| 192 | + else | |
| 193 | + op->data.nbytes = 1; | |
| 194 | + return 0; | |
| 195 | + } | |
| 196 | + } | |
| 197 | + | |
| 198 | + len = MTK_NOR_PRG_MAX_SIZE - sizeof(op->cmd.opcode) - op->addr.nbytes - | |
| 199 | + op->dummy.nbytes; | |
| 200 | + if (op->data.nbytes > len) | |
| 201 | + op->data.nbytes = len; | |
| 202 | + | |
| 203 | + return 0; | |
| 204 | +} | |
| 205 | + | |
| 206 | +static bool mtk_nor_supports_op(struct spi_mem *mem, | |
| 207 | + const struct spi_mem_op *op) | |
| 208 | +{ | |
| 209 | + size_t len; | |
| 210 | + | |
| 211 | + if (op->cmd.buswidth != 1) | |
| 212 | + return false; | |
| 213 | + | |
| 214 | + if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) { | |
| 215 | + if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op)) | |
| 216 | + return true; | |
| 217 | + else if (op->data.dir == SPI_MEM_DATA_OUT) | |
| 218 | + return (op->addr.buswidth == 1) && | |
| 219 | + (op->dummy.buswidth == 0) && | |
| 220 | + (op->data.buswidth == 1); | |
| 221 | + } | |
| 222 | + len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; | |
| 223 | + if ((len > MTK_NOR_PRG_MAX_SIZE) || | |
| 224 | + ((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE))) | |
| 225 | + return false; | |
| 226 | + return true; | |
| 227 | +} | |
| 228 | + | |
| 229 | +static void mtk_nor_setup_bus(struct mtk_nor *sp, const struct spi_mem_op *op) | |
| 230 | +{ | |
| 231 | + u32 reg = 0; | |
| 232 | + | |
| 233 | + if (op->addr.nbytes == 4) | |
| 234 | + reg |= MTK_NOR_4B_ADDR; | |
| 235 | + | |
| 236 | + if (op->data.buswidth == 4) { | |
| 237 | + reg |= MTK_NOR_QUAD_READ; | |
| 238 | + writeb(op->cmd.opcode, sp->base + MTK_NOR_REG_PRGDATA(4)); | |
| 239 | + if (op->addr.buswidth == 4) | |
| 240 | + reg |= MTK_NOR_QUAD_ADDR; | |
| 241 | + } else if (op->data.buswidth == 2) { | |
| 242 | + reg |= MTK_NOR_DUAL_READ; | |
| 243 | + writeb(op->cmd.opcode, sp->base + MTK_NOR_REG_PRGDATA(3)); | |
| 244 | + if (op->addr.buswidth == 2) | |
| 245 | + reg |= MTK_NOR_DUAL_ADDR; | |
| 246 | + } else { | |
| 247 | + if (op->cmd.opcode == 0x0b) | |
| 248 | + mtk_nor_rmw(sp, MTK_NOR_REG_CFG1, MTK_NOR_FAST_READ, 0); | |
| 249 | + else | |
| 250 | + mtk_nor_rmw(sp, MTK_NOR_REG_CFG1, 0, MTK_NOR_FAST_READ); | |
| 251 | + } | |
| 252 | + mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, reg, MTK_NOR_BUS_MODE_MASK); | |
| 253 | +} | |
| 254 | + | |
| 255 | +static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, unsigned int length, | |
| 256 | + u8 *buffer) | |
| 257 | +{ | |
| 258 | + int ret = 0; | |
| 259 | + ulong delay; | |
| 260 | + u32 reg; | |
| 261 | + dma_addr_t dma_addr; | |
| 262 | + | |
| 263 | + dma_addr = dma_map_single(sp->dev, buffer, length, DMA_FROM_DEVICE); | |
| 264 | + if (dma_mapping_error(sp->dev, dma_addr)) { | |
| 265 | + dev_err(sp->dev, "failed to map dma buffer.\n"); | |
| 266 | + return -EINVAL; | |
| 267 | + } | |
| 268 | + | |
| 269 | + writel(from, sp->base + MTK_NOR_REG_DMA_FADR); | |
| 270 | + writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR); | |
| 271 | + writel(dma_addr + length, sp->base + MTK_NOR_REG_DMA_END_DADR); | |
| 272 | + | |
| 273 | + if (sp->has_irq) { | |
| 274 | + reinit_completion(&sp->op_done); | |
| 275 | + mtk_nor_rmw(sp, MTK_NOR_REG_IRQ_EN, MTK_NOR_IRQ_DMA, 0); | |
| 276 | + } | |
| 277 | + | |
| 278 | + mtk_nor_rmw(sp, MTK_NOR_REG_DMA_CTL, MTK_NOR_DMA_START, 0); | |
| 279 | + | |
| 280 | + delay = CLK_TO_US(sp, (length + 5) * BITS_PER_BYTE); | |
| 281 | + | |
| 282 | + if (sp->has_irq) { | |
| 283 | + if (!wait_for_completion_timeout(&sp->op_done, | |
| 284 | + (delay + 1) * 100)) | |
| 285 | + ret = -ETIMEDOUT; | |
| 286 | + } else { | |
| 287 | + ret = readl_poll_timeout(sp->base + MTK_NOR_REG_DMA_CTL, reg, | |
| 288 | + !(reg & MTK_NOR_DMA_START), delay / 3, | |
| 289 | + (delay + 1) * 100); | |
| 290 | + } | |
| 291 | + | |
| 292 | + dma_unmap_single(sp->dev, dma_addr, length, DMA_FROM_DEVICE); | |
| 293 | + if (ret < 0) | |
| 294 | + dev_err(sp->dev, "dma read timeout.\n"); | |
| 295 | + | |
| 296 | + return ret; | |
| 297 | +} | |
| 298 | + | |
| 299 | +static int mtk_nor_read_bounce(struct mtk_nor *sp, u32 from, | |
| 300 | + unsigned int length, u8 *buffer) | |
| 301 | +{ | |
| 302 | + unsigned int rdlen; | |
| 303 | + int ret; | |
| 304 | + | |
| 305 | + if (length & MTK_NOR_DMA_ALIGN_MASK) | |
| 306 | + rdlen = (length + MTK_NOR_DMA_ALIGN) & ~MTK_NOR_DMA_ALIGN_MASK; | |
| 307 | + else | |
| 308 | + rdlen = length; | |
| 309 | + | |
| 310 | + ret = mtk_nor_read_dma(sp, from, rdlen, sp->buffer); | |
| 311 | + if (ret) | |
| 312 | + return ret; | |
| 313 | + | |
| 314 | + memcpy(buffer, sp->buffer, length); | |
| 315 | + return 0; | |
| 316 | +} | |
| 317 | + | |
| 318 | +static int mtk_nor_read_pio(struct mtk_nor *sp, const struct spi_mem_op *op) | |
| 319 | +{ | |
| 320 | + u8 *buf = op->data.buf.in; | |
| 321 | + int ret; | |
| 322 | + | |
| 323 | + ret = mtk_nor_cmd_exec(sp, MTK_NOR_CMD_READ, 6 * BITS_PER_BYTE); | |
| 324 | + if (!ret) | |
| 325 | + buf[0] = readb(sp->base + MTK_NOR_REG_RDATA); | |
| 326 | + return ret; | |
| 327 | +} | |
| 328 | + | |
| 329 | +static int mtk_nor_write_buffer_enable(struct mtk_nor *sp) | |
| 330 | +{ | |
| 331 | + int ret; | |
| 332 | + u32 val; | |
| 333 | + | |
| 334 | + if (sp->wbuf_en) | |
| 335 | + return 0; | |
| 336 | + | |
| 337 | + val = readl(sp->base + MTK_NOR_REG_CFG2); | |
| 338 | + writel(val | MTK_NOR_WR_BUF_EN, sp->base + MTK_NOR_REG_CFG2); | |
| 339 | + ret = readl_poll_timeout(sp->base + MTK_NOR_REG_CFG2, val, | |
| 340 | + val & MTK_NOR_WR_BUF_EN, 0, 10000); | |
| 341 | + if (!ret) | |
| 342 | + sp->wbuf_en = true; | |
| 343 | + return ret; | |
| 344 | +} | |
| 345 | + | |
| 346 | +static int mtk_nor_write_buffer_disable(struct mtk_nor *sp) | |
| 347 | +{ | |
| 348 | + int ret; | |
| 349 | + u32 val; | |
| 350 | + | |
| 351 | + if (!sp->wbuf_en) | |
| 352 | + return 0; | |
| 353 | + val = readl(sp->base + MTK_NOR_REG_CFG2); | |
| 354 | + writel(val & ~MTK_NOR_WR_BUF_EN, sp->base + MTK_NOR_REG_CFG2); | |
| 355 | + ret = readl_poll_timeout(sp->base + MTK_NOR_REG_CFG2, val, | |
| 356 | + !(val & MTK_NOR_WR_BUF_EN), 0, 10000); | |
| 357 | + if (!ret) | |
| 358 | + sp->wbuf_en = false; | |
| 359 | + return ret; | |
| 360 | +} | |
| 361 | + | |
| 362 | +static int mtk_nor_pp_buffered(struct mtk_nor *sp, const struct spi_mem_op *op) | |
| 363 | +{ | |
| 364 | + const u8 *buf = op->data.buf.out; | |
| 365 | + u32 val; | |
| 366 | + int ret, i; | |
| 367 | + | |
| 368 | + ret = mtk_nor_write_buffer_enable(sp); | |
| 369 | + if (ret < 0) | |
| 370 | + return ret; | |
| 371 | + | |
| 372 | + for (i = 0; i < op->data.nbytes; i += 4) { | |
| 373 | + val = buf[i + 3] << 24 | buf[i + 2] << 16 | buf[i + 1] << 8 | | |
| 374 | + buf[i]; | |
| 375 | + writel(val, sp->base + MTK_NOR_REG_PP_DATA); | |
| 376 | + } | |
| 377 | + return mtk_nor_cmd_exec(sp, MTK_NOR_CMD_WRITE, | |
| 378 | + (op->data.nbytes + 5) * BITS_PER_BYTE); | |
| 379 | +} | |
| 380 | + | |
| 381 | +static int mtk_nor_pp_unbuffered(struct mtk_nor *sp, | |
| 382 | + const struct spi_mem_op *op) | |
| 383 | +{ | |
| 384 | + const u8 *buf = op->data.buf.out; | |
| 385 | + int ret; | |
| 386 | + | |
| 387 | + ret = mtk_nor_write_buffer_disable(sp); | |
| 388 | + if (ret < 0) | |
| 389 | + return ret; | |
| 390 | + writeb(buf[0], sp->base + MTK_NOR_REG_WDATA); | |
| 391 | + return mtk_nor_cmd_exec(sp, MTK_NOR_CMD_WRITE, 6 * BITS_PER_BYTE); | |
| 392 | +} | |
| 393 | + | |
| 394 | +int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) | |
| 395 | +{ | |
| 396 | + struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master); | |
| 397 | + int ret; | |
| 398 | + | |
| 399 | + if ((op->data.nbytes == 0) || | |
| 400 | + ((op->addr.nbytes != 3) && (op->addr.nbytes != 4))) | |
| 401 | + return -ENOTSUPP; | |
| 402 | + | |
| 403 | + if (op->data.dir == SPI_MEM_DATA_OUT) { | |
| 404 | + mtk_nor_set_addr(sp, op); | |
| 405 | + writeb(op->cmd.opcode, sp->base + MTK_NOR_REG_PRGDATA0); | |
| 406 | + if (op->data.nbytes == MTK_NOR_PP_SIZE) | |
| 407 | + return mtk_nor_pp_buffered(sp, op); | |
| 408 | + return mtk_nor_pp_unbuffered(sp, op); | |
| 409 | + } | |
| 410 | + | |
| 411 | + if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op)) { | |
| 412 | + ret = mtk_nor_write_buffer_disable(sp); | |
| 413 | + if (ret < 0) | |
| 414 | + return ret; | |
| 415 | + mtk_nor_setup_bus(sp, op); | |
| 416 | + if (op->data.nbytes == 1) { | |
| 417 | + mtk_nor_set_addr(sp, op); | |
| 418 | + return mtk_nor_read_pio(sp, op); | |
| 419 | + } else if (((ulong)(op->data.buf.in) & | |
| 420 | + MTK_NOR_DMA_ALIGN_MASK)) { | |
| 421 | + return mtk_nor_read_bounce(sp, op->addr.val, | |
| 422 | + op->data.nbytes, | |
| 423 | + op->data.buf.in); | |
| 424 | + } else { | |
| 425 | + return mtk_nor_read_dma(sp, op->addr.val, | |
| 426 | + op->data.nbytes, | |
| 427 | + op->data.buf.in); | |
| 428 | + } | |
| 429 | + } | |
| 430 | + | |
| 431 | + return -ENOTSUPP; | |
| 432 | +} | |
| 433 | + | |
| 434 | +static int mtk_nor_setup(struct spi_device *spi) | |
| 435 | +{ | |
| 436 | + struct mtk_nor *sp = spi_controller_get_devdata(spi->master); | |
| 437 | + | |
| 438 | + if (spi->max_speed_hz && (spi->max_speed_hz < sp->spi_freq)) { | |
| 439 | + dev_err(&spi->dev, "spi clock should be %u Hz.\n", | |
| 440 | + sp->spi_freq); | |
| 441 | + return -EINVAL; | |
| 442 | + } | |
| 443 | + spi->max_speed_hz = sp->spi_freq; | |
| 444 | + | |
| 445 | + return 0; | |
| 446 | +} | |
| 447 | + | |
| 448 | +static int mtk_nor_transfer_one_message(struct spi_controller *master, | |
| 449 | + struct spi_message *m) | |
| 450 | +{ | |
| 451 | + struct mtk_nor *sp = spi_controller_get_devdata(master); | |
| 452 | + struct spi_transfer *t = NULL; | |
| 453 | + unsigned long trx_len = 0; | |
| 454 | + int stat = 0; | |
| 455 | + int reg_offset = MTK_NOR_REG_PRGDATA_MAX; | |
| 456 | + void __iomem *reg; | |
| 457 | + const u8 *txbuf; | |
| 458 | + u8 *rxbuf; | |
| 459 | + int i; | |
| 460 | + | |
| 461 | + list_for_each_entry(t, &m->transfers, transfer_list) { | |
| 462 | + txbuf = t->tx_buf; | |
| 463 | + for (i = 0; i < t->len; i++, reg_offset--) { | |
| 464 | + reg = sp->base + MTK_NOR_REG_PRGDATA(reg_offset); | |
| 465 | + if (txbuf) | |
| 466 | + writeb(txbuf[i], reg); | |
| 467 | + else | |
| 468 | + writeb(0, reg); | |
| 469 | + } | |
| 470 | + trx_len += t->len; | |
| 471 | + } | |
| 472 | + | |
| 473 | + writel(trx_len * BITS_PER_BYTE, sp->base + MTK_NOR_REG_PRG_CNT); | |
| 474 | + | |
| 475 | + stat = mtk_nor_cmd_exec(sp, MTK_NOR_CMD_PROGRAM, | |
| 476 | + trx_len * BITS_PER_BYTE); | |
| 477 | + if (stat < 0) | |
| 478 | + goto msg_done; | |
| 479 | + | |
| 480 | + reg_offset = trx_len - 1; | |
| 481 | + list_for_each_entry(t, &m->transfers, transfer_list) { | |
| 482 | + rxbuf = t->rx_buf; | |
| 483 | + for (i = 0; i < t->len; i++, reg_offset--) { | |
| 484 | + reg = sp->base + MTK_NOR_REG_SHIFT(reg_offset); | |
| 485 | + if (rxbuf) | |
| 486 | + rxbuf[i] = readb(reg); | |
| 487 | + } | |
| 488 | + } | |
| 489 | + | |
| 490 | + m->actual_length = trx_len; | |
| 491 | +msg_done: | |
| 492 | + m->status = stat; | |
| 493 | + spi_finalize_current_message(master); | |
| 494 | + | |
| 495 | + return 0; | |
| 496 | +} | |
| 497 | + | |
| 498 | +static void mtk_nor_disable_clk(struct mtk_nor *sp) | |
| 499 | +{ | |
| 500 | + clk_disable_unprepare(sp->spi_clk); | |
| 501 | + clk_disable_unprepare(sp->ctlr_clk); | |
| 502 | +} | |
| 503 | + | |
| 504 | +static int mtk_nor_enable_clk(struct mtk_nor *sp) | |
| 505 | +{ | |
| 506 | + int ret; | |
| 507 | + | |
| 508 | + ret = clk_prepare_enable(sp->spi_clk); | |
| 509 | + if (ret) | |
| 510 | + return ret; | |
| 511 | + | |
| 512 | + ret = clk_prepare_enable(sp->ctlr_clk); | |
| 513 | + if (ret) { | |
| 514 | + clk_disable_unprepare(sp->spi_clk); | |
| 515 | + return ret; | |
| 516 | + } | |
| 517 | + | |
| 518 | + return 0; | |
| 519 | +} | |
| 520 | + | |
| 521 | +static int mtk_nor_init(struct mtk_nor *sp) | |
| 522 | +{ | |
| 523 | + int ret; | |
| 524 | + | |
| 525 | + ret = mtk_nor_enable_clk(sp); | |
| 526 | + if (ret) | |
| 527 | + return ret; | |
| 528 | + | |
| 529 | + sp->spi_freq = clk_get_rate(sp->spi_clk); | |
| 530 | + | |
| 531 | + writel(MTK_NOR_ENABLE_SF_CMD, sp->base + MTK_NOR_REG_WP); | |
| 532 | + mtk_nor_rmw(sp, MTK_NOR_REG_CFG2, MTK_NOR_WR_CUSTOM_OP_EN, 0); | |
| 533 | + mtk_nor_rmw(sp, MTK_NOR_REG_CFG3, | |
| 534 | + MTK_NOR_DISABLE_WREN | MTK_NOR_DISABLE_SR_POLL, 0); | |
| 535 | + | |
| 536 | + return ret; | |
| 537 | +} | |
| 538 | + | |
| 539 | +static irqreturn_t mtk_nor_irq_handler(int irq, void *data) | |
| 540 | +{ | |
| 541 | + struct mtk_nor *sp = data; | |
| 542 | + u32 irq_status, irq_enabled; | |
| 543 | + | |
| 544 | + irq_status = readl(sp->base + MTK_NOR_REG_IRQ_STAT); | |
| 545 | + irq_enabled = readl(sp->base + MTK_NOR_REG_IRQ_EN); | |
| 546 | + // write status back to clear interrupt | |
| 547 | + writel(irq_status, sp->base + MTK_NOR_REG_IRQ_STAT); | |
| 548 | + | |
| 549 | + if (!(irq_status & irq_enabled)) | |
| 550 | + return IRQ_NONE; | |
| 551 | + | |
| 552 | + if (irq_status & MTK_NOR_IRQ_DMA) { | |
| 553 | + complete(&sp->op_done); | |
| 554 | + writel(0, sp->base + MTK_NOR_REG_IRQ_EN); | |
| 555 | + } | |
| 556 | + | |
| 557 | + return IRQ_HANDLED; | |
| 558 | +} | |
| 559 | + | |
| 560 | +static size_t mtk_max_msg_size(struct spi_device *spi) | |
| 561 | +{ | |
| 562 | + return MTK_NOR_PRG_MAX_SIZE; | |
| 563 | +} | |
| 564 | + | |
| 565 | +static const struct spi_controller_mem_ops mtk_nor_mem_ops = { | |
| 566 | + .adjust_op_size = mtk_nor_adjust_op_size, | |
| 567 | + .supports_op = mtk_nor_supports_op, | |
| 568 | + .exec_op = mtk_nor_exec_op | |
| 569 | +}; | |
| 570 | + | |
| 571 | +static const struct of_device_id mtk_nor_match[] = { | |
| 572 | + { .compatible = "mediatek,mt8173-nor" }, | |
| 573 | + { /* sentinel */ } | |
| 574 | +}; | |
| 575 | +MODULE_DEVICE_TABLE(of, mtk_nor_match); | |
| 576 | + | |
| 577 | +static int mtk_nor_probe(struct platform_device *pdev) | |
| 578 | +{ | |
| 579 | + struct spi_controller *ctlr; | |
| 580 | + struct mtk_nor *sp; | |
| 581 | + void __iomem *base; | |
| 582 | + u8 *buffer; | |
| 583 | + struct clk *spi_clk, *ctlr_clk; | |
| 584 | + int ret, irq; | |
| 585 | + | |
| 586 | + base = devm_platform_ioremap_resource(pdev, 0); | |
| 587 | + if (IS_ERR(base)) | |
| 588 | + return PTR_ERR(base); | |
| 589 | + | |
| 590 | + spi_clk = devm_clk_get(&pdev->dev, "spi"); | |
| 591 | + if (IS_ERR(spi_clk)) | |
| 592 | + return PTR_ERR(spi_clk); | |
| 593 | + | |
| 594 | + ctlr_clk = devm_clk_get(&pdev->dev, "sf"); | |
| 595 | + if (IS_ERR(ctlr_clk)) | |
| 596 | + return PTR_ERR(ctlr_clk); | |
| 597 | + | |
| 598 | + buffer = devm_kmalloc(&pdev->dev, | |
| 599 | + MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN, | |
| 600 | + GFP_KERNEL); | |
| 601 | + if (!buffer) | |
| 602 | + return -ENOMEM; | |
| 603 | + | |
| 604 | + if ((ulong)buffer & MTK_NOR_DMA_ALIGN_MASK) | |
| 605 | + buffer = (u8 *)(((ulong)buffer + MTK_NOR_DMA_ALIGN) & | |
| 606 | + ~MTK_NOR_DMA_ALIGN_MASK); | |
| 607 | + | |
| 608 | + ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp)); | |
| 609 | + if (!ctlr) { | |
| 610 | + dev_err(&pdev->dev, "failed to allocate spi controller\n"); | |
| 611 | + return -ENOMEM; | |
| 612 | + } | |
| 613 | + | |
| 614 | + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); | |
| 615 | + ctlr->dev.of_node = pdev->dev.of_node; | |
| 616 | + ctlr->max_message_size = mtk_max_msg_size; | |
| 617 | + ctlr->mem_ops = &mtk_nor_mem_ops; | |
| 618 | + ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; | |
| 619 | + ctlr->num_chipselect = 1; | |
| 620 | + ctlr->setup = mtk_nor_setup; | |
| 621 | + ctlr->transfer_one_message = mtk_nor_transfer_one_message; | |
| 622 | + | |
| 623 | + dev_set_drvdata(&pdev->dev, ctlr); | |
| 624 | + | |
| 625 | + sp = spi_controller_get_devdata(ctlr); | |
| 626 | + sp->base = base; | |
| 627 | + sp->buffer = buffer; | |
| 628 | + sp->has_irq = false; | |
| 629 | + sp->wbuf_en = false; | |
| 630 | + sp->ctlr = ctlr; | |
| 631 | + sp->dev = &pdev->dev; | |
| 632 | + sp->spi_clk = spi_clk; | |
| 633 | + sp->ctlr_clk = ctlr_clk; | |
| 634 | + | |
| 635 | + irq = platform_get_irq_optional(pdev, 0); | |
| 636 | + if (irq < 0) { | |
| 637 | + dev_warn(sp->dev, "IRQ not available."); | |
| 638 | + } else { | |
| 639 | + writel(MTK_NOR_IRQ_MASK, base + MTK_NOR_REG_IRQ_STAT); | |
| 640 | + writel(0, base + MTK_NOR_REG_IRQ_EN); | |
| 641 | + ret = devm_request_irq(sp->dev, irq, mtk_nor_irq_handler, 0, | |
| 642 | + pdev->name, sp); | |
| 643 | + if (ret < 0) { | |
| 644 | + dev_warn(sp->dev, "failed to request IRQ."); | |
| 645 | + } else { | |
| 646 | + init_completion(&sp->op_done); | |
| 647 | + sp->has_irq = true; | |
| 648 | + } | |
| 649 | + } | |
| 650 | + | |
| 651 | + ret = mtk_nor_init(sp); | |
| 652 | + if (ret < 0) { | |
| 653 | + kfree(ctlr); | |
| 654 | + return ret; | |
| 655 | + } | |
| 656 | + | |
| 657 | + dev_info(&pdev->dev, "spi frequency: %d Hz\n", sp->spi_freq); | |
| 658 | + | |
| 659 | + return devm_spi_register_controller(&pdev->dev, ctlr); | |
| 660 | +} | |
| 661 | + | |
| 662 | +static int mtk_nor_remove(struct platform_device *pdev) | |
| 663 | +{ | |
| 664 | + struct spi_controller *ctlr; | |
| 665 | + struct mtk_nor *sp; | |
| 666 | + | |
| 667 | + ctlr = dev_get_drvdata(&pdev->dev); | |
| 668 | + sp = spi_controller_get_devdata(ctlr); | |
| 669 | + | |
| 670 | + mtk_nor_disable_clk(sp); | |
| 671 | + | |
| 672 | + return 0; | |
| 673 | +} | |
| 674 | + | |
| 675 | +static struct platform_driver mtk_nor_driver = { | |
| 676 | + .driver = { | |
| 677 | + .name = DRIVER_NAME, | |
| 678 | + .of_match_table = mtk_nor_match, | |
| 679 | + }, | |
| 680 | + .probe = mtk_nor_probe, | |
| 681 | + .remove = mtk_nor_remove, | |
| 682 | +}; | |
| 683 | + | |
| 684 | +module_platform_driver(mtk_nor_driver); | |
| 685 | + | |
| 686 | +MODULE_DESCRIPTION("Mediatek SPI NOR controller driver"); | |
| 687 | +MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>"); | |
| 688 | +MODULE_LICENSE("GPL v2"); | |
| 689 | +MODULE_ALIAS("platform:" DRIVER_NAME); | |
| @@ -0,0 +1,187 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +// | |
| 3 | +// General Purpose SPI multiplexer | |
| 4 | + | |
| 5 | +#include <linux/err.h> | |
| 6 | +#include <linux/kernel.h> | |
| 7 | +#include <linux/module.h> | |
| 8 | +#include <linux/mux/consumer.h> | |
| 9 | +#include <linux/slab.h> | |
| 10 | +#include <linux/spi/spi.h> | |
| 11 | + | |
| 12 | +#define SPI_MUX_NO_CS ((unsigned int)-1) | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * DOC: Driver description | |
| 16 | + * | |
| 17 | + * This driver supports a MUX on an SPI bus. This can be useful when you need | |
| 18 | + * more chip selects than the hardware peripherals support, or than are | |
| 19 | + * available in a particular board setup. | |
| 20 | + * | |
| 21 | + * The driver will create an additional SPI controller. Devices added under the | |
| 22 | + * mux will be handled as 'chip selects' on this controller. | |
| 23 | + */ | |
| 24 | + | |
| 25 | +/** | |
| 26 | + * struct spi_mux_priv - the basic spi_mux structure | |
| 27 | + * @spi: pointer to the device struct attached to the parent | |
| 28 | + * spi controller | |
| 29 | + * @current_cs: The current chip select set in the mux | |
| 30 | + * @child_msg_complete: The mux replaces the complete callback in the child's | |
| 31 | + * message to its own callback; this field is used by the | |
| 32 | + * driver to store the child's callback during a transfer | |
| 33 | + * @child_msg_context: Used to store the child's context to the callback | |
| 34 | + * @child_msg_dev: Used to store the spi_device pointer to the child | |
| 35 | + * @mux: mux_control structure used to provide chip selects for | |
| 36 | + * downstream spi devices | |
| 37 | + */ | |
| 38 | +struct spi_mux_priv { | |
| 39 | + struct spi_device *spi; | |
| 40 | + unsigned int current_cs; | |
| 41 | + | |
| 42 | + void (*child_msg_complete)(void *context); | |
| 43 | + void *child_msg_context; | |
| 44 | + struct spi_device *child_msg_dev; | |
| 45 | + struct mux_control *mux; | |
| 46 | +}; | |
| 47 | + | |
| 48 | +/* should not get called when the parent controller is doing a transfer */ | |
| 49 | +static int spi_mux_select(struct spi_device *spi) | |
| 50 | +{ | |
| 51 | + struct spi_mux_priv *priv = spi_controller_get_devdata(spi->controller); | |
| 52 | + int ret; | |
| 53 | + | |
| 54 | + if (priv->current_cs == spi->chip_select) | |
| 55 | + return 0; | |
| 56 | + | |
| 57 | + dev_dbg(&priv->spi->dev, "setting up the mux for cs %d\n", | |
| 58 | + spi->chip_select); | |
| 59 | + | |
| 60 | + /* copy the child device's settings except for the cs */ | |
| 61 | + priv->spi->max_speed_hz = spi->max_speed_hz; | |
| 62 | + priv->spi->mode = spi->mode; | |
| 63 | + priv->spi->bits_per_word = spi->bits_per_word; | |
| 64 | + | |
| 65 | + ret = mux_control_select(priv->mux, spi->chip_select); | |
| 66 | + if (ret) | |
| 67 | + return ret; | |
| 68 | + | |
| 69 | + priv->current_cs = spi->chip_select; | |
| 70 | + | |
| 71 | + return 0; | |
| 72 | +} | |
| 73 | + | |
| 74 | +static int spi_mux_setup(struct spi_device *spi) | |
| 75 | +{ | |
| 76 | + struct spi_mux_priv *priv = spi_controller_get_devdata(spi->controller); | |
| 77 | + | |
| 78 | + /* | |
| 79 | + * can be called multiple times, won't do a valid setup now but we will | |
| 80 | + * change the settings when we do a transfer (necessary because we | |
| 81 | + * can't predict from which device it will be anyway) | |
| 82 | + */ | |
| 83 | + return spi_setup(priv->spi); | |
| 84 | +} | |
| 85 | + | |
| 86 | +static void spi_mux_complete_cb(void *context) | |
| 87 | +{ | |
| 88 | + struct spi_mux_priv *priv = (struct spi_mux_priv *)context; | |
| 89 | + struct spi_controller *ctlr = spi_get_drvdata(priv->spi); | |
| 90 | + struct spi_message *m = ctlr->cur_msg; | |
| 91 | + | |
| 92 | + m->complete = priv->child_msg_complete; | |
| 93 | + m->context = priv->child_msg_context; | |
| 94 | + m->spi = priv->child_msg_dev; | |
| 95 | + spi_finalize_current_message(ctlr); | |
| 96 | + mux_control_deselect(priv->mux); | |
| 97 | +} | |
| 98 | + | |
| 99 | +static int spi_mux_transfer_one_message(struct spi_controller *ctlr, | |
| 100 | + struct spi_message *m) | |
| 101 | +{ | |
| 102 | + struct spi_mux_priv *priv = spi_controller_get_devdata(ctlr); | |
| 103 | + struct spi_device *spi = m->spi; | |
| 104 | + int ret; | |
| 105 | + | |
| 106 | + ret = spi_mux_select(spi); | |
| 107 | + if (ret) | |
| 108 | + return ret; | |
| 109 | + | |
| 110 | + /* | |
| 111 | + * Replace the complete callback, context and spi_device with our own | |
| 112 | + * pointers. Save originals | |
| 113 | + */ | |
| 114 | + priv->child_msg_complete = m->complete; | |
| 115 | + priv->child_msg_context = m->context; | |
| 116 | + priv->child_msg_dev = m->spi; | |
| 117 | + | |
| 118 | + m->complete = spi_mux_complete_cb; | |
| 119 | + m->context = priv; | |
| 120 | + m->spi = priv->spi; | |
| 121 | + | |
| 122 | + /* do the transfer */ | |
| 123 | + return spi_async(priv->spi, m); | |
| 124 | +} | |
| 125 | + | |
| 126 | +static int spi_mux_probe(struct spi_device *spi) | |
| 127 | +{ | |
| 128 | + struct spi_controller *ctlr; | |
| 129 | + struct spi_mux_priv *priv; | |
| 130 | + int ret; | |
| 131 | + | |
| 132 | + ctlr = spi_alloc_master(&spi->dev, sizeof(*priv)); | |
| 133 | + if (!ctlr) | |
| 134 | + return -ENOMEM; | |
| 135 | + | |
| 136 | + spi_set_drvdata(spi, ctlr); | |
| 137 | + priv = spi_controller_get_devdata(ctlr); | |
| 138 | + priv->spi = spi; | |
| 139 | + | |
| 140 | + priv->mux = devm_mux_control_get(&spi->dev, NULL); | |
| 141 | + if (IS_ERR(priv->mux)) { | |
| 142 | + ret = PTR_ERR(priv->mux); | |
| 143 | + if (ret != -EPROBE_DEFER) | |
| 144 | + dev_err(&spi->dev, "failed to get control-mux\n"); | |
| 145 | + goto err_put_ctlr; | |
| 146 | + } | |
| 147 | + | |
| 148 | + priv->current_cs = SPI_MUX_NO_CS; | |
| 149 | + | |
| 150 | + /* supported modes are the same as our parent's */ | |
| 151 | + ctlr->mode_bits = spi->controller->mode_bits; | |
| 152 | + ctlr->flags = spi->controller->flags; | |
| 153 | + ctlr->transfer_one_message = spi_mux_transfer_one_message; | |
| 154 | + ctlr->setup = spi_mux_setup; | |
| 155 | + ctlr->num_chipselect = mux_control_states(priv->mux); | |
| 156 | + ctlr->bus_num = -1; | |
| 157 | + ctlr->dev.of_node = spi->dev.of_node; | |
| 158 | + | |
| 159 | + ret = devm_spi_register_controller(&spi->dev, ctlr); | |
| 160 | + if (ret) | |
| 161 | + goto err_put_ctlr; | |
| 162 | + | |
| 163 | + return 0; | |
| 164 | + | |
| 165 | +err_put_ctlr: | |
| 166 | + spi_controller_put(ctlr); | |
| 167 | + | |
| 168 | + return ret; | |
| 169 | +} | |
| 170 | + | |
| 171 | +static const struct of_device_id spi_mux_of_match[] = { | |
| 172 | + { .compatible = "spi-mux" }, | |
| 173 | + { } | |
| 174 | +}; | |
| 175 | + | |
| 176 | +static struct spi_driver spi_mux_driver = { | |
| 177 | + .probe = spi_mux_probe, | |
| 178 | + .driver = { | |
| 179 | + .name = "spi-mux", | |
| 180 | + .of_match_table = spi_mux_of_match, | |
| 181 | + }, | |
| 182 | +}; | |
| 183 | + | |
| 184 | +module_spi_driver(spi_mux_driver); | |
| 185 | + | |
| 186 | +MODULE_DESCRIPTION("SPI multiplexer"); | |
| 187 | +MODULE_LICENSE("GPL"); | |
| @@ -22,7 +22,6 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <linux/ioport.h> |
| 23 | 23 | #include <linux/of.h> |
| 24 | 24 | #include <linux/of_device.h> |
| 25 | −#include <linux/of_gpio.h> | |
| 26 | 25 | #include <linux/platform_device.h> |
| 27 | 26 | #include <linux/delay.h> |
| 28 | 27 | #include <linux/interrupt.h> |
| @@ -32,7 +31,7 @@ · 3 unmodified lines | ||
| 32 | 31 | #include <linux/clk.h> |
| 33 | 32 | #include <linux/err.h> |
| 34 | 33 | #include <linux/completion.h> |
| 35 | −#include <linux/gpio.h> | |
| 34 | +#include <linux/pinctrl/consumer.h> | |
| 36 | 35 | #include <linux/regulator/consumer.h> |
| 37 | 36 | #include <linux/pm_runtime.h> |
| 38 | 37 | #include <linux/module.h> |
| @@ -307,6 +307,7 @@ · 306 unmodified lines | ||
| 307 | 307 | |
| 308 | 308 | #define POLL_TOUT 5000 |
| 309 | 309 | #define NXP_FSPI_MAX_CHIPSELECT 4 |
| 310 | +#define NXP_FSPI_MIN_IOMAP SZ_4M | |
| 310 | 311 | |
| 311 | 312 | struct nxp_fspi_devtype_data { |
| 312 | 313 | unsigned int rxfifo; |
| @@ -324,11 +325,29 @@ static const struct nxp_fspi_devtype_data lx2160a_data = { · 11 unmodified lines | ||
| 324 | 325 | .little_endian = true, /* little-endian */ |
| 325 | 326 | }; |
| 326 | 327 | |
| 328 | +static const struct nxp_fspi_devtype_data imx8mm_data = { | |
| 329 | + .rxfifo = SZ_512, /* (64 * 64 bits) */ | |
| 330 | + .txfifo = SZ_1K, /* (128 * 64 bits) */ | |
| 331 | + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ | |
| 332 | + .quirks = 0, | |
| 333 | + .little_endian = true, /* little-endian */ | |
| 334 | +}; | |
| 335 | + | |
| 336 | +static const struct nxp_fspi_devtype_data imx8qxp_data = { | |
| 337 | + .rxfifo = SZ_512, /* (64 * 64 bits) */ | |
| 338 | + .txfifo = SZ_1K, /* (128 * 64 bits) */ | |
| 339 | + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ | |
| 340 | + .quirks = 0, | |
| 341 | + .little_endian = true, /* little-endian */ | |
| 342 | +}; | |
| 343 | + | |
| 327 | 344 | struct nxp_fspi { |
| 328 | 345 | void __iomem *iobase; |
| 329 | 346 | void __iomem *ahb_addr; |
| 330 | 347 | u32 memmap_phy; |
| 331 | 348 | u32 memmap_phy_size; |
| 349 | + u32 memmap_start; | |
| 350 | + u32 memmap_len; | |
| 332 | 351 | struct clk *clk, *clk_en; |
| 333 | 352 | struct device *dev; |
| 334 | 353 | struct completion c; |
| @@ -641,12 +660,35 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi) · 306 unmodified lines | ||
| 641 | 660 | f->selected = spi->chip_select; |
| 642 | 661 | } |
| 643 | 662 | |
| 644 | −static void nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op) | |
| 663 | +static int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op) | |
| 645 | 664 | { |
| 665 | + u32 start = op->addr.val; | |
| 646 | 666 | u32 len = op->data.nbytes; |
| 647 | 667 | |
| 668 | + /* if necessary, ioremap before AHB read */ | |
| 669 | + if ((!f->ahb_addr) || start < f->memmap_start || | |
| 670 | + start + len > f->memmap_start + f->memmap_len) { | |
| 671 | + if (f->ahb_addr) | |
| 672 | + iounmap(f->ahb_addr); | |
| 673 | + | |
| 674 | + f->memmap_start = start; | |
| 675 | + f->memmap_len = len > NXP_FSPI_MIN_IOMAP ? | |
| 676 | + len : NXP_FSPI_MIN_IOMAP; | |
| 677 | + | |
| 678 | + f->ahb_addr = ioremap_wc(f->memmap_phy + f->memmap_start, | |
| 679 | + f->memmap_len); | |
| 680 | + | |
| 681 | + if (!f->ahb_addr) { | |
| 682 | + dev_err(f->dev, "failed to alloc memory\n"); | |
| 683 | + return -ENOMEM; | |
| 684 | + } | |
| 685 | + } | |
| 686 | + | |
| 648 | 687 | /* Read out the data directly from the AHB buffer. */ |
| 649 | − memcpy_fromio(op->data.buf.in, (f->ahb_addr + op->addr.val), len); | |
| 688 | + memcpy_fromio(op->data.buf.in, | |
| 689 | + f->ahb_addr + start - f->memmap_start, len); | |
| 690 | + | |
| 691 | + return 0; | |
| 650 | 692 | } |
| 651 | 693 | |
| 652 | 694 | static void nxp_fspi_fill_txfifo(struct nxp_fspi *f, |
| @@ -806,7 +848,7 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) · 153 unmodified lines | ||
| 806 | 848 | */ |
| 807 | 849 | if (op->data.nbytes > (f->devtype_data->rxfifo - 4) && |
| 808 | 850 | op->data.dir == SPI_MEM_DATA_IN) { |
| 809 | − nxp_fspi_read_ahb(f, op); | |
| 851 | + err = nxp_fspi_read_ahb(f, op); | |
| 810 | 852 | } else { |
| 811 | 853 | if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) |
| 812 | 854 | nxp_fspi_fill_txfifo(f, op); |
| @@ -871,8 +913,9 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) · 58 unmodified lines | ||
| 871 | 913 | fspi_writel(f, FSPI_DLLBCR_OVRDEN, base + FSPI_DLLBCR); |
| 872 | 914 | |
| 873 | 915 | /* enable module */ |
| 874 | − fspi_writel(f, FSPI_MCR0_AHB_TIMEOUT(0xFF) | FSPI_MCR0_IP_TIMEOUT(0xFF), | |
| 875 | − base + FSPI_MCR0); | |
| 916 | + fspi_writel(f, FSPI_MCR0_AHB_TIMEOUT(0xFF) | | |
| 917 | + FSPI_MCR0_IP_TIMEOUT(0xFF) | (u32) FSPI_MCR0_OCTCOMB_EN, | |
| 918 | + base + FSPI_MCR0); | |
| 876 | 919 | |
| 877 | 920 | /* |
| 878 | 921 | * Disable same device enable bit and configure all slave devices |
| @@ -976,9 +1019,8 @@ static int nxp_fspi_probe(struct platform_device *pdev) · 97 unmodified lines | ||
| 976 | 1019 | |
| 977 | 1020 | /* find the resources - controller memory mapped space */ |
| 978 | 1021 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fspi_mmap"); |
| 979 | − f->ahb_addr = devm_ioremap_resource(dev, res); | |
| 980 | − if (IS_ERR(f->ahb_addr)) { | |
| 981 | − ret = PTR_ERR(f->ahb_addr); | |
| 1022 | + if (!res) { | |
| 1023 | + ret = -ENODEV; | |
| 982 | 1024 | goto err_put_ctrl; |
| 983 | 1025 | } |
| 984 | 1026 | |
| @@ -1057,6 +1099,9 @@ static int nxp_fspi_remove(struct platform_device *pdev) · 72 unmodified lines | ||
| 1057 | 1099 | |
| 1058 | 1100 | mutex_destroy(&f->lock); |
| 1059 | 1101 | |
| 1102 | + if (f->ahb_addr) | |
| 1103 | + iounmap(f->ahb_addr); | |
| 1104 | + | |
| 1060 | 1105 | return 0; |
| 1061 | 1106 | } |
| 1062 | 1107 | |
| @@ -1076,6 +1121,8 @@ static int nxp_fspi_resume(struct device *dev) · 13 unmodified lines | ||
| 1076 | 1121 | |
| 1077 | 1122 | static const struct of_device_id nxp_fspi_dt_ids[] = { |
| 1078 | 1123 | { .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, }, |
| 1124 | + { .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, }, | |
| 1125 | + { .compatible = "nxp,imx8qxp-fspi", .data = (void *)&imx8qxp_data, }, | |
| 1079 | 1126 | { /* sentinel */ } |
| 1080 | 1127 | }; |
| 1081 | 1128 | MODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids); |
| @@ -192,6 +192,11 @@ static bool is_quark_x1000_ssp(const struct driver_data *drv_data) · 191 unmodified lines | ||
| 192 | 192 | return drv_data->ssp_type == QUARK_X1000_SSP; |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | +static bool is_mmp2_ssp(const struct driver_data *drv_data) | |
| 196 | +{ | |
| 197 | + return drv_data->ssp_type == MMP2_SSP; | |
| 198 | +} | |
| 199 | + | |
| 195 | 200 | static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data) |
| 196 | 201 | { |
| 197 | 202 | switch (drv_data->ssp_type) { |
| @@ -486,8 +491,8 @@ int pxa2xx_spi_flush(struct driver_data *drv_data) · 288 unmodified lines | ||
| 486 | 491 | |
| 487 | 492 | static void pxa2xx_spi_off(struct driver_data *drv_data) |
| 488 | 493 | { |
| 489 | − /* On MMP, disabling SSE seems to corrupt the rx fifo */ | |
| 490 | − if (drv_data->ssp_type == MMP2_SSP) | |
| 494 | + /* On MMP, disabling SSE seems to corrupt the Rx FIFO */ | |
| 495 | + if (is_mmp2_ssp(drv_data)) | |
| 491 | 496 | return; |
| 492 | 497 | |
| 493 | 498 | pxa2xx_spi_write(drv_data, SSCR0, |
| @@ -1093,7 +1098,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, · 599 unmodified lines | ||
| 1093 | 1098 | || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask) |
| 1094 | 1099 | != (cr1 & change_mask)) { |
| 1095 | 1100 | /* stop the SSP, and update the other bits */ |
| 1096 | − if (drv_data->ssp_type != MMP2_SSP) | |
| 1101 | + if (!is_mmp2_ssp(drv_data)) | |
| 1097 | 1102 | pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE); |
| 1098 | 1103 | if (!pxa25x_ssp_comp(drv_data)) |
| 1099 | 1104 | pxa2xx_spi_write(drv_data, SSTO, chip->timeout); |
| @@ -1107,7 +1112,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, · 7 unmodified lines | ||
| 1107 | 1112 | pxa2xx_spi_write(drv_data, SSTO, chip->timeout); |
| 1108 | 1113 | } |
| 1109 | 1114 | |
| 1110 | − if (drv_data->ssp_type == MMP2_SSP) { | |
| 1115 | + if (is_mmp2_ssp(drv_data)) { | |
| 1111 | 1116 | u8 tx_level = (pxa2xx_spi_read(drv_data, SSSR) |
| 1112 | 1117 | & SSSR_TFL_MASK) >> 8; |
| 1113 | 1118 | |
| @@ -1571,18 +1576,18 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) · 457 unmodified lines | ||
| 1571 | 1576 | else if (pcidev_id) |
| 1572 | 1577 | type = (enum pxa_ssp_type)pcidev_id->driver_data; |
| 1573 | 1578 | else |
| 1574 | − return NULL; | |
| 1579 | + return ERR_PTR(-EINVAL); | |
| 1575 | 1580 | |
| 1576 | 1581 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
| 1577 | 1582 | if (!pdata) |
| 1578 | − return NULL; | |
| 1583 | + return ERR_PTR(-ENOMEM); | |
| 1579 | 1584 | |
| 1580 | 1585 | ssp = &pdata->ssp; |
| 1581 | 1586 | |
| 1582 | 1587 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 1583 | 1588 | ssp->mmio_base = devm_ioremap_resource(&pdev->dev, res); |
| 1584 | 1589 | if (IS_ERR(ssp->mmio_base)) |
| 1585 | − return NULL; | |
| 1590 | + return ERR_CAST(ssp->mmio_base); | |
| 1586 | 1591 | |
| 1587 | 1592 | ssp->phys_base = res->start; |
| 1588 | 1593 | |
| @@ -1596,11 +1601,11 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) · 7 unmodified lines | ||
| 1596 | 1601 | |
| 1597 | 1602 | ssp->clk = devm_clk_get(&pdev->dev, NULL); |
| 1598 | 1603 | if (IS_ERR(ssp->clk)) |
| 1599 | − return NULL; | |
| 1604 | + return ERR_CAST(ssp->clk); | |
| 1600 | 1605 | |
| 1601 | 1606 | ssp->irq = platform_get_irq(pdev, 0); |
| 1602 | 1607 | if (ssp->irq < 0) |
| 1603 | − return NULL; | |
| 1608 | + return ERR_PTR(ssp->irq); | |
| 1604 | 1609 | |
| 1605 | 1610 | ssp->type = type; |
| 1606 | 1611 | ssp->dev = &pdev->dev; |
| @@ -1657,9 +1662,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) · 50 unmodified lines | ||
| 1657 | 1662 | platform_info = dev_get_platdata(dev); |
| 1658 | 1663 | if (!platform_info) { |
| 1659 | 1664 | platform_info = pxa2xx_spi_init_pdata(pdev); |
| 1660 | − if (!platform_info) { | |
| 1665 | + if (IS_ERR(platform_info)) { | |
| 1661 | 1666 | dev_err(&pdev->dev, "missing platform data\n"); |
| 1662 | − return -ENODEV; | |
| 1667 | + return PTR_ERR(platform_info); | |
| 1663 | 1668 | } |
| 1664 | 1669 | } |
| 1665 | 1670 | |
| @@ -1907,11 +1912,7 @@ out_error_controller_alloc: · 241 unmodified lines | ||
| 1907 | 1912 | static int pxa2xx_spi_remove(struct platform_device *pdev) |
| 1908 | 1913 | { |
| 1909 | 1914 | struct driver_data *drv_data = platform_get_drvdata(pdev); |
| 1910 | − struct ssp_device *ssp; | |
| 1911 | − | |
| 1912 | − if (!drv_data) | |
| 1913 | − return 0; | |
| 1914 | − ssp = drv_data->ssp; | |
| 1915 | + struct ssp_device *ssp = drv_data->ssp; | |
| 1915 | 1916 | |
| 1916 | 1917 | pm_runtime_get_sync(&pdev->dev); |
| 1917 | 1918 | |
| @@ -843,14 +843,17 @@ static const struct dev_pm_ops rockchip_spi_pm = { · 842 unmodified lines | ||
| 843 | 843 | }; |
| 844 | 844 | |
| 845 | 845 | static const struct of_device_id rockchip_spi_dt_match[] = { |
| 846 | − { .compatible = "rockchip,rv1108-spi", }, | |
| 846 | + { .compatible = "rockchip,px30-spi", }, | |
| 847 | 847 | { .compatible = "rockchip,rk3036-spi", }, |
| 848 | 848 | { .compatible = "rockchip,rk3066-spi", }, |
| 849 | 849 | { .compatible = "rockchip,rk3188-spi", }, |
| 850 | 850 | { .compatible = "rockchip,rk3228-spi", }, |
| 851 | 851 | { .compatible = "rockchip,rk3288-spi", }, |
| 852 | + { .compatible = "rockchip,rk3308-spi", }, | |
| 853 | + { .compatible = "rockchip,rk3328-spi", }, | |
| 852 | 854 | { .compatible = "rockchip,rk3368-spi", }, |
| 853 | 855 | { .compatible = "rockchip,rk3399-spi", }, |
| 856 | + { .compatible = "rockchip,rv1108-spi", }, | |
| 854 | 857 | { }, |
| 855 | 858 | }; |
| 856 | 859 | MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match); |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #include <linux/sh_dma.h> |
| 25 | 25 | #include <linux/spi/spi.h> |
| 26 | 26 | #include <linux/spi/rspi.h> |
| 27 | +#include <linux/spinlock.h> | |
| 27 | 28 | |
| 28 | 29 | #define RSPI_SPCR 0x00 /* Control Register */ |
| 29 | 30 | #define RSPI_SSLP 0x01 /* Slave Select Polarity Register */ |
| @@ -79,8 +80,7 @@ · 49 unmodified lines | ||
| 79 | 80 | #define SPCR_BSWAP 0x01 /* Byte Swap of read-data for DMAC */ |
| 80 | 81 | |
| 81 | 82 | /* SSLP - Slave Select Polarity Register */ |
| 82 | −#define SSLP_SSL1P 0x02 /* SSL1 Signal Polarity Setting */ | |
| 83 | −#define SSLP_SSL0P 0x01 /* SSL0 Signal Polarity Setting */ | |
| 83 | +#define SSLP_SSLP(i) BIT(i) /* SSLi Signal Polarity Setting */ | |
| 84 | 84 | |
| 85 | 85 | /* SPPCR - Pin Control Register */ |
| 86 | 86 | #define SPPCR_MOIFE 0x20 /* MOSI Idle Value Fixing Enable */ |
| @@ -181,7 +181,9 @@ struct rspi_data { · 94 unmodified lines | ||
| 181 | 181 | void __iomem *addr; |
| 182 | 182 | u32 max_speed_hz; |
| 183 | 183 | struct spi_controller *ctlr; |
| 184 | + struct platform_device *pdev; | |
| 184 | 185 | wait_queue_head_t wait; |
| 186 | + spinlock_t lock; /* Protects RMW-access to RSPI_SSLP */ | |
| 185 | 187 | struct clk *clk; |
| 186 | 188 | u16 spcmd; |
| 187 | 189 | u8 spsr; |
| @@ -239,7 +241,7 @@ struct spi_ops { · 51 unmodified lines | ||
| 239 | 241 | int (*set_config_register)(struct rspi_data *rspi, int access_size); |
| 240 | 242 | int (*transfer_one)(struct spi_controller *ctlr, |
| 241 | 243 | struct spi_device *spi, struct spi_transfer *xfer); |
| 242 | − u16 mode_bits; | |
| 244 | + u16 extra_mode_bits; | |
| 243 | 245 | u16 flags; |
| 244 | 246 | u16 fifo_size; |
| 245 | 247 | u8 num_hw_ss; |
| @@ -919,6 +921,29 @@ static int qspi_setup_sequencer(struct rspi_data *rspi, · 673 unmodified lines | ||
| 919 | 921 | return 0; |
| 920 | 922 | } |
| 921 | 923 | |
| 924 | +static int rspi_setup(struct spi_device *spi) | |
| 925 | +{ | |
| 926 | + struct rspi_data *rspi = spi_controller_get_devdata(spi->controller); | |
| 927 | + u8 sslp; | |
| 928 | + | |
| 929 | + if (spi->cs_gpiod) | |
| 930 | + return 0; | |
| 931 | + | |
| 932 | + pm_runtime_get_sync(&rspi->pdev->dev); | |
| 933 | + spin_lock_irq(&rspi->lock); | |
| 934 | + | |
| 935 | + sslp = rspi_read8(rspi, RSPI_SSLP); | |
| 936 | + if (spi->mode & SPI_CS_HIGH) | |
| 937 | + sslp |= SSLP_SSLP(spi->chip_select); | |
| 938 | + else | |
| 939 | + sslp &= ~SSLP_SSLP(spi->chip_select); | |
| 940 | + rspi_write8(rspi, sslp, RSPI_SSLP); | |
| 941 | + | |
| 942 | + spin_unlock_irq(&rspi->lock); | |
| 943 | + pm_runtime_put(&rspi->pdev->dev); | |
| 944 | + return 0; | |
| 945 | +} | |
| 946 | + | |
| 922 | 947 | static int rspi_prepare_message(struct spi_controller *ctlr, |
| 923 | 948 | struct spi_message *msg) |
| 924 | 949 | { |
| @@ -933,6 +958,8 @@ static int rspi_prepare_message(struct spi_controller *ctlr, · 8 unmodified lines | ||
| 933 | 958 | rspi->spcmd |= SPCMD_CPOL; |
| 934 | 959 | if (spi->mode & SPI_CPHA) |
| 935 | 960 | rspi->spcmd |= SPCMD_CPHA; |
| 961 | + if (spi->mode & SPI_LSB_FIRST) | |
| 962 | + rspi->spcmd |= SPCMD_LSBF; | |
| 936 | 963 | |
| 937 | 964 | /* Configure slave signal to assert */ |
| 938 | 965 | rspi->spcmd |= SPCMD_SSLA(spi->cs_gpiod ? rspi->ctlr->unused_native_cs |
| @@ -1122,7 +1149,6 @@ static int rspi_remove(struct platform_device *pdev) · 183 unmodified lines | ||
| 1122 | 1149 | static const struct spi_ops rspi_ops = { |
| 1123 | 1150 | .set_config_register = rspi_set_config_register, |
| 1124 | 1151 | .transfer_one = rspi_transfer_one, |
| 1125 | − .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, | |
| 1126 | 1152 | .flags = SPI_CONTROLLER_MUST_TX, |
| 1127 | 1153 | .fifo_size = 8, |
| 1128 | 1154 | .num_hw_ss = 2, |
| @@ -1131,7 +1157,6 @@ static const struct spi_ops rspi_ops = { · 2 unmodified lines | ||
| 1131 | 1157 | static const struct spi_ops rspi_rz_ops = { |
| 1132 | 1158 | .set_config_register = rspi_rz_set_config_register, |
| 1133 | 1159 | .transfer_one = rspi_rz_transfer_one, |
| 1134 | − .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, | |
| 1135 | 1160 | .flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX, |
| 1136 | 1161 | .fifo_size = 8, /* 8 for TX, 32 for RX */ |
| 1137 | 1162 | .num_hw_ss = 1, |
| @@ -1140,8 +1165,7 @@ static const struct spi_ops rspi_rz_ops = { · 2 unmodified lines | ||
| 1140 | 1165 | static const struct spi_ops qspi_ops = { |
| 1141 | 1166 | .set_config_register = qspi_set_config_register, |
| 1142 | 1167 | .transfer_one = qspi_transfer_one, |
| 1143 | − .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP | | |
| 1144 | − SPI_TX_DUAL | SPI_TX_QUAD | | |
| 1168 | + .extra_mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | | |
| 1145 | 1169 | SPI_RX_DUAL | SPI_RX_QUAD, |
| 1146 | 1170 | .flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX, |
| 1147 | 1171 | .fifo_size = 32, |
| @@ -1249,16 +1273,20 @@ static int rspi_probe(struct platform_device *pdev) · 101 unmodified lines | ||
| 1249 | 1273 | goto error1; |
| 1250 | 1274 | } |
| 1251 | 1275 | |
| 1276 | + rspi->pdev = pdev; | |
| 1252 | 1277 | pm_runtime_enable(&pdev->dev); |
| 1253 | 1278 | |
| 1254 | 1279 | init_waitqueue_head(&rspi->wait); |
| 1280 | + spin_lock_init(&rspi->lock); | |
| 1255 | 1281 | |
| 1256 | 1282 | ctlr->bus_num = pdev->id; |
| 1283 | + ctlr->setup = rspi_setup; | |
| 1257 | 1284 | ctlr->auto_runtime_pm = true; |
| 1258 | 1285 | ctlr->transfer_one = ops->transfer_one; |
| 1259 | 1286 | ctlr->prepare_message = rspi_prepare_message; |
| 1260 | 1287 | ctlr->unprepare_message = rspi_unprepare_message; |
| 1261 | − ctlr->mode_bits = ops->mode_bits; | |
| 1288 | + ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | | |
| 1289 | + SPI_LOOP | ops->extra_mode_bits; | |
| 1262 | 1290 | ctlr->flags = ops->flags; |
| 1263 | 1291 | ctlr->dev.of_node = pdev->dev.of_node; |
| 1264 | 1292 | ctlr->use_gpio_descriptors = true; |
| @@ -227,7 +227,7 @@ static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count) · 226 unmodified lines | ||
| 227 | 227 | struct spi_fiq_code { |
| 228 | 228 | u32 length; |
| 229 | 229 | u32 ack_offset; |
| 230 | − u8 data[0]; | |
| 230 | + u8 data[]; | |
| 231 | 231 | }; |
| 232 | 232 | |
| 233 | 233 | extern struct spi_fiq_code s3c24xx_spi_fiq_txrx; |
| @@ -565,7 +565,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) · 564 unmodified lines | ||
| 565 | 565 | qspi->io_base = devm_ioremap_resource(dev, res); |
| 566 | 566 | if (IS_ERR(qspi->io_base)) { |
| 567 | 567 | ret = PTR_ERR(qspi->io_base); |
| 568 | − goto err; | |
| 568 | + goto err_master_put; | |
| 569 | 569 | } |
| 570 | 570 | |
| 571 | 571 | qspi->phys_base = res->start; |
| @@ -574,24 +574,26 @@ static int stm32_qspi_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 574 | 574 | qspi->mm_base = devm_ioremap_resource(dev, res); |
| 575 | 575 | if (IS_ERR(qspi->mm_base)) { |
| 576 | 576 | ret = PTR_ERR(qspi->mm_base); |
| 577 | − goto err; | |
| 577 | + goto err_master_put; | |
| 578 | 578 | } |
| 579 | 579 | |
| 580 | 580 | qspi->mm_size = resource_size(res); |
| 581 | 581 | if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) { |
| 582 | 582 | ret = -EINVAL; |
| 583 | − goto err; | |
| 583 | + goto err_master_put; | |
| 584 | 584 | } |
| 585 | 585 | |
| 586 | 586 | irq = platform_get_irq(pdev, 0); |
| 587 | − if (irq < 0) | |
| 588 | − return irq; | |
| 587 | + if (irq < 0) { | |
| 588 | + ret = irq; | |
| 589 | + goto err_master_put; | |
| 590 | + } | |
| 589 | 591 | |
| 590 | 592 | ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, |
| 591 | 593 | dev_name(dev), qspi); |
| 592 | 594 | if (ret) { |
| 593 | 595 | dev_err(dev, "failed to request irq\n"); |
| 594 | − goto err; | |
| 596 | + goto err_master_put; | |
| 595 | 597 | } |
| 596 | 598 | |
| 597 | 599 | init_completion(&qspi->data_completion); |
| @@ -599,23 +601,27 @@ static int stm32_qspi_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 599 | 601 | qspi->clk = devm_clk_get(dev, NULL); |
| 600 | 602 | if (IS_ERR(qspi->clk)) { |
| 601 | 603 | ret = PTR_ERR(qspi->clk); |
| 602 | − goto err; | |
| 604 | + goto err_master_put; | |
| 603 | 605 | } |
| 604 | 606 | |
| 605 | 607 | qspi->clk_rate = clk_get_rate(qspi->clk); |
| 606 | 608 | if (!qspi->clk_rate) { |
| 607 | 609 | ret = -EINVAL; |
| 608 | − goto err; | |
| 610 | + goto err_master_put; | |
| 609 | 611 | } |
| 610 | 612 | |
| 611 | 613 | ret = clk_prepare_enable(qspi->clk); |
| 612 | 614 | if (ret) { |
| 613 | 615 | dev_err(dev, "can not enable the clock\n"); |
| 614 | − goto err; | |
| 616 | + goto err_master_put; | |
| 615 | 617 | } |
| 616 | 618 | |
| 617 | 619 | rstc = devm_reset_control_get_exclusive(dev, NULL); |
| 618 | − if (!IS_ERR(rstc)) { | |
| 620 | + if (IS_ERR(rstc)) { | |
| 621 | + ret = PTR_ERR(rstc); | |
| 622 | + if (ret == -EPROBE_DEFER) | |
| 623 | + goto err_qspi_release; | |
| 624 | + } else { | |
| 619 | 625 | reset_control_assert(rstc); |
| 620 | 626 | udelay(2); |
| 621 | 627 | reset_control_deassert(rstc); |
| @@ -625,7 +631,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) · 3 unmodified lines | ||
| 625 | 631 | platform_set_drvdata(pdev, qspi); |
| 626 | 632 | ret = stm32_qspi_dma_setup(qspi); |
| 627 | 633 | if (ret) |
| 628 | − goto err; | |
| 634 | + goto err_qspi_release; | |
| 629 | 635 | |
| 630 | 636 | mutex_init(&qspi->lock); |
| 631 | 637 | |
| @@ -641,8 +647,9 @@ static int stm32_qspi_probe(struct platform_device *pdev) · 9 unmodified lines | ||
| 641 | 647 | if (!ret) |
| 642 | 648 | return 0; |
| 643 | 649 | |
| 644 | −err: | |
| 650 | +err_qspi_release: | |
| 645 | 651 | stm32_qspi_release(qspi); |
| 652 | +err_master_put: | |
| 646 | 653 | spi_master_put(qspi->ctrl); |
| 647 | 654 | |
| 648 | 655 | return ret; |
| @@ -175,7 +175,7 @@ · 174 unmodified lines | ||
| 175 | 175 | #define SPI_DMA_MIN_BYTES 16 |
| 176 | 176 | |
| 177 | 177 | /** |
| 178 | − * stm32_spi_reg - stm32 SPI register & bitfield desc | |
| 178 | + * struct stm32_spi_reg - stm32 SPI register & bitfield desc | |
| 179 | 179 | * @reg: register offset |
| 180 | 180 | * @mask: bitfield mask |
| 181 | 181 | * @shift: left shift |
| @@ -187,16 +187,16 @@ struct stm32_spi_reg { · 5 unmodified lines | ||
| 187 | 187 | }; |
| 188 | 188 | |
| 189 | 189 | /** |
| 190 | − * stm32_spi_regspec - stm32 registers definition, compatible dependent data | |
| 191 | − * en: enable register and SPI enable bit | |
| 192 | − * dma_rx_en: SPI DMA RX enable register end SPI DMA RX enable bit | |
| 193 | − * dma_tx_en: SPI DMA TX enable register end SPI DMA TX enable bit | |
| 194 | − * cpol: clock polarity register and polarity bit | |
| 195 | − * cpha: clock phase register and phase bit | |
| 196 | − * lsb_first: LSB transmitted first register and bit | |
| 197 | − * br: baud rate register and bitfields | |
| 198 | − * rx: SPI RX data register | |
| 199 | − * tx: SPI TX data register | |
| 190 | + * struct stm32_spi_regspec - stm32 registers definition, compatible dependent data | |
| 191 | + * @en: enable register and SPI enable bit | |
| 192 | + * @dma_rx_en: SPI DMA RX enable register end SPI DMA RX enable bit | |
| 193 | + * @dma_tx_en: SPI DMA TX enable register end SPI DMA TX enable bit | |
| 194 | + * @cpol: clock polarity register and polarity bit | |
| 195 | + * @cpha: clock phase register and phase bit | |
| 196 | + * @lsb_first: LSB transmitted first register and bit | |
| 197 | + * @br: baud rate register and bitfields | |
| 198 | + * @rx: SPI RX data register | |
| 199 | + * @tx: SPI TX data register | |
| 200 | 200 | */ |
| 201 | 201 | struct stm32_spi_regspec { |
| 202 | 202 | const struct stm32_spi_reg en; |
| @@ -213,7 +213,7 @@ struct stm32_spi_regspec { · 10 unmodified lines | ||
| 213 | 213 | struct stm32_spi; |
| 214 | 214 | |
| 215 | 215 | /** |
| 216 | − * stm32_spi_cfg - stm32 compatible configuration data | |
| 216 | + * struct stm32_spi_cfg - stm32 compatible configuration data | |
| 217 | 217 | * @regs: registers descriptions |
| 218 | 218 | * @get_fifo_size: routine to get fifo size |
| 219 | 219 | * @get_bpw_mask: routine to get bits per word mask |
| @@ -223,13 +223,13 @@ struct stm32_spi; · 3 unmodified lines | ||
| 223 | 223 | * @set_mode: routine to configure registers to desired mode |
| 224 | 224 | * @set_data_idleness: optional routine to configure registers to desired idle |
| 225 | 225 | * time between frames (if driver has this functionality) |
| 226 | − * set_number_of_data: optional routine to configure registers to desired | |
| 226 | + * @set_number_of_data: optional routine to configure registers to desired | |
| 227 | 227 | * number of data (if driver has this functionality) |
| 228 | 228 | * @can_dma: routine to determine if the transfer is eligible for DMA use |
| 229 | 229 | * @transfer_one_dma_start: routine to start transfer a single spi_transfer |
| 230 | 230 | * using DMA |
| 231 | − * @dma_rx cb: routine to call after DMA RX channel operation is complete | |
| 232 | − * @dma_tx cb: routine to call after DMA TX channel operation is complete | |
| 231 | + * @dma_rx_cb: routine to call after DMA RX channel operation is complete | |
| 232 | + * @dma_tx_cb: routine to call after DMA TX channel operation is complete | |
| 233 | 233 | * @transfer_one_irq: routine to configure interrupts for driver |
| 234 | 234 | * @irq_handler_event: Interrupt handler for SPI controller events |
| 235 | 235 | * @irq_handler_thread: thread of interrupt handler for SPI controller |
| @@ -587,6 +587,7 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi) · 351 unmodified lines | ||
| 587 | 587 | /** |
| 588 | 588 | * stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register |
| 589 | 589 | * @spi: pointer to the spi controller data structure |
| 590 | + * @flush: boolean indicating that FIFO should be flushed | |
| 590 | 591 | * |
| 591 | 592 | * Write in rx_buf depends on remaining bytes to avoid to write beyond |
| 592 | 593 | * rx_buf end. |
| @@ -756,6 +757,9 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) · 163 unmodified lines | ||
| 756 | 757 | |
| 757 | 758 | /** |
| 758 | 759 | * stm32_spi_can_dma - Determine if the transfer is eligible for DMA use |
| 760 | + * @master: controller master interface | |
| 761 | + * @spi_dev: pointer to the spi device | |
| 762 | + * @transfer: pointer to spi transfer | |
| 759 | 763 | * |
| 760 | 764 | * If driver has fifo and the current transfer size is greater than fifo size, |
| 761 | 765 | * use DMA. Otherwise use DMA for transfer longer than defined DMA min bytes. |
| @@ -974,6 +978,8 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) · 212 unmodified lines | ||
| 974 | 978 | |
| 975 | 979 | /** |
| 976 | 980 | * stm32_spi_prepare_msg - set up the controller to transfer a single message |
| 981 | + * @master: controller master interface | |
| 982 | + * @msg: pointer to spi message | |
| 977 | 983 | */ |
| 978 | 984 | static int stm32_spi_prepare_msg(struct spi_master *master, |
| 979 | 985 | struct spi_message *msg) |
| @@ -1026,6 +1032,7 @@ static int stm32_spi_prepare_msg(struct spi_master *master, · 46 unmodified lines | ||
| 1026 | 1032 | |
| 1027 | 1033 | /** |
| 1028 | 1034 | * stm32f4_spi_dma_tx_cb - dma callback |
| 1035 | + * @data: pointer to the spi controller data structure | |
| 1029 | 1036 | * |
| 1030 | 1037 | * DMA callback is called when the transfer is complete for DMA TX channel. |
| 1031 | 1038 | */ |
| @@ -1041,6 +1048,7 @@ static void stm32f4_spi_dma_tx_cb(void *data) · 9 unmodified lines | ||
| 1041 | 1048 | |
| 1042 | 1049 | /** |
| 1043 | 1050 | * stm32f4_spi_dma_rx_cb - dma callback |
| 1051 | + * @data: pointer to the spi controller data structure | |
| 1044 | 1052 | * |
| 1045 | 1053 | * DMA callback is called when the transfer is complete for DMA RX channel. |
| 1046 | 1054 | */ |
| @@ -1054,6 +1062,7 @@ static void stm32f4_spi_dma_rx_cb(void *data) · 7 unmodified lines | ||
| 1054 | 1062 | |
| 1055 | 1063 | /** |
| 1056 | 1064 | * stm32h7_spi_dma_cb - dma callback |
| 1065 | + * @data: pointer to the spi controller data structure | |
| 1057 | 1066 | * |
| 1058 | 1067 | * DMA callback is called when the transfer is complete or when an error |
| 1059 | 1068 | * occurs. If the transfer is complete, EOT flag is raised. |
| @@ -1079,6 +1088,9 @@ static void stm32h7_spi_dma_cb(void *data) · 19 unmodified lines | ||
| 1079 | 1088 | /** |
| 1080 | 1089 | * stm32_spi_dma_config - configure dma slave channel depending on current |
| 1081 | 1090 | * transfer bits_per_word. |
| 1091 | + * @spi: pointer to the spi controller data structure | |
| 1092 | + * @dma_conf: pointer to the dma_slave_config structure | |
| 1093 | + * @dir: direction of the dma transfer | |
| 1082 | 1094 | */ |
| 1083 | 1095 | static void stm32_spi_dma_config(struct stm32_spi *spi, |
| 1084 | 1096 | struct dma_slave_config *dma_conf, |
| @@ -1126,6 +1138,7 @@ static void stm32_spi_dma_config(struct stm32_spi *spi, · 41 unmodified lines | ||
| 1126 | 1138 | /** |
| 1127 | 1139 | * stm32f4_spi_transfer_one_irq - transfer a single spi_transfer using |
| 1128 | 1140 | * interrupts |
| 1141 | + * @spi: pointer to the spi controller data structure | |
| 1129 | 1142 | * |
| 1130 | 1143 | * It must returns 0 if the transfer is finished or 1 if the transfer is still |
| 1131 | 1144 | * in progress. |
| @@ -1166,6 +1179,7 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi) · 34 unmodified lines | ||
| 1166 | 1179 | /** |
| 1167 | 1180 | * stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using |
| 1168 | 1181 | * interrupts |
| 1182 | + * @spi: pointer to the spi controller data structure | |
| 1169 | 1183 | * |
| 1170 | 1184 | * It must returns 0 if the transfer is finished or 1 if the transfer is still |
| 1171 | 1185 | * in progress. |
| @@ -1207,6 +1221,7 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) · 35 unmodified lines | ||
| 1207 | 1221 | /** |
| 1208 | 1222 | * stm32f4_spi_transfer_one_dma_start - Set SPI driver registers to start |
| 1209 | 1223 | * transfer using DMA |
| 1224 | + * @spi: pointer to the spi controller data structure | |
| 1210 | 1225 | */ |
| 1211 | 1226 | static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) |
| 1212 | 1227 | { |
| @@ -1227,6 +1242,7 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) · 14 unmodified lines | ||
| 1227 | 1242 | /** |
| 1228 | 1243 | * stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start |
| 1229 | 1244 | * transfer using DMA |
| 1245 | + * @spi: pointer to the spi controller data structure | |
| 1230 | 1246 | */ |
| 1231 | 1247 | static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) |
| 1232 | 1248 | { |
| @@ -1243,6 +1259,8 @@ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) · 10 unmodified lines | ||
| 1243 | 1259 | |
| 1244 | 1260 | /** |
| 1245 | 1261 | * stm32_spi_transfer_one_dma - transfer a single spi_transfer using DMA |
| 1262 | + * @spi: pointer to the spi controller data structure | |
| 1263 | + * @xfer: pointer to the spi_transfer structure | |
| 1246 | 1264 | * |
| 1247 | 1265 | * It must returns 0 if the transfer is finished or 1 if the transfer is still |
| 1248 | 1266 | * in progress. |
| @@ -1405,7 +1423,7 @@ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv) · 156 unmodified lines | ||
| 1405 | 1423 | /** |
| 1406 | 1424 | * stm32_spi_communication_type - return transfer communication type |
| 1407 | 1425 | * @spi_dev: pointer to the spi device |
| 1408 | − * transfer: pointer to spi transfer | |
| 1426 | + * @transfer: pointer to spi transfer | |
| 1409 | 1427 | */ |
| 1410 | 1428 | static unsigned int stm32_spi_communication_type(struct spi_device *spi_dev, |
| 1411 | 1429 | struct spi_transfer *transfer) |
| @@ -1522,7 +1540,7 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) · 110 unmodified lines | ||
| 1522 | 1540 | /** |
| 1523 | 1541 | * stm32h7_spi_number_of_data - configure number of data at current transfer |
| 1524 | 1542 | * @spi: pointer to the spi controller data structure |
| 1525 | − * @len: transfer length | |
| 1543 | + * @nb_words: transfer length (in words) | |
| 1526 | 1544 | */ |
| 1527 | 1545 | static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) |
| 1528 | 1546 | { |
| @@ -1546,6 +1564,9 @@ static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) · 17 unmodified lines | ||
| 1546 | 1564 | * stm32_spi_transfer_one_setup - common setup to transfer a single |
| 1547 | 1565 | * spi_transfer either using DMA or |
| 1548 | 1566 | * interrupts. |
| 1567 | + * @spi: pointer to the spi controller data structure | |
| 1568 | + * @spi_dev: pointer to the spi device | |
| 1569 | + * @transfer: pointer to spi transfer | |
| 1549 | 1570 | */ |
| 1550 | 1571 | static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, |
| 1551 | 1572 | struct spi_device *spi_dev, |
| @@ -1625,6 +1646,9 @@ out: · 73 unmodified lines | ||
| 1625 | 1646 | |
| 1626 | 1647 | /** |
| 1627 | 1648 | * stm32_spi_transfer_one - transfer a single spi_transfer |
| 1649 | + * @master: controller master interface | |
| 1650 | + * @spi_dev: pointer to the spi device | |
| 1651 | + * @transfer: pointer to spi transfer | |
| 1628 | 1652 | * |
| 1629 | 1653 | * It must return 0 if the transfer is finished or 1 if the transfer is still |
| 1630 | 1654 | * in progress. |
| @@ -1658,6 +1682,8 @@ static int stm32_spi_transfer_one(struct spi_master *master, · 27 unmodified lines | ||
| 1658 | 1682 | |
| 1659 | 1683 | /** |
| 1660 | 1684 | * stm32_spi_unprepare_msg - relax the hardware |
| 1685 | + * @master: controller master interface | |
| 1686 | + * @msg: pointer to the spi message | |
| 1661 | 1687 | */ |
| 1662 | 1688 | static int stm32_spi_unprepare_msg(struct spi_master *master, |
| 1663 | 1689 | struct spi_message *msg) |
| @@ -1671,6 +1697,7 @@ static int stm32_spi_unprepare_msg(struct spi_master *master, · 7 unmodified lines | ||
| 1671 | 1697 | |
| 1672 | 1698 | /** |
| 1673 | 1699 | * stm32f4_spi_config - Configure SPI controller as SPI master |
| 1700 | + * @spi: pointer to the spi controller data structure | |
| 1674 | 1701 | */ |
| 1675 | 1702 | static int stm32f4_spi_config(struct stm32_spi *spi) |
| 1676 | 1703 | { |
| @@ -1701,6 +1728,7 @@ static int stm32f4_spi_config(struct stm32_spi *spi) · 24 unmodified lines | ||
| 1701 | 1728 | |
| 1702 | 1729 | /** |
| 1703 | 1730 | * stm32h7_spi_config - Configure SPI controller as SPI master |
| 1731 | + * @spi: pointer to the spi controller data structure | |
| 1704 | 1732 | */ |
| 1705 | 1733 | static int stm32h7_spi_config(struct stm32_spi *spi) |
| 1706 | 1734 | { |
| @@ -510,6 +510,7 @@ struct spi_device *spi_alloc_device(struct spi_controller *ctlr) · 509 unmodified lines | ||
| 510 | 510 | spi->dev.bus = &spi_bus_type; |
| 511 | 511 | spi->dev.release = spidev_release; |
| 512 | 512 | spi->cs_gpio = -ENOENT; |
| 513 | + spi->mode = ctlr->buswidth_override_bits; | |
| 513 | 514 | |
| 514 | 515 | spin_lock_init(&spi->statistics.lock); |
| 515 | 516 | |
| @@ -1514,17 +1515,15 @@ void spi_take_timestamp_pre(struct spi_controller *ctlr, · 998 unmodified lines | ||
| 1514 | 1515 | if (!xfer->ptp_sts) |
| 1515 | 1516 | return; |
| 1516 | 1517 | |
| 1517 | − if (xfer->timestamped_pre) | |
| 1518 | + if (xfer->timestamped) | |
| 1518 | 1519 | return; |
| 1519 | 1520 | |
| 1520 | − if (progress < xfer->ptp_sts_word_pre) | |
| 1521 | + if (progress > xfer->ptp_sts_word_pre) | |
| 1521 | 1522 | return; |
| 1522 | 1523 | |
| 1523 | 1524 | /* Capture the resolution of the timestamp */ |
| 1524 | 1525 | xfer->ptp_sts_word_pre = progress; |
| 1525 | 1526 | |
| 1526 | − xfer->timestamped_pre = true; | |
| 1527 | − | |
| 1528 | 1527 | if (irqs_off) { |
| 1529 | 1528 | local_irq_save(ctlr->irq_flags); |
| 1530 | 1529 | preempt_disable(); |
| @@ -1553,7 +1552,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr, · 22 unmodified lines | ||
| 1553 | 1552 | if (!xfer->ptp_sts) |
| 1554 | 1553 | return; |
| 1555 | 1554 | |
| 1556 | − if (xfer->timestamped_post) | |
| 1555 | + if (xfer->timestamped) | |
| 1557 | 1556 | return; |
| 1558 | 1557 | |
| 1559 | 1558 | if (progress < xfer->ptp_sts_word_post) |
| @@ -1569,7 +1568,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr, · 9 unmodified lines | ||
| 1569 | 1568 | /* Capture the resolution of the timestamp */ |
| 1570 | 1569 | xfer->ptp_sts_word_post = progress; |
| 1571 | 1570 | |
| 1572 | − xfer->timestamped_post = true; | |
| 1571 | + xfer->timestamped = true; | |
| 1573 | 1572 | } |
| 1574 | 1573 | EXPORT_SYMBOL_GPL(spi_take_timestamp_post); |
| 1575 | 1574 | |
| @@ -1674,12 +1673,9 @@ void spi_finalize_current_message(struct spi_controller *ctlr) · 98 unmodified lines | ||
| 1674 | 1673 | } |
| 1675 | 1674 | } |
| 1676 | 1675 | |
| 1677 | − if (unlikely(ctlr->ptp_sts_supported)) { | |
| 1678 | − list_for_each_entry(xfer, &mesg->transfers, transfer_list) { | |
| 1679 | − WARN_ON_ONCE(xfer->ptp_sts && !xfer->timestamped_pre); | |
| 1680 | − WARN_ON_ONCE(xfer->ptp_sts && !xfer->timestamped_post); | |
| 1681 | − } | |
| 1682 | − } | |
| 1676 | + if (unlikely(ctlr->ptp_sts_supported)) | |
| 1677 | + list_for_each_entry(xfer, &mesg->transfers, transfer_list) | |
| 1678 | + WARN_ON_ONCE(xfer->ptp_sts && !xfer->timestamped); | |
| 1683 | 1679 | |
| 1684 | 1680 | spi_unmap_msg(ctlr, mesg); |
| 1685 | 1681 | |
| @@ -1955,13 +1951,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, · 269 unmodified lines | ||
| 1955 | 1951 | spi->mode |= SPI_CS_HIGH; |
| 1956 | 1952 | |
| 1957 | 1953 | /* Device speed */ |
| 1958 | − rc = of_property_read_u32(nc, "spi-max-frequency", &value); | |
| 1959 | − if (rc) { | |
| 1960 | − dev_err(&ctlr->dev, | |
| 1961 | − "%pOF has no valid 'spi-max-frequency' property (%d)\n", nc, rc); | |
| 1962 | − return rc; | |
| 1963 | − } | |
| 1964 | − spi->max_speed_hz = value; | |
| 1954 | + if (!of_property_read_u32(nc, "spi-max-frequency", &value)) | |
| 1955 | + spi->max_speed_hz = value; | |
| 1965 | 1956 | |
| 1966 | 1957 | return 0; |
| 1967 | 1958 | } |
| @@ -2181,9 +2172,10 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, · 213 unmodified lines | ||
| 2181 | 2172 | return AE_NO_MEMORY; |
| 2182 | 2173 | } |
| 2183 | 2174 | |
| 2175 | + | |
| 2184 | 2176 | ACPI_COMPANION_SET(&spi->dev, adev); |
| 2185 | 2177 | spi->max_speed_hz = lookup.max_speed_hz; |
| 2186 | − spi->mode = lookup.mode; | |
| 2178 | + spi->mode |= lookup.mode; | |
| 2187 | 2179 | spi->irq = lookup.irq; |
| 2188 | 2180 | spi->bits_per_word = lookup.bits_per_word; |
| 2189 | 2181 | spi->chip_select = lookup.chip_select; |
| @@ -4034,7 +4026,7 @@ static struct spi_device *acpi_spi_find_device_by_adev(struct acpi_device *adev) · 1844 unmodified lines | ||
| 4034 | 4026 | struct device *dev; |
| 4035 | 4027 | |
| 4036 | 4028 | dev = bus_find_device_by_acpi_dev(&spi_bus_type, adev); |
| 4037 | − return dev ? to_spi_device(dev) : NULL; | |
| 4029 | + return to_spi_device(dev); | |
| 4038 | 4030 | } |
| 4039 | 4031 | |
| 4040 | 4032 | static int acpi_spi_notify(struct notifier_block *nb, unsigned long value, |
| @@ -275,14 +275,14 @@ static int spidev_message(struct spidev_data *spidev, · 274 unmodified lines | ||
| 275 | 275 | #ifdef VERBOSE |
| 276 | 276 | dev_dbg(&spidev->spi->dev, |
| 277 | 277 | " xfer len %u %s%s%s%dbits %u usec %u usec %uHz\n", |
| 278 | − u_tmp->len, | |
| 279 | − u_tmp->rx_buf ? "rx " : "", | |
| 280 | − u_tmp->tx_buf ? "tx " : "", | |
| 281 | − u_tmp->cs_change ? "cs " : "", | |
| 282 | − u_tmp->bits_per_word ? : spidev->spi->bits_per_word, | |
| 283 | − u_tmp->delay_usecs, | |
| 284 | − u_tmp->word_delay_usecs, | |
| 285 | − u_tmp->speed_hz ? : spidev->spi->max_speed_hz); | |
| 278 | + k_tmp->len, | |
| 279 | + k_tmp->rx_buf ? "rx " : "", | |
| 280 | + k_tmp->tx_buf ? "tx " : "", | |
| 281 | + k_tmp->cs_change ? "cs " : "", | |
| 282 | + k_tmp->bits_per_word ? : spidev->spi->bits_per_word, | |
| 283 | + k_tmp->delay.value, | |
| 284 | + k_tmp->word_delay.value, | |
| 285 | + k_tmp->speed_hz ? : spidev->spi->max_speed_hz); | |
| 286 | 286 | #endif |
| 287 | 287 | spi_message_add_tail(k_tmp, &msg); |
| 288 | 288 | } |
| @@ -454,10 +454,11 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 165 unmodified lines | ||
| 454 | 454 | |
| 455 | 455 | spi->max_speed_hz = tmp; |
| 456 | 456 | retval = spi_setup(spi); |
| 457 | − if (retval >= 0) | |
| 457 | + if (retval == 0) { | |
| 458 | 458 | spidev->speed_hz = tmp; |
| 459 | − else | |
| 460 | − dev_dbg(&spi->dev, "%d Hz (max)\n", tmp); | |
| 459 | + dev_dbg(&spi->dev, "%d Hz (max)\n", | |
| 460 | + spidev->speed_hz); | |
| 461 | + } | |
| 461 | 462 | spi->max_speed_hz = save; |
| 462 | 463 | } |
| 463 | 464 | break; |
| @@ -135,6 +135,8 @@ extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer); · 134 unmodified lines | ||
| 135 | 135 | * @modalias: Name of the driver to use with this device, or an alias |
| 136 | 136 | * for that name. This appears in the sysfs "modalias" attribute |
| 137 | 137 | * for driver coldplugging, and in uevents used for hotplugging |
| 138 | + * @driver_override: If the name of a driver is written to this attribute, then | |
| 139 | + * the device will bind to the named driver and only the named driver. | |
| 138 | 140 | * @cs_gpio: LEGACY: gpio number of the chipselect line (optional, -ENOENT when |
| 139 | 141 | * not using a GPIO line) use cs_gpiod in new drivers by opting in on |
| 140 | 142 | * the spi_master. |
| @@ -443,6 +445,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) · 302 unmodified lines | ||
| 443 | 445 | * @spi_transfer->ptp_sts_word_post were transmitted. |
| 444 | 446 | * If the driver does not set this, the SPI core takes the snapshot as |
| 445 | 447 | * close to the driver hand-over as possible. |
| 448 | + * @irq_flags: Interrupt enable state during PTP system timestamping | |
| 446 | 449 | * |
| 447 | 450 | * Each SPI controller can communicate with one or more @spi_device |
| 448 | 451 | * children. These make a small bus, sharing MOSI, MISO and SCK signals |
| @@ -481,6 +484,9 @@ struct spi_controller { · 32 unmodified lines | ||
| 481 | 484 | /* spi_device.mode flags understood by this controller driver */ |
| 482 | 485 | u32 mode_bits; |
| 483 | 486 | |
| 487 | + /* spi_device.mode flags override flags for this controller */ | |
| 488 | + u32 buswidth_override_bits; | |
| 489 | + | |
| 484 | 490 | /* bitmask of supported bits_per_word for transfers */ |
| 485 | 491 | u32 bits_per_word_mask; |
| 486 | 492 | #define SPI_BPW_MASK(bits) BIT((bits) - 1) |
| @@ -930,8 +936,7 @@ struct spi_transfer { · 443 unmodified lines | ||
| 930 | 936 | |
| 931 | 937 | struct ptp_system_timestamp *ptp_sts; |
| 932 | 938 | |
| 933 | − bool timestamped_pre; | |
| 934 | − bool timestamped_post; | |
| 939 | + bool timestamped; | |
| 935 | 940 | |
| 936 | 941 | struct list_head transfer_list; |
| 937 | 942 | }; |
| @@ -51,7 +51,7 @@ $(OUTPUT)spidev_fdx: $(SPIDEV_FDX_IN) · 50 unmodified lines | ||
| 51 | 51 | |
| 52 | 52 | clean: |
| 53 | 53 | rm -f $(ALL_PROGRAMS) |
| 54 | − rm -f $(OUTPUT)include/linux/spi/spidev.h | |
| 54 | + rm -rf $(OUTPUT)include/ | |
| 55 | 55 | find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete |
| 56 | 56 | |
| 57 | 57 | install: $(ALL_PROGRAMS) |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <stdio.h> |
| 14 | 14 | #include <stdlib.h> |
| 15 | 15 | #include <string.h> |
| 16 | +#include <errno.h> | |
| 16 | 17 | #include <getopt.h> |
| 17 | 18 | #include <fcntl.h> |
| 18 | 19 | #include <time.h> |
| @@ -26,7 +27,11 @@ · 7 unmodified lines | ||
| 26 | 27 | |
| 27 | 28 | static void pabort(const char *s) |
| 28 | 29 | { |
| 29 | − perror(s); | |
| 30 | + if (errno != 0) | |
| 31 | + perror(s); | |
| 32 | + else | |
| 33 | + printf("%s\n", s); | |
| 34 | + | |
| 30 | 35 | abort(); |
| 31 | 36 | } |
| 32 | 37 | |
| @@ -283,7 +288,6 @@ static void parse_opts(int argc, char *argv[]) · 250 unmodified lines | ||
| 283 | 288 | break; |
| 284 | 289 | default: |
| 285 | 290 | print_usage(argv[0]); |
| 286 | − break; | |
| 287 | 291 | } |
| 288 | 292 | } |
| 289 | 293 | if (mode & SPI_LOOP) { |
| @@ -405,6 +409,9 @@ int main(int argc, char *argv[]) · 115 unmodified lines | ||
| 405 | 409 | |
| 406 | 410 | parse_opts(argc, argv); |
| 407 | 411 | |
| 412 | + if (input_tx && input_file) | |
| 413 | + pabort("only one of -p and --input may be selected"); | |
| 414 | + | |
| 408 | 415 | fd = open(device, O_RDWR); |
| 409 | 416 | if (fd < 0) |
| 410 | 417 | pabort("can't open device"); |
| @@ -446,9 +453,6 @@ int main(int argc, char *argv[]) · 35 unmodified lines | ||
| 446 | 453 | printf("bits per word: %d\n", bits); |
| 447 | 454 | printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); |
| 448 | 455 | |
| 449 | − if (input_tx && input_file) | |
| 450 | − pabort("only one of -p and --input may be selected"); | |
| 451 | − | |
| 452 | 456 | if (input_tx) |
| 453 | 457 | transfer_escaped_string(fd, input_tx); |
| 454 | 458 | else if (input_file) |