diff options
379 files changed, 10002 insertions, 3474 deletions
diff --git a/Documentation/ABI/removed/net_dma b/Documentation/ABI/removed/net_dma new file mode 100644 index 00000000000..a173aecc2f1 --- /dev/null +++ b/Documentation/ABI/removed/net_dma @@ -0,0 +1,8 @@ +What: tcp_dma_copybreak sysctl +Date: Removed in kernel v3.13 +Contact: Dan Williams <dan.j.williams@intel.com> +Description: + Formerly the lower limit, in bytes, of the size of socket reads + that will be offloaded to a DMA copy engine. Removed due to + coherency issues of the cpu potentially touching the buffers + while dma is in flight. diff --git a/Documentation/cgroups/cpusets.txt b/Documentation/cgroups/cpusets.txt index 7740038d82b..3c94ff3f969 100644 --- a/Documentation/cgroups/cpusets.txt +++ b/Documentation/cgroups/cpusets.txt @@ -345,14 +345,14 @@ the named feature on. The implementation is simple. Setting the flag 'cpuset.memory_spread_page' turns on a per-process flag -PF_SPREAD_PAGE for each task that is in that cpuset or subsequently +PFA_SPREAD_PAGE for each task that is in that cpuset or subsequently joins that cpuset. The page allocation calls for the page cache -is modified to perform an inline check for this PF_SPREAD_PAGE task +is modified to perform an inline check for this PFA_SPREAD_PAGE task flag, and if set, a call to a new routine cpuset_mem_spread_node() returns the node to prefer for the allocation. Similarly, setting 'cpuset.memory_spread_slab' turns on the flag -PF_SPREAD_SLAB, and appropriately marked slab caches will allocate +PFA_SPREAD_SLAB, and appropriately marked slab caches will allocate pages from the node returned by cpuset_mem_spread_node(). The cpuset_mem_spread_node() routine is also simple. It uses the diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt index 02ab5ab198a..b7a93e80a30 100644 --- a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt @@ -19,6 +19,7 @@ such as pull-up, multi drive, etc. Required properties for iomux controller: - compatible: "atmel,at91rm9200-pinctrl" or "atmel,at91sam9x5-pinctrl" + or "atmel,sama5d3-pinctrl" - atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be configured in this periph mode. All the periph and bank need to be describe. @@ -85,13 +86,20 @@ Required properties for pin configuration node: PIN_BANK 0 is pioA, PIN_BANK 1 is pioB... Bits used for CONFIG: -PULL_UP (1 << 0): indicate this pin need a pull up. -MULTIDRIVE (1 << 1): indicate this pin need to be configured as multidrive. -DEGLITCH (1 << 2): indicate this pin need deglitch. -PULL_DOWN (1 << 3): indicate this pin need a pull down. -DIS_SCHMIT (1 << 4): indicate this pin need to disable schmit trigger. -DEBOUNCE (1 << 16): indicate this pin need debounce. -DEBOUNCE_VAL (0x3fff << 17): debounce val. +PULL_UP (1 << 0): indicate this pin needs a pull up. +MULTIDRIVE (1 << 1): indicate this pin needs to be configured as multi-drive. + Multi-drive is equivalent to open-drain type output. +DEGLITCH (1 << 2): indicate this pin needs deglitch. +PULL_DOWN (1 << 3): indicate this pin needs a pull down. +DIS_SCHMIT (1 << 4): indicate this pin needs to the disable schmitt trigger. +DRIVE_STRENGTH (3 << 5): indicate the drive strength of the pin using the + following values: + 00 - No change (reset state value kept) + 01 - Low + 10 - Medium + 11 - High +DEBOUNCE (1 << 16): indicate this pin needs debounce. +DEBOUNCE_VAL (0x3fff << 17): debounce value. NOTE: Some requirements for using atmel,at91rm9200-pinctrl binding: diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt index 6464bf76946..189814e7cdc 100644 --- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt @@ -10,6 +10,7 @@ Required properties: - reg: Should contain a list of base address and size pairs for: -- first entry - the drive strength and pad control registers. -- second entry - the pinmux registers + -- third entry - the MIPI_PAD_CTRL register Tegra124 adds the following optional properties for pin configuration subnodes. The macros for options are defined in the @@ -91,6 +92,12 @@ Valid values for pin and group names are: dbg, sdio3, spi, uaa, uab, uart2, uart3, sdio1, ddc, gma, gme, gmf, gmg, gmh, owr, uda, gpv, dev3, cec, usb_vbus_en, ao3, ao0, hv0, sdio4, ao4. + MIPI pad control groups: + + These support only the nvidia,function property. + + dsi_b + Valid values for nvidia,functions are: blink, cec, cldvfs, clk12, cpu, dap, dap1, dap2, dev3, displaya, @@ -101,14 +108,15 @@ Valid values for nvidia,functions are: sdmmc4, soc, spdif, spi1, spi2, spi3, spi4, spi5, spi6, trace, uarta, uartb, uartc, uartd, ulpi, usb, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6, vi, vi_alt1, vi_alt3, vimclk2, vimclk2_alt, sata, ccla, pe0, pe, pe1, - dp, rtck, sys, clk tmds. + dp, rtck, sys, clk tmds, csi, dsi_b Example: pinmux: pinmux { compatible = "nvidia,tegra124-pinmux"; - reg = <0x70000868 0x164 /* Pad control registers */ - 0x70003000 0x434>; /* PinMux registers */ + reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */ + <0x0 0x70003000 0x0 0x434>, /* Mux registers */ + <0x0 0x70000820 0x0 0x8>; /* MIPI pad control */ }; Example pinmux entries: diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index fa40a177164..98eb94d91a1 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -127,6 +127,24 @@ whether there is any interaction between the child and intermediate parent nodes, is again defined entirely by the binding for the individual pin controller device. +== Generic pin multiplexing node content == + +pin multiplexing nodes: + +function - the mux function to select +groups - the list of groups to select with this function + +Example: + +state_0_node_a { + function = "uart0"; + groups = "u0rxtx", "u0rtscts"; +}; +state_1_node_a { + function = "spi0"; + groups = "spi0pins"; +}; + == Generic pin configuration node content == Many data items that are represented in a pin configuration node are common @@ -139,8 +157,12 @@ structure of the DT nodes that contain these properties. Supported generic properties are: pins - the list of pins that properties in the node - apply to -function - the mux function to select + apply to (either this or "group" has to be + specified) +group - the group to apply the properties to, if the driver + supports configuration of whole groups rather than + individual pins (either this or "pins" has to be + specified) bias-disable - disable any pin bias bias-high-impedance - high impedance mode ("third-state", "floating") bias-bus-hold - latch weakly @@ -163,6 +185,21 @@ output-low - set the pin to output mode with low level output-high - set the pin to output mode with high level slew-rate - set the slew rate +For example: + +state_0_node_a { + pins = "GPIO0_AJ5", "GPIO2_AH4"; /* CTS+RXD */ + bias-pull-up; +}; +state_1_node_a { + pins = "GPIO1_AJ3", "GPIO3_AH3"; /* RTS+TXD */ + output-high; +}; +state_2_node_a { + group = "foo-group"; + bias-pull-up; +}; + Some of the generic properties take arguments. For those that do, the arguments are described below. @@ -170,15 +207,6 @@ arguments are described below. binding for the hardware defines: - Whether the entries are integers or strings, and their meaning. -- function takes a list of function names/IDs as a required argument. The - specific binding for the hardware defines: - - Whether the entries are integers or strings, and their meaning. - - Whether only a single entry is allowed (which is applied to all entries - in the pins property), or whether there may alternatively be one entry per - entry in the pins property, in which case the list lengths must match, and - for each list index i, the function at list index i is applied to the pin - at list index i. - - bias-pull-up, -down and -pin-default take as optional argument on hardware supporting it the pull strength in Ohm. bias-disable will disable the pull. diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,apq8064-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,apq8064-pinctrl.txt index 92fae82f35f..2fb90b37aa0 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,apq8064-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,apq8064-pinctrl.txt @@ -50,7 +50,7 @@ Valid values for function are: gsbi4_cam_i2c, gsbi5, gsbi5_spi_cs1, gsbi5_spi_cs2, gsbi5_spi_cs3, gsbi6, gsbi6_spi_cs1, gsbi6_spi_cs2, gsbi6_spi_cs3, gsbi7, gsbi7_spi_cs1, gsbi7_spi_cs2, gsbi7_spi_cs3, gsbi_cam_i2c, hdmi, mi2s, riva_bt, riva_fm, - riva_wlan, sdc2, sdc4, slimbus, spkr_i2s, tsif1, tsif2, usb2_hsic, + riva_wlan, sdc2, sdc4, slimbus, spkr_i2s, tsif1, tsif2, usb2_hsic, ps_hold Example: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,apq8084-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,apq8084-pinctrl.txt new file mode 100644 index 00000000000..ffafa1990a3 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,apq8084-pinctrl.txt @@ -0,0 +1,179 @@ +Qualcomm APQ8084 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8960 platform. + +- compatible: + Usage: required + Value type: <string> + Definition: must be "qcom,apq8084-pinctrl" + +- reg: + Usage: required + Value type: <prop-encoded-array> + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: <prop-encoded-array> + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: <none> + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: <u32> + Definition: must be 2. Specifying the pin number and flags, as defined + in <dt-bindings/interrupt-controller/irq.h> + +- gpio-controller: + Usage: required + Value type: <none> + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: <u32> + Definition: must be 2. Specifying the pin number and flags, as defined + in <dt-bindings/gpio/gpio.h> + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an abitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: <string-array> + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio0-gpio146, + sdc1_clk, + sdc1_cmd, + sdc1_data + sdc2_clk, + sdc2_cmd, + sdc2_data + +- function: + Usage: required + Value type: <string> + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + adsp_ext, audio_ref, blsp_i2c1, blsp_i2c2, blsp_i2c3, + blsp_i2c4, blsp_i2c5, blsp_i2c6, blsp_i2c7, blsp_i2c8, + blsp_i2c9, blsp_i2c10, blsp_i2c11, blsp_i2c12, + blsp_spi1, blsp_spi2, blsp_spi3, blsp_spi4, blsp_spi5, + blsp_spi6, blsp_spi7, blsp_spi8, blsp_spi9, blsp_spi10, + blsp_spi11, blsp_spi12, blsp_uart1, blsp_uart2, blsp_uart3, + blsp_uart4, blsp_uart5, blsp_uart6, blsp_uart7, blsp_uart8, + blsp_uart9, blsp_uart10, blsp_uart11, blsp_uart12, + blsp_uim1, blsp_uim2, blsp_uim3, blsp_uim4, blsp_uim5, + blsp_uim6, blsp_uim7, blsp_uim8, blsp_uim9, blsp_uim10, + blsp_uim11, blsp_uim12, cam_mclk0, cam_mclk1, cam_mclk2, + cam_mclk3, cci_async, cci_async_in0, cci_i2c0, cci_i2c1, + cci_timer0, cci_timer1, cci_timer2, cci_timer3, cci_timer4, + edp_hpd, gcc_gp1, gcc_gp2, gcc_gp3, gcc_obt, gcc_vtt,i + gp_mn, gp_pdm0, gp_pdm1, gp_pdm2, gp0_clk, gp1_clk, gpio, + hdmi_cec, hdmi_ddc, hdmi_dtest, hdmi_hpd, hdmi_rcv, hsic, + ldo_en, ldo_update, mdp_vsync, pci_e0, pci_e0_n, pci_e0_rst, + pci_e1, pci_e1_rst, pci_e1_rst_n, pci_e1_clkreq_n, pri_mi2s, + qua_mi2s, sata_act, sata_devsleep, sata_devsleep_n, + sd_write, sdc_emmc_mode, sdc3, sdc4, sec_mi2s, slimbus, + spdif_tx, spkr_i2s, spkr_i2s_ws, spss_geni, ter_mi2s, tsif1, + tsif2, uim, uim_batt_alarm + +- bias-disable: + Usage: optional + Value type: <none> + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: <none> + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: <none> + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: <none> + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: <none> + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: <u32> + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@fd510000 { + compatible = "qcom,apq8084-pinctrl"; + reg = <0xfd510000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 208 0>; + + uart2: uart2-default { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + tx { + pins = "gpio4"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt index 4658b69d4f4..388b213249f 100644 --- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt @@ -2,8 +2,8 @@ The Rockchip Pinmux Controller, enables the IC to share one PAD to several functional blocks. The sharing is done by -multiplexing the PAD input/output signals. For each PAD there are up to -4 muxing options with option 0 being the use as a GPIO. +multiplexing the PAD input/output signals. For each PAD there are several +muxing options with option 0 being the use as a GPIO. Please refer to pinctrl-bindings.txt in this directory for details of the common pinctrl bindings used by client devices, including the meaning of the @@ -58,7 +58,7 @@ Deprecated properties for gpio sub nodes: Required properties for pin configuration node: - rockchip,pins: 3 integers array, represents a group of pins mux and config setting. The format is rockchip,pins = <PIN_BANK PIN_BANK_IDX MUX &phandle>. - The MUX 0 means gpio and MUX 1 to 3 mean the specific device function. + The MUX 0 means gpio and MUX 1 to N mean the specific device function. The phandle of a node containing the generic pinconfig options to use, as described in pinctrl-bindings.txt in this directory. diff --git a/Documentation/devicetree/bindings/pinctrl/ti,omap-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ti,omap-pinctrl.txt new file mode 100644 index 00000000000..88c80273da9 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/ti,omap-pinctrl.txt @@ -0,0 +1,13 @@ +OMAP Pinctrl definitions + +Required properties: +- compatible : Should be one of: + "ti,omap2420-padconf" - OMAP2420 compatible pinctrl + "ti,omap2430-padconf" - OMAP2430 compatible pinctrl + "ti,omap3-padconf" - OMAP3 compatible pinctrl + "ti,omap4-padconf" - OMAP4 compatible pinctrl + "ti,omap5-padconf" - OMAP5 compatible pinctrl + "ti,dra7-padconf" - DRA7 compatible pinctrl + "ti,am437-padconf" - AM437x compatible pinctrl + +See Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt for further details. diff --git a/Documentation/devicetree/bindings/regmap/regmap.txt b/Documentation/devicetree/bindings/regmap/regmap.txt new file mode 100644 index 00000000000..b494f8b8ef7 --- /dev/null +++ b/Documentation/devicetree/bindings/regmap/regmap.txt @@ -0,0 +1,47 @@ +Device-Tree binding for regmap + +The endianness mode of CPU & Device scenarios: +Index Device Endianness properties +--------------------------------------------------- +1 BE 'big-endian' +2 LE 'little-endian' + +For one device driver, which will run in different scenarios above +on different SoCs using the devicetree, we need one way to simplify +this. + +Required properties: +- {big,little}-endian: these are boolean properties, if absent + meaning that the CPU and the Device are in the same endianness mode, + these properties are for register values and all the buffers only. + +Examples: +Scenario 1 : CPU in LE mode & device in LE mode. +dev: dev@40031000 { + compatible = "name"; + reg = <0x40031000 0x1000>; + ... +}; + +Scenario 2 : CPU in LE mode & device in BE mode. +dev: dev@40031000 { + compatible = "name"; + reg = <0x40031000 0x1000>; + ... + big-endian; +}; + +Scenario 3 : CPU in BE mode & device in BE mode. +dev: dev@40031000 { + compatible = "name"; + reg = <0x40031000 0x1000>; + ... +}; + +Scenario 4 : CPU in BE mode & device in LE mode. +dev: dev@40031000 { + compatible = "name"; + reg = <0x40031000 0x1000>; + ... + little-endian; +}; diff --git a/Documentation/devicetree/bindings/regulator/da9211.txt b/Documentation/devicetree/bindings/regulator/da9211.txt new file mode 100644 index 00000000000..240019a82f9 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/da9211.txt @@ -0,0 +1,63 @@ +* Dialog Semiconductor DA9211/DA9213 Voltage Regulator + +Required properties: +- compatible: "dlg,da9211" or "dlg,da9213". +- reg: I2C slave address, usually 0x68. +- interrupts: the interrupt outputs of the controller +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + BUCKA and BUCKB. + +Optional properties: +- Any optional property defined in regulator.txt + +Example 1) DA9211 + + pmic: da9211@68 { + compatible = "dlg,da9211"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <2000000>; + regulator-max-microamp = <5000000>; + }; + BUCKB { + regulator-name = "VBUCKB"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <2000000>; + regulator-max-microamp = <5000000>; + }; + }; + }; + +Example 2) DA92113 + pmic: da9213@68 { + compatible = "dlg,da9213"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <3000000>; + regulator-max-microamp = <6000000>; + }; + BUCKB { + regulator-name = "VBUCKB"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <3000000>; + regulator-max-microamp = <6000000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/fan53555.txt b/Documentation/devicetree/bindings/regulator/fan53555.txt new file mode 100644 index 00000000000..54a3f2c80e3 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/fan53555.txt @@ -0,0 +1,23 @@ +Binding for Fairchild FAN53555 regulators + +Required properties: + - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828" + - reg: I2C address + +Optional properties: + - fcs,suspend-voltage-selector: declare which of the two available + voltage selector registers should be used for the suspend + voltage. The other one is used for the runtime voltage setting + Possible values are either <0> or <1> + - vin-supply: regulator supplying the vin pin + +Example: + + regulator@40 { + compatible = "fcs,fan53555"; + regulator-name = "fan53555"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&parent_reg>; + fcs,suspend-voltage-selector = <1>; + }; diff --git a/Documentation/devicetree/bindings/regulator/isl9305.txt b/Documentation/devicetree/bindings/regulator/isl9305.txt new file mode 100644 index 00000000000..a626fc1bbf0 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/isl9305.txt @@ -0,0 +1,36 @@ +Intersil ISL9305/ISL9305H voltage regulator + +Required properties: + +- compatible: "isl,isl9305" or "isl,isl9305h" +- reg: I2C slave address, usually 0x68. +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values being "dcd1", "dcd2", "ldo1" and "ldo2". The content of each sub-node + is defined by the standard binding for regulators; see regulator.txt. +- VINDCD1-supply: A phandle to a regulator node supplying VINDCD1. + VINDCD2-supply: A phandle to a regulator node supplying VINDCD2. + VINLDO1-supply: A phandle to a regulator node supplying VINLDO1. + VINLDO2-supply: A phandle to a regulator node supplying VINLDO2. + +Optional properties: +- Per-regulator optional properties are defined in regulator.txt + +Example + + pmic: isl9305@68 { + compatible = "isl,isl9305"; + reg = <0x68>; + + VINDCD1-supply = <&system_power>; + VINDCD2-supply = <&system_power>; + VINLDO1-supply = <&system_power>; + VINLDO2-supply = <&system_power>; + + regulators { + dcd1 { + regulator-name = "VDD_DSP"; + regulator-always-on; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/max1586-regulator.txt b/Documentation/devicetree/bindings/regulator/max1586-regulator.txt new file mode 100644 index 00000000000..c050c1744cb --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max1586-regulator.txt @@ -0,0 +1,28 @@ +Maxim MAX1586 voltage regulator + +Required properties: +- compatible: must be "maxim,max1586" +- reg: I2C slave address, usually 0x14 +- v3-gain: integer specifying the V3 gain as per datasheet + (1 + R24/R25 + R24/185.5kOhm) +- any required generic properties defined in regulator.txt + +Example: + + i2c_master { + max1586@14 { + compatible = "maxim,max1586"; + reg = <0x14>; + v3-gain = <1000000>; + + regulators { + vcc_core: v3 { + regulator-name = "vcc_core"; + regulator-compatible = "Output_V3"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1705000>; + regulator-always-on; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/max77802.txt b/Documentation/devicetree/bindings/regulator/max77802.txt new file mode 100644 index 00000000000..5aeaffc0f1f --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max77802.txt @@ -0,0 +1,53 @@ +Binding for Maxim MAX77802 regulators + +This is a part of device tree bindings of MAX77802 multi-function device. +More information can be found in bindings/mfd/max77802.txt file. + +The MAX77802 PMIC has 10 high-efficiency Buck and 32 Low-dropout (LDO) +regulators that can be controlled over I2C. + +Following properties should be present in main device node of the MFD chip. + +Optional node: +- regulators : The regulators of max77802 have to be instantiated + under subnode named "regulators" using the following format. + + regulator-name { + standard regulator constraints.... + }; + refer Documentation/devicetree/bindings/regulator/regulator.txt + +The regulator node name should be initialized with a string to get matched +with their hardware counterparts as follow. The valid names are: + + -LDOn : for LDOs, where n can lie in ranges 1-15, 17-21, 23-30 + and 32-35. + example: LDO1, LDO2, LDO35. + -BUCKn : for BUCKs, where n can lie in range 1 to 10. + example: BUCK1, BUCK5, BUCK10. +Example: + + max77802@09 { + compatible = "maxim,max77802"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 0>; + reg = <0x09>; + #address-cells = <1>; + #size-cells = <0>; + + regulators { + ldo11_reg: LDO11 { + regulator-name = "vdd_ldo11"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <1900000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt new file mode 100644 index 00000000000..ce91f61feb1 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt @@ -0,0 +1,27 @@ +pwm regulator bindings + +Required properties: +- compatible: Should be "pwm-regulator" +- pwms: OF device-tree PWM specification (see PWM binding pwm.txt) +- voltage-table: voltage and duty table, include 2 members in each set of + brackets, first one is voltage(unit: uv), the next is duty(unit: percent) + +Any property defined as part of the core regulator binding defined in +regulator.txt can also be used. + +Example: + pwm_regulator { + compatible = "pwm-regulator; + pwms = <&pwm1 0 8448 0>; + + voltage-table = <1114000 0>, + <1095000 10>, + <1076000 20>, + <1056000 30>, + <1036000 40>, + <1016000 50>; + + regulator-min-microvolt = <1016000>; + regulator-max-microvolt = <1114000>; + regulator-name = "vdd_logic"; + }; diff --git a/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt b/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt new file mode 100644 index 00000000000..882455e9b36 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt @@ -0,0 +1,16 @@ +SKY81452 voltage regulator + +Required properties: +- any required generic properties defined in regulator.txt + +Optional properties: +- any available generic properties defined in regulator.txt + +Example: + + regulator { + /* generic regulator properties */ + regulator-name = "touch_en"; + regulator-min-microvolt = <4500000>; + regulator-max-microvolt = <8000000>; + }; diff --git a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt index 4256a6df9b7..aad527b357a 100644 --- a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt +++ b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt @@ -7,6 +7,9 @@ Required properties: - interrupts : Should contain CSPI/eCSPI interrupt - fsl,spi-num-chipselects : Contains the number of the chipselect - cs-gpios : Specifies the gpio pins to be used for chipselects. +- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: DMA request names should include "tx" and "rx" if present. Example: @@ -19,4 +22,6 @@ ecspi@70010000 { fsl,spi-num-chipselects = <2>; cs-gpios = <&gpio3 24 0>, /* GPIO3_24 */ <&gpio3 25 0>; /* GPIO3_25 */ + dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; + dma-names = "rx", "tx"; }; diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index f24baf3b6cc..d11c3721e7c 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -6,8 +6,17 @@ Required properties: "renesas,sh-mobile-msiof" for SH Mobile series. Examples with soctypes are: "renesas,msiof-r8a7790" (R-Car H2) - "renesas,msiof-r8a7791" (R-Car M2) -- reg : Offset and length of the register set for the device + "renesas,msiof-r8a7791" (R-Car M2-W) + "renesas,msiof-r8a7792" (R-Car V2H) + "renesas,msiof-r8a7793" (R-Car M2-N) + "renesas,msiof-r8a7794" (R-Car E2) +- reg : A list of offsets and lengths of the register sets for + the device. + If only one register set is present, it is to be used + by both the CPU and the DMA engine. + If two register sets are present, the first is to be + used by the CPU, and the second is to be used by the + DMA engine. - interrupt-parent : The phandle for the interrupt controller that services interrupts for this device - interrupts : Interrupt specifier @@ -17,12 +26,16 @@ Required properties: Optional properties: - clocks : Must contain a reference to the functional clock. - num-cs : Total number of chip-selects (default is 1) +- dmas : Must contain a list of two references to DMA + specifiers, one for transmission, and one for + reception. +- dma-names : Must contain a list of two DMA names, "tx" and "rx". Optional properties, deprecated for soctype-specific bindings: - renesas,tx-fifo-size : Overrides the default tx fifo size given in words (default is 64) - renesas,rx-fifo-size : Overrides the default rx fifo size given in words - (default is 64, or 256 on R-Car H2 and M2) + (default is 64, or 256 on R-Car Gen2) Pinctrl properties might be needed, too. See Documentation/devicetree/bindings/pinctrl/renesas,*. @@ -31,9 +44,11 @@ Example: msiof0: spi@e6e20000 { compatible = "renesas,msiof-r8a7791"; - reg = <0 0xe6e20000 0 0x0064>; + reg = <0 0xe6e20000 0 0x0064>, <0 0xe7e20000 0 0x0064>; interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>; + dmas = <&dmac0 0x51>, <&dmac0 0x52>; + dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; diff --git a/Documentation/devicetree/bindings/spi/spi-davinci.txt b/Documentation/devicetree/bindings/spi/spi-davinci.txt index f80887bca0d..12ecfe9e359 100644 --- a/Documentation/devicetree/bindings/spi/spi-davinci.txt +++ b/Documentation/devicetree/bindings/spi/spi-davinci.txt @@ -1,5 +1,10 @@ Davinci SPI controller device bindings +Links on DM: +Keystone 2 - http://www.ti.com/lit/ug/sprugp2a/sprugp2a.pdf +dm644x - http://www.ti.com/lit/ug/sprue32a/sprue32a.pdf +OMAP-L138/da830 - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf + Required properties: - #address-cells: number of cells required to define a chip select address on the SPI bus. Should be set to 1. @@ -24,6 +29,30 @@ Optional: cs-gpios = <0>, <0>, <0>, <&gpio1 30 0>, <&gpio1 31 0>; where first three are internal CS and last two are GPIO CS. +Optional properties for slave devices: +SPI slave nodes can contain the following properties. +Not all SPI Peripherals from Texas Instruments support this. +Please check SPI peripheral documentation for a device before using these. + +- ti,spi-wdelay : delay between transmission of words + (SPIFMTn.WDELAY, SPIDAT1.WDEL) must be specified in number of SPI module + clock periods. + + delay = WDELAY * SPI_module_clock_period + 2 * SPI_module_clock_period + +Below is timing diagram which shows functional meaning of +"ti,spi-wdelay" parameter. + + +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +SPI_CLK | | | | | | | | | | | | | | | | + +----------+ +-+ +-+ +-+ +-+ +---------------------------+ +-+ +-+ +- + +SPI_SOMI/SIMO+-----------------+ +----------- + +----------+ word1 +---------------------------+word2 + +-----------------+ +----------- + WDELAY + <--------------------------> + Example of a NOR flash slave device (n25q032) connected to DaVinci SPI controller device over the SPI bus. @@ -43,6 +72,7 @@ spi0:spi@20BF0000 { compatible = "st,m25p32"; spi-max-frequency = <25000000>; reg = <0>; + ti,spi-wdelay = <8>; partition@0 { label = "u-boot-spl"; diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt index 5376de40f10..cbbe16ed387 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt @@ -10,7 +10,12 @@ Required properties: - pinctrl-names: must contain a "default" entry. - spi-num-chipselects : the number of the chipselect signals. - bus-num : the slave chip chipselect signal number. -- big-endian : if DSPI modudle is big endian, the bool will be set in node. + +Optional property: +- big-endian: If present the dspi device's registers are implemented + in big endian mode, otherwise in native mode(same with CPU), for more + detail please see: Documentation/devicetree/bindings/regmap/regmap.txt. + Example: dspi0@4002c000 { diff --git a/Documentation/devicetree/bindings/spi/spi-orion.txt b/Documentation/devicetree/bindings/spi/spi-orion.txt index a3ff50fc76f..50c3a3de61c 100644 --- a/Documentation/devicetree/bindings/spi/spi-orion.txt +++ b/Documentation/devicetree/bindings/spi/spi-orion.txt @@ -1,7 +1,7 @@ Marvell Orion SPI device Required properties: -- compatible : should be "marvell,orion-spi". +- compatible : should be "marvell,orion-spi" or "marvell,armada-370-spi". - reg : offset and length of the register set for the device - cell-index : Which of multiple SPI controllers is this. Optional properties: diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt index d57d82a7405..8f4169f6393 100644 --- a/Documentation/devicetree/bindings/spi/spi-rspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt @@ -11,7 +11,10 @@ Required properties: - "renesas,rspi-sh7757" (SH) - "renesas,rspi-r7s72100" (RZ/A1H) - "renesas,qspi-r8a7790" (R-Car H2) - - "renesas,qspi-r8a7791" (R-Car M2) + - "renesas,qspi-r8a7791" (R-Car M2-W) + - "renesas,qspi-r8a7792" (R-Car V2H) + - "renesas,qspi-r8a7793" (R-Car M2-N) + - "renesas,qspi-r8a7794" (R-Car E2) - reg : Address start and address range size of the device - interrupts : A list of interrupt-specifiers, one for each entry in interrupt-names. @@ -30,6 +33,9 @@ Required properties: Optional properties: - clocks : Must contain a reference to the functional clock. +- dmas : Must contain a list of two references to DMA specifiers, + one for transmission, and one for reception. +- dma-names : Must contain a list of two DMA names, "tx" and "rx". Pinctrl properties might be needed, too. See Documentation/devicetree/bindings/pinctrl/renesas,*. @@ -58,4 +64,6 @@ Examples: num-cs = <1>; #address-cells = <1>; #size-cells = <0>; + dmas = <&dmac0 0x17>, <&dmac0 0x18>; + dma-names = "tx", "rx"; }; diff --git a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt index 578a1fca366..443bcb6134d 100644 --- a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt +++ b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt @@ -56,6 +56,9 @@ Required properties: - fsl,data-width : should be <18> or <24> - port: A port node with endpoint definitions as defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + On i.MX5, the internal two-input-multiplexer is used. + Due to hardware limitations, only one port (port@[0,1]) + can be used for each channel (lvds-channel@[0,1], respectively) On i.MX6, there should be four ports (port@[0-3]) that correspond to the four LVDS multiplexer inputs. @@ -78,6 +81,8 @@ ldb: ldb@53fa8008 { "di0", "di1"; lvds-channel@0 { + #address-cells = <1>; + #size-cells = <0>; reg = <0>; fsl,data-mapping = "spwg"; fsl,data-width = <24>; @@ -86,7 +91,9 @@ ldb: ldb@53fa8008 { /* ... */ }; - port { + port@0 { + reg = <0>; + lvds0_in: endpoint { remote-endpoint = <&ipu_di0_lvds0>; }; @@ -94,6 +101,8 @@ ldb: ldb@53fa8008 { }; lvds-channel@1 { + #address-cells = <1>; + #size-cells = <0>; reg = <1>; fsl,data-mapping = "spwg"; fsl,data-width = <24>; @@ -102,7 +111,9 @@ ldb: ldb@53fa8008 { /* ... */ }; - port { + port@1 { + reg = <1>; + lvds1_in: endpoint { remote-endpoint = <&ipu_di1_lvds1>; }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ac7269f9076..6073e76575e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -49,6 +49,7 @@ epson Seiko Epson Corp. est ESTeem Wireless Modems eukrea Eukréa Electromatique excito Excito +fcs Fairchild Semiconductor fsl Freescale Semiconductor GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. @@ -124,6 +125,7 @@ sil Silicon Image silabs Silicon Laboratories simtek sii Seiko Instruments, Inc. +silergy Silergy Corp. sirf SiRF Technology, Inc. smsc Standard Microsystems Corporation snps Synopsys, Inc. diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 29a93518bf1..caedb18d456 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -580,12 +580,6 @@ tcp_workaround_signed_windows - BOOLEAN not receive a window scaling option from them. Default: 0 -tcp_dma_copybreak - INTEGER - Lower limit, in bytes, of the size of socket reads that will be - offloaded to a DMA copy engine, if one is present in the system - and CONFIG_NET_DMA is enabled. - Default: 4096 - tcp_thin_linear_timeouts - BOOLEAN Enable dynamic triggering of linear timeouts for thin streams. If set, a check is performed upon retransmission by timeout to diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 23f1590f49f..b8f2147b96d 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -702,7 +702,7 @@ static int foo_get_groups(struct pinctrl_dev *pctldev, unsigned selector, return 0; } -int foo_enable(struct pinctrl_dev *pctldev, unsigned selector, +int foo_set_mux(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { u8 regbit = (1 << selector + group); @@ -711,21 +711,11 @@ int foo_enable(struct pinctrl_dev *pctldev, unsigned selector, return 0; } -void foo_disable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) -{ - u8 regbit = (1 << selector + group); - - writeb((readb(MUX) & ~(regbit)), MUX) - return 0; -} - struct pinmux_ops foo_pmxops = { .get_functions_count = foo_get_functions_count, .get_function_name = foo_get_fname, .get_function_groups = foo_get_groups, - .enable = foo_enable, - .disable = foo_disable, + .set_mux = foo_set_mux, }; /* Pinmux operations are handled by some pin controller */ diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary index 7982bcc4d15..d29734bff28 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary @@ -601,13 +601,13 @@ THANKS TO Contributors to Linux-SPI discussions include (in alphabetical order, by last name): +Mark Brown David Brownell Russell King +Grant Likely Dmitry Pervushin Stephen Street Mark Underwood Andrew Victor -Vitaly Wool -Grant Likely -Mark Brown Linus Walleij +Vitaly Wool diff --git a/MAINTAINERS b/MAINTAINERS index a9622c7e4ce..a12edf2624e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1025,24 +1025,20 @@ F: arch/arm/mach-pxa/colibri-pxa270-income.c ARM/INTEL IOP32X ARM ARCHITECTURE M: Lennert Buytenhek <kernel@wantstofly.org> -M: Dan Williams <dan.j.williams@intel.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained ARM/INTEL IOP33X ARM ARCHITECTURE -M: Dan Williams <dan.j.williams@intel.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained +S: Orphan ARM/INTEL IOP13XX ARM ARCHITECTURE M: Lennert Buytenhek <kernel@wantstofly.org> -M: Dan Williams <dan.j.williams@intel.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained ARM/INTEL IQ81342EX MACHINE SUPPORT M: Lennert Buytenhek <kernel@wantstofly.org> -M: Dan Williams <dan.j.williams@intel.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained @@ -1067,7 +1063,6 @@ F: drivers/pcmcia/pxa2xx_stargate2.c ARM/INTEL XSC3 (MANZANO) ARM CORE M: Lennert Buytenhek <kernel@wantstofly.org> -M: Dan Williams <dan.j.williams@intel.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained @@ -1562,9 +1557,9 @@ F: drivers/platform/x86/asus*.c F: drivers/platform/x86/eeepc*.c ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API -M: Dan Williams <dan.j.williams@intel.com> +R: Dan Williams <dan.j.williams@intel.com> W: http://sourceforge.net/projects/xscaleiop -S: Maintained +S: Odd fixes F: Documentation/crypto/async-tx-api.txt F: crypto/async_tx/ F: drivers/dma/ @@ -1665,6 +1660,12 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com> S: Supported F: drivers/tty/serial/atmel_serial.c +ATMEL Audio ALSA driver +M: Bo Shen <voice.shen@atmel.com> +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Supported +F: sound/soc/atmel + ATMEL DMA DRIVER M: Nicolas Ferre <nicolas.ferre@atmel.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -2098,7 +2099,7 @@ S: Supported F: drivers/scsi/bfa/ BROCADE BNA 10 GIGABIT ETHERNET DRIVER -M: Rasesh Mody <rmody@brocade.com> +M: Rasesh Mody <rasesh.mody@qlogic.com> L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/brocade/bna/ @@ -2989,13 +2990,11 @@ T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git DMA GENERIC OFFLOAD ENGINE SUBSYSTEM M: Vinod Koul <vinod.koul@intel.com> -M: Dan Williams <dan.j.williams@intel.com> L: dmaengine@vger.kernel.org Q: https://patchwork.kernel.org/project/linux-dmaengine/list/ -S: Supported +S: Maintained F: drivers/dma/ F: include/linux/dma* -T: git git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx.git T: git git://git.infradead.org/users/vkoul/slave-dma.git (slave-dma) DME1737 HARDWARE MONITOR DRIVER @@ -4749,8 +4748,8 @@ F: arch/x86/kernel/cpu/microcode/core* F: arch/x86/kernel/cpu/microcode/intel* INTEL I/OAT DMA DRIVER -M: Dan Williams <dan.j.williams@intel.com> M: Dave Jiang <dave.jiang@intel.com> +R: Dan Williams <dan.j.williams@intel.com> L: dmaengine@vger.kernel.org Q: https://patchwork.kernel.org/project/linux-dmaengine/list/ S: Supported @@ -4765,7 +4764,7 @@ F: drivers/iommu/intel-iommu.c F: include/linux/intel-iommu.h INTEL IOP-ADMA DMA DRIVER -M: Dan Williams <dan.j.williams@intel.com> +R: Dan Williams <dan.j.williams@intel.com> S: Odd fixes F: drivers/dma/iop-adma.c @@ -5479,7 +5478,7 @@ F: drivers/macintosh/ LINUX FOR POWERPC EMBEDDED MPC5XXX M: Anatolij Gustschin <agust@denx.de> L: linuxppc-dev@lists.ozlabs.org -T: git git://git.denx.de/linux-2.6-agust.git +T: git git://git.denx.de/linux-denx-agust.git S: Maintained F: arch/powerpc/platforms/512x/ F: arch/powerpc/platforms/52xx/ @@ -7597,6 +7596,7 @@ F: fs/reiserfs/ REGISTER MAP ABSTRACTION M: Mark Brown <broonie@kernel.org> +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git S: Supported F: drivers/base/regmap/ @@ -9896,6 +9896,7 @@ F: drivers/scsi/vmw_pvscsi.h VOLTAGE AND CURRENT REGULATOR FRAMEWORK M: Liam Girdwood <lgirdwood@gmail.com> M: Mark Brown <broonie@kernel.org> +L: linux-kernel@vger.kernel.org W: http://opensource.wolfsonmicro.com/node/15 W: http://www.slimlogic.co.uk/?p=48 T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 17 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = NAME = Shuffling Zombie Juror # *DOCUMENTATION* @@ -842,6 +842,21 @@ mod_strip_cmd = true endif # INSTALL_MOD_STRIP export mod_strip_cmd +# CONFIG_MODULE_COMPRESS, if defined, will cause module to be compressed +# after they are installed in agreement with CONFIG_MODULE_COMPRESS_GZIP +# or CONFIG_MODULE_COMPRESS_XZ. + +mod_compress_cmd = true +ifdef CONFIG_MODULE_COMPRESS + ifdef CONFIG_MODULE_COMPRESS_GZIP + mod_compress_cmd = gzip -n + endif # CONFIG_MODULE_COMPRESS_GZIP + ifdef CONFIG_MODULE_COMPRESS_XZ + mod_compress_cmd = xz + endif # CONFIG_MODULE_COMPRESS_XZ +endif # CONFIG_MODULE_COMPRESS +export mod_compress_cmd + # Select initial ramdisk compression format, default is gzip(1). # This shall be used by the dracut(8) tool while creating an initramfs image. # diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts index e03fbf3c688..b40cdadb1f8 100644 --- a/arch/arm/boot/dts/dra7-evm.dts +++ b/arch/arm/boot/dts/dra7-evm.dts @@ -447,22 +447,19 @@ gpmc,device-width = <2>; gpmc,sync-clk-ps = <0>; gpmc,cs-on-ns = <0>; - gpmc,cs-rd-off-ns = <40>; - gpmc,cs-wr-off-ns = <40>; + gpmc,cs-rd-off-ns = <80>; + gpmc,cs-wr-off-ns = <80>; gpmc,adv-on-ns = <0>; - gpmc,adv-rd-off-ns = <30>; - gpmc,adv-wr-off-ns = <30>; - gpmc,we-on-ns = <5>; - gpmc,we-off-ns = <25>; - gpmc,oe-on-ns = <2>; - gpmc,oe-off-ns = <20>; - gpmc,access-ns = <20>; - gpmc,wr-access-ns = <40>; - gpmc,rd-cycle-ns = <40>; - gpmc,wr-cycle-ns = <40>; - gpmc,wait-pin = <0>; - gpmc,wait-on-read; - gpmc,wait-on-write; + gpmc,adv-rd-off-ns = <60>; + gpmc,adv-wr-off-ns = <60>; + gpmc,we-on-ns = <10>; + gpmc,we-off-ns = <50>; + gpmc,oe-on-ns = <4>; + gpmc,oe-off-ns = <40>; + gpmc,access-ns = <40>; + gpmc,wr-access-ns = <80>; + gpmc,rd-cycle-ns = <80>; + gpmc,wr-cycle-ns = <80>; gpmc,bus-turnaround-ns = <0>; gpmc,cycle2cycle-delay-ns = <0>; gpmc,clk-activation-ns = <0>; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index c6c58c1c00e..6b675a02066 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -423,10 +423,14 @@ status = "disabled"; lvds-channel@0 { + #address-cells = <1>; + #size-cells = <0>; reg = <0>; status = "disabled"; - port { + port@0 { + reg = <0>; + lvds0_in: endpoint { remote-endpoint = <&ipu_di0_lvds0>; }; @@ -434,10 +438,14 @@ }; lvds-channel@1 { + #address-cells = <1>; + #size-cells = <0>; reg = <1>; status = "disabled"; - port { + port@1 { + reg = <1>; + lvds1_in: endpoint { remote-endpoint = <&ipu_di1_lvds1>; }; diff --git a/arch/arm/boot/dts/k2e-clocks.dtsi b/arch/arm/boot/dts/k2e-clocks.dtsi index 598afe91c67..4773d6af66a 100644 --- a/arch/arm/boot/dts/k2e-clocks.dtsi +++ b/arch/arm/boot/dts/k2e-clocks.dtsi @@ -40,7 +40,7 @@ clocks { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk16>; - clock-output-names = "usb"; + clock-output-names = "usb1"; reg = <0x02350004 0xb00>, <0x02350000 0x400>; reg-names = "control", "domain"; domain-id = <0>; @@ -60,8 +60,8 @@ clocks { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; - clock-output-names = "pcie"; - reg = <0x0235006c 0xb00>, <0x02350000 0x400>; + clock-output-names = "pcie1"; + reg = <0x0235006c 0xb00>, <0x02350048 0x400>; reg-names = "control", "domain"; domain-id = <18>; }; diff --git a/arch/arm/boot/dts/omap5-cm-t54.dts b/arch/arm/boot/dts/omap5-cm-t54.dts index b8698ca6864..429471aa7a1 100644 --- a/arch/arm/boot/dts/omap5-cm-t54.dts +++ b/arch/arm/boot/dts/omap5-cm-t54.dts @@ -353,13 +353,12 @@ }; ldo8_reg: ldo8 { - /* VDD_3v0: Does not go anywhere */ + /* VDD_3V_GP: act led/serial console */ regulator-name = "ldo8"; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; + regulator-always-on; regulator-boot-on; - /* Unused */ - status = "disabled"; }; ldo9_reg: ldo9 { diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 79ecb4f34ff..10e78d00a0b 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -466,6 +466,7 @@ static inline void __sync_cache_range_r(volatile void *p, size_t size) */ #define v7_exit_coherency_flush(level) \ asm volatile( \ + ".arch armv7-a \n\t" \ "stmfd sp!, {fp, ip} \n\t" \ "mrc p15, 0, r0, c1, c0, 0 @ get SCTLR \n\t" \ "bic r0, r0, #"__stringify(CR_C)" \n\t" \ diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h index 36172adda9d..5f833f7adba 100644 --- a/arch/arm/include/asm/tls.h +++ b/arch/arm/include/asm/tls.h @@ -81,6 +81,7 @@ static inline void set_tls(unsigned long val) asm("mcr p15, 0, %0, c13, c0, 3" : : "r" (val)); } else { +#ifdef CONFIG_KUSER_HELPERS /* * User space must never try to access this * directly. Expect your app to break @@ -89,6 +90,7 @@ static inline void set_tls(unsigned long val) * entry-armv.S for details) */ *((unsigned int *)0xffff0ff0) = val; +#endif } } diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c index 08d731294bc..b206d7790c7 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/kernel/kprobes-test.c @@ -110,10 +110,13 @@ * * @ TESTCASE_START * bl __kprobes_test_case_start - * @ start of inline data... + * .pushsection .rodata + * "10: * .ascii "mov r0, r7" @ text title for test case * .byte 0 - * .align 2, 0 + * .popsection + * @ start of inline data... + * .word 10b @ pointer to title in .rodata section * * @ TEST_ARG_REG * .byte ARG_TYPE_REG @@ -971,7 +974,7 @@ void __naked __kprobes_test_case_start(void) __asm__ __volatile__ ( "stmdb sp!, {r4-r11} \n\t" "sub sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t" - "bic r0, lr, #1 @ r0 = inline title string \n\t" + "bic r0, lr, #1 @ r0 = inline data \n\t" "mov r1, sp \n\t" "bl kprobes_test_case_start \n\t" "bx r0 \n\t" @@ -1349,15 +1352,14 @@ static unsigned long next_instruction(unsigned long pc) return pc + 4; } -static uintptr_t __used kprobes_test_case_start(const char *title, void *stack) +static uintptr_t __used kprobes_test_case_start(const char **title, void *stack) { struct test_arg *args; struct test_arg_end *end_arg; unsigned long test_code; - args = (struct test_arg *)PTR_ALIGN(title + strlen(title) + 1, 4); - - current_title = title; + current_title = *title++; + args = (struct test_arg *)title; current_args = args; current_stack = stack; diff --git a/arch/arm/kernel/kprobes-test.h b/arch/arm/kernel/kprobes-test.h index eecc90a0fd9..4430990e90e 100644 --- a/arch/arm/kernel/kprobes-test.h +++ b/arch/arm/kernel/kprobes-test.h @@ -111,11 +111,14 @@ struct test_arg_end { #define TESTCASE_START(title) \ __asm__ __volatile__ ( \ "bl __kprobes_test_case_start \n\t" \ + ".pushsection .rodata \n\t" \ + "10: \n\t" \ /* don't use .asciz here as 'title' may be */ \ /* multiple strings to be concatenated. */ \ ".ascii "#title" \n\t" \ ".byte 0 \n\t" \ - ".align 2, 0 \n\t" + ".popsection \n\t" \ + ".word 10b \n\t" #define TEST_ARG_REG(reg, val) \ ".byte "__stringify(ARG_TYPE_REG)" \n\t" \ diff --git a/arch/arm/mach-at91/include/mach/at91_pio.h b/arch/arm/mach-at91/include/mach/at91_pio.h index 732b11c37f1..7b7366253ce 100644 --- a/arch/arm/mach-at91/include/mach/at91_pio.h +++ b/arch/arm/mach-at91/include/mach/at91_pio.h @@ -71,4 +71,10 @@ #define ABCDSR_PERIPH_C 0x2 #define ABCDSR_PERIPH_D 0x3 +#define SAMA5D3_PIO_DRIVER1 0x118 /*PIO Driver 1 register offset*/ +#define SAMA5D3_PIO_DRIVER2 0x11C /*PIO Driver 2 register offset*/ + +#define AT91SAM9X5_PIO_DRIVER1 0x114 /*PIO Driver 1 register offset*/ +#define AT91SAM9X5_PIO_DRIVER2 0x118 /*PIO Driver 2 register offset*/ + #endif diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c index 84acdfd1d71..5a75cdc8189 100644 --- a/arch/arm/mach-imx/clk-gate2.c +++ b/arch/arm/mach-imx/clk-gate2.c @@ -97,7 +97,7 @@ static int clk_gate2_is_enabled(struct clk_hw *hw) struct clk_gate2 *gate = to_clk_gate2(hw); if (gate->share_count) - return !!(*gate->share_count); + return !!__clk_get_enable_count(hw->clk); else return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx); } @@ -127,10 +127,6 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, gate->bit_idx = bit_idx; gate->flags = clk_gate2_flags; gate->lock = lock; - - /* Initialize share_count per hardware state */ - if (share_count) - *share_count = clk_gate2_reg_is_enabled(reg, bit_idx) ? 1 : 0; gate->share_count = share_count; init.name = name; diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index e7189dcc930..08d4167cc7c 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -1,9 +1,6 @@ menu "TI OMAP/AM/DM/DRA Family" depends on ARCH_MULTI_V6 || ARCH_MULTI_V7 -config ARCH_OMAP - bool - config ARCH_OMAP2 bool "TI OMAP2" depends on ARCH_MULTI_V6 diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 8fd87a3055b..9e91a4e7519 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2065,7 +2065,7 @@ static void _reconfigure_io_chain(void) spin_lock_irqsave(&io_chain_lock, flags); - if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl()) + if (cpu_is_omap34xx()) omap3xxx_prm_reconfigure_io_chain(); else if (cpu_is_omap44xx()) omap44xx_prm_reconfigure_io_chain(); diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index 2458be6fc67..372de3edf4a 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -45,7 +45,7 @@ static struct omap_prcm_irq_setup omap3_prcm_irq_setup = { .ocp_barrier = &omap3xxx_prm_ocp_barrier, .save_and_clear_irqen = &omap3xxx_prm_save_and_clear_irqen, .restore_irqen = &omap3xxx_prm_restore_irqen, - .reconfigure_io_chain = &omap3xxx_prm_reconfigure_io_chain, + .reconfigure_io_chain = NULL, }; /* @@ -369,15 +369,30 @@ void __init omap3_prm_init_pm(bool has_uart4, bool has_iva) } /** - * omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain + * omap3430_pre_es3_1_reconfigure_io_chain - restart wake-up daisy chain + * + * The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only + * thing we can do is toggle EN_IO bit for earlier omaps. + */ +void omap3430_pre_es3_1_reconfigure_io_chain(void) +{ + omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, + PM_WKEN); + omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, + PM_WKEN); + omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN); +} + +/** + * omap3_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain * * Clear any previously-latched I/O wakeup events and ensure that the * I/O wakeup gates are aligned with the current mux settings. Works * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No - * return value. + * return value. These registers are only available in 3430 es3.1 and later. */ -void omap3xxx_prm_reconfigure_io_chain(void) +void omap3_prm_reconfigure_io_chain(void) { int i = 0; @@ -400,6 +415,15 @@ void omap3xxx_prm_reconfigure_io_chain(void) } /** + * omap3xxx_prm_reconfigure_io_chain - reconfigure I/O chain + */ +void omap3xxx_prm_reconfigure_io_chain(void) +{ + if (omap3_prcm_irq_setup.reconfigure_io_chain) + omap3_prcm_irq_setup.reconfigure_io_chain(); +} + +/** * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches * * Activates the I/O wakeup event latches and allows events logged by @@ -656,6 +680,13 @@ static int omap3xxx_prm_late_init(void) if (!(prm_features & PRM_HAS_IO_WAKEUP)) return 0; + if (omap3_has_io_chain_ctrl()) + omap3_prcm_irq_setup.reconfigure_io_chain = + omap3_prm_reconfigure_io_chain; + else + omap3_prcm_irq_setup.reconfigure_io_chain = + omap3430_pre_es3_1_reconfigure_io_chain; + omap3xxx_prm_enable_io_wakeup(); ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup); if (!ret) diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 630fa916bbc..04b013fbc98 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -61,7 +61,7 @@ EXPORT_SYMBOL(get_clock_tick_rate); /* * For non device-tree builds, keep legacy timer init */ -void pxa_timer_init(void) +void __init pxa_timer_init(void) { pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x40a00000), get_clock_tick_rate()); diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 0c1ab49e5f7..83792f4324e 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -41,6 +41,7 @@ * This code is not portable to processors with late data abort handling. */ #define CODING_BITS(i) (i & 0x0e000000) +#define COND_BITS(i) (i & 0xf0000000) #define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */ #define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */ @@ -821,6 +822,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) break; case 0x04000000: /* ldr or str immediate */ + if (COND_BITS(instr) == 0xf0000000) /* NEON VLDn, VSTn */ + goto bad; offset.un = OFFSET_BITS(instr); handler = do_alignment_ldrstr; break; diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S index b64e67c7f17..d3daed0ae0a 100644 --- a/arch/arm/mm/proc-v7-3level.S +++ b/arch/arm/mm/proc-v7-3level.S @@ -157,9 +157,9 @@ ENDPROC(cpu_v7_set_pte_ext) * TFR EV X F IHD LR S * .EEE ..EE PUI. .TAT 4RVI ZWRS BLDP WCAM * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced - * 11 0 110 1 0011 1100 .111 1101 < we want + * 11 0 110 0 0011 1100 .111 1101 < we want */ .align 2 .type v7_crval, #object v7_crval: - crval clear=0x0120c302, mmuset=0x30c23c7d, ucset=0x00c01c7c + crval clear=0x0122c302, mmuset=0x30c03c7d, ucset=0x00c01c7c diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 02fc10d2d63..d055db32ffc 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -1,3 +1,6 @@ +config ARCH_OMAP + bool + if ARCH_OMAP menu "TI OMAP Common Features" diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 5d25462de8a..2f7c734771f 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -129,7 +129,11 @@ NESTED(_mcount, PT_SIZE, ra) nop #endif b ftrace_stub +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#else nop +#endif static_trace: MCOUNT_SAVE_REGS @@ -139,6 +143,9 @@ static_trace: move a1, AT /* arg2: parent's return address */ MCOUNT_RESTORE_REGS +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#endif .globl ftrace_stub ftrace_stub: RETURN_BACK @@ -183,6 +190,11 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra) jal prepare_ftrace_return nop MCOUNT_RESTORE_REGS +#ifndef CONFIG_DYNAMIC_FTRACE +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#endif +#endif RETURN_BACK END(ftrace_graph_caller) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index bf0fc6b16ad..7a4727795a7 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -650,9 +650,9 @@ static inline int cop1_64bit(struct pt_regs *xcp) #define SIFROMREG(si, x) \ do { \ if (cop1_64bit(xcp)) \ - (si) = get_fpr32(&ctx->fpr[x], 0); \ + (si) = (int)get_fpr32(&ctx->fpr[x], 0); \ else \ - (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ + (si) = (int)get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ } while (0) #define SITOREG(si, x) \ @@ -667,7 +667,7 @@ do { \ } \ } while (0) -#define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1)) +#define SIFROMHREG(si, x) ((si) = (int)get_fpr32(&ctx->fpr[x], 1)) #define SITOHREG(si, x) \ do { \ diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 36327438caf..e4b1f431c7e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -137,6 +137,7 @@ config X86 select HAVE_ACPI_APEI if ACPI select HAVE_ACPI_APEI_NMI if ACPI select ACPI_LEGACY_TABLES_LOOKUP if ACPI + select X86_FEATURE_NAMES if PROC_FS config INSTRUCTION_DECODER def_bool y @@ -314,6 +315,17 @@ config SMP If you don't know what to do here, say N. +config X86_FEATURE_NAMES + bool "Processor feature human-readable names" if EMBEDDED + default y + ---help--- + This option compiles in a table of x86 feature bits and corresponding + names. This is required to support /proc/cpuinfo and a few kernel + messages. You can disable this to save space, at the expense of + making those few kernel messages show numeric feature bits instead. + + If in doubt, say Y. + config X86_X2APIC bool "Support x2apic" depends on X86_LOCAL_APIC && X86_64 && IRQ_REMAP diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 60087ca3767..5692d6ac0f1 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -253,12 +253,6 @@ archclean: $(Q)$(MAKE) $(clean)=arch/x86/tools $(Q)$(MAKE) $(clean)=arch/x86/purgatory -PHONY += kvmconfig -kvmconfig: - $(if $(wildcard $(objtree)/.config),, $(error You need an existing .config for this target)) - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m -O $(objtree) $(objtree)/.config $(srctree)/arch/x86/configs/kvm_guest.config - $(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig - define archhelp echo '* bzImage - Compressed kernel image (arch/x86/boot/bzImage)' echo ' install - Install kernel using' @@ -272,5 +266,4 @@ define archhelp echo ' bzdisk/fdimage*/isoimage also accept:' echo ' FDARGS="..." arguments for the booted kernel' echo ' FDINITRD=file initrd for the booted kernel' - echo ' kvmconfig - Enable additional options for guest kernel support' endef diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index dbe8dd2fe24..5b016e2498f 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -35,19 +35,22 @@ setup-y += video-vesa.o setup-y += video-bios.o targets += $(setup-y) -hostprogs-y := mkcpustr tools/build +hostprogs-y := tools/build +hostprogs-$(CONFIG_X86_FEATURE_NAMES) += mkcpustr HOST_EXTRACFLAGS += -I$(srctree)/tools/include \ -include include/generated/autoconf.h \ -D__EXPORTED_HEADERS__ +ifdef CONFIG_X86_FEATURE_NAMES $(obj)/cpu.o: $(obj)/cpustr.h quiet_cmd_cpustr = CPUSTR $@ cmd_cpustr = $(obj)/mkcpustr > $@ -targets += cpustr.h +targets += cpustr.h $(obj)/cpustr.h: $(obj)/mkcpustr FORCE $(call if_changed,cpustr) +endif # --------------------------------------------------------------------------- diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 7a801a310e3..704f58aa79c 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -26,18 +26,18 @@ LDFLAGS_vmlinux := -T hostprogs-y := mkpiggy HOST_EXTRACFLAGS += -I$(srctree)/tools/include -VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ - $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \ - $(obj)/piggy.o $(obj)/cpuflags.o $(obj)/aslr.o +vmlinux-objs-y := $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ + $(obj)/string.o $(obj)/cmdline.o \ + $(obj)/piggy.o $(obj)/cpuflags.o + +vmlinux-objs-$(CONFIG_EARLY_PRINTK) += $(obj)/early_serial_console.o +vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/aslr.o $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone -ifeq ($(CONFIG_EFI_STUB), y) - VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ - $(objtree)/drivers/firmware/efi/libstub/lib.a -endif +vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o -$(obj)/vmlinux: $(VMLINUX_OBJS) FORCE +$(obj)/vmlinux: $(vmlinux-objs-y) FORCE $(call if_changed,ld) @: @@ -45,7 +45,7 @@ OBJCOPYFLAGS_vmlinux.bin := -R .comment -S $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) -targets += $(patsubst $(obj)/%,%,$(VMLINUX_OBJS)) vmlinux.bin.all vmlinux.relocs +targets += $(patsubst $(obj)/%,%,$(vmlinux-objs-y)) vmlinux.bin.all vmlinux.relocs CMD_RELOCS = arch/x86/tools/relocs quiet_cmd_relocs = RELOCS $@ diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index fc6091abedb..7c68808edeb 100644 --- a/arch/x86/boot/compressed/aslr.c +++ b/arch/x86/boot/compressed/aslr.c @@ -1,6 +1,5 @@ #include "misc.h" -#ifdef CONFIG_RANDOMIZE_BASE #include <asm/msr.h> #include <asm/archrandom.h> #include <asm/e820.h> @@ -183,12 +182,27 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size, static bool mem_avoid_overlap(struct mem_vector *img) { int i; + struct setup_data *ptr; for (i = 0; i < MEM_AVOID_MAX; i++) { if (mem_overlaps(img, &mem_avoid[i])) return true; } + /* Avoid all entries in the setup_data linked list. */ + ptr = (struct setup_data *)(unsigned long)real_mode->hdr.setup_data; + while (ptr) { + struct mem_vector avoid; + + avoid.start = (u64)ptr; + avoid.size = sizeof(*ptr) + ptr->len; + + if (mem_overlaps(img, &avoid)) + return true; + + ptr = (struct setup_data *)(unsigned long)ptr->next; + } + return false; } @@ -320,5 +334,3 @@ unsigned char *choose_kernel_location(unsigned char *input, out: return (unsigned char *)choice; } - -#endif /* CONFIG_RANDOMIZE_BASE */ diff --git a/arch/x86/boot/compressed/early_serial_console.c b/arch/x86/boot/compressed/early_serial_console.c index d3d003cb548..261e81fb958 100644 --- a/arch/x86/boot/compressed/early_serial_console.c +++ b/arch/x86/boot/compressed/early_serial_console.c @@ -1,9 +1,5 @@ #include "misc.h" -#ifdef CONFIG_EARLY_PRINTK - int early_serial_base; #include "../early_serial_console.c" - -#endif diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index dca9842d8f9..de8eebd6f67 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -19,7 +19,10 @@ static efi_system_table_t *sys_table; -struct efi_config *efi_early; +static struct efi_config *efi_early; + +#define efi_call_early(f, ...) \ + efi_early->call(efi_early->f, __VA_ARGS__); #define BOOT_SERVICES(bits) \ static void setup_boot_services##bits(struct efi_config *c) \ @@ -265,21 +268,25 @@ void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str) offset = offsetof(typeof(*out), output_string); output_string = efi_early->text_output + offset; + out = (typeof(out))(unsigned long)efi_early->text_output; func = (u64 *)output_string; - efi_early->call(*func, efi_early->text_output, str); + efi_early->call(*func, out, str); } else { struct efi_simple_text_output_protocol_32 *out; u32 *func; offset = offsetof(typeof(*out), output_string); output_string = efi_early->text_output + offset; + out = (typeof(out))(unsigned long)efi_early->text_output; func = (u32 *)output_string; - efi_early->call(*func, efi_early->text_output, str); + efi_early->call(*func, out, str); } } +#include "../../../../drivers/firmware/efi/libstub/efi-stub-helper.c" + static void find_bits(unsigned long mask, u8 *pos, u8 *size) { u8 first, len; @@ -360,7 +367,7 @@ free_struct: return status; } -static efi_status_t +static void setup_efi_pci32(struct boot_params *params, void **pci_handle, unsigned long size) { @@ -403,8 +410,6 @@ setup_efi_pci32(struct boot_params *params, void **pci_handle, data = (struct setup_data *)rom; } - - return status; } static efi_status_t @@ -463,7 +468,7 @@ free_struct: } -static efi_status_t +static void setup_efi_pci64(struct boot_params *params, void **pci_handle, unsigned long size) { @@ -506,11 +511,18 @@ setup_efi_pci64(struct boot_params *params, void **pci_handle, data = (struct setup_data *)rom; } - - return status; } -static efi_status_t setup_efi_pci(struct boot_params *params) +/* + * There's no way to return an informative status from this function, + * because any analysis (and printing of error messages) needs to be + * done directly at the EFI function call-site. + * + * For example, EFI_INVALID_PARAMETER could indicate a bug or maybe we + * just didn't find any PCI devices, but there's no way to tell outside + * the context of the call. + */ +static void setup_efi_pci(struct boot_params *params) { efi_status_t status; void **pci_handle = NULL; @@ -527,7 +539,7 @@ static efi_status_t setup_efi_pci(struct boot_params *params) size, (void **)&pci_handle); if (status != EFI_SUCCESS) - return status; + return; status = efi_call_early(locate_handle, EFI_LOCATE_BY_PROTOCOL, &pci_proto, @@ -538,13 +550,12 @@ static efi_status_t setup_efi_pci(struct boot_params *params) goto free_handle; if (efi_early->is64) - status = setup_efi_pci64(params, pci_handle, size); + setup_efi_pci64(params, pci_handle, size); else - status = setup_efi_pci32(params, pci_handle, size); + setup_efi_pci32(params, pci_handle, size); free_handle: efi_call_early(free_pool, pci_handle); - return status; } static void @@ -1380,10 +1391,7 @@ struct boot_params *efi_main(struct efi_config *c, setup_graphics(boot_params); - status = setup_efi_pci(boot_params); - if (status != EFI_SUCCESS) { - efi_printk(sys_table, "setup_efi_pci() failed!\n"); - } + setup_efi_pci(boot_params); status = efi_call_early(allocate_pool, EFI_LOADER_DATA, sizeof(*gdt), (void **)&gdt); diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h index d487e727f1e..c88c31ecad1 100644 --- a/arch/x86/boot/compressed/eboot.h +++ b/arch/x86/boot/compressed/eboot.h @@ -103,4 +103,20 @@ struct efi_uga_draw_protocol { void *blt; }; +struct efi_config { + u64 image_handle; + u64 table; + u64 allocate_pool; + u64 allocate_pages; + u64 get_memory_map; + u64 free_pool; + u64 free_pages; + u64 locate_handle; + u64 handle_protocol; + u64 exit_boot_services; + u64 text_output; + efi_status_t (*call)(unsigned long, ...); + bool is64; +} __packed; + #endif /* BOOT_COMPRESSED_EBOOT_H */ diff --git a/arch/x86/boot/cpu.c b/arch/x86/boot/cpu.c index 6ec6bb6e995..29207f69ae8 100644 --- a/arch/x86/boot/cpu.c +++ b/arch/x86/boot/cpu.c @@ -16,7 +16,9 @@ */ #include "boot.h" +#ifdef CONFIG_X86_FEATURE_NAMES #include "cpustr.h" +#endif static char *cpu_name(int level) { @@ -32,11 +34,48 @@ static char *cpu_name(int level) } } +static void show_cap_strs(u32 *err_flags) +{ + int i, j; +#ifdef CONFIG_X86_FEATURE_NAMES + const unsigned char *msg_strs = (const unsigned char *)x86_cap_strs; + for (i = 0; i < NCAPINTS; i++) { + u32 e = err_flags[i]; + for (j = 0; j < 32; j++) { + if (msg_strs[0] < i || + (msg_strs[0] == i && msg_strs[1] < j)) { + /* Skip to the next string */ + msg_strs += 2; + while (*msg_strs++) + ; + } + if (e & 1) { + if (msg_strs[0] == i && + msg_strs[1] == j && + msg_strs[2]) + printf("%s ", msg_strs+2); + else + printf("%d:%d ", i, j); + } + e >>= 1; + } + } +#else + for (i = 0; i < NCAPINTS; i++) { + u32 e = err_flags[i]; + for (j = 0; j < 32; j++) { + if (e & 1) + printf("%d:%d ", i, j); + e >>= 1; + } + } +#endif +} + int validate_cpu(void) { u32 *err_flags; int cpu_level, req_level; - const unsigned char *msg_strs; check_cpu(&cpu_level, &req_level, &err_flags); @@ -49,34 +88,9 @@ int validate_cpu(void) } if (err_flags) { - int i, j; puts("This kernel requires the following features " "not present on the CPU:\n"); - - msg_strs = (const unsigned char *)x86_cap_strs; - - for (i = 0; i < NCAPINTS; i++) { - u32 e = err_flags[i]; - - for (j = 0; j < 32; j++) { - if (msg_strs[0] < i || - (msg_strs[0] == i && msg_strs[1] < j)) { - /* Skip to the next string */ - msg_strs += 2; - while (*msg_strs++) - ; - } - if (e & 1) { - if (msg_strs[0] == i && - msg_strs[1] == j && - msg_strs[2]) - printf("%s ", msg_strs+2); - else - printf("%d:%d ", i, j); - } - e >>= 1; - } - } + show_cap_strs(err_flags); putchar('\n'); return -1; } else { diff --git a/arch/x86/configs/tiny.config b/arch/x86/configs/tiny.config new file mode 100644 index 00000000000..4e2ecfa23c1 --- /dev/null +++ b/arch/x86/configs/tiny.config @@ -0,0 +1 @@ +CONFIG_NOHIGHMEM=y diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index bb9b258d60e..516903b98e0 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -250,8 +250,15 @@ #include <asm/asm.h> #include <linux/bitops.h> +#ifdef CONFIG_X86_FEATURE_NAMES extern const char * const x86_cap_flags[NCAPINTS*32]; extern const char * const x86_power_flags[32]; +#define X86_CAP_FMT "%s" +#define x86_cap_flag(flag) x86_cap_flags[flag] +#else +#define X86_CAP_FMT "%d:%d" +#define x86_cap_flag(flag) ((flag) >> 5), ((flag) & 31) +#endif /* * In order to save room, we index into this array by doing diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 044a2fd3c5f..0ec241ede5a 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -159,30 +159,6 @@ static inline efi_status_t efi_thunk_set_virtual_address_map( } #endif /* CONFIG_EFI_MIXED */ - -/* arch specific definitions used by the stub code */ - -struct efi_config { - u64 image_handle; - u64 table; - u64 allocate_pool; - u64 allocate_pages; - u64 get_memory_map; - u64 free_pool; - u64 free_pages; - u64 locate_handle; - u64 handle_protocol; - u64 exit_boot_services; - u64 text_output; - efi_status_t (*call)(unsigned long, ...); - bool is64; -} __packed; - -extern struct efi_config *efi_early; - -#define efi_call_early(f, ...) \ - efi_early->call(efi_early->f, __VA_ARGS__); - extern bool efi_reboot_required(void); #else diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index b0910f97a3e..ffb1733ac91 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -106,14 +106,14 @@ enum fixed_addresses { __end_of_permanent_fixed_addresses, /* - * 256 temporary boot-time mappings, used by early_ioremap(), + * 512 temporary boot-time mappings, used by early_ioremap(), * before ioremap() is functional. * - * If necessary we round it up to the next 256 pages boundary so + * If necessary we round it up to the next 512 pages boundary so * that we can have a single pgd entry and a single pte table: */ #define NR_FIX_BTMAPS 64 -#define FIX_BTMAPS_SLOTS 4 +#define FIX_BTMAPS_SLOTS 8 #define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS) FIX_BTMAP_END = (__end_of_permanent_fixed_addresses ^ diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 7fd54f09b01..77dcab27771 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -13,10 +13,13 @@ nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_common.o := $(nostackp) obj-y := intel_cacheinfo.o scattered.o topology.o -obj-y += proc.o capflags.o powerflags.o common.o +obj-y += common.o obj-y += rdrand.o obj-y += match.o +obj-$(CONFIG_PROC_FS) += proc.o +obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o + obj-$(CONFIG_X86_32) += bugs.o obj-$(CONFIG_X86_64) += bugs_64.o @@ -48,6 +51,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o perf_event_amd_ibs.o obj-$(CONFIG_HYPERVISOR_GUEST) += vmware.o hypervisor.o mshyperv.o +ifdef CONFIG_X86_FEATURE_NAMES quiet_cmd_mkcapflags = MKCAP $@ cmd_mkcapflags = $(CONFIG_SHELL) $(srctree)/$(src)/mkcapflags.sh $< $@ @@ -56,3 +60,4 @@ cpufeature = $(src)/../../include/asm/cpufeature.h targets += capflags.c $(obj)/capflags.c: $(cpufeature) $(src)/mkcapflags.sh FORCE $(call if_changed,mkcapflags) +endif diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index e4ab2b42bd6..c649f236e28 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -346,8 +346,8 @@ static void filter_cpuid_features(struct cpuinfo_x86 *c, bool warn) continue; printk(KERN_WARNING - "CPU: CPU feature %s disabled, no CPUID level 0x%x\n", - x86_cap_flags[df->feature], df->level); + "CPU: CPU feature " X86_CAP_FMT " disabled, no CPUID level 0x%x\n", + x86_cap_flag(df->feature), df->level); } } diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 2d872e08fab..42a2dca984b 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1284,6 +1284,9 @@ static void remove_siblinginfo(int cpu) for_each_cpu(sibling, cpu_sibling_mask(cpu)) cpumask_clear_cpu(cpu, cpu_sibling_mask(sibling)); + for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) + cpumask_clear_cpu(cpu, cpu_llc_shared_mask(sibling)); + cpumask_clear(cpu_llc_shared_mask(cpu)); cpumask_clear(cpu_sibling_mask(cpu)); cpumask_clear(cpu_core_mask(cpu)); c->phys_proc_id = 0; diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c index 3c562f5a60b..e1bce26cd4f 100644 --- a/crypto/async_tx/async_xor.c +++ b/crypto/async_tx/async_xor.c @@ -78,8 +78,6 @@ do_async_xor(struct dma_chan *chan, struct dmaengine_unmap_data *unmap, tx = dma->device_prep_dma_xor(chan, dma_dest, src_list, xor_src_cnt, unmap->len, dma_flags); - src_list[0] = tmp; - if (unlikely(!tx)) async_tx_quiesce(&submit->depend_tx); @@ -92,6 +90,7 @@ do_async_xor(struct dma_chan *chan, struct dmaengine_unmap_data *unmap, xor_src_cnt, unmap->len, dma_flags); } + src_list[0] = tmp; dma_set_unmap(tx, unmap); async_tx_submit(chan, tx, submit); diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 4251570610c..8a3f51f7b1b 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -11,12 +11,15 @@ config REGMAP config REGMAP_I2C tristate + depends on I2C config REGMAP_SPI tristate + depends on SPI config REGMAP_SPMI tristate + depends on SPMI config REGMAP_MMIO tristate diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index bfc90b8547f..0da5865df5b 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -49,8 +49,10 @@ struct regmap_async { }; struct regmap { - struct mutex mutex; - spinlock_t spinlock; + union { + struct mutex mutex; + spinlock_t spinlock; + }; unsigned long spinlock_flags; regmap_lock lock; regmap_unlock unlock; diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 5617da6dc89..f1280dc356d 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -269,8 +269,11 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, map->cache_bypass = 1; ret = _regmap_write(map, reg, val); map->cache_bypass = 0; - if (ret) + if (ret) { + dev_err(map->dev, "Unable to sync register %#x. %d\n", + reg, ret); return ret; + } dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val); } @@ -615,8 +618,11 @@ static int regcache_sync_block_single(struct regmap *map, void *block, ret = _regmap_write(map, regtmp, val); map->cache_bypass = 0; - if (ret != 0) + if (ret != 0) { + dev_err(map->dev, "Unable to sync register %#x. %d\n", + regtmp, ret); return ret; + } dev_dbg(map->dev, "Synced register %#x, value %#x\n", regtmp, val); } @@ -641,6 +647,9 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, map->cache_bypass = 1; ret = _regmap_raw_write(map, base, *data, count * val_bytes); + if (ret) + dev_err(map->dev, "Unable to sync registers %#x-%#x. %d\n", + base, cur - map->reg_stride, ret); map->cache_bypass = 0; diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 0c94b661c16..5799a0b9e6c 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -473,6 +473,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name) { struct rb_node *next; struct regmap_range_node *range_node; + const char *devname = "dummy"; /* If we don't have the debugfs root yet, postpone init */ if (!regmap_debugfs_root) { @@ -491,12 +492,15 @@ void regmap_debugfs_init(struct regmap *map, const char *name) INIT_LIST_HEAD(&map->debugfs_off_cache); mutex_init(&map->cache_lock); + if (map->dev) + devname = dev_name(map->dev); + if (name) { map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", - dev_name(map->dev), name); + devname, name); name = map->debugfs_name; } else { - name = dev_name(map->dev); + name = devname; } map->debugfs = debugfs_create_dir(name, regmap_debugfs_root); diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index ca193d1ef47..053150a7f9f 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -168,6 +168,8 @@ static struct regmap_bus regmap_i2c = { .write = regmap_i2c_write, .gather_write = regmap_i2c_gather_write, .read = regmap_i2c_read, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, }; static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 0eb3097c0d7..53d1148e80a 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c @@ -109,6 +109,8 @@ static struct regmap_bus regmap_spi = { .async_alloc = regmap_spi_async_alloc, .read = regmap_spi_read, .read_flag_mask = 0x80, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, }; /** diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 1cf427bc0d4..d2f8a818d20 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -15,6 +15,7 @@ #include <linux/export.h> #include <linux/mutex.h> #include <linux/err.h> +#include <linux/of.h> #include <linux/rbtree.h> #include <linux/sched.h> @@ -448,6 +449,71 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, } EXPORT_SYMBOL_GPL(regmap_attach_dev); +static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus, + const struct regmap_config *config) +{ + enum regmap_endian endian; + + /* Retrieve the endianness specification from the regmap config */ + endian = config->reg_format_endian; + + /* If the regmap config specified a non-default value, use that */ + if (endian != REGMAP_ENDIAN_DEFAULT) + return endian; + + /* Retrieve the endianness specification from the bus config */ + if (bus && bus->reg_format_endian_default) + endian = bus->reg_format_endian_default; + + /* If the bus specified a non-default value, use that */ + if (endian != REGMAP_ENDIAN_DEFAULT) + return endian; + + /* Use this if no other value was found */ + return REGMAP_ENDIAN_BIG; +} + +static enum regmap_endian regmap_get_val_endian(struct device *dev, + const struct regmap_bus *bus, + const struct regmap_config *config) +{ + struct device_node *np; + enum regmap_endian endian; + + /* Retrieve the endianness specification from the regmap config */ + endian = config->val_format_endian; + + /* If the regmap config specified a non-default value, use that */ + if (endian != REGMAP_ENDIAN_DEFAULT) + return endian; + + /* If the dev and dev->of_node exist try to get endianness from DT */ + if (dev && dev->of_node) { + np = dev->of_node; + + /* Parse the device's DT node for an endianness specification */ + if (of_property_read_bool(np, "big-endian")) + endian = REGMAP_ENDIAN_BIG; + else if (of_property_read_bool(np, "little-endian")) + endian = REGMAP_ENDIAN_LITTLE; + + /* If the endianness was specified in DT, use that */ + if (endian != REGMAP_ENDIAN_DEFAULT) + return endian; + } + + /* Retrieve the endianness specification from the bus config */ + if (bus && bus->val_format_endian_default) + endian = bus->val_format_endian_default; + + /* If the bus specified a non-default value, use that */ + if (endian != REGMAP_ENDIAN_DEFAULT) + return endian; + + /* Use this if no other value was found */ + return REGMAP_ENDIAN_BIG; +} + /** * regmap_init(): Initialise register map * @@ -551,17 +617,8 @@ struct regmap *regmap_init(struct device *dev, map->reg_read = _regmap_bus_read; } - reg_endian = config->reg_format_endian; - if (reg_endian == REGMAP_ENDIAN_DEFAULT) - reg_endian = bus->reg_format_endian_default; - if (reg_endian == REGMAP_ENDIAN_DEFAULT) - reg_endian = REGMAP_ENDIAN_BIG; - - val_endian = config->val_format_endian; - if (val_endian == REGMAP_ENDIAN_DEFAULT) - val_endian = bus->val_format_endian_default; - if (val_endian == REGMAP_ENDIAN_DEFAULT) - val_endian = REGMAP_ENDIAN_BIG; + reg_endian = regmap_get_reg_endian(bus, config); + val_endian = regmap_get_val_endian(dev, bus, config); switch (config->reg_bits + map->reg_shift) { case 2: @@ -1408,7 +1465,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, } #ifdef LOG_DEVICE - if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0) + if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0) dev_info(map->dev, "%x <= %x\n", reg, val); #endif @@ -1659,6 +1716,9 @@ out: } else { void *wval; + if (!val_count) + return -EINVAL; + wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL); if (!wval) { dev_err(map->dev, "Error in memory allocation\n"); @@ -2058,7 +2118,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg, ret = map->reg_read(context, reg, val); if (ret == 0) { #ifdef LOG_DEVICE - if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0) + if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0) dev_info(map->dev, "%x => %x\n", reg, *val); #endif diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 551e0106143..95254585db8 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -188,31 +188,31 @@ static struct l3_flagmux_data omap_l3_flagmux_clk3 = { }; static struct l3_masters_data omap_l3_masters[] = { - { 0x0 , "MPU"}, - { 0x10, "CS_ADP"}, - { 0x14, "xxx"}, - { 0x20, "DSP"}, - { 0x30, "IVAHD"}, - { 0x40, "ISS"}, - { 0x44, "DucatiM3"}, - { 0x48, "FaceDetect"}, - { 0x50, "SDMA_Rd"}, - { 0x54, "SDMA_Wr"}, - { 0x58, "xxx"}, - { 0x5C, "xxx"}, - { 0x60, "SGX"}, - { 0x70, "DSS"}, - { 0x80, "C2C"}, - { 0x88, "xxx"}, - { 0x8C, "xxx"}, - { 0x90, "HSI"}, - { 0xA0, "MMC1"}, - { 0xA4, "MMC2"}, - { 0xA8, "MMC6"}, - { 0xB0, "UNIPRO1"}, - { 0xC0, "USBHOSTHS"}, - { 0xC4, "USBOTGHS"}, - { 0xC8, "USBHOSTFS"} + { 0x00, "MPU"}, + { 0x04, "CS_ADP"}, + { 0x05, "xxx"}, + { 0x08, "DSP"}, + { 0x0C, "IVAHD"}, + { 0x10, "ISS"}, + { 0x11, "DucatiM3"}, + { 0x12, "FaceDetect"}, + { 0x14, "SDMA_Rd"}, + { 0x15, "SDMA_Wr"}, + { 0x16, "xxx"}, + { 0x17, "xxx"}, + { 0x18, "SGX"}, + { 0x1C, "DSS"}, + { 0x20, "C2C"}, + { 0x22, "xxx"}, + { 0x23, "xxx"}, + { 0x24, "HSI"}, + { 0x28, "MMC1"}, + { 0x29, "MMC2"}, + { 0x2A, "MMC6"}, + { 0x2C, "UNIPRO1"}, + { 0x30, "USBHOSTHS"}, + { 0x31, "USBOTGHS"}, + { 0x32, "USBHOSTFS"} }; static struct l3_flagmux_data *omap_l3_flagmux[] = { diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e6db9381b2c..f816211f062 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2796,7 +2796,6 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) = IPMI_CHANNEL_MEDIUM_IPMB; intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; - rv = -ENOSYS; intf->curr_channel = IPMI_MAX_CHANNELS; wake_up(&intf->waitq); @@ -2821,12 +2820,12 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if (rv) { /* Got an error somehow, just give up. */ + printk(KERN_WARNING PFX + "Error sending channel information for channel" + " %d: %d\n", intf->curr_channel, rv); + intf->curr_channel = IPMI_MAX_CHANNELS; wake_up(&intf->waitq); - - printk(KERN_WARNING PFX - "Error sending channel information: %d\n", - rv); } } out: @@ -2964,8 +2963,12 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, intf->null_user_handler = channel_handler; intf->curr_channel = 0; rv = send_channel_info_cmd(intf, 0); - if (rv) + if (rv) { + printk(KERN_WARNING PFX + "Error sending channel information for channel" + " 0, %d\n", rv); goto out; + } /* Wait for the channel info to be read. */ wait_event(intf->waitq, diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 5d665680ae3..5c4e1f625bb 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -965,9 +965,9 @@ static inline int ipmi_si_is_busy(struct timespec *ts) return ts->tv_nsec != -1; } -static int ipmi_thread_busy_wait(enum si_sm_result smi_result, - const struct smi_info *smi_info, - struct timespec *busy_until) +static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result, + const struct smi_info *smi_info, + struct timespec *busy_until) { unsigned int max_busy_us = 0; @@ -2658,6 +2658,9 @@ static int ipmi_probe(struct platform_device *dev) if (!match) return -EINVAL; + if (!of_device_is_available(np)) + return -EINVAL; + ret = of_address_to_resource(np, 0, &resource); if (ret) { dev_warn(&dev->dev, PFX "invalid address from OF\n"); @@ -3655,6 +3658,9 @@ static void cleanup_one_si(struct smi_info *to_clean) if (!to_clean) return; + if (to_clean->dev) + dev_set_drvdata(to_clean->dev, NULL); + list_del(&to_clean->link); /* Tell the driver that we are shutting down. */ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 6e93e7f9835..61190f6b482 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1658,10 +1658,8 @@ void cpufreq_suspend(void) if (!cpufreq_driver) return; - cpufreq_suspended = true; - if (!has_target()) - return; + goto suspend; pr_debug("%s: Suspending Governors\n", __func__); @@ -1674,6 +1672,9 @@ void cpufreq_suspend(void) pr_err("%s: Failed to suspend driver: %p\n", __func__, policy); } + +suspend: + cpufreq_suspended = true; } /** diff --git a/drivers/cpufreq/integrator-cpufreq.c b/drivers/cpufreq/integrator-cpufreq.c index c1320528b9d..6bd69adc3c5 100644 --- a/drivers/cpufreq/integrator-cpufreq.c +++ b/drivers/cpufreq/integrator-cpufreq.c @@ -213,9 +213,9 @@ static int __init integrator_cpufreq_probe(struct platform_device *pdev) return cpufreq_register_driver(&integrator_driver); } -static void __exit integrator_cpufreq_remove(struct platform_device *pdev) +static int __exit integrator_cpufreq_remove(struct platform_device *pdev) { - cpufreq_unregister_driver(&integrator_driver); + return cpufreq_unregister_driver(&integrator_driver); } static const struct of_device_id integrator_cpufreq_match[] = { diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 728a2d87949..4d2c8e86108 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -204,7 +204,6 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, u32 input_buffer; int cpu; - spin_lock(&pcc_lock); cpu = policy->cpu; pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); @@ -216,6 +215,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, freqs.old = policy->cur; freqs.new = target_freq; cpufreq_freq_transition_begin(policy, &freqs); + spin_lock(&pcc_lock); input_buffer = 0x1 | (((target_freq * 100) / (ioread32(&pcch_hdr->nominal) * 1000)) << 8); diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 9b1ea0ef59a..a016490c95a 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -427,18 +427,6 @@ config DMA_OF comment "DMA Clients" depends on DMA_ENGINE -config NET_DMA - bool "Network: TCP receive copy offload" - depends on DMA_ENGINE && NET - default (INTEL_IOATDMA || FSL_DMA) - depends on BROKEN - help - This enables the use of DMA engines in the network stack to - offload receive copy-to-user operations, freeing CPU cycles. - - Say Y here if you enabled INTEL_IOATDMA or FSL_DMA, otherwise - say N. - config ASYNC_TX_DMA bool "Async_tx: Offload support for the async_tx api" depends on DMA_ENGINE diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index c6adb925f0b..cb626c17991 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o obj-$(CONFIG_DMA_ACPI) += acpi-dma.o obj-$(CONFIG_DMA_OF) += of-dma.o -obj-$(CONFIG_NET_DMA) += iovlock.o obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o obj-$(CONFIG_DMATEST) += dmatest.o obj-$(CONFIG_INTEL_IOATDMA) += ioat/ diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index d5d30ed863c..24bfaf0b92b 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -1081,110 +1081,6 @@ dmaengine_get_unmap_data(struct device *dev, int nr, gfp_t flags) } EXPORT_SYMBOL(dmaengine_get_unmap_data); -/** - * dma_async_memcpy_pg_to_pg - offloaded copy from page to page - * @chan: DMA channel to offload copy to - * @dest_pg: destination page - * @dest_off: offset in page to copy to - * @src_pg: source page - * @src_off: offset in page to copy from - * @len: length - * - * Both @dest_page/@dest_off and @src_page/@src_off must be mappable to a bus - * address according to the DMA mapping API rules for streaming mappings. - * Both @dest_page/@dest_off and @src_page/@src_off must stay memory resident - * (kernel memory or locked user space pages). - */ -dma_cookie_t -dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg, - unsigned int dest_off, struct page *src_pg, unsigned int src_off, - size_t len) -{ - struct dma_device *dev = chan->device; - struct dma_async_tx_descriptor *tx; - struct dmaengine_unmap_data *unmap; - dma_cookie_t cookie; - unsigned long flags; - - unmap = dmaengine_get_unmap_data(dev->dev, 2, GFP_NOWAIT); - if (!unmap) - return -ENOMEM; - - unmap->to_cnt = 1; - unmap->from_cnt = 1; - unmap->addr[0] = dma_map_page(dev->dev, src_pg, src_off, len, - DMA_TO_DEVICE); - unmap->addr[1] = dma_map_page(dev->dev, dest_pg, dest_off, len, - DMA_FROM_DEVICE); - unmap->len = len; - flags = DMA_CTRL_ACK; - tx = dev->device_prep_dma_memcpy(chan, unmap->addr[1], unmap->addr[0], - len, flags); - - if (!tx) { - dmaengine_unmap_put(unmap); - return -ENOMEM; - } - - dma_set_unmap(tx, unmap); - cookie = tx->tx_submit(tx); - dmaengine_unmap_put(unmap); - - preempt_disable(); - __this_cpu_add(chan->local->bytes_transferred, len); - __this_cpu_inc(chan->local->memcpy_count); - preempt_enable(); - - return cookie; -} -EXPORT_SYMBOL(dma_async_memcpy_pg_to_pg); - -/** - * dma_async_memcpy_buf_to_buf - offloaded copy between virtual addresses - * @chan: DMA channel to offload copy to - * @dest: destination address (virtual) - * @src: source address (virtual) - * @len: length - * - * Both @dest and @src must be mappable to a bus address according to the - * DMA mapping API rules for streaming mappings. - * Both @dest and @src must stay memory resident (kernel memory or locked - * user space pages). - */ -dma_cookie_t -dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest, - void *src, size_t len) -{ - return dma_async_memcpy_pg_to_pg(chan, virt_to_page(dest), - (unsigned long) dest & ~PAGE_MASK, - virt_to_page(src), - (unsigned long) src & ~PAGE_MASK, len); -} -EXPORT_SYMBOL(dma_async_memcpy_buf_to_buf); - -/** - * dma_async_memcpy_buf_to_pg - offloaded copy from address to page - * @chan: DMA channel to offload copy to - * @page: destination page - * @offset: offset in page to copy to - * @kdata: source address (virtual) - * @len: length - * - * Both @page/@offset and @kdata must be mappable to a bus address according - * to the DMA mapping API rules for streaming mappings. - * Both @page/@offset and @kdata must stay memory resident (kernel memory or - * locked user space pages) - */ -dma_cookie_t -dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page, - unsigned int offset, void *kdata, size_t len) -{ - return dma_async_memcpy_pg_to_pg(chan, page, offset, - virt_to_page(kdata), - (unsigned long) kdata & ~PAGE_MASK, len); -} -EXPORT_SYMBOL(dma_async_memcpy_buf_to_pg); - void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, struct dma_chan *chan) { diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index e27cec25c59..a8d7809e2f4 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -688,14 +688,14 @@ static int dmatest_func(void *data) runtime = ktime_us_delta(ktime_get(), ktime); ret = 0; +err_dstbuf: for (i = 0; thread->dsts[i]; i++) kfree(thread->dsts[i]); -err_dstbuf: kfree(thread->dsts); err_dsts: +err_srcbuf: for (i = 0; thread->srcs[i]; i++) kfree(thread->srcs[i]); -err_srcbuf: kfree(thread->srcs); err_srcs: kfree(pq_coefs); diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c index 9e84d5bc930..3b55bb8d969 100644 --- a/drivers/dma/ioat/dca.c +++ b/drivers/dma/ioat/dca.c @@ -35,6 +35,7 @@ #include "dma.h" #include "registers.h" +#include "dma_v2.h" /* * Bit 7 of a tag map entry is the "valid" bit, if it is set then bits 0:6 @@ -147,7 +148,7 @@ static int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev) u16 id; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); id = dcaid_from_pcidev(pdev); @@ -179,7 +180,7 @@ static int ioat_dca_remove_requester(struct dca_provider *dca, int i; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); @@ -320,7 +321,7 @@ static int ioat2_dca_add_requester(struct dca_provider *dca, struct device *dev) u16 global_req_table; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); id = dcaid_from_pcidev(pdev); @@ -354,7 +355,7 @@ static int ioat2_dca_remove_requester(struct dca_provider *dca, u16 global_req_table; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); @@ -496,7 +497,7 @@ static int ioat3_dca_add_requester(struct dca_provider *dca, struct device *dev) u16 global_req_table; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); id = dcaid_from_pcidev(pdev); @@ -530,7 +531,7 @@ static int ioat3_dca_remove_requester(struct dca_provider *dca, u16 global_req_table; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 4e3549a1613..940c1502a8b 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -947,7 +947,7 @@ msix: for (i = 0; i < msixcnt; i++) device->msix_entries[i].entry = i; - err = pci_enable_msix(pdev, device->msix_entries, msixcnt); + err = pci_enable_msix_exact(pdev, device->msix_entries, msixcnt); if (err) goto msi; @@ -1222,7 +1222,6 @@ int ioat1_dma_probe(struct ioatdma_device *device, int dca) err = ioat_probe(device); if (err) return err; - ioat_set_tcp_copy_break(4096); err = ioat_register(device); if (err) return err; diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h index e982f00a984..d63f68b1aa3 100644 --- a/drivers/dma/ioat/dma.h +++ b/drivers/dma/ioat/dma.h @@ -214,13 +214,6 @@ __dump_desc_dbg(struct ioat_chan_common *chan, struct ioat_dma_descriptor *hw, #define dump_desc_dbg(c, d) \ ({ if (d) __dump_desc_dbg(&c->base, d->hw, &d->txd, desc_id(d)); 0; }) -static inline void ioat_set_tcp_copy_break(unsigned long copybreak) -{ - #ifdef CONFIG_NET_DMA - sysctl_tcp_dma_copybreak = copybreak; - #endif -} - static inline struct ioat_chan_common * ioat_chan_by_index(struct ioatdma_device *device, int index) { diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c index 8d1058085ee..695483e6be3 100644 --- a/drivers/dma/ioat/dma_v2.c +++ b/drivers/dma/ioat/dma_v2.c @@ -735,7 +735,8 @@ int ioat2_check_space_lock(struct ioat2_dma_chan *ioat, int num_descs) * called under bh_disabled so we need to trigger the timer * event directly */ - if (jiffies > chan->timer.expires && timer_pending(&chan->timer)) { + if (time_is_before_jiffies(chan->timer.expires) + && timer_pending(&chan->timer)) { struct ioatdma_device *device = chan->device; mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT); @@ -899,7 +900,6 @@ int ioat2_dma_probe(struct ioatdma_device *device, int dca) err = ioat_probe(device); if (err) return err; - ioat_set_tcp_copy_break(2048); list_for_each_entry(c, &dma->channels, device_node) { chan = to_chan_common(c); diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index b9b38a1cf92..895f869d6c2 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -740,7 +740,7 @@ ioat3_prep_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, return __ioat3_prep_xor_lock(chan, NULL, dest, src, src_cnt, len, flags); } -struct dma_async_tx_descriptor * +static struct dma_async_tx_descriptor * ioat3_prep_xor_val(struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt, size_t len, enum sum_check_flags *result, unsigned long flags) @@ -1091,7 +1091,7 @@ ioat3_prep_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src, } } -struct dma_async_tx_descriptor * +static struct dma_async_tx_descriptor * ioat3_prep_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, unsigned int src_cnt, const unsigned char *scf, size_t len, enum sum_check_flags *pqres, unsigned long flags) @@ -1133,7 +1133,7 @@ ioat3_prep_pqxor(struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src, flags); } -struct dma_async_tx_descriptor * +static struct dma_async_tx_descriptor * ioat3_prep_pqxor_val(struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt, size_t len, enum sum_check_flags *result, unsigned long flags) @@ -1655,7 +1655,6 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca) err = ioat_probe(device); if (err) return err; - ioat_set_tcp_copy_break(262144); list_for_each_entry(c, &dma->channels, device_node) { chan = to_chan_common(c); diff --git a/drivers/dma/iovlock.c b/drivers/dma/iovlock.c deleted file mode 100644 index bb48a57c2fc..00000000000 --- a/drivers/dma/iovlock.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. - * Portions based on net/core/datagram.c and copyrighted by their authors. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -/* - * This code allows the net stack to make use of a DMA engine for - * skb to iovec copies. - */ - -#include <linux/dmaengine.h> -#include <linux/pagemap.h> -#include <linux/slab.h> -#include <net/tcp.h> /* for memcpy_toiovec */ -#include <asm/io.h> -#include <asm/uaccess.h> - -static int num_pages_spanned(struct iovec *iov) -{ - return - ((PAGE_ALIGN((unsigned long)iov->iov_base + iov->iov_len) - - ((unsigned long)iov->iov_base & PAGE_MASK)) >> PAGE_SHIFT); -} - -/* - * Pin down all the iovec pages needed for len bytes. - * Return a struct dma_pinned_list to keep track of pages pinned down. - * - * We are allocating a single chunk of memory, and then carving it up into - * 3 sections, the latter 2 whose size depends on the number of iovecs and the - * total number of pages, respectively. - */ -struct dma_pinned_list *dma_pin_iovec_pages(struct iovec *iov, size_t len) -{ - struct dma_pinned_list *local_list; - struct page **pages; - int i; - int ret; - int nr_iovecs = 0; - int iovec_len_used = 0; - int iovec_pages_used = 0; - - /* don't pin down non-user-based iovecs */ - if (segment_eq(get_fs(), KERNEL_DS)) - return NULL; - - /* determine how many iovecs/pages there are, up front */ - do { - iovec_len_used += iov[nr_iovecs].iov_len; - iovec_pages_used += num_pages_spanned(&iov[nr_iovecs]); - nr_iovecs++; - } while (iovec_len_used < len); - - /* single kmalloc for pinned list, page_list[], and the page arrays */ - local_list = kmalloc(sizeof(*local_list) - + (nr_iovecs * sizeof (struct dma_page_list)) - + (iovec_pages_used * sizeof (struct page*)), GFP_KERNEL); - if (!local_list) - goto out; - - /* list of pages starts right after the page list array */ - pages = (struct page **) &local_list->page_list[nr_iovecs]; - - local_list->nr_iovecs = 0; - - for (i = 0; i < nr_iovecs; i++) { - struct dma_page_list *page_list = &local_list->page_list[i]; - - len -= iov[i].iov_len; - - if (!access_ok(VERIFY_WRITE, iov[i].iov_base, iov[i].iov_len)) - goto unpin; - - page_list->nr_pages = num_pages_spanned(&iov[i]); - page_list->base_address = iov[i].iov_base; - - page_list->pages = pages; - pages += page_list->nr_pages; - - /* pin pages down */ - down_read(¤t->mm->mmap_sem); - ret = get_user_pages( - current, - current->mm, - (unsigned long) iov[i].iov_base, - page_list->nr_pages, - 1, /* write */ - 0, /* force */ - page_list->pages, - NULL); - up_read(¤t->mm->mmap_sem); - - if (ret != page_list->nr_pages) - goto unpin; - - local_list->nr_iovecs = i + 1; - } - - return local_list; - -unpin: - dma_unpin_iovec_pages(local_list); -out: - return NULL; -} - -void dma_unpin_iovec_pages(struct dma_pinned_list *pinned_list) -{ - int i, j; - - if (!pinned_list) - return; - - for (i = 0; i < pinned_list->nr_iovecs; i++) { - struct dma_page_list *page_list = &pinned_list->page_list[i]; - for (j = 0; j < page_list->nr_pages; j++) { - set_page_dirty_lock(page_list->pages[j]); - page_cache_release(page_list->pages[j]); - } - } - - kfree(pinned_list); -} - - -/* - * We have already pinned down the pages we will be using in the iovecs. - * Each entry in iov array has corresponding entry in pinned_list->page_list. - * Using array indexing to keep iov[] and page_list[] in sync. - * Initial elements in iov array's iov->iov_len will be 0 if already copied into - * by another call. - * iov array length remaining guaranteed to be bigger than len. - */ -dma_cookie_t dma_memcpy_to_iovec(struct dma_chan *chan, struct iovec *iov, - struct dma_pinned_list *pinned_list, unsigned char *kdata, size_t len) -{ - int iov_byte_offset; - int copy; - dma_cookie_t dma_cookie = 0; - int iovec_idx; - int page_idx; - - if (!chan) - return memcpy_toiovec(iov, kdata, len); - - iovec_idx = 0; - while (iovec_idx < pinned_list->nr_iovecs) { - struct dma_page_list *page_list; - - /* skip already used-up iovecs */ - while (!iov[iovec_idx].iov_len) - iovec_idx++; - - page_list = &pinned_list->page_list[iovec_idx]; - - iov_byte_offset = ((unsigned long)iov[iovec_idx].iov_base & ~PAGE_MASK); - page_idx = (((unsigned long)iov[iovec_idx].iov_base & PAGE_MASK) - - ((unsigned long)page_list->base_address & PAGE_MASK)) >> PAGE_SHIFT; - - /* break up copies to not cross page boundary */ - while (iov[iovec_idx].iov_len) { - copy = min_t(int, PAGE_SIZE - iov_byte_offset, len); - copy = min_t(int, copy, iov[iovec_idx].iov_len); - - dma_cookie = dma_async_memcpy_buf_to_pg(chan, - page_list->pages[page_idx], - iov_byte_offset, - kdata, - copy); - /* poll for a descriptor slot */ - if (unlikely(dma_cookie < 0)) { - dma_async_issue_pending(chan); - continue; - } - - len -= copy; - iov[iovec_idx].iov_len -= copy; - iov[iovec_idx].iov_base += copy; - - if (!len) - return dma_cookie; - - kdata += copy; - iov_byte_offset = 0; - page_idx++; - } - iovec_idx++; - } - - /* really bad if we ever run out of iovecs */ - BUG(); - return -EFAULT; -} - -dma_cookie_t dma_memcpy_pg_to_iovec(struct dma_chan *chan, struct iovec *iov, - struct dma_pinned_list *pinned_list, struct page *page, - unsigned int offset, size_t len) -{ - int iov_byte_offset; - int copy; - dma_cookie_t dma_cookie = 0; - int iovec_idx; - int page_idx; - int err; - - /* this needs as-yet-unimplemented buf-to-buff, so punt. */ - /* TODO: use dma for this */ - if (!chan || !pinned_list) { - u8 *vaddr = kmap(page); - err = memcpy_toiovec(iov, vaddr + offset, len); - kunmap(page); - return err; - } - - iovec_idx = 0; - while (iovec_idx < pinned_list->nr_iovecs) { - struct dma_page_list *page_list; - - /* skip already used-up iovecs */ - while (!iov[iovec_idx].iov_len) - iovec_idx++; - - page_list = &pinned_list->page_list[iovec_idx]; - - iov_byte_offset = ((unsigned long)iov[iovec_idx].iov_base & ~PAGE_MASK); - page_idx = (((unsigned long)iov[iovec_idx].iov_base & PAGE_MASK) - - ((unsigned long)page_list->base_address & PAGE_MASK)) >> PAGE_SHIFT; - - /* break up copies to not cross page boundary */ - while (iov[iovec_idx].iov_len) { - copy = min_t(int, PAGE_SIZE - iov_byte_offset, len); - copy = min_t(int, copy, iov[iovec_idx].iov_len); - - dma_cookie = dma_async_memcpy_pg_to_pg(chan, - page_list->pages[page_idx], - iov_byte_offset, - page, - offset, - copy); - /* poll for a descriptor slot */ - if (unlikely(dma_cookie < 0)) { - dma_async_issue_pending(chan); - continue; - } - - len -= copy; - iov[iovec_idx].iov_len -= copy; - iov[iovec_idx].iov_base += copy; - - if (!len) - return dma_cookie; - - offset += copy; - iov_byte_offset = 0; - page_idx++; - } - iovec_idx++; - } - - /* really bad if we ever run out of iovecs */ - BUG(); - return -EFAULT; -} diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 394cbc5c93e..7938272f2ed 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -310,7 +310,8 @@ mv_xor_clean_slot(struct mv_xor_desc_slot *desc, return 0; } -static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) +/* This function must be called with the mv_xor_chan spinlock held */ +static void mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) { struct mv_xor_desc_slot *iter, *_iter; dma_cookie_t cookie = 0; @@ -366,18 +367,13 @@ static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) mv_chan->dmachan.completed_cookie = cookie; } -static void -mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) -{ - spin_lock_bh(&mv_chan->lock); - __mv_xor_slot_cleanup(mv_chan); - spin_unlock_bh(&mv_chan->lock); -} - static void mv_xor_tasklet(unsigned long data) { struct mv_xor_chan *chan = (struct mv_xor_chan *) data; + + spin_lock_bh(&chan->lock); mv_xor_slot_cleanup(chan); + spin_unlock_bh(&chan->lock); } static struct mv_xor_desc_slot * @@ -656,9 +652,10 @@ static void mv_xor_free_chan_resources(struct dma_chan *chan) struct mv_xor_desc_slot *iter, *_iter; int in_use_descs = 0; + spin_lock_bh(&mv_chan->lock); + mv_xor_slot_cleanup(mv_chan); - spin_lock_bh(&mv_chan->lock); list_for_each_entry_safe(iter, _iter, &mv_chan->chain, chain_node) { in_use_descs++; @@ -700,11 +697,12 @@ static enum dma_status mv_xor_status(struct dma_chan *chan, enum dma_status ret; ret = dma_cookie_status(chan, cookie, txstate); - if (ret == DMA_COMPLETE) { - mv_xor_clean_completed_slots(mv_chan); + if (ret == DMA_COMPLETE) return ret; - } + + spin_lock_bh(&mv_chan->lock); mv_xor_slot_cleanup(mv_chan); + spin_unlock_bh(&mv_chan->lock); return dma_cookie_status(chan, cookie, txstate); } @@ -782,7 +780,7 @@ static void mv_xor_issue_pending(struct dma_chan *chan) static int mv_xor_memcpy_self_test(struct mv_xor_chan *mv_chan) { - int i; + int i, ret; void *src, *dest; dma_addr_t src_dma, dest_dma; struct dma_chan *dma_chan; @@ -819,19 +817,44 @@ static int mv_xor_memcpy_self_test(struct mv_xor_chan *mv_chan) src_dma = dma_map_page(dma_chan->device->dev, virt_to_page(src), 0, PAGE_SIZE, DMA_TO_DEVICE); - unmap->to_cnt = 1; unmap->addr[0] = src_dma; + ret = dma_mapping_error(dma_chan->device->dev, src_dma); + if (ret) { + err = -ENOMEM; + goto free_resources; + } + unmap->to_cnt = 1; + dest_dma = dma_map_page(dma_chan->device->dev, virt_to_page(dest), 0, PAGE_SIZE, DMA_FROM_DEVICE); - unmap->from_cnt = 1; unmap->addr[1] = dest_dma; + ret = dma_mapping_error(dma_chan->device->dev, dest_dma); + if (ret) { + err = -ENOMEM; + goto free_resources; + } + unmap->from_cnt = 1; unmap->len = PAGE_SIZE; tx = mv_xor_prep_dma_memcpy(dma_chan, dest_dma, src_dma, PAGE_SIZE, 0); + if (!tx) { + dev_err(dma_chan->device->dev, + "Self-test cannot prepare operation, disabling\n"); + err = -ENODEV; + goto free_resources; + } + cookie = mv_xor_tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(dma_chan->device->dev, + "Self-test submit error, disabling\n"); + err = -ENODEV; + goto free_resources; + } + mv_xor_issue_pending(dma_chan); async_tx_ack(tx); msleep(1); @@ -866,7 +889,7 @@ out: static int mv_xor_xor_self_test(struct mv_xor_chan *mv_chan) { - int i, src_idx; + int i, src_idx, ret; struct page *dest; struct page *xor_srcs[MV_XOR_NUM_SRC_TEST]; dma_addr_t dma_srcs[MV_XOR_NUM_SRC_TEST]; @@ -929,19 +952,42 @@ mv_xor_xor_self_test(struct mv_xor_chan *mv_chan) unmap->addr[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i], 0, PAGE_SIZE, DMA_TO_DEVICE); dma_srcs[i] = unmap->addr[i]; + ret = dma_mapping_error(dma_chan->device->dev, unmap->addr[i]); + if (ret) { + err = -ENOMEM; + goto free_resources; + } unmap->to_cnt++; } unmap->addr[src_count] = dma_map_page(dma_chan->device->dev, dest, 0, PAGE_SIZE, DMA_FROM_DEVICE); dest_dma = unmap->addr[src_count]; + ret = dma_mapping_error(dma_chan->device->dev, unmap->addr[src_count]); + if (ret) { + err = -ENOMEM; + goto free_resources; + } unmap->from_cnt = 1; unmap->len = PAGE_SIZE; tx = mv_xor_prep_dma_xor(dma_chan, dest_dma, dma_srcs, src_count, PAGE_SIZE, 0); + if (!tx) { + dev_err(dma_chan->device->dev, + "Self-test cannot prepare operation, disabling\n"); + err = -ENODEV; + goto free_resources; + } cookie = mv_xor_tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(dma_chan->device->dev, + "Self-test submit error, disabling\n"); + err = -ENODEV; + goto free_resources; + } + mv_xor_issue_pending(dma_chan); async_tx_ack(tx); msleep(8); diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 4cf7d9a950d..bbea8243f9e 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -1017,6 +1017,11 @@ static int omap_dma_resume(struct omap_chan *c) return -EINVAL; if (c->paused) { + mb(); + + /* Restore channel link register */ + omap_dma_chan_write(c, CLNK_CTRL, c->desc->clnk_ctrl); + omap_dma_start(c, c->desc); c->paused = false; } diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index f8bf00010d4..bbd65149cdb 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -87,61 +87,73 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, } /* + * Select DCT to which PCI cfg accesses are routed + */ +static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct) +{ + u32 reg = 0; + + amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, ®); + reg &= (pvt->model == 0x30) ? ~3 : ~1; + reg |= dct; + amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg); +} + +/* * * Depending on the family, F2 DCT reads need special handling: * - * K8: has a single DCT only + * K8: has a single DCT only and no address offsets >= 0x100 * * F10h: each DCT has its own set of regs * DCT0 -> F2x040.. * DCT1 -> F2x140.. * - * F15h: we select which DCT we access using F1x10C[DctCfgSel] - * * F16h: has only 1 DCT + * + * F15h: we select which DCT we access using F1x10C[DctCfgSel] */ -static int k8_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, - const char *func) +static inline int amd64_read_dct_pci_cfg(struct amd64_pvt *pvt, u8 dct, + int offset, u32 *val) { - if (addr >= 0x100) - return -EINVAL; - - return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func); -} + switch (pvt->fam) { + case 0xf: + if (dct || offset >= 0x100) + return -EINVAL; + break; -static int f10_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, - const char *func) -{ - return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func); -} + case 0x10: + if (dct) { + /* + * Note: If ganging is enabled, barring the regs + * F2x[1,0]98 and F2x[1,0]9C; reads reads to F2x1xx + * return 0. (cf. Section 2.8.1 F10h BKDG) + */ + if (dct_ganging_enabled(pvt)) + return 0; -/* - * Select DCT to which PCI cfg accesses are routed - */ -static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct) -{ - u32 reg = 0; + offset += 0x100; + } + break; - amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, ®); - reg &= (pvt->model >= 0x30) ? ~3 : ~1; - reg |= dct; - amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg); -} + case 0x15: + /* + * F15h: F2x1xx addresses do not map explicitly to DCT1. + * We should select which DCT we access using F1x10C[DctCfgSel] + */ + dct = (dct && pvt->model == 0x30) ? 3 : dct; + f15h_select_dct(pvt, dct); + break; -static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, - const char *func) -{ - u8 dct = 0; + case 0x16: + if (dct) + return -EINVAL; + break; - /* For F15 M30h, the second dct is DCT 3, refer to BKDG Section 2.10 */ - if (addr >= 0x140 && addr <= 0x1a0) { - dct = (pvt->model >= 0x30) ? 3 : 1; - addr -= 0x100; + default: + break; } - - f15h_select_dct(pvt, dct); - - return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func); + return amd64_read_pci_cfg(pvt->F2, offset, val); } /* @@ -768,16 +780,17 @@ static void read_dct_base_mask(struct amd64_pvt *pvt) u32 *base0 = &pvt->csels[0].csbases[cs]; u32 *base1 = &pvt->csels[1].csbases[cs]; - if (!amd64_read_dct_pci_cfg(pvt, reg0, base0)) + if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0)) edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n", cs, *base0, reg0); - if (pvt->fam == 0xf || dct_ganging_enabled(pvt)) + if (pvt->fam == 0xf) continue; - if (!amd64_read_dct_pci_cfg(pvt, reg1, base1)) + if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1)) edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n", - cs, *base1, reg1); + cs, *base1, (pvt->fam == 0x10) ? reg1 + : reg0); } for_each_chip_select_mask(cs, 0, pvt) { @@ -786,16 +799,17 @@ static void read_dct_base_mask(struct amd64_pvt *pvt) u32 *mask0 = &pvt->csels[0].csmasks[cs]; u32 *mask1 = &pvt->csels[1].csmasks[cs]; - if (!amd64_read_dct_pci_cfg(pvt, reg0, mask0)) + if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0)) edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n", cs, *mask0, reg0); - if (pvt->fam == 0xf || dct_ganging_enabled(pvt)) + if (pvt->fam == 0xf) continue; - if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1)) + if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1)) edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n", - cs, *mask1, reg1); + cs, *mask1, (pvt->fam == 0x10) ? reg1 + : reg0); } } @@ -1198,7 +1212,7 @@ static void read_dram_ctl_register(struct amd64_pvt *pvt) if (pvt->fam == 0xf) return; - if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) { + if (!amd64_read_pci_cfg(pvt->F2, DCT_SEL_LO, &pvt->dct_sel_lo)) { edac_dbg(0, "F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n", pvt->dct_sel_lo, dct_sel_baseaddr(pvt)); @@ -1219,7 +1233,7 @@ static void read_dram_ctl_register(struct amd64_pvt *pvt) dct_sel_interleave_addr(pvt)); } - amd64_read_dct_pci_cfg(pvt, DCT_SEL_HI, &pvt->dct_sel_hi); + amd64_read_pci_cfg(pvt->F2, DCT_SEL_HI, &pvt->dct_sel_hi); } /* @@ -1430,7 +1444,7 @@ static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr) return sys_addr; } - amd64_read_dct_pci_cfg(pvt, SWAP_INTLV_REG, &swap_reg); + amd64_read_pci_cfg(pvt->F2, SWAP_INTLV_REG, &swap_reg); if (!(swap_reg & 0x1)) return sys_addr; @@ -1723,10 +1737,16 @@ static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) WARN_ON(ctrl != 0); } - dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0; - dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->csels[1].csbases - : pvt->csels[0].csbases; - + if (pvt->fam == 0x10) { + dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 + : pvt->dbam0; + dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? + pvt->csels[1].csbases : + pvt->csels[0].csbases; + } else if (ctrl) { + dbam = pvt->dbam0; + dcsb = pvt->csels[1].csbases; + } edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam); @@ -1760,7 +1780,6 @@ static struct amd64_family_type family_types[] = { .early_channel_count = k8_early_channel_count, .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow, .dbam_to_cs = k8_dbam_to_chip_select, - .read_dct_pci_cfg = k8_read_dct_pci_cfg, } }, [F10_CPUS] = { @@ -1771,7 +1790,6 @@ static struct amd64_family_type family_types[] = { .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f10_dbam_to_chip_select, - .read_dct_pci_cfg = f10_read_dct_pci_cfg, } }, [F15_CPUS] = { @@ -1782,7 +1800,6 @@ static struct amd64_family_type family_types[] = { .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f15_dbam_to_chip_select, - .read_dct_pci_cfg = f15_read_dct_pci_cfg, } }, [F15_M30H_CPUS] = { @@ -1793,7 +1810,6 @@ static struct amd64_family_type family_types[] = { .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f16_dbam_to_chip_select, - .read_dct_pci_cfg = f15_read_dct_pci_cfg, } }, [F16_CPUS] = { @@ -1804,7 +1820,6 @@ static struct amd64_family_type family_types[] = { .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f16_dbam_to_chip_select, - .read_dct_pci_cfg = f10_read_dct_pci_cfg, } }, [F16_M30H_CPUS] = { @@ -1815,7 +1830,6 @@ static struct amd64_family_type family_types[] = { .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f16_dbam_to_chip_select, - .read_dct_pci_cfg = f10_read_dct_pci_cfg, } }, }; @@ -2148,25 +2162,25 @@ static void read_mc_regs(struct amd64_pvt *pvt) read_dct_base_mask(pvt); amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar); - amd64_read_dct_pci_cfg(pvt, DBAM0, &pvt->dbam0); + amd64_read_dct_pci_cfg(pvt, 0, DBAM0, &pvt->dbam0); amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare); - amd64_read_dct_pci_cfg(pvt, DCLR0, &pvt->dclr0); - amd64_read_dct_pci_cfg(pvt, DCHR0, &pvt->dchr0); + amd64_read_dct_pci_cfg(pvt, 0, DCLR0, &pvt->dclr0); + amd64_read_dct_pci_cfg(pvt, 0, DCHR0, &pvt->dchr0); if (!dct_ganging_enabled(pvt)) { - amd64_read_dct_pci_cfg(pvt, DCLR1, &pvt->dclr1); - amd64_read_dct_pci_cfg(pvt, DCHR1, &pvt->dchr1); + amd64_read_dct_pci_cfg(pvt, 1, DCLR0, &pvt->dclr1); + amd64_read_dct_pci_cfg(pvt, 1, DCHR0, &pvt->dchr1); } pvt->ecc_sym_sz = 4; if (pvt->fam >= 0x10) { amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp); + /* F16h has only DCT0, so no need to read dbam1 */ if (pvt->fam != 0x16) - /* F16h has only DCT0 */ - amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1); + amd64_read_dct_pci_cfg(pvt, 1, DBAM0, &pvt->dbam1); /* F10h, revD and later can do x8 ECC too */ if ((pvt->fam > 0x10 || pvt->model > 7) && tmp & BIT(25)) diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index d903e0c2114..55fb5941c6d 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -481,8 +481,6 @@ struct low_ops { void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr, struct err_info *); int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, unsigned cs_mode); - int (*read_dct_pci_cfg) (struct amd64_pvt *pvt, int offset, - u32 *val, const char *func); }; struct amd64_family_type { @@ -502,9 +500,6 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, #define amd64_write_pci_cfg(pdev, offset, val) \ __amd64_write_pci_cfg_dword(pdev, offset, val, __func__) -#define amd64_read_dct_pci_cfg(pvt, offset, val) \ - pvt->ops->read_dct_pci_cfg(pvt, offset, val, __func__) - int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, u64 *hole_offset, u64 *hole_size); diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 3c2625e7980..6c9f381e8fe 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -66,7 +66,7 @@ #define EDAC_PCI "PCI" #define EDAC_DEBUG "DEBUG" -extern const char *edac_mem_types[]; +extern const char * const edac_mem_types[]; #ifdef CONFIG_EDAC_DEBUG extern int edac_debug_level; diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 9f134823fa7..c3893b0ddb1 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -128,7 +128,7 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci) /* * keep those in sync with the enum mem_type */ -const char *edac_mem_types[] = { +const char * const edac_mem_types[] = { "Empty csrow", "Reserved csrow type", "Unknown csrow type", diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index f4aec2e6ef5..7d3742edbaa 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -633,7 +633,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) if (edac_op_state == EDAC_OPSTATE_INT) { pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); res = devm_request_irq(&op->dev, pdata->irq, - mpc85xx_l2_isr, 0, + mpc85xx_l2_isr, IRQF_SHARED, "[EDAC] L2 err", edac_dev); if (res < 0) { printk(KERN_ERR diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index ef6b7e08f48..0f04d5ead52 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -974,7 +974,7 @@ static int ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) * page size (PAGE_SIZE) or the memory width (2 or 4). */ for (j = 0; j < csi->nr_channels; j++) { - struct dimm_info *dimm = csi->channels[j].dimm; + struct dimm_info *dimm = csi->channels[j]->dimm; dimm->nr_pages = nr_pages / csi->nr_channels; dimm->grain = 1; diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index d8be608a9f3..aef6a95adef 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o obj-$(CONFIG_UEFI_CPER) += cper.o obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o -obj-$(CONFIG_EFI_STUB) += libstub/ +obj-$(CONFIG_EFI_ARM_STUB) += libstub/ diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 1411613f217..e42925f76b4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1310,6 +1310,16 @@ void i915_check_and_clear_faults(struct drm_device *dev) POSTING_READ(RING_FAULT_REG(&dev_priv->ring[RCS])); } +static void i915_ggtt_flush(struct drm_i915_private *dev_priv) +{ + if (INTEL_INFO(dev_priv->dev)->gen < 6) { + intel_gtt_chipset_flush(); + } else { + I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); + POSTING_READ(GFX_FLSH_CNTL_GEN6); + } +} + void i915_gem_suspend_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1326,6 +1336,8 @@ void i915_gem_suspend_gtt_mappings(struct drm_device *dev) dev_priv->gtt.base.start, dev_priv->gtt.base.total, true); + + i915_ggtt_flush(dev_priv); } void i915_gem_restore_gtt_mappings(struct drm_device *dev) @@ -1378,7 +1390,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) gen6_write_pdes(container_of(vm, struct i915_hw_ppgtt, base)); } - i915_gem_chipset_flush(dev); + i915_ggtt_flush(dev_priv); } int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 7f84dd263ee..9842fd2e742 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -66,12 +66,12 @@ module_param_named(powersave, i915.powersave, int, 0600); MODULE_PARM_DESC(powersave, "Enable powersavings, fbc, downclocking, etc. (default: true)"); -module_param_named(semaphores, i915.semaphores, int, 0400); +module_param_named_unsafe(semaphores, i915.semaphores, int, 0400); MODULE_PARM_DESC(semaphores, "Use semaphores for inter-ring sync " "(default: -1 (use per-chip defaults))"); -module_param_named(enable_rc6, i915.enable_rc6, int, 0400); +module_param_named_unsafe(enable_rc6, i915.enable_rc6, int, 0400); MODULE_PARM_DESC(enable_rc6, "Enable power-saving render C-state 6. " "Different stages can be selected via bitmask values " @@ -79,7 +79,7 @@ MODULE_PARM_DESC(enable_rc6, "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. " "default: -1 (use per-chip default)"); -module_param_named(enable_fbc, i915.enable_fbc, int, 0600); +module_param_named_unsafe(enable_fbc, i915.enable_fbc, int, 0600); MODULE_PARM_DESC(enable_fbc, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); @@ -113,7 +113,7 @@ MODULE_PARM_DESC(enable_hangcheck, "WARNING: Disabling this can cause system wide hangs. " "(default: true)"); -module_param_named(enable_ppgtt, i915.enable_ppgtt, int, 0400); +module_param_named_unsafe(enable_ppgtt, i915.enable_ppgtt, int, 0400); MODULE_PARM_DESC(enable_ppgtt, "Override PPGTT usage. " "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)"); diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index ca52ad2ae7d..d8de1d5140a 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -396,6 +396,16 @@ int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state) return -EINVAL; } +/* + * If the vendor backlight interface is not in use and ACPI backlight interface + * is broken, do not bother processing backlight change requests from firmware. + */ +static bool should_ignore_backlight_request(void) +{ + return acpi_video_backlight_support() && + !acpi_video_verify_backlight_support(); +} + static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -404,11 +414,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); - /* - * If the acpi_video interface is not supposed to be used, don't - * bother processing backlight level change requests from firmware. - */ - if (!acpi_video_verify_backlight_support()) { + if (should_ignore_backlight_request()) { DRM_DEBUG_KMS("opregion backlight request ignored\n"); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 4b5bb5d58a5..f8cbb512132 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -1763,9 +1763,10 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp const int or = ffs(outp->or) - 1; const u32 loff = (or * 0x800) + (link * 0x80); const u16 mask = (outp->sorconf.link << 6) | outp->or; + struct dcb_output match; u8 ver, hdr; - if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp)) + if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000); } diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 99cd9e4a2aa..3440fc999f2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -285,6 +285,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) struct nouveau_software_chan *swch; struct nv_dma_v0 args = {}; int ret, i; + bool save; nvif_object_map(chan->object); @@ -386,7 +387,11 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) } /* initialise synchronisation */ - return nouveau_fence(chan->drm)->context_new(chan); + save = cli->base.super; + cli->base.super = true; /* hack until fencenv50 fixed */ + ret = nouveau_fence(chan->drm)->context_new(chan); + cli->base.super = save; + return ret; } int diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 65b4fd53dd4..4a21b2b06ce 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -550,14 +550,12 @@ nouveau_display_destroy(struct drm_device *dev) } int -nouveau_display_suspend(struct drm_device *dev) +nouveau_display_suspend(struct drm_device *dev, bool runtime) { - struct nouveau_drm *drm = nouveau_drm(dev); struct drm_crtc *crtc; nouveau_display_fini(dev); - NV_INFO(drm, "unpinning framebuffer(s)...\n"); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; @@ -579,12 +577,13 @@ nouveau_display_suspend(struct drm_device *dev) } void -nouveau_display_repin(struct drm_device *dev) +nouveau_display_resume(struct drm_device *dev, bool runtime) { struct nouveau_drm *drm = nouveau_drm(dev); struct drm_crtc *crtc; - int ret; + int ret, head; + /* re-pin fb/cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; @@ -606,13 +605,6 @@ nouveau_display_repin(struct drm_device *dev) if (ret) NV_ERROR(drm, "Could not pin/map cursor.\n"); } -} - -void -nouveau_display_resume(struct drm_device *dev) -{ - struct drm_crtc *crtc; - int head; nouveau_display_init(dev); @@ -627,6 +619,13 @@ nouveau_display_resume(struct drm_device *dev) for (head = 0; head < dev->mode_config.num_crtc; head++) drm_vblank_on(dev, head); + /* This should ensure we don't hit a locking problem when someone + * wakes us up via a connector. We should never go into suspend + * while the display is on anyways. + */ + if (runtime) + return; + drm_helper_resume_force_mode(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 88ca177cb1c..be3d5947c6b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -63,9 +63,8 @@ int nouveau_display_create(struct drm_device *dev); void nouveau_display_destroy(struct drm_device *dev); int nouveau_display_init(struct drm_device *dev); void nouveau_display_fini(struct drm_device *dev); -int nouveau_display_suspend(struct drm_device *dev); -void nouveau_display_repin(struct drm_device *dev); -void nouveau_display_resume(struct drm_device *dev); +int nouveau_display_suspend(struct drm_device *dev, bool runtime); +void nouveau_display_resume(struct drm_device *dev, bool runtime); int nouveau_display_vblank_enable(struct drm_device *, int); void nouveau_display_vblank_disable(struct drm_device *, int); int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 9c3af96a715..3ed32dd9030 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -547,9 +547,11 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) struct nouveau_cli *cli; int ret; - if (dev->mode_config.num_crtc && !runtime) { + if (dev->mode_config.num_crtc) { + NV_INFO(drm, "suspending console...\n"); + nouveau_fbcon_set_suspend(dev, 1); NV_INFO(drm, "suspending display...\n"); - ret = nouveau_display_suspend(dev); + ret = nouveau_display_suspend(dev, runtime); if (ret) return ret; } @@ -603,7 +605,7 @@ fail_client: fail_display: if (dev->mode_config.num_crtc) { NV_INFO(drm, "resuming display...\n"); - nouveau_display_resume(dev); + nouveau_display_resume(dev, runtime); } return ret; } @@ -618,9 +620,6 @@ int nouveau_pmops_suspend(struct device *dev) drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) return 0; - if (drm_dev->mode_config.num_crtc) - nouveau_fbcon_set_suspend(drm_dev, 1); - ret = nouveau_do_suspend(drm_dev, false); if (ret) return ret; @@ -633,7 +632,7 @@ int nouveau_pmops_suspend(struct device *dev) } static int -nouveau_do_resume(struct drm_device *dev) +nouveau_do_resume(struct drm_device *dev, bool runtime) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; @@ -658,7 +657,9 @@ nouveau_do_resume(struct drm_device *dev) if (dev->mode_config.num_crtc) { NV_INFO(drm, "resuming display...\n"); - nouveau_display_repin(dev); + nouveau_display_resume(dev, runtime); + NV_INFO(drm, "resuming console...\n"); + nouveau_fbcon_set_suspend(dev, 0); } return 0; @@ -681,47 +682,21 @@ int nouveau_pmops_resume(struct device *dev) return ret; pci_set_master(pdev); - ret = nouveau_do_resume(drm_dev); - if (ret) - return ret; - - if (drm_dev->mode_config.num_crtc) { - nouveau_display_resume(drm_dev); - nouveau_fbcon_set_suspend(drm_dev, 0); - } - - return 0; + return nouveau_do_resume(drm_dev, false); } static int nouveau_pmops_freeze(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - int ret; - - if (drm_dev->mode_config.num_crtc) - nouveau_fbcon_set_suspend(drm_dev, 1); - - ret = nouveau_do_suspend(drm_dev, false); - return ret; + return nouveau_do_suspend(drm_dev, false); } static int nouveau_pmops_thaw(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - int ret; - - ret = nouveau_do_resume(drm_dev); - if (ret) - return ret; - - if (drm_dev->mode_config.num_crtc) { - nouveau_display_resume(drm_dev); - nouveau_fbcon_set_suspend(drm_dev, 0); - } - - return 0; + return nouveau_do_resume(drm_dev, false); } @@ -977,7 +952,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev) return ret; pci_set_master(pdev); - ret = nouveau_do_resume(drm_dev); + ret = nouveau_do_resume(drm_dev, true); drm_kms_helper_poll_enable(drm_dev); /* do magic */ nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 8bdd27091db..49fe6075cc7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -486,6 +486,16 @@ static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { .fb_probe = nouveau_fbcon_create, }; +static void +nouveau_fbcon_set_suspend_work(struct work_struct *work) +{ + struct nouveau_fbdev *fbcon = container_of(work, typeof(*fbcon), work); + console_lock(); + nouveau_fbcon_accel_restore(fbcon->dev); + nouveau_fbcon_zfill(fbcon->dev, fbcon); + fb_set_suspend(fbcon->helper.fbdev, FBINFO_STATE_RUNNING); + console_unlock(); +} int nouveau_fbcon_init(struct drm_device *dev) @@ -503,6 +513,7 @@ nouveau_fbcon_init(struct drm_device *dev) if (!fbcon) return -ENOMEM; + INIT_WORK(&fbcon->work, nouveau_fbcon_set_suspend_work); fbcon->dev = dev; drm->fbcon = fbcon; @@ -551,14 +562,14 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state) { struct nouveau_drm *drm = nouveau_drm(dev); if (drm->fbcon) { - console_lock(); - if (state == 0) { - nouveau_fbcon_accel_restore(dev); - nouveau_fbcon_zfill(dev, drm->fbcon); + if (state == FBINFO_STATE_RUNNING) { + schedule_work(&drm->fbcon->work); + return; } + flush_work(&drm->fbcon->work); + console_lock(); fb_set_suspend(drm->fbcon->helper.fbdev, state); - if (state == 1) - nouveau_fbcon_accel_save_disable(dev); + nouveau_fbcon_accel_save_disable(dev); console_unlock(); } } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 34658cfa8f5..0b465c7d390 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -36,6 +36,7 @@ struct nouveau_fbdev { struct nouveau_framebuffer nouveau_fb; struct list_head fbdev_list; struct drm_device *dev; + struct work_struct work; unsigned int saved_flags; struct nvif_object surf2d; struct nvif_object clip; diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 3a4d64e1dfb..092d89bd322 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -674,16 +674,20 @@ static int qup_i2c_probe(struct platform_device *pdev) qup->adap.dev.of_node = pdev->dev.of_node; strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name)); - ret = i2c_add_adapter(&qup->adap); - if (ret) - goto fail; - pm_runtime_set_autosuspend_delay(qup->dev, MSEC_PER_SEC); pm_runtime_use_autosuspend(qup->dev); pm_runtime_set_active(qup->dev); pm_runtime_enable(qup->dev); + + ret = i2c_add_adapter(&qup->adap); + if (ret) + goto fail_runtime; + return 0; +fail_runtime: + pm_runtime_disable(qup->dev); + pm_runtime_set_suspended(qup->dev); fail: qup_i2c_disable_clocks(qup); return ret; diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 93cfc837200..b38b0529946 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -238,7 +238,7 @@ static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) for (i = 0; i < 8; ++i) { val = 0; for (j = 0; j < 4; ++j) { - if (i2c->processed == i2c->msg->len) + if ((i2c->processed == i2c->msg->len) && (cnt != 0)) break; if (i2c->processed == 0 && cnt == 0) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 713e3ddb43b..40b7d6c0ff1 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -466,6 +466,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { }, }, { + /* Asus X450LCP */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"), + }, + }, + { /* Avatar AVIU-145A6 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Intel"), diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 183588b11fc..9f0fbecd1eb 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -64,6 +64,10 @@ #define cpu_to_group(cpu) cpu_to_node(cpu) #define ANY_GROUP NUMA_NO_NODE +static bool devices_handle_discard_safely = false; +module_param(devices_handle_discard_safely, bool, 0644); +MODULE_PARM_DESC(devices_handle_discard_safely, + "Set to Y if all devices in each array reliably return zeroes on reads from discarded regions"); static struct workqueue_struct *raid5_wq; /* * Stripe cache @@ -6208,7 +6212,7 @@ static int run(struct mddev *mddev) mddev->queue->limits.discard_granularity = stripe; /* * unaligned part of discard request will be ignored, so can't - * guarantee discard_zerors_data + * guarantee discard_zeroes_data */ mddev->queue->limits.discard_zeroes_data = 0; @@ -6233,6 +6237,18 @@ static int run(struct mddev *mddev) !bdev_get_queue(rdev->bdev)-> limits.discard_zeroes_data) discard_supported = false; + /* Unfortunately, discard_zeroes_data is not currently + * a guarantee - just a hint. So we only allow DISCARD + * if the sysadmin has confirmed that only safe devices + * are in use by setting a module parameter. + */ + if (!devices_handle_discard_safely) { + if (discard_supported) { + pr_info("md/raid456: discard support disabled due to uncertainty.\n"); + pr_info("Set raid456.devices_handle_discard_safely=Y to override.\n"); + } + discard_supported = false; + } } if (discard_supported && diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index a7e24848f6c..9da812b8a78 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3524,6 +3524,7 @@ static struct usb_driver em28xx_usb_driver = { .disconnect = em28xx_usb_disconnect, .suspend = em28xx_usb_suspend, .resume = em28xx_usb_resume, + .reset_resume = em28xx_usb_resume, .id_table = em28xx_id_table, }; diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 2fee73b878c..823d01c5684 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -3236,8 +3236,9 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) skb->protocol = eth_type_trans(skb, bp->dev); - if ((len > (bp->dev->mtu + ETH_HLEN)) && - (ntohs(skb->protocol) != 0x8100)) { + if (len > (bp->dev->mtu + ETH_HLEN) && + skb->protocol != htons(0x8100) && + skb->protocol != htons(ETH_P_8021AD)) { dev_kfree_skb(skb); goto next_rx; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index e7d3a620d96..ba499489969 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6918,7 +6918,8 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) skb->protocol = eth_type_trans(skb, tp->dev); if (len > (tp->dev->mtu + ETH_HLEN) && - skb->protocol != htons(ETH_P_8021Q)) { + skb->protocol != htons(ETH_P_8021Q) && + skb->protocol != htons(ETH_P_8021AD)) { dev_kfree_skb_any(skb); goto drop_it_no_recycle; } diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index ca5d7798b26..e1e02fba4fc 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -30,7 +30,6 @@ #include <linux/of_device.h> #include <linux/of_mdio.h> #include <linux/of_net.h> -#include <linux/pinctrl/consumer.h> #include "macb.h" @@ -2071,7 +2070,6 @@ static int __init macb_probe(struct platform_device *pdev) struct phy_device *phydev; u32 config; int err = -ENXIO; - struct pinctrl *pinctrl; const char *mac; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -2080,15 +2078,6 @@ static int __init macb_probe(struct platform_device *pdev) goto err_out; } - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - err = PTR_ERR(pinctrl); - if (err == -EPROBE_DEFER) - goto err_out; - - dev_warn(&pdev->dev, "No pinctrl provided\n"); - } - err = -ENOMEM; dev = alloc_etherdev(sizeof(*bp)); if (!dev) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 7e2d5d57c59..871e3a5bda3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -78,13 +78,13 @@ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); #endif /* CONFIG_PCI_MSI */ static uint8_t num_vfs[3] = {0, 0, 0}; -static int num_vfs_argc = 3; +static int num_vfs_argc; module_param_array(num_vfs, byte , &num_vfs_argc, 0444); MODULE_PARM_DESC(num_vfs, "enable #num_vfs functions if num_vfs > 0\n" "num_vfs=port1,port2,port1+2"); static uint8_t probe_vf[3] = {0, 0, 0}; -static int probe_vfs_argc = 3; +static int probe_vfs_argc; module_param_array(probe_vf, byte, &probe_vfs_argc, 0444); MODULE_PARM_DESC(probe_vf, "number of vfs to probe by pf driver (num_vfs > 0)\n" "probe_vf=port1,port2,port1+2"); diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index 32058614151..5c4068353f6 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c @@ -135,6 +135,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter) int i, j; struct nx_host_tx_ring *tx_ring = adapter->tx_ring; + spin_lock(&adapter->tx_clean_lock); cmd_buf = tx_ring->cmd_buf_arr; for (i = 0; i < tx_ring->num_desc; i++) { buffrag = cmd_buf->frag_array; @@ -158,6 +159,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter) } cmd_buf++; } + spin_unlock(&adapter->tx_clean_lock); } void netxen_free_sw_resources(struct netxen_adapter *adapter) @@ -1792,9 +1794,9 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) break; } - if (count && netif_running(netdev)) { - tx_ring->sw_consumer = sw_consumer; + tx_ring->sw_consumer = sw_consumer; + if (count && netif_running(netdev)) { smp_mb(); if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 1159031f885..5ec5a2b0e98 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -1186,7 +1186,6 @@ __netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) return; smp_mb(); - spin_lock(&adapter->tx_clean_lock); netif_carrier_off(netdev); netif_tx_disable(netdev); @@ -1204,7 +1203,6 @@ __netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) netxen_napi_disable(adapter); netxen_release_tx_buffers(adapter); - spin_unlock(&adapter->tx_clean_lock); } /* Usage: During suspend and firmware recovery module */ diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 86783e1afcf..3172cdf591f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -1177,9 +1177,8 @@ static void qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter *adapter) { u32 idc_params, val; - if (qlcnic_83xx_lockless_flash_read32(adapter, - QLC_83XX_IDC_FLASH_PARAM_ADDR, - (u8 *)&idc_params, 1)) { + if (qlcnic_83xx_flash_read32(adapter, QLC_83XX_IDC_FLASH_PARAM_ADDR, + (u8 *)&idc_params, 1)) { dev_info(&adapter->pdev->dev, "%s:failed to get IDC params from flash\n", __func__); adapter->dev_init_timeo = QLC_83XX_IDC_INIT_TIMEOUT_SECS; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 141f116eb86..494e8105ade 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -1333,21 +1333,21 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev, struct qlcnic_host_tx_ring *tx_ring; struct qlcnic_esw_statistics port_stats; struct qlcnic_mac_statistics mac_stats; - int index, ret, length, size, tx_size, ring; + int index, ret, length, size, ring; char *p; - tx_size = adapter->drv_tx_rings * QLCNIC_TX_STATS_LEN; + memset(data, 0, stats->n_stats * sizeof(u64)); - memset(data, 0, tx_size * sizeof(u64)); for (ring = 0, index = 0; ring < adapter->drv_tx_rings; ring++) { - if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { + if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) { tx_ring = &adapter->tx_ring[ring]; data = qlcnic_fill_tx_queue_stats(data, tx_ring); qlcnic_update_stats(adapter); + } else { + data += QLCNIC_TX_STATS_LEN; } } - memset(data, 0, stats->n_stats * sizeof(u64)); length = QLCNIC_STATS_LEN; for (index = 0; index < length; index++) { p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 6e6ee226de0..b0c1521e08a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2786,8 +2786,15 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, if (IS_ERR(priv->stmmac_clk)) { dev_warn(priv->device, "%s: warning: cannot get CSR clock\n", __func__); - ret = PTR_ERR(priv->stmmac_clk); - goto error_clk_get; + /* If failed to obtain stmmac_clk and specific clk_csr value + * is NOT passed from the platform, probe fail. + */ + if (!priv->plat->clk_csr) { + ret = PTR_ERR(priv->stmmac_clk); + goto error_clk_get; + } else { + priv->stmmac_clk = NULL; + } } clk_prepare_enable(priv->stmmac_clk); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index a9c5eaadc42..0fcb5e7eb07 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -387,6 +387,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) int hdr_offset; u32 net_trans_info; u32 hash; + u32 skb_length = skb->len; /* We will atmost need two pages to describe the rndis @@ -562,7 +563,7 @@ do_send: drop: if (ret == 0) { - net->stats.tx_bytes += skb->len; + net->stats.tx_bytes += skb_length; net->stats.tx_packets++; } else { kfree(packet); diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 3381c4f91a8..0c6adaaf898 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -112,17 +112,15 @@ out: return err; } +/* Requires RTNL */ static int macvtap_set_queue(struct net_device *dev, struct file *file, struct macvtap_queue *q) { struct macvlan_dev *vlan = netdev_priv(dev); - int err = -EBUSY; - rtnl_lock(); if (vlan->numqueues == MAX_MACVTAP_QUEUES) - goto out; + return -EBUSY; - err = 0; rcu_assign_pointer(q->vlan, vlan); rcu_assign_pointer(vlan->taps[vlan->numvtaps], q); sock_hold(&q->sk); @@ -136,9 +134,7 @@ static int macvtap_set_queue(struct net_device *dev, struct file *file, vlan->numvtaps++; vlan->numqueues++; -out: - rtnl_unlock(); - return err; + return 0; } static int macvtap_disable_queue(struct macvtap_queue *q) @@ -454,11 +450,12 @@ static void macvtap_sock_destruct(struct sock *sk) static int macvtap_open(struct inode *inode, struct file *file) { struct net *net = current->nsproxy->net_ns; - struct net_device *dev = dev_get_by_macvtap_minor(iminor(inode)); + struct net_device *dev; struct macvtap_queue *q; - int err; + int err = -ENODEV; - err = -ENODEV; + rtnl_lock(); + dev = dev_get_by_macvtap_minor(iminor(inode)); if (!dev) goto out; @@ -498,6 +495,7 @@ out: if (dev) dev_put(dev); + rtnl_unlock(); return err; } diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 74760e8143e..604ef210a4d 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -24,7 +24,7 @@ #include <net/ip6_checksum.h> /* Version Information */ -#define DRIVER_VERSION "v1.06.0 (2014/03/03)" +#define DRIVER_VERSION "v1.06.1 (2014/10/01)" #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" @@ -1949,10 +1949,34 @@ static void rxdy_gated_en(struct r8152 *tp, bool enable) ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); } +static int rtl_start_rx(struct r8152 *tp) +{ + int i, ret = 0; + + INIT_LIST_HEAD(&tp->rx_done); + for (i = 0; i < RTL8152_MAX_RX; i++) { + INIT_LIST_HEAD(&tp->rx_info[i].list); + ret = r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL); + if (ret) + break; + } + + return ret; +} + +static int rtl_stop_rx(struct r8152 *tp) +{ + int i; + + for (i = 0; i < RTL8152_MAX_RX; i++) + usb_kill_urb(tp->rx_info[i].urb); + + return 0; +} + static int rtl_enable(struct r8152 *tp) { u32 ocp_data; - int i, ret; r8152b_reset_packet_filter(tp); @@ -1962,14 +1986,7 @@ static int rtl_enable(struct r8152 *tp) rxdy_gated_en(tp, false); - INIT_LIST_HEAD(&tp->rx_done); - ret = 0; - for (i = 0; i < RTL8152_MAX_RX; i++) { - INIT_LIST_HEAD(&tp->rx_info[i].list); - ret |= r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL); - } - - return ret; + return rtl_start_rx(tp); } static int rtl8152_enable(struct r8152 *tp) @@ -2053,8 +2070,7 @@ static void rtl_disable(struct r8152 *tp) mdelay(1); } - for (i = 0; i < RTL8152_MAX_RX; i++) - usb_kill_urb(tp->rx_info[i].urb); + rtl_stop_rx(tp); rtl8152_nic_reset(tp); } @@ -2185,28 +2201,6 @@ static void rtl_phy_reset(struct r8152 *tp) } } -static void rtl_clear_bp(struct r8152 *tp) -{ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0); - mdelay(3); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0); - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0); -} - -static void r8153_clear_bp(struct r8152 *tp) -{ - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); - ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0); - rtl_clear_bp(tp); -} - static void r8153_teredo_off(struct r8152 *tp) { u32 ocp_data; @@ -2249,8 +2243,6 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp) r8152_mdio_write(tp, MII_BMCR, data); } - rtl_clear_bp(tp); - set_bit(PHY_RESET, &tp->flags); } @@ -2401,8 +2393,6 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) r8152_mdio_write(tp, MII_BMCR, data); } - r8153_clear_bp(tp); - if (tp->version == RTL_VER_03) { data = ocp_reg_read(tp, OCP_EEE_CFG); data &= ~CTAP_SHORT_EN; @@ -3083,13 +3073,14 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); + tasklet_disable(&tp->tl); if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + rtl_stop_rx(tp); rtl_runtime_suspend_enable(tp, true); } else { - tasklet_disable(&tp->tl); tp->rtl_ops.down(tp); - tasklet_enable(&tp->tl); } + tasklet_enable(&tp->tl); } return 0; @@ -3108,17 +3099,18 @@ static int rtl8152_resume(struct usb_interface *intf) if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { rtl_runtime_suspend_enable(tp, false); clear_bit(SELECTIVE_SUSPEND, &tp->flags); + set_bit(WORK_ENABLE, &tp->flags); if (tp->speed & LINK_STATUS) - tp->rtl_ops.disable(tp); + rtl_start_rx(tp); } else { tp->rtl_ops.up(tp); rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); + tp->speed = 0; + netif_carrier_off(tp->netdev); + set_bit(WORK_ENABLE, &tp->flags); } - tp->speed = 0; - netif_carrier_off(tp->netdev); - set_bit(WORK_ENABLE, &tp->flags); usb_submit_urb(tp->intr_urb, GFP_KERNEL); } @@ -3405,7 +3397,7 @@ static void rtl8153_unload(struct r8152 *tp) if (test_bit(RTL8152_UNPLUG, &tp->flags)) return; - r8153_power_cut_en(tp, true); + r8153_power_cut_en(tp, false); } static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) @@ -3558,7 +3550,11 @@ static void rtl8152_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (tp) { - set_bit(RTL8152_UNPLUG, &tp->flags); + struct usb_device *udev = tp->udev; + + if (udev->state == USB_STATE_NOTATTACHED) + set_bit(RTL8152_UNPLUG, &tp->flags); + tasklet_kill(&tp->tl); unregister_netdev(tp->netdev); tp->rtl_ops.unload(tp); diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index a042d065a0c..8be2096c842 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -395,7 +395,8 @@ static void __init superio_serial_init(void) serial_port.iotype = UPIO_PORT; serial_port.type = PORT_16550A; serial_port.uartclk = 115200*16; - serial_port.fifosize = 16; + serial_port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | + UPF_BOOT_AUTOCONF; /* serial port #1 */ serial_port.iobase = sio_dev.sp1_base; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index bfd2c2e9f6c..64d06b52f98 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -97,95 +97,6 @@ config PINCTRL_BCM281XX BCM28145, and BCM28155 SoCs. This driver requires the pinctrl framework. GPIO is provided by a separate GPIO driver. -config PINCTRL_IMX - bool - select PINMUX - select PINCONF - -config PINCTRL_IMX1_CORE - bool - select PINMUX - select PINCONF - -config PINCTRL_IMX1 - bool "IMX1 pinctrl driver" - depends on SOC_IMX1 - select PINCTRL_IMX1_CORE - help - Say Y here to enable the imx1 pinctrl driver - -config PINCTRL_IMX27 - bool "IMX27 pinctrl driver" - depends on SOC_IMX27 - select PINCTRL_IMX1_CORE - help - Say Y here to enable the imx27 pinctrl driver - - -config PINCTRL_IMX25 - bool "IMX25 pinctrl driver" - depends on OF - depends on SOC_IMX25 - select PINCTRL_IMX - help - Say Y here to enable the imx25 pinctrl driver - -config PINCTRL_IMX35 - bool "IMX35 pinctrl driver" - depends on SOC_IMX35 - select PINCTRL_IMX - help - Say Y here to enable the imx35 pinctrl driver - -config PINCTRL_IMX50 - bool "IMX50 pinctrl driver" - depends on SOC_IMX50 - select PINCTRL_IMX - help - Say Y here to enable the imx50 pinctrl driver - -config PINCTRL_IMX51 - bool "IMX51 pinctrl driver" - depends on SOC_IMX51 - select PINCTRL_IMX - help - Say Y here to enable the imx51 pinctrl driver - -config PINCTRL_IMX53 - bool "IMX53 pinctrl driver" - depends on SOC_IMX53 - select PINCTRL_IMX - help - Say Y here to enable the imx53 pinctrl driver - -config PINCTRL_IMX6Q - bool "IMX6Q/DL pinctrl driver" - depends on SOC_IMX6Q - select PINCTRL_IMX - help - Say Y here to enable the imx6q/dl pinctrl driver - -config PINCTRL_IMX6SL - bool "IMX6SL pinctrl driver" - depends on SOC_IMX6SL - select PINCTRL_IMX - help - Say Y here to enable the imx6sl pinctrl driver - -config PINCTRL_IMX6SX - bool "IMX6SX pinctrl driver" - depends on SOC_IMX6SX - select PINCTRL_IMX - help - Say Y here to enable the imx6sx pinctrl driver - -config PINCTRL_VF610 - bool "Freescale Vybrid VF610 pinctrl driver" - depends on SOC_VF610 - select PINCTRL_IMX - help - Say Y here to enable the Freescale Vybrid VF610 pinctrl driver - config PINCTRL_LANTIQ bool depends on LANTIQ @@ -197,19 +108,6 @@ config PINCTRL_FALCON depends on SOC_FALCON depends on PINCTRL_LANTIQ -config PINCTRL_MXS - bool - select PINMUX - select PINCONF - -config PINCTRL_IMX23 - bool - select PINCTRL_MXS - -config PINCTRL_IMX28 - bool - select PINCTRL_MXS - config PINCTRL_ROCKCHIP bool select PINMUX @@ -306,6 +204,7 @@ config PINCTRL_PALMAS TPS65913, TPS80036 etc. source "drivers/pinctrl/berlin/Kconfig" +source "drivers/pinctrl/freescale/Kconfig" source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/nomadik/Kconfig" source "drivers/pinctrl/qcom/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 05d227508c9..51f52d32859 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -17,23 +17,7 @@ obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o -obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o -obj-$(CONFIG_PINCTRL_IMX1_CORE) += pinctrl-imx1-core.o -obj-$(CONFIG_PINCTRL_IMX1) += pinctrl-imx1.o -obj-$(CONFIG_PINCTRL_IMX27) += pinctrl-imx27.o -obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o -obj-$(CONFIG_PINCTRL_IMX50) += pinctrl-imx50.o -obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o -obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o -obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o -obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6dl.o -obj-$(CONFIG_PINCTRL_IMX6SL) += pinctrl-imx6sl.o -obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o -obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o -obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o -obj-$(CONFIG_PINCTRL_IMX25) += pinctrl-imx25.o -obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o @@ -52,15 +36,14 @@ obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o -obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o obj-$(CONFIG_ARCH_BERLIN) += berlin/ +obj-y += freescale/ obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-y += nomadik/ obj-$(CONFIG_ARCH_QCOM) += qcom/ -obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ -obj-$(CONFIG_ARCH_SHMOBILE) += sh-pfc/ -obj-$(CONFIG_SUPERH) += sh-pfc/ +obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/ +obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_ARCH_VT8500) += vt8500/ diff --git a/drivers/pinctrl/berlin/berlin.c b/drivers/pinctrl/berlin/berlin.c index 86db2235ab0..7f0b0f93242 100644 --- a/drivers/pinctrl/berlin/berlin.c +++ b/drivers/pinctrl/berlin/berlin.c @@ -99,30 +99,11 @@ static int berlin_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrl_dev, return 0; } -static void berlin_pinctrl_dt_free_map(struct pinctrl_dev *pctrl_dev, - struct pinctrl_map *map, - unsigned nmaps) -{ - int i; - - for (i = 0; i < nmaps; i++) { - if (map[i].type == PIN_MAP_TYPE_MUX_GROUP) { - kfree(map[i].data.mux.group); - - /* a function can be applied to multiple groups */ - if (i == 0) - kfree(map[i].data.mux.function); - } - } - - kfree(map); -} - static const struct pinctrl_ops berlin_pinctrl_ops = { .get_groups_count = &berlin_pinctrl_get_group_count, .get_group_name = &berlin_pinctrl_get_group_name, .dt_node_to_map = &berlin_pinctrl_dt_node_to_map, - .dt_free_map = &berlin_pinctrl_dt_free_map, + .dt_free_map = &pinctrl_utils_dt_free_map, }; static int berlin_pinmux_get_functions_count(struct pinctrl_dev *pctrl_dev) @@ -170,9 +151,9 @@ berlin_pinctrl_find_function_by_name(struct berlin_pinctrl *pctrl, return NULL; } -static int berlin_pinmux_enable(struct pinctrl_dev *pctrl_dev, - unsigned function, - unsigned group) +static int berlin_pinmux_set(struct pinctrl_dev *pctrl_dev, + unsigned function, + unsigned group) { struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev); const struct berlin_desc_group *group_desc = pctrl->desc->groups + group; @@ -197,7 +178,7 @@ static const struct pinmux_ops berlin_pinmux_ops = { .get_functions_count = &berlin_pinmux_get_functions_count, .get_function_name = &berlin_pinmux_get_function_name, .get_function_groups = &berlin_pinmux_get_function_groups, - .enable = &berlin_pinmux_enable, + .set_mux = &berlin_pinmux_set, }; static int berlin_pinctrl_add_function(struct berlin_pinctrl *pctrl, diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig new file mode 100644 index 00000000000..16aac38793f --- /dev/null +++ b/drivers/pinctrl/freescale/Kconfig @@ -0,0 +1,108 @@ +config PINCTRL_IMX + bool + select PINMUX + select PINCONF + +config PINCTRL_IMX1_CORE + bool + select PINMUX + select PINCONF + +config PINCTRL_IMX1 + bool "IMX1 pinctrl driver" + depends on SOC_IMX1 + select PINCTRL_IMX1_CORE + help + Say Y here to enable the imx1 pinctrl driver + +config PINCTRL_IMX21 + bool "i.MX21 pinctrl driver" + depends on SOC_IMX21 + select PINCTRL_IMX1_CORE + help + Say Y here to enable the i.MX21 pinctrl driver + +config PINCTRL_IMX27 + bool "IMX27 pinctrl driver" + depends on SOC_IMX27 + select PINCTRL_IMX1_CORE + help + Say Y here to enable the imx27 pinctrl driver + + +config PINCTRL_IMX25 + bool "IMX25 pinctrl driver" + depends on OF + depends on SOC_IMX25 + select PINCTRL_IMX + help + Say Y here to enable the imx25 pinctrl driver + +config PINCTRL_IMX35 + bool "IMX35 pinctrl driver" + depends on SOC_IMX35 + select PINCTRL_IMX + help + Say Y here to enable the imx35 pinctrl driver + +config PINCTRL_IMX50 + bool "IMX50 pinctrl driver" + depends on SOC_IMX50 + select PINCTRL_IMX + help + Say Y here to enable the imx50 pinctrl driver + +config PINCTRL_IMX51 + bool "IMX51 pinctrl driver" + depends on SOC_IMX51 + select PINCTRL_IMX + help + Say Y here to enable the imx51 pinctrl driver + +config PINCTRL_IMX53 + bool "IMX53 pinctrl driver" + depends on SOC_IMX53 + select PINCTRL_IMX + help + Say Y here to enable the imx53 pinctrl driver + +config PINCTRL_IMX6Q + bool "IMX6Q/DL pinctrl driver" + depends on SOC_IMX6Q + select PINCTRL_IMX + help + Say Y here to enable the imx6q/dl pinctrl driver + +config PINCTRL_IMX6SL + bool "IMX6SL pinctrl driver" + depends on SOC_IMX6SL + select PINCTRL_IMX + help + Say Y here to enable the imx6sl pinctrl driver + +config PINCTRL_IMX6SX + bool "IMX6SX pinctrl driver" + depends on SOC_IMX6SX + select PINCTRL_IMX + help + Say Y here to enable the imx6sx pinctrl driver + +config PINCTRL_VF610 + bool "Freescale Vybrid VF610 pinctrl driver" + depends on SOC_VF610 + select PINCTRL_IMX + help + Say Y here to enable the Freescale Vybrid VF610 pinctrl driver + +config PINCTRL_MXS + bool + select PINMUX + select PINCONF + +config PINCTRL_IMX23 + bool + select PINCTRL_MXS + +config PINCTRL_IMX28 + bool + select PINCTRL_MXS diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile new file mode 100644 index 00000000000..bba73c22f04 --- /dev/null +++ b/drivers/pinctrl/freescale/Makefile @@ -0,0 +1,19 @@ +# Freescale pin control drivers +obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o +obj-$(CONFIG_PINCTRL_IMX1_CORE) += pinctrl-imx1-core.o +obj-$(CONFIG_PINCTRL_IMX1) += pinctrl-imx1.o +obj-$(CONFIG_PINCTRL_IMX21) += pinctrl-imx21.o +obj-$(CONFIG_PINCTRL_IMX27) += pinctrl-imx27.o +obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o +obj-$(CONFIG_PINCTRL_IMX50) += pinctrl-imx50.o +obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o +obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o +obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o +obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6dl.o +obj-$(CONFIG_PINCTRL_IMX6SL) += pinctrl-imx6sl.o +obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o +obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o +obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o +obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o +obj-$(CONFIG_PINCTRL_IMX25) += pinctrl-imx25.o +obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 946d594a64d..f2446769247 100644 --- a/drivers/pinctrl/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -24,7 +24,7 @@ #include <linux/pinctrl/pinmux.h> #include <linux/slab.h> -#include "core.h" +#include "../core.h" #include "pinctrl-imx.h" /* The bits in CONFIG cell defined in binding doc*/ @@ -179,8 +179,8 @@ static const struct pinctrl_ops imx_pctrl_ops = { }; -static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) +static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); const struct imx_pinctrl_soc_info *info = ipctl->info; @@ -204,7 +204,7 @@ static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, pin_id = pin->pin; pin_reg = &info->pin_regs[pin_id]; - if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->mux_reg) { + if (pin_reg->mux_reg == -1) { dev_err(ipctl->dev, "Pin(%s) does not support mux function\n", info->pins[pin_id].name); return -EINVAL; @@ -298,7 +298,7 @@ static const struct pinmux_ops imx_pmx_ops = { .get_functions_count = imx_pmx_get_funcs_count, .get_function_name = imx_pmx_get_func_name, .get_function_groups = imx_pmx_get_groups, - .enable = imx_pmx_enable, + .set_mux = imx_pmx_set, }; static int imx_pinconf_get(struct pinctrl_dev *pctldev, @@ -308,7 +308,7 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev, const struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; - if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) { + if (pin_reg->conf_reg == -1) { dev_err(info->dev, "Pin(%s) does not support config function\n", info->pins[pin_id].name); return -EINVAL; @@ -331,7 +331,7 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev, const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; int i; - if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) { + if (pin_reg->conf_reg == -1) { dev_err(info->dev, "Pin(%s) does not support config function\n", info->pins[pin_id].name); return -EINVAL; @@ -586,10 +586,11 @@ int imx_pinctrl_probe(struct platform_device *pdev, if (!ipctl) return -ENOMEM; - info->pin_regs = devm_kzalloc(&pdev->dev, sizeof(*info->pin_regs) * + info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) * info->npins, GFP_KERNEL); if (!info->pin_regs) return -ENOMEM; + memset(info->pin_regs, 0xff, sizeof(*info->pin_regs) * info->npins); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ipctl->base = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/pinctrl/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h index db408b05700..49e55d39f7c 100644 --- a/drivers/pinctrl/pinctrl-imx.h +++ b/drivers/pinctrl/freescale/pinctrl-imx.h @@ -67,8 +67,8 @@ struct imx_pmx_func { * @conf_reg: config register offset */ struct imx_pin_reg { - u16 mux_reg; - u16 conf_reg; + s16 mux_reg; + s16 conf_reg; }; struct imx_pinctrl_soc_info { @@ -83,8 +83,7 @@ struct imx_pinctrl_soc_info { unsigned int flags; }; -#define ZERO_OFFSET_VALID 0x1 -#define SHARE_MUX_CONF_REG 0x2 +#define SHARE_MUX_CONF_REG 0x1 #define NO_MUX 0x0 #define NO_PAD 0x0 diff --git a/drivers/pinctrl/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c index 483420757c9..5ac59fbb244 100644 --- a/drivers/pinctrl/pinctrl-imx1-core.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c @@ -28,7 +28,7 @@ #include <linux/pinctrl/pinmux.h> #include <linux/slab.h> -#include "core.h" +#include "../core.h" #include "pinctrl-imx1.h" struct imx1_pinctrl { @@ -298,8 +298,8 @@ static const struct pinctrl_ops imx1_pctrl_ops = { }; -static int imx1_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) +static int imx1_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) { struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); const struct imx1_pinctrl_soc_info *info = ipctl->info; @@ -385,7 +385,7 @@ static const struct pinmux_ops imx1_pmx_ops = { .get_functions_count = imx1_pmx_get_funcs_count, .get_function_name = imx1_pmx_get_func_name, .get_function_groups = imx1_pmx_get_groups, - .enable = imx1_pmx_enable, + .set_mux = imx1_pmx_set, }; static int imx1_pinconf_get(struct pinctrl_dev *pctldev, diff --git a/drivers/pinctrl/pinctrl-imx1.c b/drivers/pinctrl/freescale/pinctrl-imx1.c index 533a6e51964..533a6e51964 100644 --- a/drivers/pinctrl/pinctrl-imx1.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1.c diff --git a/drivers/pinctrl/pinctrl-imx1.h b/drivers/pinctrl/freescale/pinctrl-imx1.h index 692a54c15cd..692a54c15cd 100644 --- a/drivers/pinctrl/pinctrl-imx1.h +++ b/drivers/pinctrl/freescale/pinctrl-imx1.h diff --git a/drivers/pinctrl/freescale/pinctrl-imx21.c b/drivers/pinctrl/freescale/pinctrl-imx21.c new file mode 100644 index 00000000000..1b3b2311b03 --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx21.c @@ -0,0 +1,342 @@ +/* + * i.MX21 pinctrl driver based on imx pinmux core + * + * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-imx1.h" + +#define PAD_ID(port, pin) ((port) * 32 + (pin)) +#define PA 0 +#define PB 1 +#define PC 2 +#define PD 3 +#define PE 4 +#define PF 5 + +enum imx21_pads { + MX21_PAD_LSCLK = PAD_ID(PA, 5), + MX21_PAD_LD0 = PAD_ID(PA, 6), + MX21_PAD_LD1 = PAD_ID(PA, 7), + MX21_PAD_LD2 = PAD_ID(PA, 8), + MX21_PAD_LD3 = PAD_ID(PA, 9), + MX21_PAD_LD4 = PAD_ID(PA, 10), + MX21_PAD_LD5 = PAD_ID(PA, 11), + MX21_PAD_LD6 = PAD_ID(PA, 12), + MX21_PAD_LD7 = PAD_ID(PA, 13), + MX21_PAD_LD8 = PAD_ID(PA, 14), + MX21_PAD_LD9 = PAD_ID(PA, 15), + MX21_PAD_LD10 = PAD_ID(PA, 16), + MX21_PAD_LD11 = PAD_ID(PA, 17), + MX21_PAD_LD12 = PAD_ID(PA, 18), + MX21_PAD_LD13 = PAD_ID(PA, 19), + MX21_PAD_LD14 = PAD_ID(PA, 20), + MX21_PAD_LD15 = PAD_ID(PA, 21), + MX21_PAD_LD16 = PAD_ID(PA, 22), + MX21_PAD_LD17 = PAD_ID(PA, 23), + MX21_PAD_REV = PAD_ID(PA, 24), + MX21_PAD_CLS = PAD_ID(PA, 25), + MX21_PAD_PS = PAD_ID(PA, 26), + MX21_PAD_SPL_SPR = PAD_ID(PA, 27), + MX21_PAD_HSYNC = PAD_ID(PA, 28), + MX21_PAD_VSYNC = PAD_ID(PA, 29), + MX21_PAD_CONTRAST = PAD_ID(PA, 30), + MX21_PAD_OE_ACD = PAD_ID(PA, 31), + MX21_PAD_SD2_D0 = PAD_ID(PB, 4), + MX21_PAD_SD2_D1 = PAD_ID(PB, 5), + MX21_PAD_SD2_D2 = PAD_ID(PB, 6), + MX21_PAD_SD2_D3 = PAD_ID(PB, 7), + MX21_PAD_SD2_CMD = PAD_ID(PB, 8), + MX21_PAD_SD2_CLK = PAD_ID(PB, 9), + MX21_PAD_CSI_D0 = PAD_ID(PB, 10), + MX21_PAD_CSI_D1 = PAD_ID(PB, 11), + MX21_PAD_CSI_D2 = PAD_ID(PB, 12), + MX21_PAD_CSI_D3 = PAD_ID(PB, 13), + MX21_PAD_CSI_D4 = PAD_ID(PB, 14), + MX21_PAD_CSI_MCLK = PAD_ID(PB, 15), + MX21_PAD_CSI_PIXCLK = PAD_ID(PB, 16), + MX21_PAD_CSI_D5 = PAD_ID(PB, 17), + MX21_PAD_CSI_D6 = PAD_ID(PB, 18), + MX21_PAD_CSI_D7 = PAD_ID(PB, 19), + MX21_PAD_CSI_VSYNC = PAD_ID(PB, 20), + MX21_PAD_CSI_HSYNC = PAD_ID(PB, 21), + MX21_PAD_USB_BYP = PAD_ID(PB, 22), + MX21_PAD_USB_PWR = PAD_ID(PB, 23), + MX21_PAD_USB_OC = PAD_ID(PB, 24), + MX21_PAD_USBH_ON = PAD_ID(PB, 25), + MX21_PAD_USBH1_FS = PAD_ID(PB, 26), + MX21_PAD_USBH1_OE = PAD_ID(PB, 27), + MX21_PAD_USBH1_TXDM = PAD_ID(PB, 28), + MX21_PAD_USBH1_TXDP = PAD_ID(PB, 29), + MX21_PAD_USBH1_RXDM = PAD_ID(PB, 30), + MX21_PAD_USBH1_RXDP = PAD_ID(PB, 31), + MX21_PAD_USBG_SDA = PAD_ID(PC, 5), + MX21_PAD_USBG_SCL = PAD_ID(PC, 6), + MX21_PAD_USBG_ON = PAD_ID(PC, 7), + MX21_PAD_USBG_FS = PAD_ID(PC, 8), + MX21_PAD_USBG_OE = PAD_ID(PC, 9), + MX21_PAD_USBG_TXDM = PAD_ID(PC, 10), + MX21_PAD_USBG_TXDP = PAD_ID(PC, 11), + MX21_PAD_USBG_RXDM = PAD_ID(PC, 12), + MX21_PAD_USBG_RXDP = PAD_ID(PC, 13), + MX21_PAD_TOUT = PAD_ID(PC, 14), + MX21_PAD_TIN = PAD_ID(PC, 15), + MX21_PAD_SAP_FS = PAD_ID(PC, 16), + MX21_PAD_SAP_RXD = PAD_ID(PC, 17), + MX21_PAD_SAP_TXD = PAD_ID(PC, 18), + MX21_PAD_SAP_CLK = PAD_ID(PC, 19), + MX21_PAD_SSI1_FS = PAD_ID(PC, 20), + MX21_PAD_SSI1_RXD = PAD_ID(PC, 21), + MX21_PAD_SSI1_TXD = PAD_ID(PC, 22), + MX21_PAD_SSI1_CLK = PAD_ID(PC, 23), + MX21_PAD_SSI2_FS = PAD_ID(PC, 24), + MX21_PAD_SSI2_RXD = PAD_ID(PC, 25), + MX21_PAD_SSI2_TXD = PAD_ID(PC, 26), + MX21_PAD_SSI2_CLK = PAD_ID(PC, 27), + MX21_PAD_SSI3_FS = PAD_ID(PC, 28), + MX21_PAD_SSI3_RXD = PAD_ID(PC, 29), + MX21_PAD_SSI3_TXD = PAD_ID(PC, 30), + MX21_PAD_SSI3_CLK = PAD_ID(PC, 31), + MX21_PAD_I2C_DATA = PAD_ID(PD, 17), + MX21_PAD_I2C_CLK = PAD_ID(PD, 18), + MX21_PAD_CSPI2_SS2 = PAD_ID(PD, 19), + MX21_PAD_CSPI2_SS1 = PAD_ID(PD, 20), + MX21_PAD_CSPI2_SS0 = PAD_ID(PD, 21), + MX21_PAD_CSPI2_SCLK = PAD_ID(PD, 22), + MX21_PAD_CSPI2_MISO = PAD_ID(PD, 23), + MX21_PAD_CSPI2_MOSI = PAD_ID(PD, 24), + MX21_PAD_CSPI1_RDY = PAD_ID(PD, 25), + MX21_PAD_CSPI1_SS2 = PAD_ID(PD, 26), + MX21_PAD_CSPI1_SS1 = PAD_ID(PD, 27), + MX21_PAD_CSPI1_SS0 = PAD_ID(PD, 28), + MX21_PAD_CSPI1_SCLK = PAD_ID(PD, 29), + MX21_PAD_CSPI1_MISO = PAD_ID(PD, 30), + MX21_PAD_CSPI1_MOSI = PAD_ID(PD, 31), + MX21_PAD_TEST_WB2 = PAD_ID(PE, 0), + MX21_PAD_TEST_WB1 = PAD_ID(PE, 1), + MX21_PAD_TEST_WB0 = PAD_ID(PE, 2), + MX21_PAD_UART2_CTS = PAD_ID(PE, 3), + MX21_PAD_UART2_RTS = PAD_ID(PE, 4), + MX21_PAD_PWMO = PAD_ID(PE, 5), + MX21_PAD_UART2_TXD = PAD_ID(PE, 6), + MX21_PAD_UART2_RXD = PAD_ID(PE, 7), + MX21_PAD_UART3_TXD = PAD_ID(PE, 8), + MX21_PAD_UART3_RXD = PAD_ID(PE, 9), + MX21_PAD_UART3_CTS = PAD_ID(PE, 10), + MX21_PAD_UART3_RTS = PAD_ID(PE, 11), + MX21_PAD_UART1_TXD = PAD_ID(PE, 12), + MX21_PAD_UART1_RXD = PAD_ID(PE, 13), + MX21_PAD_UART1_CTS = PAD_ID(PE, 14), + MX21_PAD_UART1_RTS = PAD_ID(PE, 15), + MX21_PAD_RTCK = PAD_ID(PE, 16), + MX21_PAD_RESET_OUT = PAD_ID(PE, 17), + MX21_PAD_SD1_D0 = PAD_ID(PE, 18), + MX21_PAD_SD1_D1 = PAD_ID(PE, 19), + MX21_PAD_SD1_D2 = PAD_ID(PE, 20), + MX21_PAD_SD1_D3 = PAD_ID(PE, 21), + MX21_PAD_SD1_CMD = PAD_ID(PE, 22), + MX21_PAD_SD1_CLK = PAD_ID(PE, 23), + MX21_PAD_NFRB = PAD_ID(PF, 0), + MX21_PAD_NFCE = PAD_ID(PF, 1), + MX21_PAD_NFWP = PAD_ID(PF, 2), + MX21_PAD_NFCLE = PAD_ID(PF, 3), + MX21_PAD_NFALE = PAD_ID(PF, 4), + MX21_PAD_NFRE = PAD_ID(PF, 5), + MX21_PAD_NFWE = PAD_ID(PF, 6), + MX21_PAD_NFIO0 = PAD_ID(PF, 7), + MX21_PAD_NFIO1 = PAD_ID(PF, 8), + MX21_PAD_NFIO2 = PAD_ID(PF, 9), + MX21_PAD_NFIO3 = PAD_ID(PF, 10), + MX21_PAD_NFIO4 = PAD_ID(PF, 11), + MX21_PAD_NFIO5 = PAD_ID(PF, 12), + MX21_PAD_NFIO6 = PAD_ID(PF, 13), + MX21_PAD_NFIO7 = PAD_ID(PF, 14), + MX21_PAD_CLKO = PAD_ID(PF, 15), + MX21_PAD_RESERVED = PAD_ID(PF, 16), + MX21_PAD_CS4 = PAD_ID(PF, 21), + MX21_PAD_CS5 = PAD_ID(PF, 22), +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx21_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX21_PAD_LSCLK), + IMX_PINCTRL_PIN(MX21_PAD_LD0), + IMX_PINCTRL_PIN(MX21_PAD_LD1), + IMX_PINCTRL_PIN(MX21_PAD_LD2), + IMX_PINCTRL_PIN(MX21_PAD_LD3), + IMX_PINCTRL_PIN(MX21_PAD_LD4), + IMX_PINCTRL_PIN(MX21_PAD_LD5), + IMX_PINCTRL_PIN(MX21_PAD_LD6), + IMX_PINCTRL_PIN(MX21_PAD_LD7), + IMX_PINCTRL_PIN(MX21_PAD_LD8), + IMX_PINCTRL_PIN(MX21_PAD_LD9), + IMX_PINCTRL_PIN(MX21_PAD_LD10), + IMX_PINCTRL_PIN(MX21_PAD_LD11), + IMX_PINCTRL_PIN(MX21_PAD_LD12), + IMX_PINCTRL_PIN(MX21_PAD_LD13), + IMX_PINCTRL_PIN(MX21_PAD_LD14), + IMX_PINCTRL_PIN(MX21_PAD_LD15), + IMX_PINCTRL_PIN(MX21_PAD_LD16), + IMX_PINCTRL_PIN(MX21_PAD_LD17), + IMX_PINCTRL_PIN(MX21_PAD_REV), + IMX_PINCTRL_PIN(MX21_PAD_CLS), + IMX_PINCTRL_PIN(MX21_PAD_PS), + IMX_PINCTRL_PIN(MX21_PAD_SPL_SPR), + IMX_PINCTRL_PIN(MX21_PAD_HSYNC), + IMX_PINCTRL_PIN(MX21_PAD_VSYNC), + IMX_PINCTRL_PIN(MX21_PAD_CONTRAST), + IMX_PINCTRL_PIN(MX21_PAD_OE_ACD), + IMX_PINCTRL_PIN(MX21_PAD_SD2_D0), + IMX_PINCTRL_PIN(MX21_PAD_SD2_D1), + IMX_PINCTRL_PIN(MX21_PAD_SD2_D2), + IMX_PINCTRL_PIN(MX21_PAD_SD2_D3), + IMX_PINCTRL_PIN(MX21_PAD_SD2_CMD), + IMX_PINCTRL_PIN(MX21_PAD_SD2_CLK), + IMX_PINCTRL_PIN(MX21_PAD_CSI_D0), + IMX_PINCTRL_PIN(MX21_PAD_CSI_D1), + IMX_PINCTRL_PIN(MX21_PAD_CSI_D2), + IMX_PINCTRL_PIN(MX21_PAD_CSI_D3), + IMX_PINCTRL_PIN(MX21_PAD_CSI_D4), + IMX_PINCTRL_PIN(MX21_PAD_CSI_MCLK), + IMX_PINCTRL_PIN(MX21_PAD_CSI_PIXCLK), + IMX_PINCTRL_PIN(MX21_PAD_CSI_D5), + IMX_PINCTRL_PIN(MX21_PAD_CSI_D6), + IMX_PINCTRL_PIN(MX21_PAD_CSI_D7), + IMX_PINCTRL_PIN(MX21_PAD_CSI_VSYNC), + IMX_PINCTRL_PIN(MX21_PAD_CSI_HSYNC), + IMX_PINCTRL_PIN(MX21_PAD_USB_BYP), + IMX_PINCTRL_PIN(MX21_PAD_USB_PWR), + IMX_PINCTRL_PIN(MX21_PAD_USB_OC), + IMX_PINCTRL_PIN(MX21_PAD_USBH_ON), + IMX_PINCTRL_PIN(MX21_PAD_USBH1_FS), + IMX_PINCTRL_PIN(MX21_PAD_USBH1_OE), + IMX_PINCTRL_PIN(MX21_PAD_USBH1_TXDM), + IMX_PINCTRL_PIN(MX21_PAD_USBH1_TXDP), + IMX_PINCTRL_PIN(MX21_PAD_USBH1_RXDM), + IMX_PINCTRL_PIN(MX21_PAD_USBH1_RXDP), + IMX_PINCTRL_PIN(MX21_PAD_USBG_SDA), + IMX_PINCTRL_PIN(MX21_PAD_USBG_SCL), + IMX_PINCTRL_PIN(MX21_PAD_USBG_ON), + IMX_PINCTRL_PIN(MX21_PAD_USBG_FS), + IMX_PINCTRL_PIN(MX21_PAD_USBG_OE), + IMX_PINCTRL_PIN(MX21_PAD_USBG_TXDM), + IMX_PINCTRL_PIN(MX21_PAD_USBG_TXDP), + IMX_PINCTRL_PIN(MX21_PAD_USBG_RXDM), + IMX_PINCTRL_PIN(MX21_PAD_USBG_RXDP), + IMX_PINCTRL_PIN(MX21_PAD_TOUT), + IMX_PINCTRL_PIN(MX21_PAD_TIN), + IMX_PINCTRL_PIN(MX21_PAD_SAP_FS), + IMX_PINCTRL_PIN(MX21_PAD_SAP_RXD), + IMX_PINCTRL_PIN(MX21_PAD_SAP_TXD), + IMX_PINCTRL_PIN(MX21_PAD_SAP_CLK), + IMX_PINCTRL_PIN(MX21_PAD_SSI1_FS), + IMX_PINCTRL_PIN(MX21_PAD_SSI1_RXD), + IMX_PINCTRL_PIN(MX21_PAD_SSI1_TXD), + IMX_PINCTRL_PIN(MX21_PAD_SSI1_CLK), + IMX_PINCTRL_PIN(MX21_PAD_SSI2_FS), + IMX_PINCTRL_PIN(MX21_PAD_SSI2_RXD), + IMX_PINCTRL_PIN(MX21_PAD_SSI2_TXD), + IMX_PINCTRL_PIN(MX21_PAD_SSI2_CLK), + IMX_PINCTRL_PIN(MX21_PAD_SSI3_FS), + IMX_PINCTRL_PIN(MX21_PAD_SSI3_RXD), + IMX_PINCTRL_PIN(MX21_PAD_SSI3_TXD), + IMX_PINCTRL_PIN(MX21_PAD_SSI3_CLK), + IMX_PINCTRL_PIN(MX21_PAD_I2C_DATA), + IMX_PINCTRL_PIN(MX21_PAD_I2C_CLK), + IMX_PINCTRL_PIN(MX21_PAD_CSPI2_SS2), + IMX_PINCTRL_PIN(MX21_PAD_CSPI2_SS1), + IMX_PINCTRL_PIN(MX21_PAD_CSPI2_SS0), + IMX_PINCTRL_PIN(MX21_PAD_CSPI2_SCLK), + IMX_PINCTRL_PIN(MX21_PAD_CSPI2_MISO), + IMX_PINCTRL_PIN(MX21_PAD_CSPI2_MOSI), + IMX_PINCTRL_PIN(MX21_PAD_CSPI1_RDY), + IMX_PINCTRL_PIN(MX21_PAD_CSPI1_SS2), + IMX_PINCTRL_PIN(MX21_PAD_CSPI1_SS1), + IMX_PINCTRL_PIN(MX21_PAD_CSPI1_SS0), + IMX_PINCTRL_PIN(MX21_PAD_CSPI1_SCLK), + IMX_PINCTRL_PIN(MX21_PAD_CSPI1_MISO), + IMX_PINCTRL_PIN(MX21_PAD_CSPI1_MOSI), + IMX_PINCTRL_PIN(MX21_PAD_TEST_WB2), + IMX_PINCTRL_PIN(MX21_PAD_TEST_WB1), + IMX_PINCTRL_PIN(MX21_PAD_TEST_WB0), + IMX_PINCTRL_PIN(MX21_PAD_UART2_CTS), + IMX_PINCTRL_PIN(MX21_PAD_UART2_RTS), + IMX_PINCTRL_PIN(MX21_PAD_PWMO), + IMX_PINCTRL_PIN(MX21_PAD_UART2_TXD), + IMX_PINCTRL_PIN(MX21_PAD_UART2_RXD), + IMX_PINCTRL_PIN(MX21_PAD_UART3_TXD), + IMX_PINCTRL_PIN(MX21_PAD_UART3_RXD), + IMX_PINCTRL_PIN(MX21_PAD_UART3_CTS), + IMX_PINCTRL_PIN(MX21_PAD_UART3_RTS), + IMX_PINCTRL_PIN(MX21_PAD_UART1_TXD), + IMX_PINCTRL_PIN(MX21_PAD_UART1_RXD), + IMX_PINCTRL_PIN(MX21_PAD_UART1_CTS), + IMX_PINCTRL_PIN(MX21_PAD_UART1_RTS), + IMX_PINCTRL_PIN(MX21_PAD_RTCK), + IMX_PINCTRL_PIN(MX21_PAD_RESET_OUT), + IMX_PINCTRL_PIN(MX21_PAD_SD1_D0), + IMX_PINCTRL_PIN(MX21_PAD_SD1_D1), + IMX_PINCTRL_PIN(MX21_PAD_SD1_D2), + IMX_PINCTRL_PIN(MX21_PAD_SD1_D3), + IMX_PINCTRL_PIN(MX21_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX21_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX21_PAD_NFRB), + IMX_PINCTRL_PIN(MX21_PAD_NFCE), + IMX_PINCTRL_PIN(MX21_PAD_NFWP), + IMX_PINCTRL_PIN(MX21_PAD_NFCLE), + IMX_PINCTRL_PIN(MX21_PAD_NFALE), + IMX_PINCTRL_PIN(MX21_PAD_NFRE), + IMX_PINCTRL_PIN(MX21_PAD_NFWE), + IMX_PINCTRL_PIN(MX21_PAD_NFIO0), + IMX_PINCTRL_PIN(MX21_PAD_NFIO1), + IMX_PINCTRL_PIN(MX21_PAD_NFIO2), + IMX_PINCTRL_PIN(MX21_PAD_NFIO3), + IMX_PINCTRL_PIN(MX21_PAD_NFIO4), + IMX_PINCTRL_PIN(MX21_PAD_NFIO5), + IMX_PINCTRL_PIN(MX21_PAD_NFIO6), + IMX_PINCTRL_PIN(MX21_PAD_NFIO7), + IMX_PINCTRL_PIN(MX21_PAD_CLKO), + IMX_PINCTRL_PIN(MX21_PAD_RESERVED), + IMX_PINCTRL_PIN(MX21_PAD_CS4), + IMX_PINCTRL_PIN(MX21_PAD_CS5), +}; + +static struct imx1_pinctrl_soc_info imx21_pinctrl_info = { + .pins = imx21_pinctrl_pads, + .npins = ARRAY_SIZE(imx21_pinctrl_pads), +}; + +static int __init imx21_pinctrl_probe(struct platform_device *pdev) +{ + return imx1_pinctrl_core_probe(pdev, &imx21_pinctrl_info); +} + +static const struct of_device_id imx21_pinctrl_of_match[] = { + { .compatible = "fsl,imx21-iomuxc", }, + { } +}; +MODULE_DEVICE_TABLE(of, imx21_pinctrl_of_match); + +static struct platform_driver imx21_pinctrl_driver = { + .driver = { + .name = "imx21-pinctrl", + .owner = THIS_MODULE, + .of_match_table = imx21_pinctrl_of_match, + }, + .remove = imx1_pinctrl_core_remove, +}; +module_platform_driver_probe(imx21_pinctrl_driver, imx21_pinctrl_probe); + +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("Freescale i.MX21 pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-imx23.c b/drivers/pinctrl/freescale/pinctrl-imx23.c index e76d75c9d1b..df79096becb 100644 --- a/drivers/pinctrl/pinctrl-imx23.c +++ b/drivers/pinctrl/freescale/pinctrl-imx23.c @@ -272,7 +272,7 @@ static int imx23_pinctrl_probe(struct platform_device *pdev) return mxs_pinctrl_probe(pdev, &imx23_pinctrl_data); } -static struct of_device_id imx23_pinctrl_of_match[] = { +static const struct of_device_id imx23_pinctrl_of_match[] = { { .compatible = "fsl,imx23-pinctrl", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx25.c b/drivers/pinctrl/freescale/pinctrl-imx25.c index 1aae1b61c4d..550e6d77ac2 100644 --- a/drivers/pinctrl/pinctrl-imx25.c +++ b/drivers/pinctrl/freescale/pinctrl-imx25.c @@ -315,7 +315,7 @@ static struct imx_pinctrl_soc_info imx25_pinctrl_info = { .npins = ARRAY_SIZE(imx25_pinctrl_pads), }; -static struct of_device_id imx25_pinctrl_of_match[] = { +static const struct of_device_id imx25_pinctrl_of_match[] = { { .compatible = "fsl,imx25-iomuxc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx27.c b/drivers/pinctrl/freescale/pinctrl-imx27.c index f8dfefb6996..945eccadea7 100644 --- a/drivers/pinctrl/pinctrl-imx27.c +++ b/drivers/pinctrl/freescale/pinctrl-imx27.c @@ -389,7 +389,7 @@ static struct imx1_pinctrl_soc_info imx27_pinctrl_info = { .npins = ARRAY_SIZE(imx27_pinctrl_pads), }; -static struct of_device_id imx27_pinctrl_of_match[] = { +static const struct of_device_id imx27_pinctrl_of_match[] = { { .compatible = "fsl,imx27-iomuxc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx28.c b/drivers/pinctrl/freescale/pinctrl-imx28.c index 79c9c8d296a..3bd45da2122 100644 --- a/drivers/pinctrl/pinctrl-imx28.c +++ b/drivers/pinctrl/freescale/pinctrl-imx28.c @@ -388,7 +388,7 @@ static int imx28_pinctrl_probe(struct platform_device *pdev) return mxs_pinctrl_probe(pdev, &imx28_pinctrl_data); } -static struct of_device_id imx28_pinctrl_of_match[] = { +static const struct of_device_id imx28_pinctrl_of_match[] = { { .compatible = "fsl,imx28-pinctrl", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx35.c b/drivers/pinctrl/freescale/pinctrl-imx35.c index 278a04ae894..6bfbcd0112c 100644 --- a/drivers/pinctrl/pinctrl-imx35.c +++ b/drivers/pinctrl/freescale/pinctrl-imx35.c @@ -1005,7 +1005,7 @@ static struct imx_pinctrl_soc_info imx35_pinctrl_info = { .npins = ARRAY_SIZE(imx35_pinctrl_pads), }; -static struct of_device_id imx35_pinctrl_of_match[] = { +static const struct of_device_id imx35_pinctrl_of_match[] = { { .compatible = "fsl,imx35-iomuxc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx50.c b/drivers/pinctrl/freescale/pinctrl-imx50.c index b06feed1b03..e8bd604ab14 100644 --- a/drivers/pinctrl/pinctrl-imx50.c +++ b/drivers/pinctrl/freescale/pinctrl-imx50.c @@ -391,7 +391,7 @@ static struct imx_pinctrl_soc_info imx50_pinctrl_info = { .npins = ARRAY_SIZE(imx50_pinctrl_pads), }; -static struct of_device_id imx50_pinctrl_of_match[] = { +static const struct of_device_id imx50_pinctrl_of_match[] = { { .compatible = "fsl,imx50-iomuxc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx51.c b/drivers/pinctrl/freescale/pinctrl-imx51.c index 19ab182bef6..b818051db7c 100644 --- a/drivers/pinctrl/pinctrl-imx51.c +++ b/drivers/pinctrl/freescale/pinctrl-imx51.c @@ -768,7 +768,7 @@ static struct imx_pinctrl_soc_info imx51_pinctrl_info = { .npins = ARRAY_SIZE(imx51_pinctrl_pads), }; -static struct of_device_id imx51_pinctrl_of_match[] = { +static const struct of_device_id imx51_pinctrl_of_match[] = { { .compatible = "fsl,imx51-iomuxc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx53.c b/drivers/pinctrl/freescale/pinctrl-imx53.c index f8d45c4cfde..1884d53cf75 100644 --- a/drivers/pinctrl/pinctrl-imx53.c +++ b/drivers/pinctrl/freescale/pinctrl-imx53.c @@ -454,7 +454,7 @@ static struct imx_pinctrl_soc_info imx53_pinctrl_info = { .npins = ARRAY_SIZE(imx53_pinctrl_pads), }; -static struct of_device_id imx53_pinctrl_of_match[] = { +static const struct of_device_id imx53_pinctrl_of_match[] = { { .compatible = "fsl,imx53-iomuxc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx6dl.c b/drivers/pinctrl/freescale/pinctrl-imx6dl.c index db2a1489bd9..656c4b08cc2 100644 --- a/drivers/pinctrl/pinctrl-imx6dl.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6dl.c @@ -460,7 +460,7 @@ static struct imx_pinctrl_soc_info imx6dl_pinctrl_info = { .npins = ARRAY_SIZE(imx6dl_pinctrl_pads), }; -static struct of_device_id imx6dl_pinctrl_of_match[] = { +static const struct of_device_id imx6dl_pinctrl_of_match[] = { { .compatible = "fsl,imx6dl-iomuxc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx6q.c b/drivers/pinctrl/freescale/pinctrl-imx6q.c index 8eb5ac1bd5f..59bb5b4ec0f 100644 --- a/drivers/pinctrl/pinctrl-imx6q.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6q.c @@ -466,7 +466,7 @@ static struct imx_pinctrl_soc_info imx6q_pinctrl_info = { .npins = ARRAY_SIZE(imx6q_pinctrl_pads), }; -static struct of_device_id imx6q_pinctrl_of_match[] = { +static const struct of_device_id imx6q_pinctrl_of_match[] = { { .compatible = "fsl,imx6q-iomuxc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-imx6sl.c b/drivers/pinctrl/freescale/pinctrl-imx6sl.c index f21b7389df3..e0924bd7b98 100644 --- a/drivers/pinctrl/pinctrl-imx6sl.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6sl.c @@ -366,10 +366,11 @@ static struct imx_pinctrl_soc_info imx6sl_pinctrl_info = { .npins = ARRAY_SIZE(imx6sl_pinctrl_pads), }; -static struct of_device_id imx6sl_pinctrl_of_match[] = { +static const struct of_device_id imx6sl_pinctrl_of_match[] = { { .compatible = "fsl,imx6sl-iomuxc", }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, imx6sl_pinctrl_of_match); static int imx6sl_pinctrl_probe(struct platform_device *pdev) { diff --git a/drivers/pinctrl/pinctrl-imx6sx.c b/drivers/pinctrl/freescale/pinctrl-imx6sx.c index 09758a56b9d..840344c8580 100644 --- a/drivers/pinctrl/pinctrl-imx6sx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6sx.c @@ -370,7 +370,7 @@ static struct imx_pinctrl_soc_info imx6sx_pinctrl_info = { .npins = ARRAY_SIZE(imx6sx_pinctrl_pads), }; -static struct of_device_id imx6sx_pinctrl_of_match[] = { +static const struct of_device_id imx6sx_pinctrl_of_match[] = { { .compatible = "fsl,imx6sx-iomuxc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c index 40c76f26998..f98c6bb0f76 100644 --- a/drivers/pinctrl/pinctrl-mxs.c +++ b/drivers/pinctrl/freescale/pinctrl-mxs.c @@ -21,7 +21,7 @@ #include <linux/pinctrl/pinmux.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include "core.h" +#include "../core.h" #include "pinctrl-mxs.h" #define SUFFIX_LEN 4 @@ -195,8 +195,8 @@ static int mxs_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, return 0; } -static int mxs_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) +static int mxs_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) { struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); struct mxs_group *g = &d->soc->groups[group]; @@ -223,7 +223,7 @@ static const struct pinmux_ops mxs_pinmux_ops = { .get_functions_count = mxs_pinctrl_get_funcs_count, .get_function_name = mxs_pinctrl_get_func_name, .get_function_groups = mxs_pinctrl_get_func_groups, - .enable = mxs_pinctrl_enable, + .set_mux = mxs_pinctrl_set_mux, }; static int mxs_pinconf_get(struct pinctrl_dev *pctldev, diff --git a/drivers/pinctrl/pinctrl-mxs.h b/drivers/pinctrl/freescale/pinctrl-mxs.h index fdd88d0bae2..fdd88d0bae2 100644 --- a/drivers/pinctrl/pinctrl-mxs.h +++ b/drivers/pinctrl/freescale/pinctrl-mxs.h diff --git a/drivers/pinctrl/pinctrl-vf610.c b/drivers/pinctrl/freescale/pinctrl-vf610.c index bddd913d28b..b788e157895 100644 --- a/drivers/pinctrl/pinctrl-vf610.c +++ b/drivers/pinctrl/freescale/pinctrl-vf610.c @@ -299,7 +299,7 @@ static const struct pinctrl_pin_desc vf610_pinctrl_pads[] = { static struct imx_pinctrl_soc_info vf610_pinctrl_info = { .pins = vf610_pinctrl_pads, .npins = ARRAY_SIZE(vf610_pinctrl_pads), - .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG, + .flags = SHARE_MUX_CONF_REG, }; static struct of_device_id vf610_pinctrl_of_match[] = { diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c index 9908374f8f9..f3b426cdaf8 100644 --- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -259,8 +259,8 @@ static int mvebu_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned fid, return 0; } -static int mvebu_pinmux_enable(struct pinctrl_dev *pctldev, unsigned fid, - unsigned gid) +static int mvebu_pinmux_set(struct pinctrl_dev *pctldev, unsigned fid, + unsigned gid) { struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct mvebu_pinctrl_function *func = &pctl->functions[fid]; @@ -344,7 +344,7 @@ static const struct pinmux_ops mvebu_pinmux_ops = { .get_function_groups = mvebu_pinmux_get_groups, .gpio_request_enable = mvebu_pinmux_gpio_request_enable, .gpio_set_direction = mvebu_pinmux_gpio_set_direction, - .enable = mvebu_pinmux_enable, + .set_mux = mvebu_pinmux_set, }; static int mvebu_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 8c6fd8d4dd3..47f49314986 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -34,6 +34,7 @@ #include "pinctrl-abx500.h" #include "../core.h" #include "../pinconf.h" +#include "../pinctrl-utils.h" /* * The AB9540 and AB8540 GPIO support are extended versions @@ -708,8 +709,8 @@ static int abx500_pmx_get_func_groups(struct pinctrl_dev *pctldev, return 0; } -static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, - unsigned group) +static int abx500_pmx_set(struct pinctrl_dev *pctldev, unsigned function, + unsigned group) { struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); struct gpio_chip *chip = &pct->chip; @@ -783,7 +784,7 @@ static const struct pinmux_ops abx500_pinmux_ops = { .get_functions_count = abx500_pmx_get_funcs_cnt, .get_function_name = abx500_pmx_get_func_name, .get_function_groups = abx500_pmx_get_func_groups, - .enable = abx500_pmx_enable, + .set_mux = abx500_pmx_set, .gpio_request_enable = abx500_gpio_request_enable, .gpio_disable_free = abx500_gpio_disable_free, }; @@ -826,41 +827,6 @@ static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev, chip->base + offset - 1); } -static void abx500_dt_free_map(struct pinctrl_dev *pctldev, - struct pinctrl_map *map, unsigned num_maps) -{ - int i; - - for (i = 0; i < num_maps; i++) - if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN) - kfree(map[i].data.configs.configs); - kfree(map); -} - -static int abx500_dt_reserve_map(struct pinctrl_map **map, - unsigned *reserved_maps, - unsigned *num_maps, - unsigned reserve) -{ - unsigned old_num = *reserved_maps; - unsigned new_num = *num_maps + reserve; - struct pinctrl_map *new_map; - - if (old_num >= new_num) - return 0; - - new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); - if (!new_map) - return -ENOMEM; - - memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); - - *map = new_map; - *reserved_maps = new_num; - - return 0; -} - static int abx500_dt_add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, unsigned *num_maps, const char *group, @@ -926,19 +892,32 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, unsigned long *configs; unsigned int nconfigs = 0; bool has_config = 0; - unsigned reserve = 0; struct property *prop; const char *group, *gpio_name; struct device_node *np_config; ret = of_property_read_string(np, "ste,function", &function); - if (ret >= 0) - reserve = 1; + if (ret >= 0) { + ret = of_property_count_strings(np, "ste,pins"); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, + num_maps, ret); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "ste,pins", prop, group) { + ret = abx500_dt_add_map_mux(map, reserved_maps, + num_maps, group, function); + if (ret < 0) + goto exit; + } + } ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs); if (nconfigs) has_config = 1; - np_config = of_parse_phandle(np, "ste,config", 0); if (np_config) { ret = pinconf_generic_parse_dt_config(np_config, &configs, @@ -947,28 +926,18 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, goto exit; has_config |= nconfigs; } + if (has_config) { + ret = of_property_count_strings(np, "ste,pins"); + if (ret < 0) + goto exit; - ret = of_property_count_strings(np, "ste,pins"); - if (ret < 0) - goto exit; - - if (has_config) - reserve++; - - reserve *= ret; - - ret = abx500_dt_reserve_map(map, reserved_maps, num_maps, reserve); - if (ret < 0) - goto exit; + ret = pinctrl_utils_reserve_map(pctldev, map, + reserved_maps, + num_maps, ret); + if (ret < 0) + goto exit; - of_property_for_each_string(np, "ste,pins", prop, group) { - if (function) { - ret = abx500_dt_add_map_mux(map, reserved_maps, - num_maps, group, function); - if (ret < 0) - goto exit; - } - if (has_config) { + of_property_for_each_string(np, "ste,pins", prop, group) { gpio_name = abx500_find_pin_name(pctldev, group); ret = abx500_dt_add_map_configs(map, reserved_maps, @@ -976,8 +945,8 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; } - } + exit: return ret; } @@ -998,7 +967,7 @@ static int abx500_dt_node_to_map(struct pinctrl_dev *pctldev, ret = abx500_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); if (ret < 0) { - abx500_dt_free_map(pctldev, *map, *num_maps); + pinctrl_utils_dt_free_map(pctldev, *map, *num_maps); return ret; } } @@ -1012,7 +981,7 @@ static const struct pinctrl_ops abx500_pinctrl_ops = { .get_group_pins = abx500_get_group_pins, .pin_dbg_show = abx500_pin_dbg_show, .dt_node_to_map = abx500_dt_node_to_map, - .dt_free_map = abx500_dt_free_map, + .dt_free_map = pinctrl_utils_dt_free_map, }; static int abx500_pin_config_get(struct pinctrl_dev *pctldev, diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index e7cab07eef4..3c29d918714 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -32,6 +32,7 @@ #include <linux/pinctrl/consumer.h> #include "pinctrl-nomadik.h" #include "../core.h" +#include "../pinctrl-utils.h" /* * The GPIO module in the Nomadik family of Systems-on-Chip is an @@ -985,6 +986,7 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, container_of(chip, struct nmk_gpio_chip, chip); int mode; bool is_out; + bool data_out; bool pull; u32 bit = 1 << offset; const char *modes[] = { @@ -997,28 +999,41 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, [NMK_GPIO_ALT_C+3] = "altC3", [NMK_GPIO_ALT_C+4] = "altC4", }; + const char *pulls[] = { + "none ", + "pull down", + "pull up ", + }; clk_enable(nmk_chip->clk); is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit); pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit); + data_out = !!(readl(nmk_chip->addr + NMK_GPIO_DAT) & bit); mode = nmk_gpio_get_mode(gpio); if ((mode == NMK_GPIO_ALT_C) && pctldev) mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio); - seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s", - gpio, label ?: "(none)", - is_out ? "out" : "in ", - chip->get - ? (chip->get(chip, offset) ? "hi" : "lo") - : "? ", - (mode < 0) ? "unknown" : modes[mode], - pull ? "pull" : "none"); - - if (!is_out) { + if (is_out) { + seq_printf(s, " gpio-%-3d (%-20.20s) out %s %s", + gpio, + label ?: "(none)", + data_out ? "hi" : "lo", + (mode < 0) ? "unknown" : modes[mode]); + } else { int irq = gpio_to_irq(gpio); struct irq_desc *desc = irq_to_desc(irq); + int pullidx = 0; - /* This races with request_irq(), set_irq_type(), + if (pull) + pullidx = data_out ? 1 : 2; + + seq_printf(s, " gpio-%-3d (%-20.20s) in %s %s", + gpio, + label ?: "(none)", + pulls[pullidx], + (mode < 0) ? "unknown" : modes[mode]); + /* + * This races with request_irq(), set_irq_type(), * and set_irq_wake() ... but those are "rare". */ if (irq > 0 && desc && desc->action) { @@ -1338,39 +1353,6 @@ static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset); } -static void nmk_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, - struct pinctrl_map *map, unsigned num_maps) -{ - int i; - - for (i = 0; i < num_maps; i++) - if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN) - kfree(map[i].data.configs.configs); - kfree(map); -} - -static int nmk_dt_reserve_map(struct pinctrl_map **map, unsigned *reserved_maps, - unsigned *num_maps, unsigned reserve) -{ - unsigned old_num = *reserved_maps; - unsigned new_num = *num_maps + reserve; - struct pinctrl_map *new_map; - - if (old_num >= new_num) - return 0; - - new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); - if (!new_map) - return -ENOMEM; - - memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); - - *map = new_map; - *reserved_maps = new_num; - - return 0; -} - static int nmk_dt_add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, unsigned *num_maps, const char *group, const char *function) @@ -1537,51 +1519,55 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, const char *function = NULL; unsigned long configs = 0; bool has_config = 0; - unsigned reserve = 0; struct property *prop; const char *group, *gpio_name; struct device_node *np_config; ret = of_property_read_string(np, "ste,function", &function); - if (ret >= 0) - reserve = 1; - - has_config = nmk_pinctrl_dt_get_config(np, &configs); - - np_config = of_parse_phandle(np, "ste,config", 0); - if (np_config) - has_config |= nmk_pinctrl_dt_get_config(np_config, &configs); - - ret = of_property_count_strings(np, "ste,pins"); - if (ret < 0) - goto exit; - - if (has_config) - reserve++; - - reserve *= ret; - - ret = nmk_dt_reserve_map(map, reserved_maps, num_maps, reserve); - if (ret < 0) - goto exit; - - of_property_for_each_string(np, "ste,pins", prop, group) { - if (function) { + if (ret >= 0) { + ret = of_property_count_strings(np, "ste,pins"); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_reserve_map(pctldev, map, + reserved_maps, + num_maps, ret); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "ste,pins", prop, group) { ret = nmk_dt_add_map_mux(map, reserved_maps, num_maps, group, function); if (ret < 0) goto exit; } - if (has_config) { + } + + has_config = nmk_pinctrl_dt_get_config(np, &configs); + np_config = of_parse_phandle(np, "ste,config", 0); + if (np_config) + has_config |= nmk_pinctrl_dt_get_config(np_config, &configs); + if (has_config) { + ret = of_property_count_strings(np, "ste,pins"); + if (ret < 0) + goto exit; + ret = pinctrl_utils_reserve_map(pctldev, map, + reserved_maps, + num_maps, ret); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "ste,pins", prop, group) { gpio_name = nmk_find_pin_name(pctldev, group); - ret = nmk_dt_add_map_configs(map, reserved_maps, num_maps, - gpio_name, &configs, 1); + ret = nmk_dt_add_map_configs(map, reserved_maps, + num_maps, + gpio_name, &configs, 1); if (ret < 0) goto exit; } - } + exit: return ret; } @@ -1602,7 +1588,7 @@ static int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, ret = nmk_pinctrl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); if (ret < 0) { - nmk_pinctrl_dt_free_map(pctldev, *map, *num_maps); + pinctrl_utils_dt_free_map(pctldev, *map, *num_maps); return ret; } } @@ -1616,7 +1602,7 @@ static const struct pinctrl_ops nmk_pinctrl_ops = { .get_group_pins = nmk_get_group_pins, .pin_dbg_show = nmk_pin_dbg_show, .dt_node_to_map = nmk_pinctrl_dt_node_to_map, - .dt_free_map = nmk_pinctrl_dt_free_map, + .dt_free_map = pinctrl_utils_dt_free_map, }; static int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) @@ -1647,8 +1633,8 @@ static int nmk_pmx_get_func_groups(struct pinctrl_dev *pctldev, return 0; } -static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, - unsigned group) +static int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function, + unsigned group) { struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); const struct nmk_pingroup *g; @@ -1810,7 +1796,7 @@ static const struct pinmux_ops nmk_pinmux_ops = { .get_functions_count = nmk_pmx_get_funcs_cnt, .get_function_name = nmk_pmx_get_func_name, .get_function_groups = nmk_pmx_get_func_groups, - .enable = nmk_pmx_enable, + .set_mux = nmk_pmx_set, .gpio_request_enable = nmk_gpio_request_enable, .gpio_disable_free = nmk_gpio_disable_free, }; diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c index b092b93c67a..8434439c501 100644 --- a/drivers/pinctrl/pinctrl-adi2.c +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -619,8 +619,8 @@ static struct pinctrl_ops adi_pctrl_ops = { .get_group_pins = adi_get_group_pins, }; -static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned func_id, - unsigned group_id) +static int adi_pinmux_set(struct pinctrl_dev *pctldev, unsigned func_id, + unsigned group_id) { struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); struct gpio_port *port; @@ -698,7 +698,7 @@ static int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev, } static struct pinmux_ops adi_pinmux_ops = { - .enable = adi_pinmux_enable, + .set_mux = adi_pinmux_set, .get_functions_count = adi_pinmux_get_funcs_count, .get_function_name = adi_pinmux_get_func_name, .get_function_groups = adi_pinmux_get_groups, @@ -1041,7 +1041,6 @@ static int adi_gpio_remove(struct platform_device *pdev) u8 offset; list_del(&port->node); - gpiochip_remove_pin_ranges(&port->chip); gpiochip_remove(&port->chip); if (port->pint) { for (offset = 0; offset < port->width; offset++) diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c index 0e4ec91f4d4..1f790a4b83f 100644 --- a/drivers/pinctrl/pinctrl-as3722.c +++ b/drivers/pinctrl/pinctrl-as3722.c @@ -230,7 +230,7 @@ static int as3722_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, return 0; } -static int as3722_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function, +static int as3722_pinctrl_set(struct pinctrl_dev *pctldev, unsigned function, unsigned group) { struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); @@ -327,7 +327,7 @@ static const struct pinmux_ops as3722_pinmux_ops = { .get_functions_count = as3722_pinctrl_get_funcs_count, .get_function_name = as3722_pinctrl_get_func_name, .get_function_groups = as3722_pinctrl_get_func_groups, - .enable = as3722_pinctrl_enable, + .set_mux = as3722_pinctrl_set, .gpio_request_enable = as3722_pinctrl_gpio_request_enable, .gpio_set_direction = as3722_pinctrl_gpio_set_direction, }; diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 60464a2648a..354a81d4092 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -58,11 +58,28 @@ static int gpio_banks; #define DEGLITCH (1 << 2) #define PULL_DOWN (1 << 3) #define DIS_SCHMIT (1 << 4) +#define DRIVE_STRENGTH_SHIFT 5 +#define DRIVE_STRENGTH_MASK 0x3 +#define DRIVE_STRENGTH (DRIVE_STRENGTH_MASK << DRIVE_STRENGTH_SHIFT) #define DEBOUNCE (1 << 16) #define DEBOUNCE_VAL_SHIFT 17 #define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT) /** + * These defines will translated the dt binding settings to our internal + * settings. They are not necessarily the same value as the register setting. + * The actual drive strength current of low, medium and high must be looked up + * from the corresponding device datasheet. This value is different for pins + * that are even in the same banks. It is also dependent on VCC. + * DRIVE_STRENGTH_DEFAULT is just a placeholder to avoid changing the drive + * strength when there is no dt config for it. + */ +#define DRIVE_STRENGTH_DEFAULT (0 << DRIVE_STRENGTH_SHIFT) +#define DRIVE_STRENGTH_LOW (1 << DRIVE_STRENGTH_SHIFT) +#define DRIVE_STRENGTH_MED (2 << DRIVE_STRENGTH_SHIFT) +#define DRIVE_STRENGTH_HI (3 << DRIVE_STRENGTH_SHIFT) + +/** * struct at91_pmx_func - describes AT91 pinmux functions * @name: the name of this specific function * @groups: corresponding pin groups @@ -148,6 +165,9 @@ struct at91_pinctrl_mux_ops { void (*set_pulldown)(void __iomem *pio, unsigned mask, bool is_on); bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin); void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask); + unsigned (*get_drivestrength)(void __iomem *pio, unsigned pin); + void (*set_drivestrength)(void __iomem *pio, unsigned pin, + u32 strength); /* irq */ int (*irq_type)(struct irq_data *d, unsigned type); }; @@ -315,6 +335,30 @@ static unsigned pin_to_mask(unsigned int pin) return 1 << pin; } +static unsigned two_bit_pin_value_shift_amount(unsigned int pin) +{ + /* return the shift value for a pin for "two bit" per pin registers, + * i.e. drive strength */ + return 2*((pin >= MAX_NB_GPIO_PER_BANK/2) + ? pin - MAX_NB_GPIO_PER_BANK/2 : pin); +} + +static unsigned sama5d3_get_drive_register(unsigned int pin) +{ + /* drive strength is split between two registers + * with two bits per pin */ + return (pin >= MAX_NB_GPIO_PER_BANK/2) + ? SAMA5D3_PIO_DRIVER2 : SAMA5D3_PIO_DRIVER1; +} + +static unsigned at91sam9x5_get_drive_register(unsigned int pin) +{ + /* drive strength is split between two registers + * with two bits per pin */ + return (pin >= MAX_NB_GPIO_PER_BANK/2) + ? AT91SAM9X5_PIO_DRIVER2 : AT91SAM9X5_PIO_DRIVER1; +} + static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask) { writel_relaxed(mask, pio + PIO_IDR); @@ -327,6 +371,9 @@ static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin) static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on) { + if (on) + writel_relaxed(mask, pio + PIO_PPDDR); + writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR)); } @@ -455,6 +502,9 @@ static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin) static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on) { + if (is_on) + __raw_writel(mask, pio + PIO_PUDR); + __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR)); } @@ -468,6 +518,79 @@ static bool at91_mux_pio3_get_schmitt_trig(void __iomem *pio, unsigned pin) return (__raw_readl(pio + PIO_SCHMITT) >> pin) & 0x1; } +static inline u32 read_drive_strength(void __iomem *reg, unsigned pin) +{ + unsigned tmp = __raw_readl(reg); + + tmp = tmp >> two_bit_pin_value_shift_amount(pin); + + return tmp & DRIVE_STRENGTH_MASK; +} + +static unsigned at91_mux_sama5d3_get_drivestrength(void __iomem *pio, + unsigned pin) +{ + unsigned tmp = read_drive_strength(pio + + sama5d3_get_drive_register(pin), pin); + + /* SAMA5 strength is 1:1 with our defines, + * except 0 is equivalent to low per datasheet */ + if (!tmp) + tmp = DRIVE_STRENGTH_LOW; + + return tmp; +} + +static unsigned at91_mux_sam9x5_get_drivestrength(void __iomem *pio, + unsigned pin) +{ + unsigned tmp = read_drive_strength(pio + + at91sam9x5_get_drive_register(pin), pin); + + /* strength is inverse in SAM9x5s hardware with the pinctrl defines + * hardware: 0 = hi, 1 = med, 2 = low, 3 = rsvd */ + tmp = DRIVE_STRENGTH_HI - tmp; + + return tmp; +} + +static void set_drive_strength(void __iomem *reg, unsigned pin, u32 strength) +{ + unsigned tmp = __raw_readl(reg); + unsigned shift = two_bit_pin_value_shift_amount(pin); + + tmp &= ~(DRIVE_STRENGTH_MASK << shift); + tmp |= strength << shift; + + __raw_writel(tmp, reg); +} + +static void at91_mux_sama5d3_set_drivestrength(void __iomem *pio, unsigned pin, + u32 setting) +{ + /* do nothing if setting is zero */ + if (!setting) + return; + + /* strength is 1 to 1 with setting for SAMA5 */ + set_drive_strength(pio + sama5d3_get_drive_register(pin), pin, setting); +} + +static void at91_mux_sam9x5_set_drivestrength(void __iomem *pio, unsigned pin, + u32 setting) +{ + /* do nothing if setting is zero */ + if (!setting) + return; + + /* strength is inverse on SAM9x5s with our defines + * 0 = hi, 1 = med, 2 = low, 3 = rsvd */ + setting = DRIVE_STRENGTH_HI - setting; + + set_drive_strength(pio + at91sam9x5_get_drive_register(pin), pin, + setting); +} + static struct at91_pinctrl_mux_ops at91rm9200_ops = { .get_periph = at91_mux_get_periph, .mux_A_periph = at91_mux_set_A_periph, @@ -491,6 +614,27 @@ static struct at91_pinctrl_mux_ops at91sam9x5_ops = { .set_pulldown = at91_mux_pio3_set_pulldown, .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig, .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, + .get_drivestrength = at91_mux_sam9x5_get_drivestrength, + .set_drivestrength = at91_mux_sam9x5_set_drivestrength, + .irq_type = alt_gpio_irq_type, +}; + +static struct at91_pinctrl_mux_ops sama5d3_ops = { + .get_periph = at91_mux_pio3_get_periph, + .mux_A_periph = at91_mux_pio3_set_A_periph, + .mux_B_periph = at91_mux_pio3_set_B_periph, + .mux_C_periph = at91_mux_pio3_set_C_periph, + .mux_D_periph = at91_mux_pio3_set_D_periph, + .get_deglitch = at91_mux_pio3_get_deglitch, + .set_deglitch = at91_mux_pio3_set_deglitch, + .get_debounce = at91_mux_pio3_get_debounce, + .set_debounce = at91_mux_pio3_set_debounce, + .get_pulldown = at91_mux_pio3_get_pulldown, + .set_pulldown = at91_mux_pio3_set_pulldown, + .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig, + .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, + .get_drivestrength = at91_mux_sama5d3_get_drivestrength, + .set_drivestrength = at91_mux_sama5d3_set_drivestrength, .irq_type = alt_gpio_irq_type, }; @@ -554,8 +698,8 @@ static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input) writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER)); } -static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) +static int at91_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) { struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf; @@ -684,7 +828,7 @@ static const struct pinmux_ops at91_pmx_ops = { .get_functions_count = at91_pmx_get_funcs_count, .get_function_name = at91_pmx_get_func_name, .get_function_groups = at91_pmx_get_groups, - .enable = at91_pmx_enable, + .set_mux = at91_pmx_set, .gpio_request_enable = at91_gpio_request_enable, .gpio_disable_free = at91_gpio_disable_free, }; @@ -716,6 +860,9 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev, *config |= PULL_DOWN; if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin)) *config |= DIS_SCHMIT; + if (info->ops->get_drivestrength) + *config |= (info->ops->get_drivestrength(pio, pin) + << DRIVE_STRENGTH_SHIFT); return 0; } @@ -729,6 +876,7 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, void __iomem *pio; int i; unsigned long config; + unsigned pin; for (i = 0; i < num_configs; i++) { config = configs[i]; @@ -737,7 +885,8 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config); pio = pin_to_controller(info, pin_to_bank(pin_id)); - mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK); + pin = pin_id % MAX_NB_GPIO_PER_BANK; + mask = pin_to_mask(pin); if (config & PULL_UP && config & PULL_DOWN) return -EINVAL; @@ -753,6 +902,10 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, info->ops->set_pulldown(pio, mask, config & PULL_DOWN); if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT) info->ops->disable_schmitt_trig(pio, mask); + if (info->ops->set_drivestrength) + info->ops->set_drivestrength(pio, pin, + (config & DRIVE_STRENGTH) + >> DRIVE_STRENGTH_SHIFT); } /* for each config */ @@ -768,6 +921,15 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, } \ } while (0) +#define DBG_SHOW_FLAG_MASKED(mask,flag) do { \ + if ((config & mask) == flag) { \ + if (num_conf) \ + seq_puts(s, "|"); \ + seq_puts(s, #flag); \ + num_conf++; \ + } \ +} while (0) + static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin_id) { @@ -781,6 +943,9 @@ static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev, DBG_SHOW_FLAG(PULL_DOWN); DBG_SHOW_FLAG(DIS_SCHMIT); DBG_SHOW_FLAG(DEGLITCH); + DBG_SHOW_FLAG_MASKED(DRIVE_STRENGTH, DRIVE_STRENGTH_LOW); + DBG_SHOW_FLAG_MASKED(DRIVE_STRENGTH, DRIVE_STRENGTH_MED); + DBG_SHOW_FLAG_MASKED(DRIVE_STRENGTH, DRIVE_STRENGTH_HI); DBG_SHOW_FLAG(DEBOUNCE); if (config & DEBOUNCE) { val = config >> DEBOUNCE_VAL_SHIFT; @@ -945,6 +1110,7 @@ static int at91_pinctrl_parse_functions(struct device_node *np, } static struct of_device_id at91_pinctrl_of_match[] = { + { .compatible = "atmel,sama5d3-pinctrl", .data = &sama5d3_ops }, { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops }, { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops }, { /* sentinel */ } @@ -1445,7 +1611,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) /* now it may re-trigger */ } -static int at91_gpio_of_irq_setup(struct device_node *node, +static int at91_gpio_of_irq_setup(struct platform_device *pdev, struct at91_gpio_chip *at91_gpio) { struct at91_gpio_chip *prev = NULL; @@ -1470,9 +1636,11 @@ static int at91_gpio_of_irq_setup(struct device_node *node, 0, handle_edge_irq, IRQ_TYPE_EDGE_BOTH); - if (ret) - panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n", + if (ret) { + dev_err(&pdev->dev, "at91_gpio.%d: Couldn't add irqchip to gpiochip.\n", at91_gpio->pioc_idx); + return ret; + } /* Setup chained handler */ if (at91_gpio->pioc_idx) @@ -1575,19 +1743,22 @@ static int at91_gpio_probe(struct platform_device *pdev) at91_chip->pioc_virq = irq; at91_chip->pioc_idx = alias_idx; - at91_chip->clock = clk_get(&pdev->dev, NULL); + at91_chip->clock = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(at91_chip->clock)) { dev_err(&pdev->dev, "failed to get clock, ignoring.\n"); + ret = PTR_ERR(at91_chip->clock); goto err; } - if (clk_prepare(at91_chip->clock)) - goto clk_prep_err; + ret = clk_prepare(at91_chip->clock); + if (ret) + goto clk_prepare_err; /* enable PIO controller's clock */ - if (clk_enable(at91_chip->clock)) { + ret = clk_enable(at91_chip->clock); + if (ret) { dev_err(&pdev->dev, "failed to enable clock, ignoring.\n"); - goto clk_err; + goto clk_enable_err; } at91_chip->chip = at91_gpio_template; @@ -1612,7 +1783,7 @@ static int at91_gpio_probe(struct platform_device *pdev) if (!names) { ret = -ENOMEM; - goto clk_err; + goto clk_enable_err; } for (i = 0; i < chip->ngpio; i++) @@ -1630,23 +1801,28 @@ static int at91_gpio_probe(struct platform_device *pdev) ret = gpiochip_add(chip); if (ret) - goto clk_err; + goto gpiochip_add_err; gpio_chips[alias_idx] = at91_chip; gpio_banks = max(gpio_banks, alias_idx + 1); at91_gpio_probe_fixup(); - at91_gpio_of_irq_setup(np, at91_chip); + ret = at91_gpio_of_irq_setup(pdev, at91_chip); + if (ret) + goto irq_setup_err; dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase); return 0; -clk_err: +irq_setup_err: + gpiochip_remove(chip); +gpiochip_add_err: + clk_disable(at91_chip->clock); +clk_enable_err: clk_unprepare(at91_chip->clock); -clk_prep_err: - clk_put(at91_chip->clock); +clk_prepare_err: err: dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx); diff --git a/drivers/pinctrl/pinctrl-bcm281xx.c b/drivers/pinctrl/pinctrl-bcm281xx.c index c5ca9e633ff..a26e0c2ba33 100644 --- a/drivers/pinctrl/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/pinctrl-bcm281xx.c @@ -1055,9 +1055,9 @@ static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, return 0; } -static int bcm281xx_pinmux_enable(struct pinctrl_dev *pctldev, - unsigned function, - unsigned group) +static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); const struct bcm281xx_pin_function *f = &pdata->functions[function]; @@ -1084,7 +1084,7 @@ static struct pinmux_ops bcm281xx_pinctrl_pinmux_ops = { .get_functions_count = bcm281xx_pinctrl_get_fcns_count, .get_function_name = bcm281xx_pinctrl_get_fcn_name, .get_function_groups = bcm281xx_pinctrl_get_fcn_groups, - .enable = bcm281xx_pinmux_enable, + .set_mux = bcm281xx_pinmux_set, }; static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c index 5bcfd7ace0c..eabba02f71f 100644 --- a/drivers/pinctrl/pinctrl-bcm2835.c +++ b/drivers/pinctrl/pinctrl-bcm2835.c @@ -830,7 +830,7 @@ static int bcm2835_pmx_get_function_groups(struct pinctrl_dev *pctldev, return 0; } -static int bcm2835_pmx_enable(struct pinctrl_dev *pctldev, +static int bcm2835_pmx_set(struct pinctrl_dev *pctldev, unsigned func_selector, unsigned group_selector) { @@ -869,7 +869,7 @@ static const struct pinmux_ops bcm2835_pmx_ops = { .get_functions_count = bcm2835_pmx_get_functions_count, .get_function_name = bcm2835_pmx_get_function_name, .get_function_groups = bcm2835_pmx_get_function_groups, - .enable = bcm2835_pmx_enable, + .set_mux = bcm2835_pmx_set, .gpio_disable_free = bcm2835_pmx_gpio_disable_free, .gpio_set_direction = bcm2835_pmx_gpio_set_direction, }; diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c index d22ca252b80..296e5b37f76 100644 --- a/drivers/pinctrl/pinctrl-lantiq.c +++ b/drivers/pinctrl/pinctrl-lantiq.c @@ -257,9 +257,9 @@ static int match_group_mux(const struct ltq_pin_group *grp, return ret; } -static int ltq_pmx_enable(struct pinctrl_dev *pctrldev, - unsigned func, - unsigned group) +static int ltq_pmx_set(struct pinctrl_dev *pctrldev, + unsigned func, + unsigned group) { struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); const struct ltq_pin_group *pin_grp = &info->grps[group]; @@ -316,7 +316,7 @@ static const struct pinmux_ops ltq_pmx_ops = { .get_functions_count = ltq_pmx_func_count, .get_function_name = ltq_pmx_func_name, .get_function_groups = ltq_pmx_get_groups, - .enable = ltq_pmx_enable, + .set_mux = ltq_pmx_set, .gpio_request_enable = ltq_pmx_gpio_request_enable, }; diff --git a/drivers/pinctrl/pinctrl-palmas.c b/drivers/pinctrl/pinctrl-palmas.c index f13d0e78a41..e3079d3d19f 100644 --- a/drivers/pinctrl/pinctrl-palmas.c +++ b/drivers/pinctrl/pinctrl-palmas.c @@ -685,7 +685,8 @@ static int palmas_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, return 0; } -static int palmas_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function, +static int palmas_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned function, unsigned group) { struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev); @@ -742,7 +743,7 @@ static const struct pinmux_ops palmas_pinmux_ops = { .get_functions_count = palmas_pinctrl_get_funcs_count, .get_function_name = palmas_pinctrl_get_func_name, .get_function_groups = palmas_pinctrl_get_func_groups, - .enable = palmas_pinctrl_enable, + .set_mux = palmas_pinctrl_set_mux, }; static int palmas_pinconf_get(struct pinctrl_dev *pctldev, diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 0c372a300cb..016f4578e49 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -816,8 +816,8 @@ static int rockchip_pmx_get_groups(struct pinctrl_dev *pctldev, return 0; } -static int rockchip_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) +static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) { struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); const unsigned int *pins = info->groups[group].pins; @@ -892,7 +892,7 @@ static const struct pinmux_ops rockchip_pmx_ops = { .get_functions_count = rockchip_pmx_get_funcs_count, .get_function_name = rockchip_pmx_get_func_name, .get_function_groups = rockchip_pmx_get_groups, - .enable = rockchip_pmx_enable, + .set_mux = rockchip_pmx_set, .gpio_set_direction = rockchip_pmx_gpio_set_direction, }; diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 95dd9cf55cb..fb94b772ad6 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -447,7 +447,7 @@ static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin, return 0; } -static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, +static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector, unsigned group) { struct pcs_device *pcs; @@ -519,7 +519,7 @@ static const struct pinmux_ops pcs_pinmux_ops = { .get_functions_count = pcs_get_functions_count, .get_function_name = pcs_get_function_name, .get_function_groups = pcs_get_function_groups, - .enable = pcs_enable, + .set_mux = pcs_set_mux, .gpio_request_enable = pcs_request_gpio, }; @@ -1981,6 +1981,18 @@ static const struct pcs_soc_data pinctrl_single_omap_wkup = { .irq_status_mask = (1 << 15), /* OMAP_WAKEUP_EVENT */ }; +static const struct pcs_soc_data pinctrl_single_dra7 = { + .flags = PCS_QUIRK_SHARED_IRQ, + .irq_enable_mask = (1 << 24), /* WAKEUPENABLE */ + .irq_status_mask = (1 << 25), /* WAKEUPEVENT */ +}; + +static const struct pcs_soc_data pinctrl_single_am437x = { + .flags = PCS_QUIRK_SHARED_IRQ, + .irq_enable_mask = (1 << 29), /* OMAP_WAKEUP_EN */ + .irq_status_mask = (1 << 30), /* OMAP_WAKEUP_EVENT */ +}; + static const struct pcs_soc_data pinctrl_single = { }; @@ -1992,6 +2004,8 @@ static struct of_device_id pcs_of_match[] = { { .compatible = "ti,omap3-padconf", .data = &pinctrl_single_omap_wkup }, { .compatible = "ti,omap4-padconf", .data = &pinctrl_single_omap_wkup }, { .compatible = "ti,omap5-padconf", .data = &pinctrl_single_omap_wkup }, + { .compatible = "ti,dra7-padconf", .data = &pinctrl_single_dra7 }, + { .compatible = "ti,am437-padconf", .data = &pinctrl_single_am437x }, { .compatible = "pinctrl-single", .data = &pinctrl_single }, { .compatible = "pinconf-single", .data = &pinconf_single }, { }, diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index 5475374d803..4b1792aad3d 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -914,8 +914,8 @@ static struct st_pio_control *st_get_pio_control( return &bank->pc; } -static int st_pmx_enable(struct pinctrl_dev *pctldev, unsigned fselector, - unsigned group) +static int st_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned fselector, + unsigned group) { struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct st_pinconf *conf = info->groups[group].pin_conf; @@ -951,7 +951,7 @@ static struct pinmux_ops st_pmxops = { .get_functions_count = st_pmx_get_funcs_count, .get_function_name = st_pmx_get_fname, .get_function_groups = st_pmx_get_groups, - .enable = st_pmx_enable, + .set_mux = st_pmx_set_mux, .gpio_set_direction = st_pmx_set_gpio_direction, }; @@ -1517,6 +1517,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info, 0, handle_simple_irq, IRQ_TYPE_LEVEL_LOW); if (err) { + gpiochip_remove(&bank->gpio_chip); dev_info(dev, "could not add irqchip\n"); return err; } diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c index 71c5d4f0c53..3b9bfcf717a 100644 --- a/drivers/pinctrl/pinctrl-tb10x.c +++ b/drivers/pinctrl/pinctrl-tb10x.c @@ -697,7 +697,7 @@ static void tb10x_gpio_disable_free(struct pinctrl_dev *pctl, mutex_unlock(&state->mutex); } -static int tb10x_pctl_enable(struct pinctrl_dev *pctl, +static int tb10x_pctl_set_mux(struct pinctrl_dev *pctl, unsigned func_selector, unsigned group_selector) { struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); @@ -744,7 +744,7 @@ static struct pinmux_ops tb10x_pinmux_ops = { .get_function_groups = tb10x_get_function_groups, .gpio_request_enable = tb10x_gpio_request_enable, .gpio_disable_free = tb10x_gpio_disable_free, - .enable = tb10x_pctl_enable, + .set_mux = tb10x_pctl_set_mux, }; static struct pinctrl_desc tb10x_pindesc = { diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c index e641b4226c4..1631ec94fb0 100644 --- a/drivers/pinctrl/pinctrl-tegra-xusb.c +++ b/drivers/pinctrl/pinctrl-tegra-xusb.c @@ -281,9 +281,9 @@ static int tegra_xusb_padctl_get_function_groups(struct pinctrl_dev *pinctrl, return 0; } -static int tegra_xusb_padctl_pinmux_enable(struct pinctrl_dev *pinctrl, - unsigned int function, - unsigned int group) +static int tegra_xusb_padctl_pinmux_set(struct pinctrl_dev *pinctrl, + unsigned int function, + unsigned int group) { struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); const struct tegra_xusb_padctl_lane *lane; @@ -311,7 +311,7 @@ static const struct pinmux_ops tegra_xusb_padctl_pinmux_ops = { .get_functions_count = tegra_xusb_padctl_get_functions_count, .get_function_name = tegra_xusb_padctl_get_function_name, .get_function_groups = tegra_xusb_padctl_get_function_groups, - .enable = tegra_xusb_padctl_pinmux_enable, + .set_mux = tegra_xusb_padctl_pinmux_set, }; static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl, diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index 150af5503c0..e5949d51bc5 100644 --- a/drivers/pinctrl/pinctrl-tegra.c +++ b/drivers/pinctrl/pinctrl-tegra.c @@ -262,8 +262,9 @@ static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, return 0; } -static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function, - unsigned group) +static int tegra_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct tegra_pingroup *g; @@ -294,7 +295,7 @@ static const struct pinmux_ops tegra_pinmux_ops = { .get_functions_count = tegra_pinctrl_get_funcs_count, .get_function_name = tegra_pinctrl_get_func_name, .get_function_groups = tegra_pinctrl_get_func_groups, - .enable = tegra_pinctrl_enable, + .set_mux = tegra_pinctrl_set_mux, }; static int tegra_pinconf_reg(struct tegra_pmx *pmx, diff --git a/drivers/pinctrl/pinctrl-tegra114.c b/drivers/pinctrl/pinctrl-tegra114.c index 33614baab4c..a3db85b0b75 100644 --- a/drivers/pinctrl/pinctrl-tegra114.c +++ b/drivers/pinctrl/pinctrl-tegra114.c @@ -1850,7 +1850,7 @@ static int tegra114_pinctrl_probe(struct platform_device *pdev) return tegra_pinctrl_probe(pdev, &tegra114_pinctrl); } -static struct of_device_id tegra114_pinctrl_of_match[] = { +static const struct of_device_id tegra114_pinctrl_of_match[] = { { .compatible = "nvidia,tegra114-pinmux", }, { }, }; diff --git a/drivers/pinctrl/pinctrl-tegra124.c b/drivers/pinctrl/pinctrl-tegra124.c index e80797e2001..2f9b75c1496 100644 --- a/drivers/pinctrl/pinctrl-tegra124.c +++ b/drivers/pinctrl/pinctrl-tegra124.c @@ -224,6 +224,16 @@ #define TEGRA_PIN_OWR _PIN(5) #define TEGRA_PIN_CLK_32K_IN _PIN(6) #define TEGRA_PIN_JTAG_RTCK _PIN(7) +#define TEGRA_PIN_DSI_B_CLK_P _PIN(8) +#define TEGRA_PIN_DSI_B_CLK_N _PIN(9) +#define TEGRA_PIN_DSI_B_D0_P _PIN(10) +#define TEGRA_PIN_DSI_B_D0_N _PIN(11) +#define TEGRA_PIN_DSI_B_D1_P _PIN(12) +#define TEGRA_PIN_DSI_B_D1_N _PIN(13) +#define TEGRA_PIN_DSI_B_D2_P _PIN(14) +#define TEGRA_PIN_DSI_B_D2_N _PIN(15) +#define TEGRA_PIN_DSI_B_D3_P _PIN(16) +#define TEGRA_PIN_DSI_B_D3_N _PIN(17) static const struct pinctrl_pin_desc tegra124_pins[] = { PINCTRL_PIN(TEGRA_PIN_CLK_32K_OUT_PA0, "CLK_32K_OUT PA0"), @@ -417,6 +427,16 @@ static const struct pinctrl_pin_desc tegra124_pins[] = { PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"), PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"), PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK, "JTAG_RTCK"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_CLK_P, "DSI_B_CLK_P"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_CLK_N, "DSI_B_CLK_N"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_D0_P, "DSI_B_D0_P"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_D0_N, "DSI_B_D0_N"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_D1_P, "DSI_B_D1_P"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_D1_N, "DSI_B_D1_N"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_D2_P, "DSI_B_D2_P"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_D2_N, "DSI_B_D2_N"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_D3_P, "DSI_B_D3_P"), + PINCTRL_PIN(TEGRA_PIN_DSI_B_D3_N, "DSI_B_D3_N"), }; static const unsigned clk_32k_out_pa0_pins[] = { @@ -1495,6 +1515,19 @@ static const unsigned drive_ao4_pins[] = { TEGRA_PIN_JTAG_RTCK, }; +static const unsigned mipi_pad_ctrl_dsi_b_pins[] = { + TEGRA_PIN_DSI_B_CLK_P, + TEGRA_PIN_DSI_B_CLK_N, + TEGRA_PIN_DSI_B_D0_P, + TEGRA_PIN_DSI_B_D0_N, + TEGRA_PIN_DSI_B_D1_P, + TEGRA_PIN_DSI_B_D1_N, + TEGRA_PIN_DSI_B_D2_P, + TEGRA_PIN_DSI_B_D2_N, + TEGRA_PIN_DSI_B_D3_P, + TEGRA_PIN_DSI_B_D3_N, +}; + enum tegra_mux { TEGRA_MUX_BLINK, TEGRA_MUX_CCLA, @@ -1580,6 +1613,8 @@ enum tegra_mux { TEGRA_MUX_VI_ALT3, TEGRA_MUX_VIMCLK2, TEGRA_MUX_VIMCLK2_ALT, + TEGRA_MUX_CSI, + TEGRA_MUX_DSI_B, }; #define FUNCTION(fname) \ @@ -1672,10 +1707,13 @@ static struct tegra_function tegra124_functions[] = { FUNCTION(vi_alt3), FUNCTION(vimclk2), FUNCTION(vimclk2_alt), + FUNCTION(csi), + FUNCTION(dsi_b), }; #define DRV_PINGROUP_REG_A 0x868 /* bank 0 */ #define PINGROUP_REG_A 0x3000 /* bank 1 */ +#define MIPI_PAD_CTRL_PINGROUP_REG_A 0x820 /* bank 2 */ #define PINGROUP_REG(r) ((r) - PINGROUP_REG_A) @@ -1744,6 +1782,32 @@ static struct tegra_function tegra124_functions[] = { .drvtype_bit = PINGROUP_BIT_##drvtype(6), \ } +#define MIPI_PAD_CTRL_PINGROUP_REG_Y(r) ((r) - MIPI_PAD_CTRL_PINGROUP_REG_A) + +#define MIPI_PAD_CTRL_PINGROUP(pg_name, r, b, f0, f1) \ + { \ + .name = "mipi_pad_ctrl_" #pg_name, \ + .pins = mipi_pad_ctrl_##pg_name##_pins, \ + .npins = ARRAY_SIZE(mipi_pad_ctrl_##pg_name##_pins), \ + .funcs = { \ + TEGRA_MUX_ ## f0, \ + TEGRA_MUX_ ## f1, \ + TEGRA_MUX_RSVD3, \ + TEGRA_MUX_RSVD4, \ + }, \ + .mux_reg = MIPI_PAD_CTRL_PINGROUP_REG_Y(r), \ + .mux_bank = 2, \ + .mux_bit = b, \ + .pupd_reg = -1, \ + .tri_reg = -1, \ + .einput_bit = -1, \ + .odrain_bit = -1, \ + .lock_bit = -1, \ + .ioreset_bit = -1, \ + .rcv_sel_bit = -1, \ + .drv_reg = -1, \ + } + static const struct tegra_pingroup tegra124_groups[] = { /* pg_name, f0, f1, f2, f3, r, od, ior, rcv_sel */ PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, 0x3000, N, N, N), @@ -1979,6 +2043,9 @@ static const struct tegra_pingroup tegra124_groups[] = { DRV_PINGROUP(hv0, 0x9b4, 2, 3, 4, 12, 5, -1, -1, 28, 2, -1, -1, N), DRV_PINGROUP(sdio4, 0x9c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), DRV_PINGROUP(ao4, 0x9c8, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), + + /* pg_name, r b f0, f1 */ + MIPI_PAD_CTRL_PINGROUP(dsi_b, 0x820, 1, CSI, DSI_B) }; static const struct tegra_pinctrl_soc_data tegra124_pinctrl = { @@ -1996,7 +2063,7 @@ static int tegra124_pinctrl_probe(struct platform_device *pdev) return tegra_pinctrl_probe(pdev, &tegra124_pinctrl); } -static struct of_device_id tegra124_pinctrl_of_match[] = { +static const struct of_device_id tegra124_pinctrl_of_match[] = { { .compatible = "nvidia,tegra124-pinmux", }, { }, }; diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c index 7563ebc9c79..c9805d2e71b 100644 --- a/drivers/pinctrl/pinctrl-tegra20.c +++ b/drivers/pinctrl/pinctrl-tegra20.c @@ -2228,7 +2228,7 @@ static int tegra20_pinctrl_probe(struct platform_device *pdev) return tegra_pinctrl_probe(pdev, &tegra20_pinctrl); } -static struct of_device_id tegra20_pinctrl_of_match[] = { +static const struct of_device_id tegra20_pinctrl_of_match[] = { { .compatible = "nvidia,tegra20-pinmux", }, { }, }; diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c index fe2d2cf78ad..e7b72e91655 100644 --- a/drivers/pinctrl/pinctrl-tegra30.c +++ b/drivers/pinctrl/pinctrl-tegra30.c @@ -2484,7 +2484,7 @@ static int tegra30_pinctrl_probe(struct platform_device *pdev) return tegra_pinctrl_probe(pdev, &tegra30_pinctrl); } -static struct of_device_id tegra30_pinctrl_of_match[] = { +static const struct of_device_id tegra30_pinctrl_of_match[] = { { .compatible = "nvidia,tegra30-pinmux", }, { }, }; diff --git a/drivers/pinctrl/pinctrl-tz1090-pdc.c b/drivers/pinctrl/pinctrl-tz1090-pdc.c index 41e81a35cab..3bb6a3b7886 100644 --- a/drivers/pinctrl/pinctrl-tz1090-pdc.c +++ b/drivers/pinctrl/pinctrl-tz1090-pdc.c @@ -547,8 +547,9 @@ static void tz1090_pdc_pinctrl_mux(struct tz1090_pdc_pmx *pmx, __global_unlock2(flags); } -static int tz1090_pdc_pinctrl_enable(struct pinctrl_dev *pctldev, - unsigned int function, unsigned int group) +static int tz1090_pdc_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, + unsigned int group) { struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct tz1090_pdc_pingroup *grp = &tz1090_pdc_groups[group]; @@ -634,7 +635,7 @@ static struct pinmux_ops tz1090_pdc_pinmux_ops = { .get_functions_count = tz1090_pdc_pinctrl_get_funcs_count, .get_function_name = tz1090_pdc_pinctrl_get_func_name, .get_function_groups = tz1090_pdc_pinctrl_get_func_groups, - .enable = tz1090_pdc_pinctrl_enable, + .set_mux = tz1090_pdc_pinctrl_set_mux, .gpio_request_enable = tz1090_pdc_pinctrl_gpio_request_enable, .gpio_disable_free = tz1090_pdc_pinctrl_gpio_disable_free, }; diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c index 24082216842..48d36413b99 100644 --- a/drivers/pinctrl/pinctrl-tz1090.c +++ b/drivers/pinctrl/pinctrl-tz1090.c @@ -1415,8 +1415,8 @@ found_mux: * the effect is the same as enabling the function on each individual pin in the * group. */ -static int tz1090_pinctrl_enable(struct pinctrl_dev *pctldev, - unsigned int function, unsigned int group) +static int tz1090_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) { struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct tz1090_pingroup *grp; @@ -1517,7 +1517,7 @@ static struct pinmux_ops tz1090_pinmux_ops = { .get_functions_count = tz1090_pinctrl_get_funcs_count, .get_function_name = tz1090_pinctrl_get_func_name, .get_function_groups = tz1090_pinctrl_get_func_groups, - .enable = tz1090_pinctrl_enable, + .set_mux = tz1090_pinctrl_set_mux, .gpio_request_enable = tz1090_pinctrl_gpio_request_enable, .gpio_disable_free = tz1090_pinctrl_gpio_disable_free, }; diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 0959bb36450..e9c7113d81f 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -955,8 +955,8 @@ static void u300_pmx_endisable(struct u300_pmx *upmx, unsigned selector, } } -static int u300_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) +static int u300_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) { struct u300_pmx *upmx; @@ -994,7 +994,7 @@ static const struct pinmux_ops u300_pmx_ops = { .get_functions_count = u300_pmx_get_funcs_count, .get_function_name = u300_pmx_get_func_name, .get_function_groups = u300_pmx_get_groups, - .enable = u300_pmx_enable, + .set_mux = u300_pmx_set_mux, }; static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c index e66f4cae763..37040ab4289 100644 --- a/drivers/pinctrl/pinctrl-xway.c +++ b/drivers/pinctrl/pinctrl-xway.c @@ -801,6 +801,7 @@ static int pinmux_xway_probe(struct platform_device *pdev) of_gpiochip_add(&xway_chip); ret = gpiochip_add(&xway_chip); if (ret) { + of_gpiochip_remove(&xway_chip); dev_err(&pdev->dev, "Failed to register gpio chip\n"); return ret; } @@ -822,6 +823,7 @@ static int pinmux_xway_probe(struct platform_device *pdev) /* register with the generic lantiq layer */ ret = ltq_pinctrl_register(pdev, &xway_info); if (ret) { + gpiochip_remove(&xway_chip); dev_err(&pdev->dev, "Failed to register pinctrl driver\n"); return ret; } diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index c055daf9a80..b874458dcb8 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -41,7 +41,7 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev) !ops->get_functions_count || !ops->get_function_name || !ops->get_function_groups || - !ops->enable) { + !ops->set_mux) { dev_err(pctldev->dev, "pinmux ops lacks necessary functions\n"); return -EINVAL; } @@ -445,15 +445,15 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting) desc->mux_setting = &(setting->data.mux); } - ret = ops->enable(pctldev, setting->data.mux.func, - setting->data.mux.group); + ret = ops->set_mux(pctldev, setting->data.mux.func, + setting->data.mux.group); if (ret) - goto err_enable; + goto err_set_mux; return 0; -err_enable: +err_set_mux: for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc) diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index d160a710d70..81275af9638 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -15,6 +15,14 @@ config PINCTRL_APQ8064 This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm TLMM block found in the Qualcomm APQ8064 platform. +config PINCTRL_APQ8084 + tristate "Qualcomm APQ8084 pin controller driver" + depends on GPIOLIB && OF + select PINCTRL_MSM + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm TLMM block found in the Qualcomm APQ8084 platform. + config PINCTRL_IPQ8064 tristate "Qualcomm IPQ8064 pin controller driver" depends on GPIOLIB && OF diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 2a02602d715..ba8519fcd8d 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -1,6 +1,7 @@ # Qualcomm pin control drivers obj-$(CONFIG_PINCTRL_MSM) += pinctrl-msm.o obj-$(CONFIG_PINCTRL_APQ8064) += pinctrl-apq8064.o +obj-$(CONFIG_PINCTRL_APQ8084) += pinctrl-apq8084.o obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o diff --git a/drivers/pinctrl/qcom/pinctrl-apq8064.c b/drivers/pinctrl/qcom/pinctrl-apq8064.c index feb6f152f9b..c832d7d6b91 100644 --- a/drivers/pinctrl/qcom/pinctrl-apq8064.c +++ b/drivers/pinctrl/qcom/pinctrl-apq8064.c @@ -258,6 +258,7 @@ static const unsigned int sdc3_data_pins[] = { 95 }; .intr_status_bit = 0, \ .intr_ack_high = 1, \ .intr_target_bit = 0, \ + .intr_target_kpss_val = 4, \ .intr_raw_status_bit = 3, \ .intr_polarity_bit = 1, \ .intr_detection_bit = 2, \ @@ -283,6 +284,7 @@ static const unsigned int sdc3_data_pins[] = { 95 }; .intr_enable_bit = -1, \ .intr_status_bit = -1, \ .intr_target_bit = -1, \ + .intr_target_kpss_val = -1, \ .intr_raw_status_bit = -1, \ .intr_polarity_bit = -1, \ .intr_detection_bit = -1, \ @@ -324,6 +326,7 @@ enum apq8064_functions { APQ_MUX_tsif1, APQ_MUX_tsif2, APQ_MUX_usb2_hsic, + APQ_MUX_ps_hold, APQ_MUX_NA, }; @@ -351,6 +354,9 @@ static const char * const gpio_groups[] = { "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89" }; +static const char * const ps_hold_groups[] = { + "gpio78" +}; static const char * const gsbi1_groups[] = { "gpio18", "gpio19", "gpio20", "gpio21" }; @@ -477,6 +483,7 @@ static const struct msm_function apq8064_functions[] = { FUNCTION(tsif1), FUNCTION(tsif2), FUNCTION(usb2_hsic), + FUNCTION(ps_hold), }; static const struct msm_pingroup apq8064_groups[] = { @@ -558,7 +565,7 @@ static const struct msm_pingroup apq8064_groups[] = { PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(76, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(77, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(78, ps_hold, NA, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(79, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(81, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), diff --git a/drivers/pinctrl/qcom/pinctrl-apq8084.c b/drivers/pinctrl/qcom/pinctrl-apq8084.c new file mode 100644 index 00000000000..138cbf6134a --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-apq8084.c @@ -0,0 +1,1245 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-msm.h" + +static const struct pinctrl_pin_desc apq8084_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "GPIO_133"), + PINCTRL_PIN(134, "GPIO_134"), + PINCTRL_PIN(135, "GPIO_135"), + PINCTRL_PIN(136, "GPIO_136"), + PINCTRL_PIN(137, "GPIO_137"), + PINCTRL_PIN(138, "GPIO_138"), + PINCTRL_PIN(139, "GPIO_139"), + PINCTRL_PIN(140, "GPIO_140"), + PINCTRL_PIN(141, "GPIO_141"), + PINCTRL_PIN(142, "GPIO_142"), + PINCTRL_PIN(143, "GPIO_143"), + PINCTRL_PIN(144, "GPIO_144"), + PINCTRL_PIN(145, "GPIO_145"), + PINCTRL_PIN(146, "GPIO_146"), + + PINCTRL_PIN(147, "SDC1_CLK"), + PINCTRL_PIN(148, "SDC1_CMD"), + PINCTRL_PIN(149, "SDC1_DATA"), + PINCTRL_PIN(150, "SDC2_CLK"), + PINCTRL_PIN(151, "SDC2_CMD"), + PINCTRL_PIN(152, "SDC2_DATA"), +}; + +#define DECLARE_APQ_GPIO_PINS(pin) static const unsigned int gpio##pin##_pins[] = { pin } + +DECLARE_APQ_GPIO_PINS(0); +DECLARE_APQ_GPIO_PINS(1); +DECLARE_APQ_GPIO_PINS(2); +DECLARE_APQ_GPIO_PINS(3); +DECLARE_APQ_GPIO_PINS(4); +DECLARE_APQ_GPIO_PINS(5); +DECLARE_APQ_GPIO_PINS(6); +DECLARE_APQ_GPIO_PINS(7); +DECLARE_APQ_GPIO_PINS(8); +DECLARE_APQ_GPIO_PINS(9); +DECLARE_APQ_GPIO_PINS(10); +DECLARE_APQ_GPIO_PINS(11); +DECLARE_APQ_GPIO_PINS(12); +DECLARE_APQ_GPIO_PINS(13); +DECLARE_APQ_GPIO_PINS(14); +DECLARE_APQ_GPIO_PINS(15); +DECLARE_APQ_GPIO_PINS(16); +DECLARE_APQ_GPIO_PINS(17); +DECLARE_APQ_GPIO_PINS(18); +DECLARE_APQ_GPIO_PINS(19); +DECLARE_APQ_GPIO_PINS(20); +DECLARE_APQ_GPIO_PINS(21); +DECLARE_APQ_GPIO_PINS(22); +DECLARE_APQ_GPIO_PINS(23); +DECLARE_APQ_GPIO_PINS(24); +DECLARE_APQ_GPIO_PINS(25); +DECLARE_APQ_GPIO_PINS(26); +DECLARE_APQ_GPIO_PINS(27); +DECLARE_APQ_GPIO_PINS(28); +DECLARE_APQ_GPIO_PINS(29); +DECLARE_APQ_GPIO_PINS(30); +DECLARE_APQ_GPIO_PINS(31); +DECLARE_APQ_GPIO_PINS(32); +DECLARE_APQ_GPIO_PINS(33); +DECLARE_APQ_GPIO_PINS(34); +DECLARE_APQ_GPIO_PINS(35); +DECLARE_APQ_GPIO_PINS(36); +DECLARE_APQ_GPIO_PINS(37); +DECLARE_APQ_GPIO_PINS(38); +DECLARE_APQ_GPIO_PINS(39); +DECLARE_APQ_GPIO_PINS(40); +DECLARE_APQ_GPIO_PINS(41); +DECLARE_APQ_GPIO_PINS(42); +DECLARE_APQ_GPIO_PINS(43); +DECLARE_APQ_GPIO_PINS(44); +DECLARE_APQ_GPIO_PINS(45); +DECLARE_APQ_GPIO_PINS(46); +DECLARE_APQ_GPIO_PINS(47); +DECLARE_APQ_GPIO_PINS(48); +DECLARE_APQ_GPIO_PINS(49); +DECLARE_APQ_GPIO_PINS(50); +DECLARE_APQ_GPIO_PINS(51); +DECLARE_APQ_GPIO_PINS(52); +DECLARE_APQ_GPIO_PINS(53); +DECLARE_APQ_GPIO_PINS(54); +DECLARE_APQ_GPIO_PINS(55); +DECLARE_APQ_GPIO_PINS(56); +DECLARE_APQ_GPIO_PINS(57); +DECLARE_APQ_GPIO_PINS(58); +DECLARE_APQ_GPIO_PINS(59); +DECLARE_APQ_GPIO_PINS(60); +DECLARE_APQ_GPIO_PINS(61); +DECLARE_APQ_GPIO_PINS(62); +DECLARE_APQ_GPIO_PINS(63); +DECLARE_APQ_GPIO_PINS(64); +DECLARE_APQ_GPIO_PINS(65); +DECLARE_APQ_GPIO_PINS(66); +DECLARE_APQ_GPIO_PINS(67); +DECLARE_APQ_GPIO_PINS(68); +DECLARE_APQ_GPIO_PINS(69); +DECLARE_APQ_GPIO_PINS(70); +DECLARE_APQ_GPIO_PINS(71); +DECLARE_APQ_GPIO_PINS(72); +DECLARE_APQ_GPIO_PINS(73); +DECLARE_APQ_GPIO_PINS(74); +DECLARE_APQ_GPIO_PINS(75); +DECLARE_APQ_GPIO_PINS(76); +DECLARE_APQ_GPIO_PINS(77); +DECLARE_APQ_GPIO_PINS(78); +DECLARE_APQ_GPIO_PINS(79); +DECLARE_APQ_GPIO_PINS(80); +DECLARE_APQ_GPIO_PINS(81); +DECLARE_APQ_GPIO_PINS(82); +DECLARE_APQ_GPIO_PINS(83); +DECLARE_APQ_GPIO_PINS(84); +DECLARE_APQ_GPIO_PINS(85); +DECLARE_APQ_GPIO_PINS(86); +DECLARE_APQ_GPIO_PINS(87); +DECLARE_APQ_GPIO_PINS(88); +DECLARE_APQ_GPIO_PINS(89); +DECLARE_APQ_GPIO_PINS(90); +DECLARE_APQ_GPIO_PINS(91); +DECLARE_APQ_GPIO_PINS(92); +DECLARE_APQ_GPIO_PINS(93); +DECLARE_APQ_GPIO_PINS(94); +DECLARE_APQ_GPIO_PINS(95); +DECLARE_APQ_GPIO_PINS(96); +DECLARE_APQ_GPIO_PINS(97); +DECLARE_APQ_GPIO_PINS(98); +DECLARE_APQ_GPIO_PINS(99); +DECLARE_APQ_GPIO_PINS(100); +DECLARE_APQ_GPIO_PINS(101); +DECLARE_APQ_GPIO_PINS(102); +DECLARE_APQ_GPIO_PINS(103); +DECLARE_APQ_GPIO_PINS(104); +DECLARE_APQ_GPIO_PINS(105); +DECLARE_APQ_GPIO_PINS(106); +DECLARE_APQ_GPIO_PINS(107); +DECLARE_APQ_GPIO_PINS(108); +DECLARE_APQ_GPIO_PINS(109); +DECLARE_APQ_GPIO_PINS(110); +DECLARE_APQ_GPIO_PINS(111); +DECLARE_APQ_GPIO_PINS(112); +DECLARE_APQ_GPIO_PINS(113); +DECLARE_APQ_GPIO_PINS(114); +DECLARE_APQ_GPIO_PINS(115); +DECLARE_APQ_GPIO_PINS(116); +DECLARE_APQ_GPIO_PINS(117); +DECLARE_APQ_GPIO_PINS(118); +DECLARE_APQ_GPIO_PINS(119); +DECLARE_APQ_GPIO_PINS(120); +DECLARE_APQ_GPIO_PINS(121); +DECLARE_APQ_GPIO_PINS(122); +DECLARE_APQ_GPIO_PINS(123); +DECLARE_APQ_GPIO_PINS(124); +DECLARE_APQ_GPIO_PINS(125); +DECLARE_APQ_GPIO_PINS(126); +DECLARE_APQ_GPIO_PINS(127); +DECLARE_APQ_GPIO_PINS(128); +DECLARE_APQ_GPIO_PINS(129); +DECLARE_APQ_GPIO_PINS(130); +DECLARE_APQ_GPIO_PINS(131); +DECLARE_APQ_GPIO_PINS(132); +DECLARE_APQ_GPIO_PINS(133); +DECLARE_APQ_GPIO_PINS(134); +DECLARE_APQ_GPIO_PINS(135); +DECLARE_APQ_GPIO_PINS(136); +DECLARE_APQ_GPIO_PINS(137); +DECLARE_APQ_GPIO_PINS(138); +DECLARE_APQ_GPIO_PINS(139); +DECLARE_APQ_GPIO_PINS(140); +DECLARE_APQ_GPIO_PINS(141); +DECLARE_APQ_GPIO_PINS(142); +DECLARE_APQ_GPIO_PINS(143); +DECLARE_APQ_GPIO_PINS(144); +DECLARE_APQ_GPIO_PINS(145); +DECLARE_APQ_GPIO_PINS(146); + +static const unsigned int sdc1_clk_pins[] = { 147 }; +static const unsigned int sdc1_cmd_pins[] = { 148 }; +static const unsigned int sdc1_data_pins[] = { 149 }; +static const unsigned int sdc2_clk_pins[] = { 150 }; +static const unsigned int sdc2_cmd_pins[] = { 151 }; +static const unsigned int sdc2_data_pins[] = { 152 }; + +#define FUNCTION(fname) \ + [APQ_MUX_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + APQ_MUX_gpio, \ + APQ_MUX_##f1, \ + APQ_MUX_##f2, \ + APQ_MUX_##f3, \ + APQ_MUX_##f4, \ + APQ_MUX_##f5, \ + APQ_MUX_##f6, \ + APQ_MUX_##f7 \ + }, \ + .nfuncs = 8, \ + .ctl_reg = 0x1000 + 0x10 * id, \ + .io_reg = 0x1004 + 0x10 * id, \ + .intr_cfg_reg = 0x1008 + 0x10 * id, \ + .intr_status_reg = 0x100c + 0x10 * id, \ + .intr_target_reg = 0x1008 + 0x10 * id, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_ack_high = 0, \ + .intr_target_bit = 5, \ + .intr_target_kpss_val = 3, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_target_kpss_val = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +enum apq8084_functions { + APQ_MUX_adsp_ext, + APQ_MUX_audio_ref, + APQ_MUX_blsp_i2c1, + APQ_MUX_blsp_i2c2, + APQ_MUX_blsp_i2c3, + APQ_MUX_blsp_i2c4, + APQ_MUX_blsp_i2c5, + APQ_MUX_blsp_i2c6, + APQ_MUX_blsp_i2c7, + APQ_MUX_blsp_i2c8, + APQ_MUX_blsp_i2c9, + APQ_MUX_blsp_i2c10, + APQ_MUX_blsp_i2c11, + APQ_MUX_blsp_i2c12, + APQ_MUX_blsp_spi1, + APQ_MUX_blsp_spi1_cs1, + APQ_MUX_blsp_spi1_cs2, + APQ_MUX_blsp_spi1_cs3, + APQ_MUX_blsp_spi2, + APQ_MUX_blsp_spi3, + APQ_MUX_blsp_spi3_cs1, + APQ_MUX_blsp_spi3_cs2, + APQ_MUX_blsp_spi3_cs3, + APQ_MUX_blsp_spi4, + APQ_MUX_blsp_spi5, + APQ_MUX_blsp_spi6, + APQ_MUX_blsp_spi7, + APQ_MUX_blsp_spi8, + APQ_MUX_blsp_spi9, + APQ_MUX_blsp_spi10, + APQ_MUX_blsp_spi10_cs1, + APQ_MUX_blsp_spi10_cs2, + APQ_MUX_blsp_spi10_cs3, + APQ_MUX_blsp_spi11, + APQ_MUX_blsp_spi12, + APQ_MUX_blsp_uart1, + APQ_MUX_blsp_uart2, + APQ_MUX_blsp_uart3, + APQ_MUX_blsp_uart4, + APQ_MUX_blsp_uart5, + APQ_MUX_blsp_uart6, + APQ_MUX_blsp_uart7, + APQ_MUX_blsp_uart8, + APQ_MUX_blsp_uart9, + APQ_MUX_blsp_uart10, + APQ_MUX_blsp_uart11, + APQ_MUX_blsp_uart12, + APQ_MUX_blsp_uim1, + APQ_MUX_blsp_uim2, + APQ_MUX_blsp_uim3, + APQ_MUX_blsp_uim4, + APQ_MUX_blsp_uim5, + APQ_MUX_blsp_uim6, + APQ_MUX_blsp_uim7, + APQ_MUX_blsp_uim8, + APQ_MUX_blsp_uim9, + APQ_MUX_blsp_uim10, + APQ_MUX_blsp_uim11, + APQ_MUX_blsp_uim12, + APQ_MUX_cam_mclk0, + APQ_MUX_cam_mclk1, + APQ_MUX_cam_mclk2, + APQ_MUX_cam_mclk3, + APQ_MUX_cci_async, + APQ_MUX_cci_async_in0, + APQ_MUX_cci_i2c0, + APQ_MUX_cci_i2c1, + APQ_MUX_cci_timer0, + APQ_MUX_cci_timer1, + APQ_MUX_cci_timer2, + APQ_MUX_cci_timer3, + APQ_MUX_cci_timer4, + APQ_MUX_edp_hpd, + APQ_MUX_gcc_gp1, + APQ_MUX_gcc_gp2, + APQ_MUX_gcc_gp3, + APQ_MUX_gcc_obt, + APQ_MUX_gcc_vtt, + APQ_MUX_gp_mn, + APQ_MUX_gp_pdm0, + APQ_MUX_gp_pdm1, + APQ_MUX_gp_pdm2, + APQ_MUX_gp0_clk, + APQ_MUX_gp1_clk, + APQ_MUX_gpio, + APQ_MUX_hdmi_cec, + APQ_MUX_hdmi_ddc, + APQ_MUX_hdmi_dtest, + APQ_MUX_hdmi_hpd, + APQ_MUX_hdmi_rcv, + APQ_MUX_hsic, + APQ_MUX_ldo_en, + APQ_MUX_ldo_update, + APQ_MUX_mdp_vsync, + APQ_MUX_pci_e0, + APQ_MUX_pci_e0_n, + APQ_MUX_pci_e0_rst, + APQ_MUX_pci_e1, + APQ_MUX_pci_e1_rst, + APQ_MUX_pci_e1_rst_n, + APQ_MUX_pci_e1_clkreq_n, + APQ_MUX_pri_mi2s, + APQ_MUX_qua_mi2s, + APQ_MUX_sata_act, + APQ_MUX_sata_devsleep, + APQ_MUX_sata_devsleep_n, + APQ_MUX_sd_write, + APQ_MUX_sdc_emmc_mode, + APQ_MUX_sdc3, + APQ_MUX_sdc4, + APQ_MUX_sec_mi2s, + APQ_MUX_slimbus, + APQ_MUX_spdif_tx, + APQ_MUX_spkr_i2s, + APQ_MUX_spkr_i2s_ws, + APQ_MUX_spss_geni, + APQ_MUX_ter_mi2s, + APQ_MUX_tsif1, + APQ_MUX_tsif2, + APQ_MUX_uim, + APQ_MUX_uim_batt_alarm, + APQ_MUX_NA, +}; + +static const char * const gpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", + "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", + "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", + "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", + "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", + "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", + "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", + "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", + "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", + "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", + "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", + "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116", + "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122", + "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128", + "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134", + "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140", + "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146" +}; + +static const char * const adsp_ext_groups[] = { + "gpio34" +}; +static const char * const audio_ref_groups[] = { + "gpio100" +}; +static const char * const blsp_i2c1_groups[] = { + "gpio2", "gpio3" +}; +static const char * const blsp_i2c2_groups[] = { + "gpio6", "gpio7" +}; +static const char * const blsp_i2c3_groups[] = { + "gpio10", "gpio11" +}; +static const char * const blsp_i2c4_groups[] = { + "gpio29", "gpio30" +}; +static const char * const blsp_i2c5_groups[] = { + "gpio41", "gpio42" +}; +static const char * const blsp_i2c6_groups[] = { + "gpio45", "gpio46" +}; +static const char * const blsp_i2c7_groups[] = { + "gpio132", "gpio133" +}; +static const char * const blsp_i2c8_groups[] = { + "gpio53", "gpio54" +}; +static const char * const blsp_i2c9_groups[] = { + "gpio57", "gpio58" +}; +static const char * const blsp_i2c10_groups[] = { + "gpio61", "gpio62" +}; +static const char * const blsp_i2c11_groups[] = { + "gpio65", "gpio66" +}; +static const char * const blsp_i2c12_groups[] = { + "gpio49", "gpio50" +}; +static const char * const blsp_spi1_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3" +}; +static const char * const blsp_spi2_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7" +}; +static const char * const blsp_spi3_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11" +}; +static const char * const blsp_spi4_groups[] = { + "gpio27", "gpio28", "gpio29", "gpio30" +}; +static const char * const blsp_spi5_groups[] = { + "gpio39", "gpio40", "gpio41", "gpio42" +}; +static const char * const blsp_spi6_groups[] = { + "gpio43", "gpio44", "gpio45", "gpio46" +}; +static const char * const blsp_spi7_groups[] = { + "gpio130", "gpio131", "gpio132", "gpio133" +}; +static const char * const blsp_spi8_groups[] = { + "gpio51", "gpio52", "gpio53", "gpio54" +}; +static const char * const blsp_spi9_groups[] = { + "gpio55", "gpio56", "gpio57", "gpio58" +}; +static const char * const blsp_spi10_groups[] = { + "gpio59", "gpio60", "gpio61", "gpio62" +}; +static const char * const blsp_spi11_groups[] = { + "gpio63", "gpio64", "gpio65", "gpio66" +}; +static const char * const blsp_spi12_groups[] = { + "gpio47", "gpio48", "gpio49", "gpio50" +}; +static const char * const blsp_uart1_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3" +}; +static const char * const blsp_uart2_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7" +}; +static const char * const blsp_uart3_groups[] = { + "gpio8" +}; +static const char * const blsp_uart4_groups[] = { + "gpio27", "gpio28", "gpio29", "gpio30" +}; +static const char * const blsp_uart5_groups[] = { + "gpio39", "gpio40", "gpio41", "gpio42" +}; +static const char * const blsp_uart6_groups[] = { + "gpio43", "gpio44", "gpio45", "gpio46" +}; +static const char * const blsp_uart7_groups[] = { + "gpio130", "gpio131", "gpio132", "gpio133" +}; +static const char * const blsp_uart8_groups[] = { + "gpio51", "gpio52", "gpio53", "gpio54" +}; +static const char * const blsp_uart9_groups[] = { + "gpio55", "gpio56", "gpio57", "gpio58" +}; +static const char * const blsp_uart10_groups[] = { + "gpio59", "gpio60", "gpio61", "gpio62" +}; +static const char * const blsp_uart11_groups[] = { + "gpio63", "gpio64", "gpio65", "gpio66" +}; +static const char * const blsp_uart12_groups[] = { + "gpio47", "gpio48", "gpio49", "gpio50" +}; +static const char * const blsp_uim1_groups[] = { + "gpio0", "gpio1" +}; +static const char * const blsp_uim2_groups[] = { + "gpio4", "gpio5" +}; +static const char * const blsp_uim3_groups[] = { + "gpio8", "gpio9" +}; +static const char * const blsp_uim4_groups[] = { + "gpio27", "gpio28" +}; +static const char * const blsp_uim5_groups[] = { + "gpio39", "gpio40" +}; +static const char * const blsp_uim6_groups[] = { + "gpio43", "gpio44" +}; +static const char * const blsp_uim7_groups[] = { + "gpio130", "gpio131" +}; +static const char * const blsp_uim8_groups[] = { + "gpio51", "gpio52" +}; +static const char * const blsp_uim9_groups[] = { + "gpio55", "gpio56" +}; +static const char * const blsp_uim10_groups[] = { + "gpio59", "gpio60" +}; +static const char * const blsp_uim11_groups[] = { + "gpio63", "gpio64" +}; +static const char * const blsp_uim12_groups[] = { + "gpio47", "gpio48" +}; +static const char * const blsp_spi1_cs1_groups[] = { + "gpio116" +}; +static const char * const blsp_spi1_cs2_groups[] = { + "gpio117" +}; +static const char * const blsp_spi1_cs3_groups[] = { + "gpio118" +}; +static const char * const blsp_spi3_cs1_groups[] = { + "gpio67" +}; +static const char * const blsp_spi3_cs2_groups[] = { + "gpio71" +}; +static const char * const blsp_spi3_cs3_groups[] = { + "gpio72" +}; +static const char * const blsp_spi10_cs1_groups[] = { + "gpio106" +}; +static const char * const blsp_spi10_cs2_groups[] = { + "gpio111" +}; +static const char * const blsp_spi10_cs3_groups[] = { + "gpio128" +}; +static const char * const cam_mclk0_groups[] = { + "gpio15" +}; +static const char * const cam_mclk1_groups[] = { + "gpio16" +}; +static const char * const cam_mclk2_groups[] = { + "gpio17" +}; +static const char * const cam_mclk3_groups[] = { + "gpio18" +}; +static const char * const cci_async_groups[] = { + "gpio26", "gpio119" +}; +static const char * const cci_async_in0_groups[] = { + "gpio120" +}; +static const char * const cci_i2c0_groups[] = { + "gpio19", "gpio20" +}; +static const char * const cci_i2c1_groups[] = { + "gpio21", "gpio22" +}; +static const char * const cci_timer0_groups[] = { + "gpio23" +}; +static const char * const cci_timer1_groups[] = { + "gpio24" +}; +static const char * const cci_timer2_groups[] = { + "gpio25" +}; +static const char * const cci_timer3_groups[] = { + "gpio26" +}; +static const char * const cci_timer4_groups[] = { + "gpio119" +}; +static const char * const edp_hpd_groups[] = { + "gpio103" +}; +static const char * const gcc_gp1_groups[] = { + "gpio37" +}; +static const char * const gcc_gp2_groups[] = { + "gpio38" +}; +static const char * const gcc_gp3_groups[] = { + "gpio86" +}; +static const char * const gcc_obt_groups[] = { + "gpio127" +}; +static const char * const gcc_vtt_groups[] = { + "gpio126" +}; +static const char * const gp_mn_groups[] = { + "gpio29" +}; +static const char * const gp_pdm0_groups[] = { + "gpio48", "gpio83" +}; +static const char * const gp_pdm1_groups[] = { + "gpio84", "gpio101" +}; +static const char * const gp_pdm2_groups[] = { + "gpio85", "gpio110" +}; +static const char * const gp0_clk_groups[] = { + "gpio25" +}; +static const char * const gp1_clk_groups[] = { + "gpio26" +}; +static const char * const hdmi_cec_groups[] = { + "gpio31" +}; +static const char * const hdmi_ddc_groups[] = { + "gpio32", "gpio33" +}; +static const char * const hdmi_dtest_groups[] = { + "gpio123" +}; +static const char * const hdmi_hpd_groups[] = { + "gpio34" +}; +static const char * const hdmi_rcv_groups[] = { + "gpio125" +}; +static const char * const hsic_groups[] = { + "gpio134", "gpio135" +}; +static const char * const ldo_en_groups[] = { + "gpio124" +}; +static const char * const ldo_update_groups[] = { + "gpio125" +}; +static const char * const mdp_vsync_groups[] = { + "gpio12", "gpio13", "gpio14" +}; +static const char * const pci_e0_groups[] = { + "gpio68", "gpio70" +}; +static const char * const pci_e0_n_groups[] = { + "gpio68", "gpio70" +}; +static const char * const pci_e0_rst_groups[] = { + "gpio70" +}; +static const char * const pci_e1_groups[] = { + "gpio140" +}; +static const char * const pci_e1_rst_groups[] = { + "gpio140" +}; +static const char * const pci_e1_rst_n_groups[] = { + "gpio140" +}; +static const char * const pci_e1_clkreq_n_groups[] = { + "gpio141" +}; +static const char * const pri_mi2s_groups[] = { + "gpio76", "gpio77", "gpio78", "gpio79", "gpio80" +}; +static const char * const qua_mi2s_groups[] = { + "gpio91", "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97" +}; +static const char * const sata_act_groups[] = { + "gpio129" +}; +static const char * const sata_devsleep_groups[] = { + "gpio119" +}; +static const char * const sata_devsleep_n_groups[] = { + "gpio119" +}; +static const char * const sd_write_groups[] = { + "gpio75" +}; +static const char * const sdc_emmc_mode_groups[] = { + "gpio146" +}; +static const char * const sdc3_groups[] = { + "gpio67", "gpio68", "gpio69", "gpio70", "gpio71", "gpio72" +}; +static const char * const sdc4_groups[] = { + "gpio82", "gpio83", "gpio84", "gpio85", "gpio86", + "gpio91", "gpio95", "gpio96", "gpio97", "gpio101" +}; +static const char * const sec_mi2s_groups[] = { + "gpio81", "gpio82", "gpio83", "gpio84", "gpio85" +}; +static const char * const slimbus_groups[] = { + "gpio98", "gpio99" +}; +static const char * const spdif_tx_groups[] = { + "gpio124", "gpio136", "gpio142" +}; +static const char * const spkr_i2s_groups[] = { + "gpio98", "gpio99", "gpio100" +}; +static const char * const spkr_i2s_ws_groups[] = { + "gpio104" +}; +static const char * const spss_geni_groups[] = { + "gpio8", "gpio9" +}; +static const char * const ter_mi2s_groups[] = { + "gpio86", "gpio87", "gpio88", "gpio89", "gpio90" +}; +static const char * const tsif1_groups[] = { + "gpio82", "gpio83", "gpio84", "gpio85", "gpio86" +}; +static const char * const tsif2_groups[] = { + "gpio91", "gpio95", "gpio96", "gpio97", "gpio101" +}; +static const char * const uim_groups[] = { + "gpio130", "gpio131", "gpio132", "gpio133" +}; +static const char * const uim_batt_alarm_groups[] = { + "gpio102" +}; +static const struct msm_function apq8084_functions[] = { + FUNCTION(adsp_ext), + FUNCTION(audio_ref), + FUNCTION(blsp_i2c1), + FUNCTION(blsp_i2c2), + FUNCTION(blsp_i2c3), + FUNCTION(blsp_i2c4), + FUNCTION(blsp_i2c5), + FUNCTION(blsp_i2c6), + FUNCTION(blsp_i2c7), + FUNCTION(blsp_i2c8), + FUNCTION(blsp_i2c9), + FUNCTION(blsp_i2c10), + FUNCTION(blsp_i2c11), + FUNCTION(blsp_i2c12), + FUNCTION(blsp_spi1), + FUNCTION(blsp_spi1_cs1), + FUNCTION(blsp_spi1_cs2), + FUNCTION(blsp_spi1_cs3), + FUNCTION(blsp_spi2), + FUNCTION(blsp_spi3), + FUNCTION(blsp_spi3_cs1), + FUNCTION(blsp_spi3_cs2), + FUNCTION(blsp_spi3_cs3), + FUNCTION(blsp_spi4), + FUNCTION(blsp_spi5), + FUNCTION(blsp_spi6), + FUNCTION(blsp_spi7), + FUNCTION(blsp_spi8), + FUNCTION(blsp_spi9), + FUNCTION(blsp_spi10), + FUNCTION(blsp_spi10_cs1), + FUNCTION(blsp_spi10_cs2), + FUNCTION(blsp_spi10_cs3), + FUNCTION(blsp_spi11), + FUNCTION(blsp_spi12), + FUNCTION(blsp_uart1), + FUNCTION(blsp_uart2), + FUNCTION(blsp_uart3), + FUNCTION(blsp_uart4), + FUNCTION(blsp_uart5), + FUNCTION(blsp_uart6), + FUNCTION(blsp_uart7), + FUNCTION(blsp_uart8), + FUNCTION(blsp_uart9), + FUNCTION(blsp_uart10), + FUNCTION(blsp_uart11), + FUNCTION(blsp_uart12), + FUNCTION(blsp_uim1), + FUNCTION(blsp_uim2), + FUNCTION(blsp_uim3), + FUNCTION(blsp_uim4), + FUNCTION(blsp_uim5), + FUNCTION(blsp_uim6), + FUNCTION(blsp_uim7), + FUNCTION(blsp_uim8), + FUNCTION(blsp_uim9), + FUNCTION(blsp_uim10), + FUNCTION(blsp_uim11), + FUNCTION(blsp_uim12), + FUNCTION(cam_mclk0), + FUNCTION(cam_mclk1), + FUNCTION(cam_mclk2), + FUNCTION(cam_mclk3), + FUNCTION(cci_async), + FUNCTION(cci_async_in0), + FUNCTION(cci_i2c0), + FUNCTION(cci_i2c1), + FUNCTION(cci_timer0), + FUNCTION(cci_timer1), + FUNCTION(cci_timer2), + FUNCTION(cci_timer3), + FUNCTION(cci_timer4), + FUNCTION(edp_hpd), + FUNCTION(gcc_gp1), + FUNCTION(gcc_gp2), + FUNCTION(gcc_gp3), + FUNCTION(gcc_obt), + FUNCTION(gcc_vtt), + FUNCTION(gp_mn), + FUNCTION(gp_pdm0), + FUNCTION(gp_pdm1), + FUNCTION(gp_pdm2), + FUNCTION(gp0_clk), + FUNCTION(gp1_clk), + FUNCTION(gpio), + FUNCTION(hdmi_cec), + FUNCTION(hdmi_ddc), + FUNCTION(hdmi_dtest), + FUNCTION(hdmi_hpd), + FUNCTION(hdmi_rcv), + FUNCTION(hsic), + FUNCTION(ldo_en), + FUNCTION(ldo_update), + FUNCTION(mdp_vsync), + FUNCTION(pci_e0), + FUNCTION(pci_e0_n), + FUNCTION(pci_e0_rst), + FUNCTION(pci_e1), + FUNCTION(pci_e1_rst), + FUNCTION(pci_e1_rst_n), + FUNCTION(pci_e1_clkreq_n), + FUNCTION(pri_mi2s), + FUNCTION(qua_mi2s), + FUNCTION(sata_act), + FUNCTION(sata_devsleep), + FUNCTION(sata_devsleep_n), + FUNCTION(sd_write), + FUNCTION(sdc_emmc_mode), + FUNCTION(sdc3), + FUNCTION(sdc4), + FUNCTION(sec_mi2s), + FUNCTION(slimbus), + FUNCTION(spdif_tx), + FUNCTION(spkr_i2s), + FUNCTION(spkr_i2s_ws), + FUNCTION(spss_geni), + FUNCTION(ter_mi2s), + FUNCTION(tsif1), + FUNCTION(tsif2), + FUNCTION(uim), + FUNCTION(uim_batt_alarm), +}; + +static const struct msm_pingroup apq8084_groups[] = { + PINGROUP(0, blsp_spi1, blsp_uart1, blsp_uim1, NA, NA, NA, NA), + PINGROUP(1, blsp_spi1, blsp_uart1, blsp_uim1, NA, NA, NA, NA), + PINGROUP(2, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA), + PINGROUP(3, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA), + PINGROUP(4, blsp_spi2, blsp_uart2, blsp_uim2, NA, NA, NA, NA), + PINGROUP(5, blsp_spi2, blsp_uart2, blsp_uim2, NA, NA, NA, NA), + PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA), + PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA), + PINGROUP(8, blsp_spi3, blsp_uart3, blsp_uim3, spss_geni, NA, NA, NA), + PINGROUP(9, blsp_spi3, blsp_uim3, blsp_uart3, spss_geni, NA, NA, NA), + PINGROUP(10, blsp_spi3, blsp_uart3, blsp_i2c3, NA, NA, NA, NA), + PINGROUP(11, blsp_spi3, blsp_uart3, blsp_i2c3, NA, NA, NA, NA), + PINGROUP(12, mdp_vsync, NA, NA, NA, NA, NA, NA), + PINGROUP(13, mdp_vsync, NA, NA, NA, NA, NA, NA), + PINGROUP(14, mdp_vsync, NA, NA, NA, NA, NA, NA), + PINGROUP(15, cam_mclk0, NA, NA, NA, NA, NA, NA), + PINGROUP(16, cam_mclk1, NA, NA, NA, NA, NA, NA), + PINGROUP(17, cam_mclk2, NA, NA, NA, NA, NA, NA), + PINGROUP(18, cam_mclk3, NA, NA, NA, NA, NA, NA), + PINGROUP(19, cci_i2c0, NA, NA, NA, NA, NA, NA), + PINGROUP(20, cci_i2c0, NA, NA, NA, NA, NA, NA), + PINGROUP(21, cci_i2c1, NA, NA, NA, NA, NA, NA), + PINGROUP(22, cci_i2c1, NA, NA, NA, NA, NA, NA), + PINGROUP(23, cci_timer0, NA, NA, NA, NA, NA, NA), + PINGROUP(24, cci_timer1, NA, NA, NA, NA, NA, NA), + PINGROUP(25, cci_timer2, gp0_clk, NA, NA, NA, NA, NA), + PINGROUP(26, cci_timer3, cci_async, gp1_clk, NA, NA, NA, NA), + PINGROUP(27, blsp_spi4, blsp_uart4, blsp_uim4, NA, NA, NA, NA), + PINGROUP(28, blsp_spi4, blsp_uart4, blsp_uim4, NA, NA, NA, NA), + PINGROUP(29, blsp_spi4, blsp_uart4, blsp_i2c4, gp_mn, NA, NA, NA), + PINGROUP(30, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA), + PINGROUP(31, hdmi_cec, NA, NA, NA, NA, NA, NA), + PINGROUP(32, hdmi_ddc, NA, NA, NA, NA, NA, NA), + PINGROUP(33, hdmi_ddc, NA, NA, NA, NA, NA, NA), + PINGROUP(34, hdmi_hpd, NA, adsp_ext, NA, NA, NA, NA), + PINGROUP(35, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(36, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(37, gcc_gp1, NA, NA, NA, NA, NA, NA), + PINGROUP(38, gcc_gp2, NA, NA, NA, NA, NA, NA), + PINGROUP(39, blsp_spi5, blsp_uart5, blsp_uim5, NA, NA, NA, NA), + PINGROUP(40, blsp_spi5, blsp_uart5, blsp_uim5, NA, NA, NA, NA), + PINGROUP(41, blsp_spi5, blsp_uart5, blsp_i2c5, NA, NA, NA, NA), + PINGROUP(42, blsp_spi5, blsp_uart5, blsp_i2c5, NA, NA, NA, NA), + PINGROUP(43, blsp_spi6, blsp_uart6, blsp_uim6, NA, NA, NA, NA), + PINGROUP(44, blsp_spi6, blsp_uart6, blsp_uim6, NA, NA, NA, NA), + PINGROUP(45, blsp_spi6, blsp_uart6, blsp_i2c6, NA, NA, NA, NA), + PINGROUP(46, blsp_spi6, blsp_uart6, blsp_i2c6, NA, NA, NA, NA), + PINGROUP(47, blsp_spi12, blsp_uart12, blsp_uim12, NA, NA, NA, NA), + PINGROUP(48, blsp_spi12, blsp_uart12, blsp_uim12, gp_pdm0, NA, NA, NA), + PINGROUP(49, blsp_spi12, blsp_uart12, blsp_i2c12, NA, NA, NA, NA), + PINGROUP(50, blsp_spi12, blsp_uart12, blsp_i2c12, NA, NA, NA, NA), + PINGROUP(51, blsp_spi8, blsp_uart8, blsp_uim8, NA, NA, NA, NA), + PINGROUP(52, blsp_spi8, blsp_uart8, blsp_uim8, NA, NA, NA, NA), + PINGROUP(53, blsp_spi8, blsp_uart8, blsp_i2c8, NA, NA, NA, NA), + PINGROUP(54, blsp_spi8, blsp_uart8, blsp_i2c8, NA, NA, NA, NA), + PINGROUP(55, blsp_spi9, blsp_uart9, blsp_uim9, NA, NA, NA, NA), + PINGROUP(56, blsp_spi9, blsp_uart9, blsp_uim9, NA, NA, NA, NA), + PINGROUP(57, blsp_spi9, blsp_uart9, blsp_i2c9, NA, NA, NA, NA), + PINGROUP(58, blsp_spi9, blsp_uart9, blsp_i2c9, NA, NA, NA, NA), + PINGROUP(59, blsp_spi10, blsp_uart10, blsp_uim10, NA, NA, NA, NA), + PINGROUP(60, blsp_spi10, blsp_uart10, blsp_uim10, NA, NA, NA, NA), + PINGROUP(61, blsp_spi10, blsp_uart10, blsp_i2c10, NA, NA, NA, NA), + PINGROUP(62, blsp_spi10, blsp_uart10, blsp_i2c10, NA, NA, NA, NA), + PINGROUP(63, blsp_spi11, blsp_uart11, blsp_uim11, NA, NA, NA, NA), + PINGROUP(64, blsp_spi11, blsp_uart11, blsp_uim11, NA, NA, NA, NA), + PINGROUP(65, blsp_spi11, blsp_uart11, blsp_i2c11, NA, NA, NA, NA), + PINGROUP(66, blsp_spi11, blsp_uart11, blsp_i2c11, NA, NA, NA, NA), + PINGROUP(67, sdc3, blsp_spi3_cs1, NA, NA, NA, NA, NA), + PINGROUP(68, sdc3, pci_e0, NA, NA, NA, NA, NA), + PINGROUP(69, sdc3, NA, NA, NA, NA, NA, NA), + PINGROUP(70, sdc3, pci_e0_n, pci_e0, NA, NA, NA, NA), + PINGROUP(71, sdc3, blsp_spi3_cs2, NA, NA, NA, NA, NA), + PINGROUP(72, sdc3, blsp_spi3_cs3, NA, NA, NA, NA, NA), + PINGROUP(73, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(74, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(75, sd_write, NA, NA, NA, NA, NA, NA), + PINGROUP(76, pri_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(77, pri_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(78, pri_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(79, pri_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(80, pri_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(81, sec_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(82, sec_mi2s, sdc4, tsif1, NA, NA, NA, NA), + PINGROUP(83, sec_mi2s, sdc4, tsif1, NA, NA, NA, gp_pdm0), + PINGROUP(84, sec_mi2s, sdc4, tsif1, NA, NA, NA, gp_pdm1), + PINGROUP(85, sec_mi2s, sdc4, tsif1, NA, gp_pdm2, NA, NA), + PINGROUP(86, ter_mi2s, sdc4, tsif1, NA, NA, NA, gcc_gp3), + PINGROUP(87, ter_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(88, ter_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(89, ter_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(90, ter_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(91, qua_mi2s, sdc4, tsif2, NA, NA, NA, NA), + PINGROUP(92, qua_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(93, qua_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(94, qua_mi2s, NA, NA, NA, NA, NA, NA), + PINGROUP(95, qua_mi2s, sdc4, tsif2, NA, NA, NA, gcc_gp1), + PINGROUP(96, qua_mi2s, sdc4, tsif2, NA, NA, NA, gcc_gp2), + PINGROUP(97, qua_mi2s, sdc4, tsif2, NA, gcc_gp3, NA, NA), + PINGROUP(98, slimbus, spkr_i2s, NA, NA, NA, NA, NA), + PINGROUP(99, slimbus, spkr_i2s, NA, NA, NA, NA, NA), + PINGROUP(100, audio_ref, spkr_i2s, NA, NA, NA, NA, NA), + PINGROUP(101, sdc4, tsif2, gp_pdm1, NA, NA, NA, NA), + PINGROUP(102, uim_batt_alarm, NA, NA, NA, NA, NA, NA), + PINGROUP(103, edp_hpd, NA, NA, NA, NA, NA, NA), + PINGROUP(104, spkr_i2s, NA, NA, NA, NA, NA, NA), + PINGROUP(105, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(106, blsp_spi10_cs1, NA, NA, NA, NA, NA, NA), + PINGROUP(107, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(108, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(109, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(110, gp_pdm2, NA, NA, NA, NA, NA, NA), + PINGROUP(111, blsp_spi10_cs2, NA, NA, NA, NA, NA, NA), + PINGROUP(112, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(113, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(114, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(115, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(116, blsp_spi1_cs1, NA, NA, NA, NA, NA, NA), + PINGROUP(117, blsp_spi1_cs2, NA, NA, NA, NA, NA, NA), + PINGROUP(118, blsp_spi1_cs3, NA, NA, NA, NA, NA, NA), + PINGROUP(119, cci_timer4, cci_async, sata_devsleep, sata_devsleep_n, NA, NA, NA), + PINGROUP(120, cci_async, NA, NA, NA, NA, NA, NA), + PINGROUP(121, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(122, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(123, hdmi_dtest, NA, NA, NA, NA, NA, NA), + PINGROUP(124, spdif_tx, ldo_en, NA, NA, NA, NA, NA), + PINGROUP(125, ldo_update, hdmi_rcv, NA, NA, NA, NA, NA), + PINGROUP(126, gcc_vtt, NA, NA, NA, NA, NA, NA), + PINGROUP(127, gcc_obt, NA, NA, NA, NA, NA, NA), + PINGROUP(128, blsp_spi10_cs3, NA, NA, NA, NA, NA, NA), + PINGROUP(129, sata_act, NA, NA, NA, NA, NA, NA), + PINGROUP(130, uim, blsp_spi7, blsp_uart7, blsp_uim7, NA, NA, NA), + PINGROUP(131, uim, blsp_spi7, blsp_uart7, blsp_uim7, NA, NA, NA), + PINGROUP(132, uim, blsp_spi7, blsp_uart7, blsp_i2c7, NA, NA, NA), + PINGROUP(133, uim, blsp_spi7, blsp_uart7, blsp_i2c7, NA, NA, NA), + PINGROUP(134, hsic, NA, NA, NA, NA, NA, NA), + PINGROUP(135, hsic, NA, NA, NA, NA, NA, NA), + PINGROUP(136, spdif_tx, NA, NA, NA, NA, NA, NA), + PINGROUP(137, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(138, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(139, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(140, pci_e1_rst_n, pci_e1_rst, NA, NA, NA, NA, NA), + PINGROUP(141, pci_e1_clkreq_n, NA, NA, NA, NA, NA, NA), + PINGROUP(142, spdif_tx, NA, NA, NA, NA, NA, NA), + PINGROUP(143, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(144, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(145, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(146, sdc_emmc_mode, NA, NA, NA, NA, NA, NA), + + SDC_PINGROUP(sdc1_clk, 0x2044, 13, 6), + SDC_PINGROUP(sdc1_cmd, 0x2044, 11, 3), + SDC_PINGROUP(sdc1_data, 0x2044, 9, 0), + SDC_PINGROUP(sdc2_clk, 0x2048, 14, 6), + SDC_PINGROUP(sdc2_cmd, 0x2048, 11, 3), + SDC_PINGROUP(sdc2_data, 0x2048, 9, 0), +}; + +#define NUM_GPIO_PINGROUPS 147 + +static const struct msm_pinctrl_soc_data apq8084_pinctrl = { + .pins = apq8084_pins, + .npins = ARRAY_SIZE(apq8084_pins), + .functions = apq8084_functions, + .nfunctions = ARRAY_SIZE(apq8084_functions), + .groups = apq8084_groups, + .ngroups = ARRAY_SIZE(apq8084_groups), + .ngpios = NUM_GPIO_PINGROUPS, +}; + +static int apq8084_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &apq8084_pinctrl); +} + +static const struct of_device_id apq8084_pinctrl_of_match[] = { + { .compatible = "qcom,apq8084-pinctrl", }, + { }, +}; + +static struct platform_driver apq8084_pinctrl_driver = { + .driver = { + .name = "apq8084-pinctrl", + .owner = THIS_MODULE, + .of_match_table = apq8084_pinctrl_of_match, + }, + .probe = apq8084_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init apq8084_pinctrl_init(void) +{ + return platform_driver_register(&apq8084_pinctrl_driver); +} +arch_initcall(apq8084_pinctrl_init); + +static void __exit apq8084_pinctrl_exit(void) +{ + platform_driver_unregister(&apq8084_pinctrl_driver); +} +module_exit(apq8084_pinctrl_exit); + +MODULE_DESCRIPTION("Qualcomm APQ8084 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, apq8084_pinctrl_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c index 767cf1120b2..81f49a9b4db 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c @@ -211,6 +211,7 @@ static const unsigned int sdc3_data_pins[] = { 71 }; .intr_status_bit = 0, \ .intr_ack_high = 1, \ .intr_target_bit = 0, \ + .intr_target_kpss_val = 4, \ .intr_raw_status_bit = 3, \ .intr_polarity_bit = 1, \ .intr_detection_bit = 2, \ @@ -236,6 +237,7 @@ static const unsigned int sdc3_data_pins[] = { 71 }; .intr_enable_bit = -1, \ .intr_status_bit = -1, \ .intr_target_bit = -1, \ + .intr_target_kpss_val = -1, \ .intr_raw_status_bit = -1, \ .intr_polarity_bit = -1, \ .intr_detection_bit = -1, \ diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 2738108caff..d30dddd2132 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -12,6 +12,7 @@ * GNU General Public License for more details. */ +#include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> #include <linux/module.h> @@ -26,6 +27,7 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/spinlock.h> +#include <linux/reboot.h> #include "../core.h" #include "../pinconf.h" @@ -33,12 +35,14 @@ #include "../pinctrl-utils.h" #define MAX_NR_GPIO 300 +#define PS_HOLD_OFFSET 0x820 /** * struct msm_pinctrl - state for a pinctrl-msm device * @dev: device handle. * @pctrl: pinctrl handle. * @chip: gpiochip handle. + * @restart_nb: restart notifier block. * @irq: parent irq for the TLMM irq_chip. * @lock: Spinlock to protect register resources as well * as msm_pinctrl data structures. @@ -52,6 +56,7 @@ struct msm_pinctrl { struct device *dev; struct pinctrl_dev *pctrl; struct gpio_chip chip; + struct notifier_block restart_nb; int irq; spinlock_t lock; @@ -130,9 +135,9 @@ static int msm_get_function_groups(struct pinctrl_dev *pctldev, return 0; } -static int msm_pinmux_enable(struct pinctrl_dev *pctldev, - unsigned function, - unsigned group) +static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const struct msm_pingroup *g; @@ -166,7 +171,7 @@ static const struct pinmux_ops msm_pinmux_ops = { .get_functions_count = msm_get_functions_count, .get_function_name = msm_get_function_name, .get_function_groups = msm_get_function_groups, - .enable = msm_pinmux_enable, + .set_mux = msm_pinmux_set_mux, }; static int msm_config_reg(struct msm_pinctrl *pctrl, @@ -649,8 +654,6 @@ static void msm_gpio_irq_ack(struct irq_data *d) spin_unlock_irqrestore(&pctrl->lock, flags); } -#define INTR_TARGET_PROC_APPS 4 - static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); @@ -674,7 +677,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) /* Route interrupts to application cpu */ val = readl(pctrl->regs + g->intr_target_reg); val &= ~(7 << g->intr_target_bit); - val |= INTR_TARGET_PROC_APPS << g->intr_target_bit; + val |= g->intr_target_kpss_val << g->intr_target_bit; writel(val, pctrl->regs + g->intr_target_reg); /* Update configuration for gpio. @@ -829,6 +832,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio); if (ret) { dev_err(pctrl->dev, "Failed to add pin range\n"); + gpiochip_remove(&pctrl->chip); return ret; } @@ -839,6 +843,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) IRQ_TYPE_NONE); if (ret) { dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n"); + gpiochip_remove(&pctrl->chip); return -ENOSYS; } @@ -848,6 +853,32 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) return 0; } +static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct msm_pinctrl *pctrl = container_of(nb, struct msm_pinctrl, restart_nb); + + writel(0, pctrl->regs + PS_HOLD_OFFSET); + mdelay(1000); + return NOTIFY_DONE; +} + +static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) +{ + int i = 0; + const struct msm_function *func = pctrl->soc->functions; + + for (; i <= pctrl->soc->nfunctions; i++) + if (!strcmp(func[i].name, "ps_hold")) { + pctrl->restart_nb.notifier_call = msm_ps_hold_restart; + pctrl->restart_nb.priority = 128; + if (register_restart_handler(&pctrl->restart_nb)) + dev_err(pctrl->dev, + "failed to setup restart handler.\n"); + break; + } +} + int msm_pinctrl_probe(struct platform_device *pdev, const struct msm_pinctrl_soc_data *soc_data) { @@ -871,6 +902,8 @@ int msm_pinctrl_probe(struct platform_device *pdev, if (IS_ERR(pctrl->regs)) return PTR_ERR(pctrl->regs); + msm_pinctrl_setup_pm_reset(pctrl); + pctrl->irq = platform_get_irq(pdev, 0); if (pctrl->irq < 0) { dev_err(&pdev->dev, "No interrupt defined for msmgpio\n"); @@ -913,6 +946,8 @@ int msm_pinctrl_remove(struct platform_device *pdev) pinctrl_unregister(pctrl->pctrl); + unregister_restart_handler(&pctrl->restart_nb); + return 0; } EXPORT_SYMBOL(msm_pinctrl_remove); diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h index 7b2a227a590..b952c4b4a8e 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.h +++ b/drivers/pinctrl/qcom/pinctrl-msm.h @@ -53,6 +53,8 @@ struct msm_function { * @intr_status_bit: Offset in @intr_status_reg for reading and acking the interrupt * status. * @intr_target_bit: Offset in @intr_target_reg for configuring the interrupt routing. + * @intr_target_kpss_val: Value in @intr_target_bit for specifying that the interrupt from + * this gpio should get routed to the KPSS processor. * @intr_raw_status_bit: Offset in @intr_cfg_reg for the raw status bit. * @intr_polarity_bit: Offset in @intr_cfg_reg for specifying polarity of the interrupt. * @intr_detection_bit: Offset in @intr_cfg_reg for specifying interrupt type. @@ -88,6 +90,7 @@ struct msm_pingroup { unsigned intr_ack_high:1; unsigned intr_target_bit:5; + unsigned intr_target_kpss_val:5; unsigned intr_raw_status_bit:5; unsigned intr_polarity_bit:5; unsigned intr_detection_bit:5; diff --git a/drivers/pinctrl/qcom/pinctrl-msm8960.c b/drivers/pinctrl/qcom/pinctrl-msm8960.c index 35047036a05..2ab21ce5575 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8960.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8960.c @@ -384,6 +384,7 @@ static const unsigned int sdc3_data_pins[] = { 157 }; .intr_status_bit = 0, \ .intr_ack_high = 1, \ .intr_target_bit = 0, \ + .intr_target_kpss_val = 4, \ .intr_raw_status_bit = 3, \ .intr_polarity_bit = 1, \ .intr_detection_bit = 2, \ @@ -409,6 +410,7 @@ static const unsigned int sdc3_data_pins[] = { 157 }; .intr_enable_bit = -1, \ .intr_status_bit = -1, \ .intr_target_bit = -1, \ + .intr_target_kpss_val = -1, \ .intr_raw_status_bit = -1, \ .intr_polarity_bit = -1, \ .intr_detection_bit = -1, \ diff --git a/drivers/pinctrl/qcom/pinctrl-msm8x74.c b/drivers/pinctrl/qcom/pinctrl-msm8x74.c index 8c9720154d1..3c858384d04 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8x74.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8x74.c @@ -366,6 +366,7 @@ static const unsigned int sdc2_data_pins[] = { 151 }; .intr_enable_bit = 0, \ .intr_status_bit = 0, \ .intr_target_bit = 5, \ + .intr_target_kpss_val = 4, \ .intr_raw_status_bit = 4, \ .intr_polarity_bit = 1, \ .intr_detection_bit = 2, \ @@ -391,6 +392,7 @@ static const unsigned int sdc2_data_pins[] = { 151 }; .intr_enable_bit = -1, \ .intr_status_bit = -1, \ .intr_target_bit = -1, \ + .intr_target_kpss_val = -1, \ .intr_raw_status_bit = -1, \ .intr_polarity_bit = -1, \ .intr_detection_bit = -1, \ diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c index 603da2f9dd9..b995ec2c5d1 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c @@ -364,8 +364,9 @@ static void exynos5440_pinmux_setup(struct pinctrl_dev *pctldev, unsigned select } /* enable a specified pinmux by writing to registers */ -static int exynos5440_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) +static int exynos5440_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned selector, + unsigned group) { exynos5440_pinmux_setup(pctldev, selector, group, true); return 0; @@ -387,7 +388,7 @@ static const struct pinmux_ops exynos5440_pinmux_ops = { .get_functions_count = exynos5440_get_functions_count, .get_function_name = exynos5440_pinmux_get_fname, .get_function_groups = exynos5440_pinmux_get_groups, - .enable = exynos5440_pinmux_enable, + .set_mux = exynos5440_pinmux_set_mux, .gpio_set_direction = exynos5440_pinmux_gpio_set_direction, }; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index b07406da333..4a47691c32b 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -401,8 +401,9 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, } /* enable a specified pinmux by writing to registers */ -static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) +static int samsung_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned selector, + unsigned group) { samsung_pinmux_setup(pctldev, selector, group, true); return 0; @@ -413,7 +414,7 @@ static const struct pinmux_ops samsung_pinmux_ops = { .get_functions_count = samsung_get_functions_count, .get_function_name = samsung_pinmux_get_fname, .get_function_groups = samsung_pinmux_get_groups, - .enable = samsung_pinmux_enable, + .set_mux = samsung_pinmux_set_mux, }; /* set or get the pin config settings for a specified pin */ diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index b9b464d0578..6572c233f73 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -542,7 +542,7 @@ static int sh_pfc_probe(struct platform_device *pdev) */ ret = sh_pfc_register_pinctrl(pfc); if (unlikely(ret != 0)) - goto error; + return ret; #ifdef CONFIG_GPIO_SH_PFC /* @@ -564,11 +564,6 @@ static int sh_pfc_probe(struct platform_device *pdev) dev_info(pfc->dev, "%s support registered\n", info->name); return 0; - -error: - if (info->ops && info->ops->exit) - info->ops->exit(pfc); - return ret; } static int sh_pfc_remove(struct platform_device *pdev) @@ -580,9 +575,6 @@ static int sh_pfc_remove(struct platform_device *pdev) #endif sh_pfc_unregister_pinctrl(pfc); - if (pfc->info->ops && pfc->info->ops->exit) - pfc->info->ops->exit(pfc); - return 0; } diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h index b7b0e6ccf30..3daaa5241c4 100644 --- a/drivers/pinctrl/sh-pfc/core.h +++ b/drivers/pinctrl/sh-pfc/core.h @@ -33,7 +33,6 @@ struct sh_pfc_pin_range { struct sh_pfc { struct device *dev; const struct sh_pfc_soc_info *info; - void *soc_data; spinlock_t lock; unsigned int num_windows; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c index ce9fb7aa8ba..280a56f9778 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c @@ -2717,14 +2717,14 @@ static void r8a73a4_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin, iowrite8(value, addr); } -static const struct sh_pfc_soc_operations r8a73a4_pinmux_ops = { +static const struct sh_pfc_soc_operations r8a73a4_pfc_ops = { .get_bias = r8a73a4_pinmux_get_bias, .set_bias = r8a73a4_pinmux_set_bias, }; const struct sh_pfc_soc_info r8a73a4_pinmux_info = { .name = "r8a73a4_pfc", - .ops = &r8a73a4_pinmux_ops, + .ops = &r8a73a4_pfc_ops, .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END }, .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END }, diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c index e4c1ef47705..b486e9d20cc 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c @@ -3752,14 +3752,14 @@ static void r8a7740_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin, iowrite8(value, addr); } -static const struct sh_pfc_soc_operations r8a7740_pinmux_ops = { +static const struct sh_pfc_soc_operations r8a7740_pfc_ops = { .get_bias = r8a7740_pinmux_get_bias, .set_bias = r8a7740_pinmux_set_bias, }; const struct sh_pfc_soc_info r8a7740_pinmux_info = { .name = "r8a7740_pfc", - .ops = &r8a7740_pinmux_ops, + .ops = &r8a7740_pfc_ops, .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END }, diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7372.c b/drivers/pinctrl/sh-pfc/pfc-sh7372.c index d9158b3b291..8211f66a2f6 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7372.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7372.c @@ -2614,14 +2614,14 @@ static void sh7372_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin, iowrite8(value, addr); } -static const struct sh_pfc_soc_operations sh7372_pinmux_ops = { +static const struct sh_pfc_soc_operations sh7372_pfc_ops = { .get_bias = sh7372_pinmux_get_bias, .set_bias = sh7372_pinmux_set_bias, }; const struct sh_pfc_soc_info sh7372_pinmux_info = { .name = "sh7372_pfc", - .ops = &sh7372_pinmux_ops, + .ops = &sh7372_pfc_ops, .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END }, .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END }, diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c index 0bd8f4401b4..d2efbfb776a 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c @@ -3824,39 +3824,28 @@ static void sh73a0_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin, * SoC information */ -struct sh73a0_pinmux_data { - struct regulator_dev *vccq_mc0; -}; - static int sh73a0_pinmux_soc_init(struct sh_pfc *pfc) { - struct sh73a0_pinmux_data *data; struct regulator_config cfg = { }; + struct regulator_dev *vccq; int ret; - data = devm_kzalloc(pfc->dev, sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - cfg.dev = pfc->dev; cfg.init_data = &sh73a0_vccq_mc0_init_data; cfg.driver_data = pfc; - data->vccq_mc0 = devm_regulator_register(pfc->dev, - &sh73a0_vccq_mc0_desc, &cfg); - if (IS_ERR(data->vccq_mc0)) { - ret = PTR_ERR(data->vccq_mc0); + vccq = devm_regulator_register(pfc->dev, &sh73a0_vccq_mc0_desc, &cfg); + if (IS_ERR(vccq)) { + ret = PTR_ERR(vccq); dev_err(pfc->dev, "Failed to register VCCQ MC0 regulator: %d\n", ret); return ret; } - pfc->soc_data = data; - return 0; } -static const struct sh_pfc_soc_operations sh73a0_pinmux_ops = { +static const struct sh_pfc_soc_operations sh73a0_pfc_ops = { .init = sh73a0_pinmux_soc_init, .get_bias = sh73a0_pinmux_get_bias, .set_bias = sh73a0_pinmux_set_bias, @@ -3864,7 +3853,7 @@ static const struct sh_pfc_soc_operations sh73a0_pinmux_ops = { const struct sh_pfc_soc_info sh73a0_pinmux_info = { .name = "sh73a0_pfc", - .ops = &sh73a0_pinmux_ops, + .ops = &sh73a0_pfc_ops, .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END }, .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END }, diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index 11db3ee39d4..910deaefa0a 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -312,8 +312,8 @@ static int sh_pfc_get_function_groups(struct pinctrl_dev *pctldev, return 0; } -static int sh_pfc_func_enable(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group) +static int sh_pfc_func_set_mux(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) { struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); struct sh_pfc *pfc = pmx->pfc; @@ -442,7 +442,7 @@ static const struct pinmux_ops sh_pfc_pinmux_ops = { .get_functions_count = sh_pfc_get_functions_count, .get_function_name = sh_pfc_get_function_name, .get_function_groups = sh_pfc_get_function_groups, - .enable = sh_pfc_func_enable, + .set_mux = sh_pfc_func_set_mux, .gpio_request_enable = sh_pfc_gpio_request_enable, .gpio_disable_free = sh_pfc_gpio_disable_free, .gpio_set_direction = sh_pfc_gpio_set_direction, diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h index d482c40b012..5b7283182c1 100644 --- a/drivers/pinctrl/sh-pfc/sh_pfc.h +++ b/drivers/pinctrl/sh-pfc/sh_pfc.h @@ -116,7 +116,6 @@ struct sh_pfc; struct sh_pfc_soc_operations { int (*init)(struct sh_pfc *pfc); - void (*exit)(struct sh_pfc *pfc); unsigned int (*get_bias)(struct sh_pfc *pfc, unsigned int pin); void (*set_bias)(struct sh_pfc *pfc, unsigned int pin, unsigned int bias); diff --git a/drivers/pinctrl/sirf/pinctrl-atlas6.c b/drivers/pinctrl/sirf/pinctrl-atlas6.c index c4dd3d5cf9c..45f8391ddb3 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas6.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas6.c @@ -134,8 +134,9 @@ static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = { .mask = BIT(30) | BIT(31), }, { .group = 2, - .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | - BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | + .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | + BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(15) | + BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(31), }, }; @@ -148,14 +149,15 @@ static const struct sirfsoc_padmux lcd_16bits_padmux = { .funcval = 0, }; -static const unsigned lcd_16bits_pins[] = { 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, - 84, 85, 86, 95 }; +static const unsigned lcd_16bits_pins[] = { 62, 63, 65, 70, 71, 72, 73, 74, 75, + 76, 77, 79, 80, 81, 82, 83, 84, 85, 86, 95 }; static const struct sirfsoc_muxmask lcd_18bits_muxmask[] = { { .group = 2, - .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | - BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | + .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | + BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(15) | + BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(31), }, { .group = 1, @@ -174,21 +176,23 @@ static const struct sirfsoc_padmux lcd_18bits_padmux = { .funcval = 0, }; -static const unsigned lcd_18bits_pins[] = { 16, 17, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, - 84, 85, 86, 95 }; +static const unsigned lcd_18bits_pins[] = { 16, 17, 62, 63, 65, 70, 71, 72, 73, + 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 86, 95 }; static const struct sirfsoc_muxmask lcd_24bits_muxmask[] = { { .group = 2, - .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | - BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | + .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | + BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(15) | + BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(31), }, { .group = 1, .mask = BIT(30) | BIT(31), }, { .group = 0, - .mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23), + .mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | + BIT(21) | BIT(22) | BIT(23), }, }; @@ -200,14 +204,16 @@ static const struct sirfsoc_padmux lcd_24bits_padmux = { .funcval = 0, }; -static const unsigned lcd_24bits_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, - 80, 81, 82, 83, 84, 85, 86, 95}; +static const unsigned lcd_24bits_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 62, + 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, + 85, 86, 95}; static const struct sirfsoc_muxmask lcdrom_muxmask[] = { { .group = 2, - .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | - BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | + .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | + BIT(11) | BIT(12) | BIT(13) | BIT(15) | BIT(16) | + BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(31), }, { .group = 1, @@ -226,8 +232,8 @@ static const struct sirfsoc_padmux lcdrom_padmux = { .funcval = BIT(4), }; -static const unsigned lcdrom_pins[] = { 8, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, - 84, 85, 86, 95}; +static const unsigned lcdrom_pins[] = { 8, 62, 63, 65, 70, 71, 72, 73, 74, 75, + 76, 77, 79, 80, 81, 82, 83, 84, 85, 86, 95}; static const struct sirfsoc_muxmask uart0_muxmask[] = { { @@ -371,11 +377,42 @@ static const struct sirfsoc_padmux cko1_padmux = { static const unsigned cko1_pins[] = { 42 }; -static const struct sirfsoc_muxmask i2s_muxmask[] = { +static const struct sirfsoc_muxmask i2s_mclk_muxmask[] = { { .group = 1, .mask = BIT(10), - }, { + }, +}; + +static const struct sirfsoc_padmux i2s_mclk_padmux = { + .muxmask_counts = ARRAY_SIZE(i2s_mclk_muxmask), + .muxmask = i2s_mclk_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, + .funcmask = BIT(3), + .funcval = BIT(3), +}; + +static const unsigned i2s_mclk_pins[] = { 42 }; + +static const struct sirfsoc_muxmask i2s_ext_clk_input_muxmask[] = { + { + .group = 1, + .mask = BIT(19), + }, +}; + +static const struct sirfsoc_padmux i2s_ext_clk_input_padmux = { + .muxmask_counts = ARRAY_SIZE(i2s_ext_clk_input_muxmask), + .muxmask = i2s_ext_clk_input_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, + .funcmask = BIT(2), + .funcval = BIT(2), +}; + +static const unsigned i2s_ext_clk_input_pins[] = { 51 }; + +static const struct sirfsoc_muxmask i2s_muxmask[] = { + { .group = 3, .mask = BIT(2) | BIT(3) | BIT(4) | BIT(5), }, @@ -385,17 +422,12 @@ static const struct sirfsoc_padmux i2s_padmux = { .muxmask_counts = ARRAY_SIZE(i2s_muxmask), .muxmask = i2s_muxmask, .ctrlreg = SIRFSOC_RSC_PIN_MUX, - .funcmask = BIT(3), - .funcval = BIT(3), }; -static const unsigned i2s_pins[] = { 42, 98, 99, 100, 101 }; +static const unsigned i2s_pins[] = { 98, 99, 100, 101 }; static const struct sirfsoc_muxmask i2s_no_din_muxmask[] = { { - .group = 1, - .mask = BIT(10), - }, { .group = 3, .mask = BIT(2) | BIT(3) | BIT(4), }, @@ -405,17 +437,12 @@ static const struct sirfsoc_padmux i2s_no_din_padmux = { .muxmask_counts = ARRAY_SIZE(i2s_no_din_muxmask), .muxmask = i2s_no_din_muxmask, .ctrlreg = SIRFSOC_RSC_PIN_MUX, - .funcmask = BIT(3), - .funcval = BIT(3), }; -static const unsigned i2s_no_din_pins[] = { 42, 98, 99, 100 }; +static const unsigned i2s_no_din_pins[] = { 98, 99, 100 }; static const struct sirfsoc_muxmask i2s_6chn_muxmask[] = { { - .group = 1, - .mask = BIT(10) | BIT(20) | BIT(23), - }, { .group = 3, .mask = BIT(2) | BIT(3) | BIT(4) | BIT(5), }, @@ -425,11 +452,11 @@ static const struct sirfsoc_padmux i2s_6chn_padmux = { .muxmask_counts = ARRAY_SIZE(i2s_6chn_muxmask), .muxmask = i2s_6chn_muxmask, .ctrlreg = SIRFSOC_RSC_PIN_MUX, - .funcmask = BIT(1) | BIT(3) | BIT(9), - .funcval = BIT(1) | BIT(3) | BIT(9), + .funcmask = BIT(1) | BIT(9), + .funcval = BIT(1) | BIT(9), }; -static const unsigned i2s_6chn_pins[] = { 42, 52, 55, 98, 99, 100, 101 }; +static const unsigned i2s_6chn_pins[] = { 52, 55, 98, 99, 100, 101 }; static const struct sirfsoc_muxmask ac97_muxmask[] = { { @@ -716,7 +743,8 @@ static const struct sirfsoc_padmux vip_padmux = { .funcval = BIT(18), }; -static const unsigned vip_pins[] = { 36, 37, 38, 40, 41, 56, 57, 58, 59, 60, 61 }; +static const unsigned vip_pins[] = { 36, 37, 38, 40, 41, 56, 57, 58, 59, + 60, 61 }; static const struct sirfsoc_muxmask vip_noupli_muxmask[] = { { @@ -737,7 +765,8 @@ static const struct sirfsoc_padmux vip_noupli_padmux = { .funcval = BIT(15), }; -static const unsigned vip_noupli_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 87, 88, 89 }; +static const unsigned vip_noupli_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, + 87, 88, 89 }; static const struct sirfsoc_muxmask i2c0_muxmask[] = { { @@ -876,7 +905,8 @@ static const struct sirfsoc_padmux usb0_upli_drvbus_padmux = { .funcval = 0, }; -static const unsigned usb0_upli_drvbus_pins[] = { 36, 37, 38, 39, 40, 41, 56, 57, 58, 59, 60, 61 }; +static const unsigned usb0_upli_drvbus_pins[] = { 36, 37, 38, 39, 40, + 41, 56, 57, 58, 59, 60, 61 }; static const struct sirfsoc_muxmask usb1_utmi_drvbus_muxmask[] = { { @@ -968,6 +998,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("usb1_dp_dngrp", usb1_dp_dn_pins), SIRFSOC_PIN_GROUP("uart1_route_io_usb1grp", uart1_route_io_usb1_pins), SIRFSOC_PIN_GROUP("pulse_countgrp", pulse_count_pins), + SIRFSOC_PIN_GROUP("i2smclkgrp", i2s_mclk_pins), + SIRFSOC_PIN_GROUP("i2s_ext_clk_inputgrp", i2s_ext_clk_input_pins), SIRFSOC_PIN_GROUP("i2sgrp", i2s_pins), SIRFSOC_PIN_GROUP("i2s_no_dingrp", i2s_no_din_pins), SIRFSOC_PIN_GROUP("i2s_6chngrp", i2s_6chn_pins), @@ -1017,8 +1049,11 @@ static const char * const sdmmc2_nowpgrp[] = { "sdmmc2_nowpgrp" }; static const char * const usb0_upli_drvbusgrp[] = { "usb0_upli_drvbusgrp" }; static const char * const usb1_utmi_drvbusgrp[] = { "usb1_utmi_drvbusgrp" }; static const char * const usb1_dp_dngrp[] = { "usb1_dp_dngrp" }; -static const char * const uart1_route_io_usb1grp[] = { "uart1_route_io_usb1grp" }; +static const char * const + uart1_route_io_usb1grp[] = { "uart1_route_io_usb1grp" }; static const char * const pulse_countgrp[] = { "pulse_countgrp" }; +static const char * const i2smclkgrp[] = { "i2smclkgrp" }; +static const char * const i2s_ext_clk_inputgrp[] = { "i2s_ext_clk_inputgrp" }; static const char * const i2sgrp[] = { "i2sgrp" }; static const char * const i2s_no_dingrp[] = { "i2s_no_dingrp" }; static const char * const i2s_6chngrp[] = { "i2s_6chngrp" }; @@ -1038,7 +1073,8 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { uart0_nostreamctrl_padmux), SIRFSOC_PMX_FUNCTION("uart1", uart1grp, uart1_padmux), SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux), - SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux), + SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", + uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux), SIRFSOC_PMX_FUNCTION("usp0", usp0grp, usp0_padmux), SIRFSOC_PMX_FUNCTION("usp0_uart_nostreamctrl", usp0_uart_nostreamctrl_grp, @@ -1068,12 +1104,19 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { SIRFSOC_PMX_FUNCTION("sdmmc2", sdmmc2grp, sdmmc2_padmux), SIRFSOC_PMX_FUNCTION("sdmmc3", sdmmc3grp, sdmmc3_padmux), SIRFSOC_PMX_FUNCTION("sdmmc5", sdmmc5grp, sdmmc5_padmux), - SIRFSOC_PMX_FUNCTION("sdmmc2_nowp", sdmmc2_nowpgrp, sdmmc2_nowp_padmux), - SIRFSOC_PMX_FUNCTION("usb0_upli_drvbus", usb0_upli_drvbusgrp, usb0_upli_drvbus_padmux), - SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux), + SIRFSOC_PMX_FUNCTION("sdmmc2_nowp", + sdmmc2_nowpgrp, sdmmc2_nowp_padmux), + SIRFSOC_PMX_FUNCTION("usb0_upli_drvbus", + usb0_upli_drvbusgrp, usb0_upli_drvbus_padmux), + SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", + usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux), SIRFSOC_PMX_FUNCTION("usb1_dp_dn", usb1_dp_dngrp, usb1_dp_dn_padmux), - SIRFSOC_PMX_FUNCTION("uart1_route_io_usb1", uart1_route_io_usb1grp, uart1_route_io_usb1_padmux), + SIRFSOC_PMX_FUNCTION("uart1_route_io_usb1", + uart1_route_io_usb1grp, uart1_route_io_usb1_padmux), SIRFSOC_PMX_FUNCTION("pulse_count", pulse_countgrp, pulse_count_padmux), + SIRFSOC_PMX_FUNCTION("i2s_mclk", i2smclkgrp, i2s_mclk_padmux), + SIRFSOC_PMX_FUNCTION("i2s_ext_clk_input", i2s_ext_clk_inputgrp, + i2s_ext_clk_input_padmux), SIRFSOC_PMX_FUNCTION("i2s", i2sgrp, i2s_padmux), SIRFSOC_PMX_FUNCTION("i2s_no_din", i2s_no_dingrp, i2s_no_din_padmux), SIRFSOC_PMX_FUNCTION("i2s_6chn", i2s_6chngrp, i2s_6chn_padmux), diff --git a/drivers/pinctrl/sirf/pinctrl-prima2.c b/drivers/pinctrl/sirf/pinctrl-prima2.c index 8aa76f0776d..357678ee28e 100644 --- a/drivers/pinctrl/sirf/pinctrl-prima2.c +++ b/drivers/pinctrl/sirf/pinctrl-prima2.c @@ -135,8 +135,9 @@ static const struct pinctrl_pin_desc sirfsoc_pads[] = { static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = { { .group = 3, - .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | - BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | + .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | + BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | + BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | BIT(17) | BIT(18), }, { .group = 2, @@ -152,14 +153,15 @@ static const struct sirfsoc_padmux lcd_16bits_padmux = { .funcval = 0, }; -static const unsigned lcd_16bits_pins[] = { 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 }; +static const unsigned lcd_16bits_pins[] = { 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 }; static const struct sirfsoc_muxmask lcd_18bits_muxmask[] = { { .group = 3, - .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | - BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | + .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | + BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | + BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | BIT(17) | BIT(18), }, { .group = 2, @@ -178,21 +180,23 @@ static const struct sirfsoc_padmux lcd_18bits_padmux = { .funcval = 0, }; -static const unsigned lcd_18bits_pins[] = { 16, 17, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114}; +static const unsigned lcd_18bits_pins[] = { 16, 17, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114}; static const struct sirfsoc_muxmask lcd_24bits_muxmask[] = { { .group = 3, - .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | - BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | + .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | + BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | + BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | BIT(17) | BIT(18), }, { .group = 2, .mask = BIT(31), }, { .group = 0, - .mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23), + .mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | + BIT(21) | BIT(22) | BIT(23), }, }; @@ -204,14 +208,16 @@ static const struct sirfsoc_padmux lcd_24bits_padmux = { .funcval = 0, }; -static const unsigned lcd_24bits_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 }; +static const unsigned lcd_24bits_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114 }; static const struct sirfsoc_muxmask lcdrom_muxmask[] = { { .group = 3, - .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | - BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | + .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | + BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | + BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | BIT(17) | BIT(18), }, { .group = 2, @@ -230,8 +236,8 @@ static const struct sirfsoc_padmux lcdrom_padmux = { .funcval = BIT(4), }; -static const unsigned lcdrom_pins[] = { 23, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 }; +static const unsigned lcdrom_pins[] = { 23, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 }; static const struct sirfsoc_muxmask uart0_muxmask[] = { { @@ -380,12 +386,44 @@ static const struct sirfsoc_padmux cko1_padmux = { static const unsigned cko1_pins[] = { 42 }; +static const struct sirfsoc_muxmask i2s_mclk_muxmask[] = { + { + .group = 1, + .mask = BIT(10), + }, +}; + +static const struct sirfsoc_padmux i2s_mclk_padmux = { + .muxmask_counts = ARRAY_SIZE(i2s_mclk_muxmask), + .muxmask = i2s_mclk_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, + .funcmask = BIT(3), + .funcval = BIT(3), +}; + +static const unsigned i2s_mclk_pins[] = { 42 }; + +static const struct sirfsoc_muxmask i2s_ext_clk_input_muxmask[] = { + { + .group = 1, + .mask = BIT(19), + }, +}; + +static const struct sirfsoc_padmux i2s_ext_clk_input_padmux = { + .muxmask_counts = ARRAY_SIZE(i2s_ext_clk_input_muxmask), + .muxmask = i2s_ext_clk_input_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, + .funcmask = BIT(2), + .funcval = BIT(2), +}; + +static const unsigned i2s_ext_clk_input_pins[] = { 51 }; + static const struct sirfsoc_muxmask i2s_muxmask[] = { { .group = 1, - .mask = - BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(19) - | BIT(23) | BIT(28), + .mask = BIT(11) | BIT(12) | BIT(13) | BIT(14), }, }; @@ -393,11 +431,42 @@ static const struct sirfsoc_padmux i2s_padmux = { .muxmask_counts = ARRAY_SIZE(i2s_muxmask), .muxmask = i2s_muxmask, .ctrlreg = SIRFSOC_RSC_PIN_MUX, - .funcmask = BIT(3) | BIT(9), - .funcval = BIT(3), }; -static const unsigned i2s_pins[] = { 42, 43, 44, 45, 46, 51, 55, 60 }; +static const unsigned i2s_pins[] = { 43, 44, 45, 46 }; + +static const struct sirfsoc_muxmask i2s_no_din_muxmask[] = { + { + .group = 1, + .mask = BIT(11) | BIT(12) | BIT(14), + }, +}; + +static const struct sirfsoc_padmux i2s_no_din_padmux = { + .muxmask_counts = ARRAY_SIZE(i2s_no_din_muxmask), + .muxmask = i2s_no_din_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, +}; + +static const unsigned i2s_no_din_pins[] = { 43, 44, 46 }; + +static const struct sirfsoc_muxmask i2s_6chn_muxmask[] = { + { + .group = 1, + .mask = BIT(11) | BIT(12) | BIT(13) | BIT(14) + | BIT(23) | BIT(28), + }, +}; + +static const struct sirfsoc_padmux i2s_6chn_padmux = { + .muxmask_counts = ARRAY_SIZE(i2s_6chn_muxmask), + .muxmask = i2s_6chn_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, + .funcmask = BIT(1) | BIT(9), + .funcval = BIT(1) | BIT(9), +}; + +static const unsigned i2s_6chn_pins[] = { 43, 44, 45, 46, 55, 60 }; static const struct sirfsoc_muxmask ac97_muxmask[] = { { @@ -685,7 +754,8 @@ static const struct sirfsoc_padmux vip_padmux = { .funcval = 0, }; -static const unsigned vip_pins[] = { 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 }; +static const unsigned vip_pins[] = { 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89 }; static const struct sirfsoc_muxmask i2c0_muxmask[] = { { @@ -735,7 +805,8 @@ static const struct sirfsoc_padmux viprom_padmux = { .funcval = BIT(0), }; -static const unsigned viprom_pins[] = { 12, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 }; +static const unsigned viprom_pins[] = { 12, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89 }; static const struct sirfsoc_muxmask pwm0_muxmask[] = { { @@ -918,7 +989,11 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("usb1_dp_dngrp", usb1_dp_dn_pins), SIRFSOC_PIN_GROUP("uart1_route_io_usb1grp", uart1_route_io_usb1_pins), SIRFSOC_PIN_GROUP("pulse_countgrp", pulse_count_pins), + SIRFSOC_PIN_GROUP("i2smclkgrp", i2s_mclk_pins), + SIRFSOC_PIN_GROUP("i2s_ext_clk_inputgrp", i2s_ext_clk_input_pins), SIRFSOC_PIN_GROUP("i2sgrp", i2s_pins), + SIRFSOC_PIN_GROUP("i2s_no_dingrp", i2s_no_din_pins), + SIRFSOC_PIN_GROUP("i2s_6chngrp", i2s_6chn_pins), SIRFSOC_PIN_GROUP("ac97grp", ac97_pins), SIRFSOC_PIN_GROUP("nandgrp", nand_pins), SIRFSOC_PIN_GROUP("spi0grp", spi0_pins), @@ -936,16 +1011,19 @@ static const char * const uart1grp[] = { "uart1grp" }; static const char * const uart2grp[] = { "uart2grp" }; static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" }; static const char * const usp0grp[] = { "usp0grp" }; -static const char * const usp0_uart_nostreamctrl_grp[] = - { "usp0_uart_nostreamctrl_grp" }; +static const char * const usp0_uart_nostreamctrl_grp[] = { + "usp0_uart_nostreamctrl_grp" +}; static const char * const usp0_only_utfs_grp[] = { "usp0_only_utfs_grp" }; static const char * const usp0_only_urfs_grp[] = { "usp0_only_urfs_grp" }; static const char * const usp1grp[] = { "usp1grp" }; -static const char * const usp1_uart_nostreamctrl_grp[] = - { "usp1_uart_nostreamctrl_grp" }; +static const char * const usp1_uart_nostreamctrl_grp[] = { + "usp1_uart_nostreamctrl_grp" +}; static const char * const usp2grp[] = { "usp2grp" }; -static const char * const usp2_uart_nostreamctrl_grp[] = - { "usp2_uart_nostreamctrl_grp" }; +static const char * const usp2_uart_nostreamctrl_grp[] = { + "usp2_uart_nostreamctrl_grp" +}; static const char * const i2c0grp[] = { "i2c0grp" }; static const char * const i2c1grp[] = { "i2c1grp" }; static const char * const pwm0grp[] = { "pwm0grp" }; @@ -966,9 +1044,14 @@ static const char * const sdmmc5grp[] = { "sdmmc5grp" }; static const char * const usb0_utmi_drvbusgrp[] = { "usb0_utmi_drvbusgrp" }; static const char * const usb1_utmi_drvbusgrp[] = { "usb1_utmi_drvbusgrp" }; static const char * const usb1_dp_dngrp[] = { "usb1_dp_dngrp" }; -static const char * const uart1_route_io_usb1grp[] = { "uart1_route_io_usb1grp" }; +static const char * const + uart1_route_io_usb1grp[] = { "uart1_route_io_usb1grp" }; static const char * const pulse_countgrp[] = { "pulse_countgrp" }; +static const char * const i2smclkgrp[] = { "i2smclkgrp" }; +static const char * const i2s_ext_clk_inputgrp[] = { "i2s_ext_clk_inputgrp" }; static const char * const i2sgrp[] = { "i2sgrp" }; +static const char * const i2s_no_dingrp[] = { "i2s_no_dingrp" }; +static const char * const i2s_6chngrp[] = { "i2s_6chngrp" }; static const char * const ac97grp[] = { "ac97grp" }; static const char * const nandgrp[] = { "nandgrp" }; static const char * const spi0grp[] = { "spi0grp" }; @@ -981,15 +1064,19 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { SIRFSOC_PMX_FUNCTION("lcd_24bits", lcd_24bitsgrp, lcd_24bits_padmux), SIRFSOC_PMX_FUNCTION("lcdrom", lcdromgrp, lcdrom_padmux), SIRFSOC_PMX_FUNCTION("uart0", uart0grp, uart0_padmux), - SIRFSOC_PMX_FUNCTION("uart0_nostreamctrl", uart0_nostreamctrlgrp, uart0_nostreamctrl_padmux), + SIRFSOC_PMX_FUNCTION("uart0_nostreamctrl", + uart0_nostreamctrlgrp, uart0_nostreamctrl_padmux), SIRFSOC_PMX_FUNCTION("uart1", uart1grp, uart1_padmux), SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux), - SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux), + SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", + uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux), SIRFSOC_PMX_FUNCTION("usp0", usp0grp, usp0_padmux), SIRFSOC_PMX_FUNCTION("usp0_uart_nostreamctrl", usp0_uart_nostreamctrl_grp, usp0_uart_nostreamctrl_padmux), - SIRFSOC_PMX_FUNCTION("usp0_only_utfs", usp0_only_utfs_grp, usp0_only_utfs_padmux), - SIRFSOC_PMX_FUNCTION("usp0_only_urfs", usp0_only_urfs_grp, usp0_only_urfs_padmux), + SIRFSOC_PMX_FUNCTION("usp0_only_utfs", + usp0_only_utfs_grp, usp0_only_utfs_padmux), + SIRFSOC_PMX_FUNCTION("usp0_only_urfs", + usp0_only_urfs_grp, usp0_only_urfs_padmux), SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux), SIRFSOC_PMX_FUNCTION("usp1_uart_nostreamctrl", usp1_uart_nostreamctrl_grp, usp1_uart_nostreamctrl_padmux), @@ -1013,12 +1100,20 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { SIRFSOC_PMX_FUNCTION("sdmmc3", sdmmc3grp, sdmmc3_padmux), SIRFSOC_PMX_FUNCTION("sdmmc4", sdmmc4grp, sdmmc4_padmux), SIRFSOC_PMX_FUNCTION("sdmmc5", sdmmc5grp, sdmmc5_padmux), - SIRFSOC_PMX_FUNCTION("usb0_utmi_drvbus", usb0_utmi_drvbusgrp, usb0_utmi_drvbus_padmux), - SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux), + SIRFSOC_PMX_FUNCTION("usb0_utmi_drvbus", + usb0_utmi_drvbusgrp, usb0_utmi_drvbus_padmux), + SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", + usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux), SIRFSOC_PMX_FUNCTION("usb1_dp_dn", usb1_dp_dngrp, usb1_dp_dn_padmux), - SIRFSOC_PMX_FUNCTION("uart1_route_io_usb1", uart1_route_io_usb1grp, uart1_route_io_usb1_padmux), + SIRFSOC_PMX_FUNCTION("uart1_route_io_usb1", + uart1_route_io_usb1grp, uart1_route_io_usb1_padmux), SIRFSOC_PMX_FUNCTION("pulse_count", pulse_countgrp, pulse_count_padmux), + SIRFSOC_PMX_FUNCTION("i2s_mclk", i2smclkgrp, i2s_mclk_padmux), + SIRFSOC_PMX_FUNCTION("i2s_ext_clk_input", i2s_ext_clk_inputgrp, + i2s_ext_clk_input_padmux), SIRFSOC_PMX_FUNCTION("i2s", i2sgrp, i2s_padmux), + SIRFSOC_PMX_FUNCTION("i2s_no_din", i2s_no_dingrp, i2s_no_din_padmux), + SIRFSOC_PMX_FUNCTION("i2s_6chn", i2s_6chngrp, i2s_6chn_padmux), SIRFSOC_PMX_FUNCTION("ac97", ac97grp, ac97_padmux), SIRFSOC_PMX_FUNCTION("nand", nandgrp, nand_padmux), SIRFSOC_PMX_FUNCTION("spi0", spi0grp, spi0_padmux), diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 4c1d7c68666..b713bd59ffb 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -58,17 +58,18 @@ static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev, return sirfsoc_pin_groups[selector].name; } -static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, - const unsigned **pins, - unsigned *num_pins) +static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, + const unsigned **pins, + unsigned *num_pins) { *pins = sirfsoc_pin_groups[selector].pins; *num_pins = sirfsoc_pin_groups[selector].num_pins; return 0; } -static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, - unsigned offset) +static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned offset) { seq_printf(s, " " DRIVER_NAME); } @@ -138,22 +139,25 @@ static struct pinctrl_ops sirfsoc_pctrl_ops = { static struct sirfsoc_pmx_func *sirfsoc_pmx_functions; static int sirfsoc_pmxfunc_cnt; -static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector, - bool enable) +static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, + unsigned selector, bool enable) { int i; - const struct sirfsoc_padmux *mux = sirfsoc_pmx_functions[selector].padmux; + const struct sirfsoc_padmux *mux = + sirfsoc_pmx_functions[selector].padmux; const struct sirfsoc_muxmask *mask = mux->muxmask; for (i = 0; i < mux->muxmask_counts; i++) { u32 muxval; if (!spmx->is_marco) { - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + muxval = readl(spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(mask[i].group)); if (enable) muxval = muxval & ~mask[i].mask; else muxval = muxval | mask[i].mask; - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + writel(muxval, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(mask[i].group)); } else { if (enable) writel(mask[i].mask, spmx->gpio_virtbase + @@ -175,8 +179,9 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector } } -static int sirfsoc_pinmux_enable(struct pinctrl_dev *pmxdev, unsigned selector, - unsigned group) +static int sirfsoc_pinmux_set_mux(struct pinctrl_dev *pmxdev, + unsigned selector, + unsigned group) { struct sirfsoc_pmx *spmx; @@ -197,9 +202,10 @@ static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev, return sirfsoc_pmx_functions[selector].name; } -static int sirfsoc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector, - const char * const **groups, - unsigned * const num_groups) +static int sirfsoc_pinmux_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) { *groups = sirfsoc_pmx_functions[selector].groups; *num_groups = sirfsoc_pmx_functions[selector].num_groups; @@ -218,9 +224,11 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, spmx = pinctrl_dev_get_drvdata(pmxdev); if (!spmx->is_marco) { - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + muxval = readl(spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(group)); muxval = muxval | (1 << (offset - range->pin_base)); - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + writel(muxval, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(group)); } else { writel(1 << (offset - range->pin_base), spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); @@ -230,7 +238,7 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, } static struct pinmux_ops sirfsoc_pinmux_ops = { - .enable = sirfsoc_pinmux_enable, + .set_mux = sirfsoc_pinmux_set_mux, .get_functions_count = sirfsoc_pinmux_get_funcs_count, .get_function_name = sirfsoc_pinmux_get_func_name, .get_function_groups = sirfsoc_pinmux_get_groups, @@ -518,24 +526,29 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) case IRQ_TYPE_NONE: break; case IRQ_TYPE_EDGE_RISING: - val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; + val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | + SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; val &= ~SIRFSOC_GPIO_CTL_INTR_LOW_MASK; break; case IRQ_TYPE_EDGE_FALLING: val &= ~SIRFSOC_GPIO_CTL_INTR_HIGH_MASK; - val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; + val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK | + SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; break; case IRQ_TYPE_EDGE_BOTH: - val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_LOW_MASK | - SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; + val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | + SIRFSOC_GPIO_CTL_INTR_LOW_MASK | + SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; break; case IRQ_TYPE_LEVEL_LOW: - val &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); + val &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | + SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK; break; case IRQ_TYPE_LEVEL_HIGH: val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK; - val &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); + val &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | + SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); break; } @@ -694,7 +707,8 @@ static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_chip *sgpio, spin_unlock_irqrestore(&bank->lock, flags); } -static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) +static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, + unsigned gpio, int value) { struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip); struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, gpio); @@ -839,7 +853,7 @@ static int sirfsoc_gpio_probe(struct device_node *np) if (err) { dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); - goto out; + goto out_banks; } for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { @@ -898,8 +912,8 @@ static int __init sirfsoc_gpio_init(void) } subsys_initcall(sirfsoc_gpio_init); -MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, " - "Yuping Luo <yuping.luo@csr.com>, " - "Barry Song <baohua.song@csr.com>"); +MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>"); +MODULE_AUTHOR("Yuping Luo <yuping.luo@csr.com>"); +MODULE_AUTHOR("Barry Song <baohua.song@csr.com>"); MODULE_DESCRIPTION("SIRFSOC pin control driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index f72cc4e192b..abdb05ac43d 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -268,7 +268,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, return 0; } -static int spear_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function, +static int spear_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned function, unsigned group) { return spear_pinctrl_endisable(pctldev, function, group, true); @@ -338,7 +338,7 @@ static const struct pinmux_ops spear_pinmux_ops = { .get_functions_count = spear_pinctrl_get_funcs_count, .get_function_name = spear_pinctrl_get_func_name, .get_function_groups = spear_pinctrl_get_func_groups, - .enable = spear_pinctrl_enable, + .set_mux = spear_pinctrl_set_mux, .gpio_request_enable = gpio_request_enable, .gpio_disable_free = gpio_disable_free, }; diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c index 1a8bbfec60c..6d57d43ab64 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1310.c +++ b/drivers/pinctrl/spear/pinctrl-spear1310.c @@ -2692,7 +2692,7 @@ static struct spear_pinctrl_machdata spear1310_machdata = { .modes_supported = false, }; -static struct of_device_id spear1310_pinctrl_of_match[] = { +static const struct of_device_id spear1310_pinctrl_of_match[] = { { .compatible = "st,spear1310-pinmux", }, diff --git a/drivers/pinctrl/spear/pinctrl-spear1340.c b/drivers/pinctrl/spear/pinctrl-spear1340.c index 873966e2b99..d243e43e7f6 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1340.c +++ b/drivers/pinctrl/spear/pinctrl-spear1340.c @@ -2008,7 +2008,7 @@ static struct spear_pinctrl_machdata spear1340_machdata = { .modes_supported = false, }; -static struct of_device_id spear1340_pinctrl_of_match[] = { +static const struct of_device_id spear1340_pinctrl_of_match[] = { { .compatible = "st,spear1340-pinmux", }, diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c index 4777c0d0e73..9db83e9ee18 100644 --- a/drivers/pinctrl/spear/pinctrl-spear300.c +++ b/drivers/pinctrl/spear/pinctrl-spear300.c @@ -646,7 +646,7 @@ static struct spear_function *spear300_functions[] = { &gpio1_function, }; -static struct of_device_id spear300_pinctrl_of_match[] = { +static const struct of_device_id spear300_pinctrl_of_match[] = { { .compatible = "st,spear300-pinmux", }, diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c index ed1d3608f48..db775a414b7 100644 --- a/drivers/pinctrl/spear/pinctrl-spear310.c +++ b/drivers/pinctrl/spear/pinctrl-spear310.c @@ -371,7 +371,7 @@ static struct spear_function *spear310_functions[] = { &tdm_function, }; -static struct of_device_id spear310_pinctrl_of_match[] = { +static const struct of_device_id spear310_pinctrl_of_match[] = { { .compatible = "st,spear310-pinmux", }, diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c index b8e290a8c8c..80fbd68e17b 100644 --- a/drivers/pinctrl/spear/pinctrl-spear320.c +++ b/drivers/pinctrl/spear/pinctrl-spear320.c @@ -3410,7 +3410,7 @@ static struct spear_function *spear320_functions[] = { &i2c2_function, }; -static struct of_device_id spear320_pinctrl_of_match[] = { +static const struct of_device_id spear320_pinctrl_of_match[] = { { .compatible = "st,spear320-pinmux", }, diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 3df66e366c8..ef9d804e55d 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -393,9 +393,9 @@ static void sunxi_pmx_set(struct pinctrl_dev *pctldev, spin_unlock_irqrestore(&pctl->lock, flags); } -static int sunxi_pmx_enable(struct pinctrl_dev *pctldev, - unsigned function, - unsigned group) +static int sunxi_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) { struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct sunxi_pinctrl_group *g = pctl->groups + group; @@ -441,7 +441,7 @@ static const struct pinmux_ops sunxi_pmx_ops = { .get_functions_count = sunxi_pmx_get_funcs_cnt, .get_function_name = sunxi_pmx_get_func_name, .get_function_groups = sunxi_pmx_get_func_groups, - .enable = sunxi_pmx_enable, + .set_mux = sunxi_pmx_set_mux, .gpio_set_direction = sunxi_pmx_gpio_set_direction, }; diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c index 8cea355f9a8..d055d63309e 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wmt.c +++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c @@ -131,9 +131,9 @@ static int wmt_set_pinmux(struct wmt_pinctrl_data *data, unsigned func, return 0; } -static int wmt_pmx_enable(struct pinctrl_dev *pctldev, - unsigned func_selector, - unsigned group_selector) +static int wmt_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned func_selector, + unsigned group_selector) { struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); u32 pinnum = data->pins[group_selector].number; @@ -168,7 +168,7 @@ static struct pinmux_ops wmt_pinmux_ops = { .get_functions_count = wmt_pmx_get_functions_count, .get_function_name = wmt_pmx_get_function_name, .get_function_groups = wmt_pmx_get_function_groups, - .enable = wmt_pmx_enable, + .set_mux = wmt_pmx_set_mux, .gpio_disable_free = wmt_pmx_gpio_disable_free, .gpio_set_direction = wmt_pmx_gpio_set_direction, }; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 2dc8289e5db..55d7b7b0f2e 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -199,13 +199,14 @@ config REGULATOR_DA9210 interface. config REGULATOR_DA9211 - tristate "Dialog Semiconductor DA9211/DA9212 regulator" + tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214 regulator" depends on I2C select REGMAP_I2C help - Say y here to support for the Dialog Semiconductor DA9211/DA9212. - The DA9211/DA9212 is a multi-phase synchronous step down - converter 12A DC-DC Buck controlled through an I2C + Say y here to support for the Dialog Semiconductor DA9211/DA9212 + /DA9213/DA9214. + The DA9211/DA9212/DA9213/DA9214 is a multi-phase synchronous + step down converter 12A or 16A DC-DC Buck controlled through an I2C interface. config REGULATOR_DBX500_PRCMU @@ -240,6 +241,23 @@ config REGULATOR_GPIO and the platform has to provide a mapping of GPIO-states to target volts/amps. +config REGULATOR_HI6421 + tristate "HiSilicon Hi6421 PMIC voltage regulator support" + depends on MFD_HI6421_PMIC && OF + help + This driver provides support for the voltage regulators on the + HiSilicon Hi6421 PMU / Codec IC. + Hi6421 is a multi-function device which, on regulator part, provides + 21 general purpose LDOs, 3 dedicated LDOs, and 5 BUCKs. All + of them come with support to either ECO (idle) or sleep mode. + +config REGULATOR_ISL9305 + tristate "Intersil ISL9305 regulator" + depends on I2C + select REGMAP_I2C + help + This driver supports ISL9305 voltage regulator chip. + config REGULATOR_ISL6271A tristate "Intersil ISL6271A Power regulator" depends on I2C @@ -387,6 +405,15 @@ config REGULATOR_MAX77693 and one current regulator 'CHARGER'. This is suitable for Exynos-4x12 chips. +config REGULATOR_MAX77802 + tristate "Maxim 77802 regulator" + depends on MFD_MAX77686 + help + This driver controls a Maxim 77802 regulator + via I2C bus. The provided regulator is suitable for + Exynos5420/Exynos5800 SoCs to control various voltages. + It includes support for control of voltage and ramp speed. + config REGULATOR_MC13XXX_CORE tristate @@ -449,6 +476,25 @@ config REGULATOR_PFUZE100 Say y here to support the regulators found on the Freescale PFUZE100/PFUZE200 PMIC. +config REGULATOR_PWM + tristate "PWM voltage regulator" + depends on PWM + help + This driver supports PWM controlled voltage regulators. PWM + duty cycle can increase or decrease the voltage. + +config REGULATOR_QCOM_RPM + tristate "Qualcomm RPM regulator driver" + depends on MFD_QCOM_RPM + help + If you say yes to this option, support will be included for the + regulators exposed by the Resource Power Manager found in Qualcomm + 8660, 8960 and 8064 based devices. + + Say M here if you want to include support for the regulators on the + Qualcomm RPM as a module. The module will be named + "qcom_rpm-regulator". + config REGULATOR_RC5T583 tristate "RICOH RC5T583 Power regulators" depends on MFD_RC5T583 @@ -459,6 +505,22 @@ config REGULATOR_RC5T583 through regulator interface. The device supports multiple DCDC/LDO outputs which can be controlled by i2c communication. +config REGULATOR_RK808 + tristate "Rockchip RK808 Power regulators" + depends on MFD_RK808 + help + Select this option to enable the power regulator of ROCKCHIP + PMIC RK808. + This driver supports the control of different power rails of device + through regulator interface. The device supports multiple DCDC/LDO + outputs which can be controlled by i2c communication. + +config REGULATOR_RN5T618 + tristate "Ricoh RN5T618 voltage regulators" + depends on MFD_RN5T618 + help + Say y here to support the regulators found on Ricoh RN5T618 PMIC. + config REGULATOR_S2MPA01 tristate "Samsung S2MPA01 voltage regulator" depends on MFD_SEC_CORE @@ -483,11 +545,16 @@ config REGULATOR_S5M8767 via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and supports DVS mode with 8bits of output voltage control. -config REGULATOR_ST_PWM - tristate "STMicroelectronics PWM voltage regulator" - depends on ARCH_STI +config REGULATOR_SKY81452 + tristate "Skyworks Solutions SKY81452 voltage regulator" + depends on SKY81452 help - This driver supports ST's PWM controlled voltage regulators. + This driver supports Skyworks SKY81452 voltage output regulator + via I2C bus. SKY81452 has one voltage linear regulator can be + programmed from 4.5V to 20V. + + This driver can also be built as a module. If so, the module + will be called sky81452-regulator. config REGULATOR_TI_ABB tristate "TI Adaptive Body Bias on-chip LDO" diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index aa4a6aa7b55..1029ed39c51 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -32,7 +32,9 @@ obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o +obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o +obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o @@ -52,20 +54,25 @@ obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o +obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o +obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o +obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o +obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o +obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o -obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o +obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index b47283f91e2..8459b0b648c 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -22,12 +22,10 @@ struct as3711_regulator_info { struct regulator_desc desc; - unsigned int max_uV; }; struct as3711_regulator { struct as3711_regulator_info *reg_info; - struct regulator_dev *rdev; }; /* @@ -132,39 +130,37 @@ static const struct regulator_linear_range as3711_dldo_ranges[] = { REGULATOR_LINEAR_RANGE(1750000, 0x20, 0x3f, 50000), }; -#define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx) \ - [AS3711_REGULATOR_ ## _id] = { \ - .desc = { \ - .name = "as3711-regulator-" # _id, \ - .id = AS3711_REGULATOR_ ## _id, \ - .n_voltages = (_vmask + 1), \ - .ops = &as3711_ ## _sfx ## _ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .vsel_reg = AS3711_ ## _id ## _VOLTAGE, \ - .vsel_mask = _vmask << _vshift, \ - .enable_reg = AS3711_ ## _en_reg, \ - .enable_mask = BIT(_en_bit), \ - .min_uV = _min_uV, \ - .linear_ranges = as3711_ ## _sfx ## _ranges, \ - .n_linear_ranges = ARRAY_SIZE(as3711_ ## _sfx ## _ranges), \ - }, \ - .max_uV = _max_uV, \ +#define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _sfx) \ + [AS3711_REGULATOR_ ## _id] = { \ + .desc = { \ + .name = "as3711-regulator-" # _id, \ + .id = AS3711_REGULATOR_ ## _id, \ + .n_voltages = (_vmask + 1), \ + .ops = &as3711_ ## _sfx ## _ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = AS3711_ ## _id ## _VOLTAGE, \ + .vsel_mask = _vmask, \ + .enable_reg = AS3711_ ## _en_reg, \ + .enable_mask = BIT(_en_bit), \ + .linear_ranges = as3711_ ## _sfx ## _ranges, \ + .n_linear_ranges = ARRAY_SIZE(as3711_ ## _sfx ## _ranges), \ + }, \ } static struct as3711_regulator_info as3711_reg_info[] = { - AS3711_REG(SD_1, SD_CONTROL, 0, 0x7f, 0, 612500, 3350000, sd), - AS3711_REG(SD_2, SD_CONTROL, 1, 0x7f, 0, 612500, 3350000, sd), - AS3711_REG(SD_3, SD_CONTROL, 2, 0x7f, 0, 612500, 3350000, sd), - AS3711_REG(SD_4, SD_CONTROL, 3, 0x7f, 0, 612500, 3350000, sd), - AS3711_REG(LDO_1, LDO_1_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo), - AS3711_REG(LDO_2, LDO_2_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo), - AS3711_REG(LDO_3, LDO_3_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), - AS3711_REG(LDO_4, LDO_4_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), - AS3711_REG(LDO_5, LDO_5_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), - AS3711_REG(LDO_6, LDO_6_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), - AS3711_REG(LDO_7, LDO_7_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), - AS3711_REG(LDO_8, LDO_8_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(SD_1, SD_CONTROL, 0, 0x7f, sd), + AS3711_REG(SD_2, SD_CONTROL, 1, 0x7f, sd), + AS3711_REG(SD_3, SD_CONTROL, 2, 0x7f, sd), + AS3711_REG(SD_4, SD_CONTROL, 3, 0x7f, sd), + AS3711_REG(LDO_1, LDO_1_VOLTAGE, 7, 0x1f, aldo), + AS3711_REG(LDO_2, LDO_2_VOLTAGE, 7, 0x1f, aldo), + AS3711_REG(LDO_3, LDO_3_VOLTAGE, 7, 0x3f, dldo), + AS3711_REG(LDO_4, LDO_4_VOLTAGE, 7, 0x3f, dldo), + AS3711_REG(LDO_5, LDO_5_VOLTAGE, 7, 0x3f, dldo), + AS3711_REG(LDO_6, LDO_6_VOLTAGE, 7, 0x3f, dldo), + AS3711_REG(LDO_7, LDO_7_VOLTAGE, 7, 0x3f, dldo), + AS3711_REG(LDO_8, LDO_8_VOLTAGE, 7, 0x3f, dldo), /* StepUp output voltage depends on supplying regulator */ }; @@ -263,7 +259,6 @@ static int as3711_regulator_probe(struct platform_device *pdev) ri->desc.name); return PTR_ERR(rdev); } - reg->rdev = rdev; } platform_set_drvdata(pdev, regs); return 0; diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 004aadb7bcc..2e1010a34dd 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -245,7 +245,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) for (i = 0; i < AXP20X_REG_ID_MAX; i++) { init_data = axp20x_matches[i].init_data; - config.dev = &pdev->dev; + config.dev = pdev->dev.parent; config.init_data = init_data; config.regmap = axp20x->regmap; config.of_node = axp20x_matches[i].of_node; diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index 5d1fd6f3d10..fe6ac69549a 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -202,7 +202,6 @@ static struct bcm590xx_info bcm590xx_regs[] = { struct bcm590xx_reg { struct regulator_desc *desc; struct bcm590xx *mfd; - struct bcm590xx_info **info; }; static int bcm590xx_get_vsel_register(int id) @@ -389,11 +388,6 @@ static int bcm590xx_probe(struct platform_device *pdev) if (!pmu->desc) return -ENOMEM; - pmu->info = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * - sizeof(struct bcm590xx_info *), GFP_KERNEL); - if (!pmu->info) - return -ENOMEM; - info = bcm590xx_regs; for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) { @@ -403,8 +397,6 @@ static int bcm590xx_probe(struct platform_device *pdev) reg_data = NULL; /* Register the regulators */ - pmu->info[i] = info; - pmu->desc[i].name = info->name; pmu->desc[i].supply_name = info->vin_name; pmu->desc[i].id = i; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a3c3785901f..cd87c0c3703 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -102,7 +102,7 @@ static int _regulator_disable(struct regulator_dev *rdev); static int _regulator_get_voltage(struct regulator_dev *rdev); static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); -static void _notifier_call_chain(struct regulator_dev *rdev, +static int _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data); static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV); @@ -839,7 +839,7 @@ static void print_constraints(struct regulator_dev *rdev) static int machine_constraints_voltage(struct regulator_dev *rdev, struct regulation_constraints *constraints) { - struct regulator_ops *ops = rdev->desc->ops; + const struct regulator_ops *ops = rdev->desc->ops; int ret; /* do we need to apply the constraint voltage */ @@ -938,7 +938,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, static int machine_constraints_current(struct regulator_dev *rdev, struct regulation_constraints *constraints) { - struct regulator_ops *ops = rdev->desc->ops; + const struct regulator_ops *ops = rdev->desc->ops; int ret; if (!constraints->min_uA && !constraints->max_uA) @@ -982,7 +982,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, const struct regulation_constraints *constraints) { int ret = 0; - struct regulator_ops *ops = rdev->desc->ops; + const struct regulator_ops *ops = rdev->desc->ops; if (constraints) rdev->constraints = kmemdup(constraints, sizeof(*constraints), @@ -1759,6 +1759,45 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) return 0; } +/** + * _regulator_enable_delay - a delay helper function + * @delay: time to delay in microseconds + * + * Delay for the requested amount of time as per the guidelines in: + * + * Documentation/timers/timers-howto.txt + * + * The assumption here is that regulators will never be enabled in + * atomic context and therefore sleeping functions can be used. + */ +static void _regulator_enable_delay(unsigned int delay) +{ + unsigned int ms = delay / 1000; + unsigned int us = delay % 1000; + + if (ms > 0) { + /* + * For small enough values, handle super-millisecond + * delays in the usleep_range() call below. + */ + if (ms < 20) + us += ms * 1000; + else + msleep(ms); + } + + /* + * Give the scheduler some room to coalesce with any other + * wakeup sources. For delays shorter than 10 us, don't even + * bother setting up high-resolution timers and just busy- + * loop. + */ + if (us >= 10) + usleep_range(us, us + 100); + else + udelay(us); +} + static int _regulator_do_enable(struct regulator_dev *rdev) { int ret, delay; @@ -1774,6 +1813,31 @@ static int _regulator_do_enable(struct regulator_dev *rdev) trace_regulator_enable(rdev_get_name(rdev)); + if (rdev->desc->off_on_delay) { + /* if needed, keep a distance of off_on_delay from last time + * this regulator was disabled. + */ + unsigned long start_jiffy = jiffies; + unsigned long intended, max_delay, remaining; + + max_delay = usecs_to_jiffies(rdev->desc->off_on_delay); + intended = rdev->last_off_jiffy + max_delay; + + if (time_before(start_jiffy, intended)) { + /* calc remaining jiffies to deal with one-time + * timer wrapping. + * in case of multiple timer wrapping, either it can be + * detected by out-of-range remaining, or it cannot be + * detected and we gets a panelty of + * _regulator_enable_delay(). + */ + remaining = intended - start_jiffy; + if (remaining <= max_delay) + _regulator_enable_delay( + jiffies_to_usecs(remaining)); + } + } + if (rdev->ena_pin) { ret = regulator_ena_gpio_ctrl(rdev, true); if (ret < 0) @@ -1792,40 +1856,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) * together. */ trace_regulator_enable_delay(rdev_get_name(rdev)); - /* - * Delay for the requested amount of time as per the guidelines in: - * - * Documentation/timers/timers-howto.txt - * - * The assumption here is that regulators will never be enabled in - * atomic context and therefore sleeping functions can be used. - */ - if (delay) { - unsigned int ms = delay / 1000; - unsigned int us = delay % 1000; - - if (ms > 0) { - /* - * For small enough values, handle super-millisecond - * delays in the usleep_range() call below. - */ - if (ms < 20) - us += ms * 1000; - else - msleep(ms); - } - - /* - * Give the scheduler some room to coalesce with any other - * wakeup sources. For delays shorter than 10 us, don't even - * bother setting up high-resolution timers and just busy- - * loop. - */ - if (us >= 10) - usleep_range(us, us + 100); - else - udelay(us); - } + _regulator_enable_delay(delay); trace_regulator_enable_complete(rdev_get_name(rdev)); @@ -1919,6 +1950,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev) return ret; } + /* cares about last_off_jiffy only if off_on_delay is required by + * device. + */ + if (rdev->desc->off_on_delay) + rdev->last_off_jiffy = jiffies; + trace_regulator_disable_complete(rdev_get_name(rdev)); return 0; @@ -2208,9 +2245,9 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages); */ int regulator_list_voltage(struct regulator *regulator, unsigned selector) { - struct regulator_dev *rdev = regulator->rdev; - struct regulator_ops *ops = rdev->desc->ops; - int ret; + struct regulator_dev *rdev = regulator->rdev; + const struct regulator_ops *ops = rdev->desc->ops; + int ret; if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) return rdev->desc->fixed_uV; @@ -2270,8 +2307,8 @@ int regulator_get_hardware_vsel_register(struct regulator *regulator, unsigned *vsel_reg, unsigned *vsel_mask) { - struct regulator_dev *rdev = regulator->rdev; - struct regulator_ops *ops = rdev->desc->ops; + struct regulator_dev *rdev = regulator->rdev; + const struct regulator_ops *ops = rdev->desc->ops; if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) return -EOPNOTSUPP; @@ -2297,8 +2334,8 @@ EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register); int regulator_list_hardware_vsel(struct regulator *regulator, unsigned selector) { - struct regulator_dev *rdev = regulator->rdev; - struct regulator_ops *ops = rdev->desc->ops; + struct regulator_dev *rdev = regulator->rdev; + const struct regulator_ops *ops = rdev->desc->ops; if (selector >= rdev->desc->n_voltages) return -EINVAL; @@ -2369,6 +2406,55 @@ int regulator_is_supported_voltage(struct regulator *regulator, } EXPORT_SYMBOL_GPL(regulator_is_supported_voltage); +static int _regulator_call_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned *selector) +{ + struct pre_voltage_change_data data; + int ret; + + data.old_uV = _regulator_get_voltage(rdev); + data.min_uV = min_uV; + data.max_uV = max_uV; + ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, + &data); + if (ret & NOTIFY_STOP_MASK) + return -EINVAL; + + ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, selector); + if (ret >= 0) + return ret; + + _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE, + (void *)data.old_uV); + + return ret; +} + +static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, + int uV, unsigned selector) +{ + struct pre_voltage_change_data data; + int ret; + + data.old_uV = _regulator_get_voltage(rdev); + data.min_uV = uV; + data.max_uV = uV; + ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, + &data); + if (ret & NOTIFY_STOP_MASK) + return -EINVAL; + + ret = rdev->desc->ops->set_voltage_sel(rdev, selector); + if (ret >= 0) + return ret; + + _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE, + (void *)data.old_uV); + + return ret; +} + static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { @@ -2396,8 +2482,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, } if (rdev->desc->ops->set_voltage) { - ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, - &selector); + ret = _regulator_call_set_voltage(rdev, min_uV, max_uV, + &selector); if (ret >= 0) { if (rdev->desc->ops->list_voltage) @@ -2432,8 +2518,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, if (old_selector == selector) ret = 0; else - ret = rdev->desc->ops->set_voltage_sel( - rdev, ret); + ret = _regulator_call_set_voltage_sel( + rdev, best_val, selector); } else { ret = -EINVAL; } @@ -2572,8 +2658,8 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage); int regulator_set_voltage_time(struct regulator *regulator, int old_uV, int new_uV) { - struct regulator_dev *rdev = regulator->rdev; - struct regulator_ops *ops = rdev->desc->ops; + struct regulator_dev *rdev = regulator->rdev; + const struct regulator_ops *ops = rdev->desc->ops; int old_sel = -1; int new_sel = -1; int voltage; @@ -3079,11 +3165,11 @@ EXPORT_SYMBOL_GPL(regulator_unregister_notifier); /* notify regulator consumers and downstream regulator consumers. * Note mutex must be held by caller. */ -static void _notifier_call_chain(struct regulator_dev *rdev, +static int _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data) { /* call rdev chain first */ - blocking_notifier_call_chain(&rdev->notifier, event, data); + return blocking_notifier_call_chain(&rdev->notifier, event, data); } /** @@ -3336,9 +3422,9 @@ EXPORT_SYMBOL_GPL(regulator_mode_to_status); */ static int add_regulator_attributes(struct regulator_dev *rdev) { - struct device *dev = &rdev->dev; - struct regulator_ops *ops = rdev->desc->ops; - int status = 0; + struct device *dev = &rdev->dev; + const struct regulator_ops *ops = rdev->desc->ops; + int status = 0; /* some attributes need specific methods to be displayed */ if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || @@ -3516,12 +3602,17 @@ regulator_register(const struct regulator_desc *regulator_desc, return ERR_PTR(-EINVAL); } - init_data = config->init_data; - rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); if (rdev == NULL) return ERR_PTR(-ENOMEM); + init_data = regulator_of_get_init_data(dev, regulator_desc, + &rdev->dev.of_node); + if (!init_data) { + init_data = config->init_data; + rdev->dev.of_node = of_node_get(config->of_node); + } + mutex_lock(®ulator_list_mutex); mutex_init(&rdev->mutex); @@ -3548,7 +3639,6 @@ regulator_register(const struct regulator_desc *regulator_desc, /* register with sysfs */ rdev->dev.class = ®ulator_class; - rdev->dev.of_node = of_node_get(config->of_node); rdev->dev.parent = dev; dev_set_name(&rdev->dev, "regulator.%d", atomic_inc_return(®ulator_no) - 1); @@ -3905,7 +3995,7 @@ core_initcall(regulator_init); static int __init regulator_init_complete(void) { struct regulator_dev *rdev; - struct regulator_ops *ops; + const struct regulator_ops *ops; struct regulation_constraints *c; int enabled, ret; diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 1482adafa1a..c78d2106d6c 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -1,5 +1,5 @@ /* - * da9211-regulator.c - Regulator device driver for DA9211 + * da9211-regulator.c - Regulator device driver for DA9211/DA9213 * Copyright (C) 2014 Dialog Semiconductor Ltd. * * This library is free software; you can redistribute it and/or @@ -24,9 +24,14 @@ #include <linux/regmap.h> #include <linux/irq.h> #include <linux/interrupt.h> +#include <linux/regulator/of_regulator.h> #include <linux/regulator/da9211.h> #include "da9211-regulator.h" +/* DEVICE IDs */ +#define DA9211_DEVICE_ID 0x22 +#define DA9213_DEVICE_ID 0x23 + #define DA9211_BUCK_MODE_SLEEP 1 #define DA9211_BUCK_MODE_SYNC 2 #define DA9211_BUCK_MODE_AUTO 3 @@ -42,6 +47,7 @@ struct da9211 { struct regulator_dev *rdev[DA9211_MAX_REGULATORS]; int num_regulator; int chip_irq; + int chip_id; }; static const struct regmap_range_cfg da9211_regmap_range[] = { @@ -52,14 +58,14 @@ static const struct regmap_range_cfg da9211_regmap_range[] = { .window_start = 0, .window_len = 256, .range_min = 0, - .range_max = 2*256, + .range_max = 5*128, }, }; static const struct regmap_config da9211_regmap_config = { .reg_bits = 8, .val_bits = 8, - .max_register = 2 * 256, + .max_register = 5 * 128, .ranges = da9211_regmap_range, .num_ranges = ARRAY_SIZE(da9211_regmap_range), }; @@ -69,11 +75,20 @@ static const struct regmap_config da9211_regmap_config = { #define DA9211_MAX_MV 1570 #define DA9211_STEP_MV 10 -/* Current limits for buck (uA) indices corresponds with register values */ +/* Current limits for DA9211 buck (uA) indices + * corresponds with register values + */ static const int da9211_current_limits[] = { 2000000, 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000, 4800000, 5000000 }; +/* Current limits for DA9213 buck (uA) indices + * corresponds with register values + */ +static const int da9213_current_limits[] = { + 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, + 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000 +}; static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev) { @@ -129,12 +144,26 @@ static int da9211_set_current_limit(struct regulator_dev *rdev, int min, { int id = rdev_get_id(rdev); struct da9211 *chip = rdev_get_drvdata(rdev); - int i; + int i, max_size; + const int *current_limits; + + switch (chip->chip_id) { + case DA9211: + current_limits = da9211_current_limits; + max_size = ARRAY_SIZE(da9211_current_limits)-1; + break; + case DA9213: + current_limits = da9213_current_limits; + max_size = ARRAY_SIZE(da9213_current_limits)-1; + break; + default: + return -EINVAL; + } /* search for closest to maximum */ - for (i = ARRAY_SIZE(da9211_current_limits)-1; i >= 0; i--) { - if (min <= da9211_current_limits[i] && - max >= da9211_current_limits[i]) { + for (i = max_size; i >= 0; i--) { + if (min <= current_limits[i] && + max >= current_limits[i]) { return regmap_update_bits(chip->regmap, DA9211_REG_BUCK_ILIM, (0x0F << id*4), (i << id*4)); @@ -150,14 +179,28 @@ static int da9211_get_current_limit(struct regulator_dev *rdev) struct da9211 *chip = rdev_get_drvdata(rdev); unsigned int data; int ret; + const int *current_limits; + + switch (chip->chip_id) { + case DA9211: + current_limits = da9211_current_limits; + break; + case DA9213: + current_limits = da9213_current_limits; + break; + default: + return -EINVAL; + } ret = regmap_read(chip->regmap, DA9211_REG_BUCK_ILIM, &data); if (ret < 0) return ret; - /* select one of 16 values: 0000 (2000mA) to 1111 (5000mA) */ + /* select one of 16 values: 0000 (2000mA or 3000mA) + * to 1111 (5000mA or 6000mA). + */ data = (data >> id*4) & 0x0F; - return da9211_current_limits[data]; + return current_limits[data]; } static struct regulator_ops da9211_buck_ops = { @@ -194,6 +237,59 @@ static struct regulator_desc da9211_regulators[] = { DA9211_BUCK(BUCKB), }; +#ifdef CONFIG_OF +static struct of_regulator_match da9211_matches[] = { + [DA9211_ID_BUCKA] = { .name = "BUCKA" }, + [DA9211_ID_BUCKB] = { .name = "BUCKB" }, + }; + +static struct da9211_pdata *da9211_parse_regulators_dt( + struct device *dev) +{ + struct da9211_pdata *pdata; + struct device_node *node; + int i, num, n; + + node = of_get_child_by_name(dev->of_node, "regulators"); + if (!node) { + dev_err(dev, "regulators node not found\n"); + return ERR_PTR(-ENODEV); + } + + num = of_regulator_match(dev, node, da9211_matches, + ARRAY_SIZE(da9211_matches)); + of_node_put(node); + if (num < 0) { + dev_err(dev, "Failed to match regulators\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->num_buck = num; + + n = 0; + for (i = 0; i < ARRAY_SIZE(da9211_matches); i++) { + if (!da9211_matches[i].init_data) + continue; + + pdata->init_data[n] = da9211_matches[i].init_data; + + n++; + } + + return pdata; +} +#else +static struct da9211_pdata *da9211_parse_regulators_dt( + struct device *dev) +{ + return ERR_PTR(-ENODEV); +} +#endif + static irqreturn_t da9211_irq_handler(int irq, void *data) { struct da9211 *chip = data; @@ -264,13 +360,11 @@ static int da9211_regulator_init(struct da9211 *chip) } for (i = 0; i < chip->num_regulator; i++) { - if (chip->pdata) - config.init_data = - &(chip->pdata->init_data[i]); - + config.init_data = chip->pdata->init_data[i]; config.dev = chip->dev; config.driver_data = chip; config.regmap = chip->regmap; + config.of_node = chip->dev->of_node; chip->rdev[i] = devm_regulator_register(chip->dev, &da9211_regulators[i], &config); @@ -282,7 +376,7 @@ static int da9211_regulator_init(struct da9211 *chip) if (chip->chip_irq != 0) { ret = regmap_update_bits(chip->regmap, - DA9211_REG_MASK_B, DA9211_M_OV_CURR_A << i, 1); + DA9211_REG_MASK_B, DA9211_M_OV_CURR_A << i, 0); if (ret < 0) { dev_err(chip->dev, "Failed to update mask reg: %d\n", ret); @@ -293,6 +387,7 @@ static int da9211_regulator_init(struct da9211 *chip) return 0; } + /* * I2C driver interface functions */ @@ -301,14 +396,17 @@ static int da9211_i2c_probe(struct i2c_client *i2c, { struct da9211 *chip; int error, ret; + unsigned int data; chip = devm_kzalloc(&i2c->dev, sizeof(struct da9211), GFP_KERNEL); + if (!chip) + return -ENOMEM; chip->dev = &i2c->dev; chip->regmap = devm_regmap_init_i2c(i2c, &da9211_regmap_config); if (IS_ERR(chip->regmap)) { error = PTR_ERR(chip->regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + dev_err(chip->dev, "Failed to allocate register map: %d\n", error); return error; } @@ -316,11 +414,33 @@ static int da9211_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, chip); chip->pdata = i2c->dev.platform_data; - if (!chip->pdata) { - dev_err(&i2c->dev, "No platform init data supplied\n"); + + ret = regmap_read(chip->regmap, DA9211_REG_DEVICE_ID, &data); + if (ret < 0) { + dev_err(chip->dev, "Failed to read DEVICE_ID reg: %d\n", ret); + return ret; + } + + switch (data) { + case DA9211_DEVICE_ID: + chip->chip_id = DA9211; + break; + case DA9213_DEVICE_ID: + chip->chip_id = DA9213; + break; + default: + dev_err(chip->dev, "Unsupported device id = 0x%x.\n", data); return -ENODEV; } + if (!chip->pdata) + chip->pdata = da9211_parse_regulators_dt(chip->dev); + + if (IS_ERR(chip->pdata)) { + dev_err(chip->dev, "No regulators defined for the platform\n"); + return PTR_ERR(chip->pdata); + } + chip->chip_irq = i2c->irq; if (chip->chip_irq != 0) { @@ -340,22 +460,32 @@ static int da9211_i2c_probe(struct i2c_client *i2c, ret = da9211_regulator_init(chip); if (ret < 0) - dev_err(&i2c->dev, "Failed to initialize regulator: %d\n", ret); + dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret); return ret; } static const struct i2c_device_id da9211_i2c_id[] = { - {"da9211", 0}, + {"da9211", DA9211}, + {"da9213", DA9213}, {}, }; - MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); +#ifdef CONFIG_OF +static const struct of_device_id da9211_dt_ids[] = { + { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, + { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] }, + {}, +}; +MODULE_DEVICE_TABLE(of, da9211_dt_ids); +#endif + static struct i2c_driver da9211_regulator_driver = { .driver = { .name = "da9211", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(da9211_dt_ids), }, .probe = da9211_i2c_probe, .id_table = da9211_i2c_id, @@ -364,5 +494,5 @@ static struct i2c_driver da9211_regulator_driver = { module_i2c_driver(da9211_regulator_driver); MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); -MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211"); +MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h index 88b1769e805..93fa9df2721 100644 --- a/drivers/regulator/da9211-regulator.h +++ b/drivers/regulator/da9211-regulator.h @@ -1,5 +1,5 @@ /* - * da9211-regulator.h - Regulator definitions for DA9211 + * da9211-regulator.h - Regulator definitions for DA9211/DA9213 * Copyright (C) 2014 Dialog Semiconductor Ltd. * * This library is free software; you can redistribute it and/or @@ -53,12 +53,15 @@ /* BUCK Phase Selection*/ #define DA9211_REG_CONFIG_E 0x147 +/* Device ID */ +#define DA9211_REG_DEVICE_ID 0x201 + /* * Registers bits */ /* DA9211_REG_PAGE_CON (addr=0x00) */ #define DA9211_REG_PAGE_SHIFT 1 -#define DA9211_REG_PAGE_MASK 0x02 +#define DA9211_REG_PAGE_MASK 0x06 /* On I2C registers 0x00 - 0xFF */ #define DA9211_REG_PAGE0 0 /* On I2C registers 0x100 - 0x1FF */ diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 714fd9a89aa..f8e4257aef9 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -18,6 +18,8 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/of_device.h> #include <linux/i2c.h> #include <linux/slab.h> #include <linux/regmap.h> @@ -50,6 +52,11 @@ #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ +enum fan53555_vendor { + FAN53555_VENDOR_FAIRCHILD = 0, + FAN53555_VENDOR_SILERGY, +}; + /* IC Type */ enum { FAN53555_CHIP_ID_00 = 0, @@ -60,7 +67,12 @@ enum { FAN53555_CHIP_ID_05, }; +enum { + SILERGY_SYR82X = 8, +}; + struct fan53555_device_info { + enum fan53555_vendor vendor; struct regmap *regmap; struct device *dev; struct regulator_desc desc; @@ -135,6 +147,38 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev) return REGULATOR_MODE_NORMAL; } +static int slew_rates[] = { + 64000, + 32000, + 16000, + 8000, + 4000, + 2000, + 1000, + 500, +}; + +static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) +{ + struct fan53555_device_info *di = rdev_get_drvdata(rdev); + int regval = -1, i; + + for (i = 0; i < ARRAY_SIZE(slew_rates); i++) { + if (ramp <= slew_rates[i]) + regval = i; + else + break; + } + + if (regval < 0) { + dev_err(di->dev, "unsupported ramp value %d\n", ramp); + return -EINVAL; + } + + return regmap_update_bits(di->regmap, FAN53555_CONTROL, + CTL_SLEW_MASK, regval << CTL_SLEW_SHIFT); +} + static struct regulator_ops fan53555_regulator_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -146,8 +190,50 @@ static struct regulator_ops fan53555_regulator_ops = { .is_enabled = regulator_is_enabled_regmap, .set_mode = fan53555_set_mode, .get_mode = fan53555_get_mode, + .set_ramp_delay = fan53555_set_ramp, }; +static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) +{ + /* Init voltage range and step */ + switch (di->chip_id) { + case FAN53555_CHIP_ID_00: + case FAN53555_CHIP_ID_01: + case FAN53555_CHIP_ID_03: + case FAN53555_CHIP_ID_05: + di->vsel_min = 600000; + di->vsel_step = 10000; + break; + case FAN53555_CHIP_ID_04: + di->vsel_min = 603000; + di->vsel_step = 12826; + break; + default: + dev_err(di->dev, + "Chip ID %d not supported!\n", di->chip_id); + return -EINVAL; + } + + return 0; +} + +static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) +{ + /* Init voltage range and step */ + switch (di->chip_id) { + case SILERGY_SYR82X: + di->vsel_min = 712500; + di->vsel_step = 12500; + break; + default: + dev_err(di->dev, + "Chip ID %d not supported!\n", di->chip_id); + return -EINVAL; + } + + return 0; +} + /* For 00,01,03,05 options: * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. * For 04 option: @@ -156,7 +242,7 @@ static struct regulator_ops fan53555_regulator_ops = { static int fan53555_device_setup(struct fan53555_device_info *di, struct fan53555_platform_data *pdata) { - unsigned int reg, data, mask; + int ret = 0; /* Setup voltage control register */ switch (pdata->sleep_vsel_id) { @@ -172,33 +258,20 @@ static int fan53555_device_setup(struct fan53555_device_info *di, dev_err(di->dev, "Invalid VSEL ID!\n"); return -EINVAL; } - /* Init voltage range and step */ - switch (di->chip_id) { - case FAN53555_CHIP_ID_00: - case FAN53555_CHIP_ID_01: - case FAN53555_CHIP_ID_03: - case FAN53555_CHIP_ID_05: - di->vsel_min = 600000; - di->vsel_step = 10000; + + switch (di->vendor) { + case FAN53555_VENDOR_FAIRCHILD: + ret = fan53555_voltages_setup_fairchild(di); break; - case FAN53555_CHIP_ID_04: - di->vsel_min = 603000; - di->vsel_step = 12826; + case FAN53555_VENDOR_SILERGY: + ret = fan53555_voltages_setup_silergy(di); break; default: - dev_err(di->dev, - "Chip ID[%d]\n not supported!\n", di->chip_id); + dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; } - /* Init slew rate */ - if (pdata->slew_rate & 0x7) - di->slew_rate = pdata->slew_rate; - else - di->slew_rate = FAN53555_SLEW_RATE_64MV; - reg = FAN53555_CONTROL; - data = di->slew_rate << CTL_SLEW_SHIFT; - mask = CTL_SLEW_MASK; - return regmap_update_bits(di->regmap, reg, mask, data); + + return ret; } static int fan53555_regulator_register(struct fan53555_device_info *di, @@ -207,6 +280,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, struct regulator_desc *rdesc = &di->desc; rdesc->name = "fan53555-reg"; + rdesc->supply_name = "vin"; rdesc->ops = &fan53555_regulator_ops; rdesc->type = REGULATOR_VOLTAGE; rdesc->n_voltages = FAN53555_NVOLTAGES; @@ -227,9 +301,46 @@ static struct regmap_config fan53555_regmap_config = { .val_bits = 8, }; +static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, + struct device_node *np) +{ + struct fan53555_platform_data *pdata; + int ret; + u32 tmp; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->regulator = of_get_regulator_init_data(dev, np); + + ret = of_property_read_u32(np, "fcs,suspend-voltage-selector", + &tmp); + if (!ret) + pdata->sleep_vsel_id = tmp; + + return pdata; +} + +static const struct of_device_id fan53555_dt_ids[] = { + { + .compatible = "fcs,fan53555", + .data = (void *)FAN53555_VENDOR_FAIRCHILD + }, { + .compatible = "silergy,syr827", + .data = (void *)FAN53555_VENDOR_SILERGY, + }, { + .compatible = "silergy,syr828", + .data = (void *)FAN53555_VENDOR_SILERGY, + }, + { } +}; +MODULE_DEVICE_TABLE(of, fan53555_dt_ids); + static int fan53555_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device_node *np = client->dev.of_node; struct fan53555_device_info *di; struct fan53555_platform_data *pdata; struct regulator_config config = { }; @@ -237,6 +348,9 @@ static int fan53555_regulator_probe(struct i2c_client *client, int ret; pdata = dev_get_platdata(&client->dev); + if (!pdata) + pdata = fan53555_parse_dt(&client->dev, np); + if (!pdata || !pdata->regulator) { dev_err(&client->dev, "Platform data not found!\n"); return -ENODEV; @@ -247,13 +361,35 @@ static int fan53555_regulator_probe(struct i2c_client *client, if (!di) return -ENOMEM; + di->regulator = pdata->regulator; + if (client->dev.of_node) { + const struct of_device_id *match; + + match = of_match_device(of_match_ptr(fan53555_dt_ids), + &client->dev); + if (!match) + return -ENODEV; + + di->vendor = (unsigned long) match->data; + } else { + /* if no ramp constraint set, get the pdata ramp_delay */ + if (!di->regulator->constraints.ramp_delay) { + int slew_idx = (pdata->slew_rate & 0x7) + ? pdata->slew_rate : 0; + + di->regulator->constraints.ramp_delay + = slew_rates[slew_idx]; + } + + di->vendor = id->driver_data; + } + di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config); if (IS_ERR(di->regmap)) { dev_err(&client->dev, "Failed to allocate regmap!\n"); return PTR_ERR(di->regmap); } di->dev = &client->dev; - di->regulator = pdata->regulator; i2c_set_clientdata(client, di); /* Get chip ID */ ret = regmap_read(di->regmap, FAN53555_ID1, &val); @@ -282,6 +418,8 @@ static int fan53555_regulator_probe(struct i2c_client *client, config.init_data = di->regulator; config.regmap = di->regmap; config.driver_data = di; + config.of_node = np; + ret = fan53555_regulator_register(di, &config); if (ret < 0) dev_err(&client->dev, "Failed to register regulator!\n"); @@ -290,13 +428,20 @@ static int fan53555_regulator_probe(struct i2c_client *client, } static const struct i2c_device_id fan53555_id[] = { - {"fan53555", -1}, + { + .name = "fan53555", + .driver_data = FAN53555_VENDOR_FAIRCHILD + }, { + .name = "syr82x", + .driver_data = FAN53555_VENDOR_SILERGY + }, { }, }; static struct i2c_driver fan53555_regulator_driver = { .driver = { .name = "fan53555-regulator", + .of_match_table = of_match_ptr(fan53555_dt_ids), }, .probe = fan53555_regulator_probe, .id_table = fan53555_id, diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c new file mode 100644 index 00000000000..156d0d1a55f --- /dev/null +++ b/drivers/regulator/hi6421-regulator.c @@ -0,0 +1,634 @@ +/* + * Device driver for regulators in Hi6421 IC + * + * Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd. + * http://www.hisilicon.com + * Copyright (c) <2013-2014> Linaro Ltd. + * http://www.linaro.org + * + * Author: Guodong Xu <guodong.xu@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/mfd/hi6421-pmic.h> + +/* + * struct hi6421_regulator_pdata - Hi6421 regulator data of platform device + * @lock: mutex to serialize regulator enable + */ +struct hi6421_regulator_pdata { + struct mutex lock; +}; + +/* + * struct hi6421_regulator_info - hi6421 regulator information + * @desc: regulator description + * @mode_mask: ECO mode bitmask of LDOs; for BUCKs, this masks sleep + * @eco_microamp: eco mode load upper limit (in uA), valid for LDOs only + */ +struct hi6421_regulator_info { + struct regulator_desc desc; + u8 mode_mask; + u32 eco_microamp; +}; + +/* HI6421 regulators */ +enum hi6421_regulator_id { + HI6421_LDO0, + HI6421_LDO1, + HI6421_LDO2, + HI6421_LDO3, + HI6421_LDO4, + HI6421_LDO5, + HI6421_LDO6, + HI6421_LDO7, + HI6421_LDO8, + HI6421_LDO9, + HI6421_LDO10, + HI6421_LDO11, + HI6421_LDO12, + HI6421_LDO13, + HI6421_LDO14, + HI6421_LDO15, + HI6421_LDO16, + HI6421_LDO17, + HI6421_LDO18, + HI6421_LDO19, + HI6421_LDO20, + HI6421_LDOAUDIO, + HI6421_BUCK0, + HI6421_BUCK1, + HI6421_BUCK2, + HI6421_BUCK3, + HI6421_BUCK4, + HI6421_BUCK5, + HI6421_NUM_REGULATORS, +}; + +#define HI6421_REGULATOR_OF_MATCH(_name, id) \ +{ \ + .name = #_name, \ + .driver_data = (void *) HI6421_##id, \ +} + +static struct of_regulator_match hi6421_regulator_match[] = { + HI6421_REGULATOR_OF_MATCH(hi6421_vout0, LDO0), + HI6421_REGULATOR_OF_MATCH(hi6421_vout1, LDO1), + HI6421_REGULATOR_OF_MATCH(hi6421_vout2, LDO2), + HI6421_REGULATOR_OF_MATCH(hi6421_vout3, LDO3), + HI6421_REGULATOR_OF_MATCH(hi6421_vout4, LDO4), + HI6421_REGULATOR_OF_MATCH(hi6421_vout5, LDO5), + HI6421_REGULATOR_OF_MATCH(hi6421_vout6, LDO6), + HI6421_REGULATOR_OF_MATCH(hi6421_vout7, LDO7), + HI6421_REGULATOR_OF_MATCH(hi6421_vout8, LDO8), + HI6421_REGULATOR_OF_MATCH(hi6421_vout9, LDO9), + HI6421_REGULATOR_OF_MATCH(hi6421_vout10, LDO10), + HI6421_REGULATOR_OF_MATCH(hi6421_vout11, LDO11), + HI6421_REGULATOR_OF_MATCH(hi6421_vout12, LDO12), + HI6421_REGULATOR_OF_MATCH(hi6421_vout13, LDO13), + HI6421_REGULATOR_OF_MATCH(hi6421_vout14, LDO14), + HI6421_REGULATOR_OF_MATCH(hi6421_vout15, LDO15), + HI6421_REGULATOR_OF_MATCH(hi6421_vout16, LDO16), + HI6421_REGULATOR_OF_MATCH(hi6421_vout17, LDO17), + HI6421_REGULATOR_OF_MATCH(hi6421_vout18, LDO18), + HI6421_REGULATOR_OF_MATCH(hi6421_vout19, LDO19), + HI6421_REGULATOR_OF_MATCH(hi6421_vout20, LDO20), + HI6421_REGULATOR_OF_MATCH(hi6421_vout_audio, LDOAUDIO), + HI6421_REGULATOR_OF_MATCH(hi6421_buck0, BUCK0), + HI6421_REGULATOR_OF_MATCH(hi6421_buck1, BUCK1), + HI6421_REGULATOR_OF_MATCH(hi6421_buck2, BUCK2), + HI6421_REGULATOR_OF_MATCH(hi6421_buck3, BUCK3), + HI6421_REGULATOR_OF_MATCH(hi6421_buck4, BUCK4), + HI6421_REGULATOR_OF_MATCH(hi6421_buck5, BUCK5), +}; + +/* LDO 0, 4~7, 9~14, 16~20 have same voltage table. */ +static const unsigned int ldo_0_voltages[] = { + 1500000, 1800000, 2400000, 2500000, + 2600000, 2700000, 2850000, 3000000, +}; + +/* LDO 8, 15 have same voltage table. */ +static const unsigned int ldo_8_voltages[] = { + 1500000, 1800000, 2400000, 2600000, + 2700000, 2850000, 3000000, 3300000, +}; + +/* Ranges are sorted in ascending order. */ +static const struct regulator_linear_range ldo_audio_volt_range[] = { + REGULATOR_LINEAR_RANGE(2800000, 0, 3, 50000), + REGULATOR_LINEAR_RANGE(3000000, 4, 7, 100000), +}; + +static const unsigned int buck_3_voltages[] = { + 950000, 1050000, 1100000, 1117000, + 1134000, 1150000, 1167000, 1200000, +}; + +static const unsigned int buck_4_voltages[] = { + 1150000, 1200000, 1250000, 1350000, + 1700000, 1800000, 1900000, 2000000, +}; + +static const unsigned int buck_5_voltages[] = { + 1150000, 1200000, 1250000, 1350000, + 1600000, 1700000, 1800000, 1900000, +}; + +static const struct regulator_ops hi6421_ldo_ops; +static const struct regulator_ops hi6421_ldo_linear_ops; +static const struct regulator_ops hi6421_ldo_linear_range_ops; +static const struct regulator_ops hi6421_buck012_ops; +static const struct regulator_ops hi6421_buck345_ops; + +#define HI6421_LDO_ENABLE_TIME (350) +/* + * _id - LDO id name string + * v_table - voltage table + * vreg - voltage select register + * vmask - voltage select mask + * ereg - enable register + * emask - enable mask + * odelay - off/on delay time in uS + * ecomask - eco mode mask + * ecoamp - eco mode load uppler limit in uA + */ +#define HI6421_LDO(_id, v_table, vreg, vmask, ereg, emask, \ + odelay, ecomask, ecoamp) \ + [HI6421_##_id] = { \ + .desc = { \ + .name = #_id, \ + .ops = &hi6421_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = HI6421_##_id, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(v_table), \ + .volt_table = v_table, \ + .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ + .vsel_mask = vmask, \ + .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ + .enable_mask = emask, \ + .enable_time = HI6421_LDO_ENABLE_TIME, \ + .off_on_delay = odelay, \ + }, \ + .mode_mask = ecomask, \ + .eco_microamp = ecoamp, \ + } + +/* HI6421 LDO1~3 are linear voltage regulators at fixed uV_step + * + * _id - LDO id name string + * _min_uV - minimum voltage supported in uV + * n_volt - number of votages available + * vstep - voltage increase in each linear step in uV + * vreg - voltage select register + * vmask - voltage select mask + * ereg - enable register + * emask - enable mask + * odelay - off/on delay time in uS + * ecomask - eco mode mask + * ecoamp - eco mode load uppler limit in uA + */ +#define HI6421_LDO_LINEAR(_id, _min_uV, n_volt, vstep, vreg, vmask, \ + ereg, emask, odelay, ecomask, ecoamp) \ + [HI6421_##_id] = { \ + .desc = { \ + .name = #_id, \ + .ops = &hi6421_ldo_linear_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = HI6421_##_id, \ + .owner = THIS_MODULE, \ + .min_uV = _min_uV, \ + .n_voltages = n_volt, \ + .uV_step = vstep, \ + .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ + .vsel_mask = vmask, \ + .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ + .enable_mask = emask, \ + .enable_time = HI6421_LDO_ENABLE_TIME, \ + .off_on_delay = odelay, \ + }, \ + .mode_mask = ecomask, \ + .eco_microamp = ecoamp, \ + } + +/* HI6421 LDOAUDIO is a linear voltage regulator with two 4-step ranges + * + * _id - LDO id name string + * n_volt - number of votages available + * volt_ranges - array of regulator_linear_range + * vstep - voltage increase in each linear step in uV + * vreg - voltage select register + * vmask - voltage select mask + * ereg - enable register + * emask - enable mask + * odelay - off/on delay time in uS + * ecomask - eco mode mask + * ecoamp - eco mode load uppler limit in uA + */ +#define HI6421_LDO_LINEAR_RANGE(_id, n_volt, volt_ranges, vreg, vmask, \ + ereg, emask, odelay, ecomask, ecoamp) \ + [HI6421_##_id] = { \ + .desc = { \ + .name = #_id, \ + .ops = &hi6421_ldo_linear_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = HI6421_##_id, \ + .owner = THIS_MODULE, \ + .n_voltages = n_volt, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ + .vsel_mask = vmask, \ + .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ + .enable_mask = emask, \ + .enable_time = HI6421_LDO_ENABLE_TIME, \ + .off_on_delay = odelay, \ + }, \ + .mode_mask = ecomask, \ + .eco_microamp = ecoamp, \ + } + +/* HI6421 BUCK0/1/2 are linear voltage regulators at fixed uV_step + * + * _id - BUCK0/1/2 id name string + * vreg - voltage select register + * vmask - voltage select mask + * ereg - enable register + * emask - enable mask + * sleepmask - mask of sleep mode + * etime - enable time + * odelay - off/on delay time in uS + */ +#define HI6421_BUCK012(_id, vreg, vmask, ereg, emask, sleepmask, \ + etime, odelay) \ + [HI6421_##_id] = { \ + .desc = { \ + .name = #_id, \ + .ops = &hi6421_buck012_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = HI6421_##_id, \ + .owner = THIS_MODULE, \ + .min_uV = 700000, \ + .n_voltages = 128, \ + .uV_step = 7086, \ + .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ + .vsel_mask = vmask, \ + .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ + .enable_mask = emask, \ + .enable_time = etime, \ + .off_on_delay = odelay, \ + }, \ + .mode_mask = sleepmask, \ + } + +/* HI6421 BUCK3/4/5 share similar configurations as LDOs, with exception + * that it supports SLEEP mode, so has different .ops. + * + * _id - LDO id name string + * v_table - voltage table + * vreg - voltage select register + * vmask - voltage select mask + * ereg - enable register + * emask - enable mask + * odelay - off/on delay time in uS + * sleepmask - mask of sleep mode + */ +#define HI6421_BUCK345(_id, v_table, vreg, vmask, ereg, emask, \ + odelay, sleepmask) \ + [HI6421_##_id] = { \ + .desc = { \ + .name = #_id, \ + .ops = &hi6421_buck345_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = HI6421_##_id, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(v_table), \ + .volt_table = v_table, \ + .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ + .vsel_mask = vmask, \ + .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ + .enable_mask = emask, \ + .enable_time = HI6421_LDO_ENABLE_TIME, \ + .off_on_delay = odelay, \ + }, \ + .mode_mask = sleepmask, \ + } + +/* HI6421 regulator information */ +static struct hi6421_regulator_info + hi6421_regulator_info[HI6421_NUM_REGULATORS] = { + HI6421_LDO(LDO0, ldo_0_voltages, 0x20, 0x07, 0x20, 0x10, + 10000, 0x20, 8000), + HI6421_LDO_LINEAR(LDO1, 1700000, 4, 100000, 0x21, 0x03, 0x21, 0x10, + 10000, 0x20, 5000), + HI6421_LDO_LINEAR(LDO2, 1050000, 8, 50000, 0x22, 0x07, 0x22, 0x10, + 20000, 0x20, 8000), + HI6421_LDO_LINEAR(LDO3, 1050000, 8, 50000, 0x23, 0x07, 0x23, 0x10, + 20000, 0x20, 8000), + HI6421_LDO(LDO4, ldo_0_voltages, 0x24, 0x07, 0x24, 0x10, + 20000, 0x20, 8000), + HI6421_LDO(LDO5, ldo_0_voltages, 0x25, 0x07, 0x25, 0x10, + 20000, 0x20, 8000), + HI6421_LDO(LDO6, ldo_0_voltages, 0x26, 0x07, 0x26, 0x10, + 20000, 0x20, 8000), + HI6421_LDO(LDO7, ldo_0_voltages, 0x27, 0x07, 0x27, 0x10, + 20000, 0x20, 5000), + HI6421_LDO(LDO8, ldo_8_voltages, 0x28, 0x07, 0x28, 0x10, + 20000, 0x20, 8000), + HI6421_LDO(LDO9, ldo_0_voltages, 0x29, 0x07, 0x29, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO10, ldo_0_voltages, 0x2a, 0x07, 0x2a, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO11, ldo_0_voltages, 0x2b, 0x07, 0x2b, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO12, ldo_0_voltages, 0x2c, 0x07, 0x2c, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO13, ldo_0_voltages, 0x2d, 0x07, 0x2d, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO14, ldo_0_voltages, 0x2e, 0x07, 0x2e, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO15, ldo_8_voltages, 0x2f, 0x07, 0x2f, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO16, ldo_0_voltages, 0x30, 0x07, 0x30, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO17, ldo_0_voltages, 0x31, 0x07, 0x31, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO18, ldo_0_voltages, 0x32, 0x07, 0x32, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO19, ldo_0_voltages, 0x33, 0x07, 0x33, 0x10, + 40000, 0x20, 8000), + HI6421_LDO(LDO20, ldo_0_voltages, 0x34, 0x07, 0x34, 0x10, + 40000, 0x20, 8000), + HI6421_LDO_LINEAR_RANGE(LDOAUDIO, 8, ldo_audio_volt_range, 0x36, + 0x70, 0x36, 0x01, 40000, 0x02, 5000), + HI6421_BUCK012(BUCK0, 0x0d, 0x7f, 0x0c, 0x01, 0x10, 400, 20000), + HI6421_BUCK012(BUCK1, 0x0f, 0x7f, 0x0e, 0x01, 0x10, 400, 20000), + HI6421_BUCK012(BUCK2, 0x11, 0x7f, 0x10, 0x01, 0x10, 350, 100), + HI6421_BUCK345(BUCK3, buck_3_voltages, 0x13, 0x07, 0x12, 0x01, + 20000, 0x10), + HI6421_BUCK345(BUCK4, buck_4_voltages, 0x15, 0x07, 0x14, 0x01, + 20000, 0x10), + HI6421_BUCK345(BUCK5, buck_5_voltages, 0x17, 0x07, 0x16, 0x01, + 20000, 0x10), +}; + +static int hi6421_regulator_enable(struct regulator_dev *rdev) +{ + struct hi6421_regulator_pdata *pdata; + + pdata = dev_get_drvdata(rdev->dev.parent); + /* hi6421 spec requires regulator enablement must be serialized: + * - Because when BUCK, LDO switching from off to on, it will have + * a huge instantaneous current; so you can not turn on two or + * more LDO or BUCKs simultaneously, or it may burn the chip. + */ + mutex_lock(&pdata->lock); + + /* call regulator regmap helper */ + regulator_enable_regmap(rdev); + + mutex_unlock(&pdata->lock); + return 0; +} + +static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev) +{ + struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); + u32 reg_val; + + regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val); + if (reg_val & info->mode_mask) + return REGULATOR_MODE_IDLE; + + return REGULATOR_MODE_NORMAL; +} + +static unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev) +{ + struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); + u32 reg_val; + + regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val); + if (reg_val & info->mode_mask) + return REGULATOR_MODE_STANDBY; + + return REGULATOR_MODE_NORMAL; +} + +static int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); + u32 new_mode; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + new_mode = 0; + break; + case REGULATOR_MODE_IDLE: + new_mode = info->mode_mask; + break; + default: + return -EINVAL; + } + + /* set mode */ + regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + info->mode_mask, new_mode); + + return 0; +} + +static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); + u32 new_mode; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + new_mode = 0; + break; + case REGULATOR_MODE_STANDBY: + new_mode = info->mode_mask; + break; + default: + return -EINVAL; + } + + /* set mode */ + regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + info->mode_mask, new_mode); + + return 0; +} + +unsigned int hi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev, + int input_uV, int output_uV, int load_uA) +{ + struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); + + if (load_uA > info->eco_microamp) + return REGULATOR_MODE_NORMAL; + + return REGULATOR_MODE_IDLE; +} + +static const struct regulator_ops hi6421_ldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = hi6421_regulator_enable, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_mode = hi6421_regulator_ldo_get_mode, + .set_mode = hi6421_regulator_ldo_set_mode, + .get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode, +}; + +static const struct regulator_ops hi6421_ldo_linear_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = hi6421_regulator_enable, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_mode = hi6421_regulator_ldo_get_mode, + .set_mode = hi6421_regulator_ldo_set_mode, + .get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode, +}; + +static const struct regulator_ops hi6421_ldo_linear_range_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = hi6421_regulator_enable, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_mode = hi6421_regulator_ldo_get_mode, + .set_mode = hi6421_regulator_ldo_set_mode, + .get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode, +}; + +static const struct regulator_ops hi6421_buck012_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = hi6421_regulator_enable, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_mode = hi6421_regulator_buck_get_mode, + .set_mode = hi6421_regulator_buck_set_mode, +}; + +static const struct regulator_ops hi6421_buck345_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = hi6421_regulator_enable, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_mode = hi6421_regulator_buck_get_mode, + .set_mode = hi6421_regulator_buck_set_mode, +}; + +static int hi6421_regulator_register(struct platform_device *pdev, + struct regmap *rmap, + struct regulator_init_data *init_data, + int id, struct device_node *np) +{ + struct hi6421_regulator_info *info = NULL; + struct regulator_config config = { }; + struct regulator_dev *rdev; + + /* assign per-regulator data */ + info = &hi6421_regulator_info[id]; + + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = info; + config.regmap = rmap; + config.of_node = np; + + /* register regulator with framework */ + rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + info->desc.name); + return PTR_ERR(rdev); + } + + return 0; +} + +static int hi6421_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np; + struct hi6421_pmic *pmic; + struct hi6421_regulator_pdata *pdata; + int i, ret = 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + mutex_init(&pdata->lock); + platform_set_drvdata(pdev, pdata); + + np = of_get_child_by_name(dev->parent->of_node, "regulators"); + if (!np) + return -ENODEV; + + ret = of_regulator_match(dev, np, + hi6421_regulator_match, + ARRAY_SIZE(hi6421_regulator_match)); + of_node_put(np); + if (ret < 0) { + dev_err(dev, "Error parsing regulator init data: %d\n", ret); + return ret; + } + + pmic = dev_get_drvdata(dev->parent); + + for (i = 0; i < ARRAY_SIZE(hi6421_regulator_info); i++) { + ret = hi6421_regulator_register(pdev, pmic->regmap, + hi6421_regulator_match[i].init_data, i, + hi6421_regulator_match[i].of_node); + if (ret) + return ret; + } + + return 0; +} + +static struct platform_driver hi6421_regulator_driver = { + .driver = { + .name = "hi6421-regulator", + .owner = THIS_MODULE, + }, + .probe = hi6421_regulator_probe, +}; +module_platform_driver(hi6421_regulator_driver); + +MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>"); +MODULE_DESCRIPTION("Hi6421 regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index 84bbda10c39..80ba2a35a04 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -35,4 +35,18 @@ struct regulator { struct dentry *debugfs; }; +#ifdef CONFIG_OF +struct regulator_init_data *regulator_of_get_init_data(struct device *dev, + const struct regulator_desc *desc, + struct device_node **node); +#else +static inline struct regulator_init_data * +regulator_of_get_init_data(struct device *dev, + const struct regulator_desc *desc, + struct device_node **node) +{ + return NULL; +} +#endif + #endif diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c new file mode 100644 index 00000000000..92fefd98da5 --- /dev/null +++ b/drivers/regulator/isl9305.c @@ -0,0 +1,207 @@ +/* + * isl9305 - Intersil ISL9305 DCDC regulator + * + * Copyright 2014 Linaro Ltd + * + * Author: Mark Brown <broonie@kernel.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/of.h> +#include <linux/platform_data/isl9305.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> +#include <linux/slab.h> + +/* + * Registers + */ +#define ISL9305_DCD1OUT 0x0 +#define ISL9305_DCD2OUT 0x1 +#define ISL9305_LDO1OUT 0x2 +#define ISL9305_LDO2OUT 0x3 +#define ISL9305_DCD_PARAMETER 0x4 +#define ISL9305_SYSTEM_PARAMETER 0x5 +#define ISL9305_DCD_SRCTL 0x6 + +#define ISL9305_MAX_REG ISL9305_DCD_SRCTL + +/* + * DCD_PARAMETER + */ +#define ISL9305_DCD_PHASE 0x40 +#define ISL9305_DCD2_ULTRA 0x20 +#define ISL9305_DCD1_ULTRA 0x10 +#define ISL9305_DCD2_BLD 0x08 +#define ISL9305_DCD1_BLD 0x04 +#define ISL9305_DCD2_MODE 0x02 +#define ISL9305_DCD1_MODE 0x01 + +/* + * SYSTEM_PARAMETER + */ +#define ISL9305_I2C_EN 0x40 +#define ISL9305_DCDPOR_MASK 0x30 +#define ISL9305_LDO2_EN 0x08 +#define ISL9305_LDO1_EN 0x04 +#define ISL9305_DCD2_EN 0x02 +#define ISL9305_DCD1_EN 0x01 + +/* + * DCD_SRCTL + */ +#define ISL9305_DCD2SR_MASK 0xc0 +#define ISL9305_DCD1SR_MASK 0x07 + +static const struct regulator_ops isl9305_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_desc isl9305_regulators[] = { + [ISL9305_DCD1] = { + .name = "DCD1", + .of_match = of_match_ptr("dcd1"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x70, + .min_uV = 825000, + .uV_step = 25000, + .vsel_reg = ISL9305_DCD1OUT, + .vsel_mask = 0x7f, + .enable_reg = ISL9305_SYSTEM_PARAMETER, + .enable_mask = ISL9305_DCD1_EN, + .supply_name = "VINDCD1", + .ops = &isl9305_ops, + }, + [ISL9305_DCD2] = { + .name = "DCD2", + .of_match = of_match_ptr("dcd2"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x70, + .min_uV = 825000, + .uV_step = 25000, + .vsel_reg = ISL9305_DCD2OUT, + .vsel_mask = 0x7f, + .enable_reg = ISL9305_SYSTEM_PARAMETER, + .enable_mask = ISL9305_DCD2_EN, + .supply_name = "VINDCD2", + .ops = &isl9305_ops, + }, + [ISL9305_LDO1] = { + .name = "LDO1", + .of_match = of_match_ptr("ldo1"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x37, + .min_uV = 900000, + .uV_step = 50000, + .vsel_reg = ISL9305_LDO1OUT, + .vsel_mask = 0x3f, + .enable_reg = ISL9305_SYSTEM_PARAMETER, + .enable_mask = ISL9305_LDO1_EN, + .supply_name = "VINLDO1", + .ops = &isl9305_ops, + }, + [ISL9305_LDO2] = { + .name = "LDO2", + .of_match = of_match_ptr("ldo2"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x37, + .min_uV = 900000, + .uV_step = 50000, + .vsel_reg = ISL9305_LDO2OUT, + .vsel_mask = 0x3f, + .enable_reg = ISL9305_SYSTEM_PARAMETER, + .enable_mask = ISL9305_LDO2_EN, + .supply_name = "VINLDO2", + .ops = &isl9305_ops, + }, +}; + +static const struct regmap_config isl9305_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = ISL9305_MAX_REG, + .cache_type = REGCACHE_RBTREE, +}; + +static int isl9305_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regulator_config config = { }; + struct isl9305_pdata *pdata = i2c->dev.platform_data; + struct regulator_dev *rdev; + struct regmap *regmap; + int i, ret; + + regmap = devm_regmap_init_i2c(i2c, &isl9305_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); + return ret; + } + + config.dev = &i2c->dev; + + for (i = 0; i < ARRAY_SIZE(isl9305_regulators); i++) { + if (pdata) + config.init_data = pdata->init_data[i]; + else + config.init_data = NULL; + + rdev = devm_regulator_register(&i2c->dev, + &isl9305_regulators[i], + &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&i2c->dev, "Failed to register %s: %d\n", + isl9305_regulators[i].name, ret); + return ret; + } + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id isl9305_dt_ids[] = { + { .compatible = "isl,isl9305" }, + { .compatible = "isl,isl9305h" }, + {}, +}; +#endif + +static const struct i2c_device_id isl9305_i2c_id[] = { + { "isl9305", }, + { "isl9305h", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, isl9305_i2c_id); + +static struct i2c_driver isl9305_regulator_driver = { + .driver = { + .name = "isl9305", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(isl9305_dt_ids), + }, + .probe = isl9305_i2c_probe, + .id_table = isl9305_i2c_id, +}; + +module_i2c_driver(isl9305_regulator_driver); + +MODULE_AUTHOR("Mark Brown"); +MODULE_DESCRIPTION("Intersil ISL9305 DCDC regulator"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index c756955bfcc..0ce8e4e0fa7 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -372,6 +372,7 @@ static bool ltc3589_volatile_reg(struct device *dev, unsigned int reg) switch (reg) { case LTC3589_IRQSTAT: case LTC3589_PGSTAT: + case LTC3589_VCCR: return true; } return false; diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index d23d0577754..86db310d530 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -24,6 +24,8 @@ #include <linux/regulator/driver.h> #include <linux/slab.h> #include <linux/regulator/max1586.h> +#include <linux/of_device.h> +#include <linux/regulator/of_regulator.h> #define MAX1586_V3_MAX_VSEL 31 #define MAX1586_V6_MAX_VSEL 3 @@ -157,13 +159,87 @@ static struct regulator_desc max1586_reg[] = { }, }; +static int of_get_max1586_platform_data(struct device *dev, + struct max1586_platform_data *pdata) +{ + struct max1586_subdev_data *sub; + struct of_regulator_match rmatch[ARRAY_SIZE(max1586_reg)]; + struct device_node *np = dev->of_node; + int i, matched; + + if (of_property_read_u32(np, "v3-gain", + &pdata->v3_gain) < 0) { + dev_err(dev, "%s has no 'v3-gain' property\n", np->full_name); + return -EINVAL; + } + + np = of_get_child_by_name(np, "regulators"); + if (!np) { + dev_err(dev, "missing 'regulators' subnode in DT\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(rmatch); i++) + rmatch[i].name = max1586_reg[i].name; + + matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch)); + of_node_put(np); + /* + * If matched is 0, ie. neither Output_V3 nor Output_V6 have been found, + * return 0, which signals the normal situation where no subregulator is + * available. This is normal because the max1586 doesn't provide any + * readback support, so the subregulators can't report any status + * anyway. If matched < 0, return the error. + */ + if (matched <= 0) + return matched; + + pdata->subdevs = devm_kzalloc(dev, sizeof(struct max1586_subdev_data) * + matched, GFP_KERNEL); + if (!pdata->subdevs) + return -ENOMEM; + + pdata->num_subdevs = matched; + sub = pdata->subdevs; + + for (i = 0; i < matched; i++) { + sub->id = i; + sub->name = rmatch[i].of_node->name; + sub->platform_data = rmatch[i].init_data; + sub++; + } + + return 0; +} + +static const struct of_device_id max1586_of_match[] = { + { .compatible = "maxim,max1586", }, + {}, +}; +MODULE_DEVICE_TABLE(of, max1586_of_match); + static int max1586_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { - struct max1586_platform_data *pdata = dev_get_platdata(&client->dev); + struct max1586_platform_data *pdata, pdata_of; struct regulator_config config = { }; struct max1586_data *max1586; - int i, id; + int i, id, ret; + const struct of_device_id *match; + + pdata = dev_get_platdata(&client->dev); + if (client->dev.of_node && !pdata) { + match = of_match_device(of_match_ptr(max1586_of_match), + &client->dev); + if (!match) { + dev_err(&client->dev, "Error: No device match found\n"); + return -ENODEV; + } + ret = of_get_max1586_platform_data(&client->dev, &pdata_of); + if (ret < 0) + return ret; + pdata = &pdata_of; + } max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data), GFP_KERNEL); @@ -229,6 +305,7 @@ static struct i2c_driver max1586_pmic_driver = { .driver = { .name = "max1586", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max1586_of_match), }, .id_table = max1586_id, }; diff --git a/drivers/regulator/max77802.c b/drivers/regulator/max77802.c new file mode 100644 index 00000000000..d89792b084e --- /dev/null +++ b/drivers/regulator/max77802.c @@ -0,0 +1,586 @@ +/* + * max77802.c - Regulator driver for the Maxim 77802 + * + * Copyright (C) 2013-2014 Google, Inc + * Simon Glass <sjg@chromium.org> + * + * Copyright (C) 2012 Samsung Electronics + * Chiwoong Byun <woong.byun@smasung.com> + * Jonghwa Lee <jonghwa3.lee@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This driver is based on max8997.c + */ + +#include <linux/kernel.h> +#include <linux/bug.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/gpio/consumer.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/mfd/max77686.h> +#include <linux/mfd/max77686-private.h> + +/* Default ramp delay in case it is not manually set */ +#define MAX77802_RAMP_DELAY 100000 /* uV/us */ + +#define MAX77802_OPMODE_SHIFT_LDO 6 +#define MAX77802_OPMODE_BUCK234_SHIFT 4 +#define MAX77802_OPMODE_MASK 0x3 + +#define MAX77802_VSEL_MASK 0x3F +#define MAX77802_DVS_VSEL_MASK 0xFF + +#define MAX77802_RAMP_RATE_MASK_2BIT 0xC0 +#define MAX77802_RAMP_RATE_SHIFT_2BIT 6 +#define MAX77802_RAMP_RATE_MASK_4BIT 0xF0 +#define MAX77802_RAMP_RATE_SHIFT_4BIT 4 + +/* MAX77802 has two register formats: 2-bit and 4-bit */ +static const unsigned int ramp_table_77802_2bit[] = { + 12500, + 25000, + 50000, + 100000, +}; + +static unsigned int ramp_table_77802_4bit[] = { + 1000, 2000, 3030, 4000, + 5000, 5880, 7140, 8330, + 9090, 10000, 11110, 12500, + 16670, 25000, 50000, 100000, +}; + +struct max77802_regulator_prv { + unsigned int opmode[MAX77802_REG_MAX]; +}; + +static int max77802_get_opmode_shift(int id) +{ + if (id == MAX77802_BUCK1 || (id >= MAX77802_BUCK5 && + id <= MAX77802_BUCK10)) + return 0; + + if (id >= MAX77802_BUCK2 && id <= MAX77802_BUCK4) + return MAX77802_OPMODE_BUCK234_SHIFT; + + if (id >= MAX77802_LDO1 && id <= MAX77802_LDO35) + return MAX77802_OPMODE_SHIFT_LDO; + + return -EINVAL; +} + +/* + * Some BUCKS supports Normal[ON/OFF] mode during suspend + * + * BUCK 1, 6, 2-4, 5, 7-10 (all) + * + * The other mode (0x02) will make PWRREQ switch between normal + * and low power. + */ +static int max77802_buck_set_suspend_disable(struct regulator_dev *rdev) +{ + unsigned int val = MAX77802_OPMODE_STANDBY; + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int shift = max77802_get_opmode_shift(id); + + max77802->opmode[id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val << shift); +} + +/* + * Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state + * (Enable Control Logic1 by PWRREQ) + * + * LDOs 2, 4-19, 22-35. + * + */ +static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev, + unsigned int mode) +{ + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + unsigned int val; + int shift = max77802_get_opmode_shift(id); + + switch (mode) { + case REGULATOR_MODE_IDLE: /* ON in LP Mode */ + val = MAX77802_OPMODE_LP; + break; + case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ + val = MAX77802_OPMODE_NORMAL; + break; + case REGULATOR_MODE_STANDBY: /* ON/OFF by PWRREQ */ + val = MAX77802_OPMODE_STANDBY; + break; + default: + dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + max77802->opmode[id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val << shift); +} + +/* + * Mode 1 (Output[ON/OFF] by PWRREQ) is not supported on some LDOs + * (Enable Control Logic2 by PWRREQ) + * + * LDOs 1, 20, 21, and 3, + * + */ +static int max77802_ldo_set_suspend_mode_logic2(struct regulator_dev *rdev, + unsigned int mode) +{ + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + unsigned int val; + int shift = max77802_get_opmode_shift(id); + + switch (mode) { + case REGULATOR_MODE_IDLE: /* ON in LP Mode */ + val = MAX77802_OPMODE_LP; + break; + case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ + val = MAX77802_OPMODE_NORMAL; + break; + default: + dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + max77802->opmode[id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val << shift); +} + +static int max77802_enable(struct regulator_dev *rdev) +{ + struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int shift = max77802_get_opmode_shift(id); + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + max77802->opmode[id] << shift); +} + +static int max77802_find_ramp_value(struct regulator_dev *rdev, + const unsigned int limits[], int size, + unsigned int ramp_delay) +{ + int i; + + for (i = 0; i < size; i++) { + if (ramp_delay <= limits[i]) + return i; + } + + /* Use maximum value for no ramp control */ + dev_warn(&rdev->dev, "%s: ramp_delay: %d not supported, setting 100000\n", + rdev->desc->name, ramp_delay); + return size - 1; +} + +/* Used for BUCKs 2-4 */ +static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev, + int ramp_delay) +{ + int id = rdev_get_id(rdev); + unsigned int ramp_value; + + if (id > MAX77802_BUCK4) { + dev_warn(&rdev->dev, + "%s: regulator: ramp delay not supported\n", + rdev->desc->name); + return -EINVAL; + } + ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit, + ARRAY_SIZE(ramp_table_77802_2bit), ramp_delay); + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + MAX77802_RAMP_RATE_MASK_2BIT, + ramp_value << MAX77802_RAMP_RATE_SHIFT_2BIT); +} + +/* For BUCK1, 6 */ +static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev, + int ramp_delay) +{ + unsigned int ramp_value; + + ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_4bit, + ARRAY_SIZE(ramp_table_77802_4bit), ramp_delay); + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + MAX77802_RAMP_RATE_MASK_4BIT, + ramp_value << MAX77802_RAMP_RATE_SHIFT_4BIT); +} + +/* + * LDOs 2, 4-19, 22-35 + */ +static struct regulator_ops max77802_ldo_ops_logic1 = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_mode = max77802_ldo_set_suspend_mode_logic1, +}; + +/* + * LDOs 1, 20, 21, 3 + */ +static struct regulator_ops max77802_ldo_ops_logic2 = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_mode = max77802_ldo_set_suspend_mode_logic2, +}; + +/* BUCKS 1, 6 */ +static struct regulator_ops max77802_buck_16_dvs_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = max77802_set_ramp_delay_4bit, + .set_suspend_disable = max77802_buck_set_suspend_disable, +}; + +/* BUCKs 2-4, 5, 7-10 */ +static struct regulator_ops max77802_buck_dvs_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77802_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = max77802_set_ramp_delay_2bit, + .set_suspend_disable = max77802_buck_set_suspend_disable, +}; + +/* LDOs 3-7, 9-14, 18-26, 28, 29, 32-34 */ +#define regulator_77802_desc_p_ldo(num, supply, log) { \ + .name = "LDO"#num, \ + .id = MAX77802_LDO##num, \ + .supply_name = "inl"#supply, \ + .ops = &max77802_ldo_ops_logic##log, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 800000, \ + .uV_step = 50000, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 6, \ + .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77802_VSEL_MASK, \ + .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ +} + +/* LDOs 1, 2, 8, 15, 17, 27, 30, 35 */ +#define regulator_77802_desc_n_ldo(num, supply, log) { \ + .name = "LDO"#num, \ + .id = MAX77802_LDO##num, \ + .supply_name = "inl"#supply, \ + .ops = &max77802_ldo_ops_logic##log, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 800000, \ + .uV_step = 25000, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 6, \ + .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77802_VSEL_MASK, \ + .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ +} + +/* BUCKs 1, 6 */ +#define regulator_77802_desc_16_buck(num) { \ + .name = "BUCK"#num, \ + .id = MAX77802_BUCK##num, \ + .supply_name = "inb"#num, \ + .ops = &max77802_buck_16_dvs_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 612500, \ + .uV_step = 6250, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 8, \ + .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \ + .vsel_mask = MAX77802_DVS_VSEL_MASK, \ + .enable_reg = MAX77802_REG_BUCK ## num ## CTRL, \ + .enable_mask = MAX77802_OPMODE_MASK, \ +} + +/* BUCKS 2-4 */ +#define regulator_77802_desc_234_buck(num) { \ + .name = "BUCK"#num, \ + .id = MAX77802_BUCK##num, \ + .supply_name = "inb"#num, \ + .ops = &max77802_buck_dvs_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 600000, \ + .uV_step = 6250, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 0x91, \ + .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \ + .vsel_mask = MAX77802_DVS_VSEL_MASK, \ + .enable_reg = MAX77802_REG_BUCK ## num ## CTRL1, \ + .enable_mask = MAX77802_OPMODE_MASK << \ + MAX77802_OPMODE_BUCK234_SHIFT, \ +} + +/* BUCK 5 */ +#define regulator_77802_desc_buck5(num) { \ + .name = "BUCK"#num, \ + .id = MAX77802_BUCK##num, \ + .supply_name = "inb"#num, \ + .ops = &max77802_buck_dvs_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 750000, \ + .uV_step = 50000, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 6, \ + .vsel_reg = MAX77802_REG_BUCK5OUT, \ + .vsel_mask = MAX77802_VSEL_MASK, \ + .enable_reg = MAX77802_REG_BUCK5CTRL, \ + .enable_mask = MAX77802_OPMODE_MASK, \ +} + +/* BUCKs 7-10 */ +#define regulator_77802_desc_buck7_10(num) { \ + .name = "BUCK"#num, \ + .id = MAX77802_BUCK##num, \ + .supply_name = "inb"#num, \ + .ops = &max77802_buck_dvs_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 750000, \ + .uV_step = 50000, \ + .ramp_delay = MAX77802_RAMP_DELAY, \ + .n_voltages = 1 << 6, \ + .vsel_reg = MAX77802_REG_BUCK7OUT + (num - 7) * 3, \ + .vsel_mask = MAX77802_VSEL_MASK, \ + .enable_reg = MAX77802_REG_BUCK7CTRL + (num - 7) * 3, \ + .enable_mask = MAX77802_OPMODE_MASK, \ +} + +static struct regulator_desc regulators[] = { + regulator_77802_desc_16_buck(1), + regulator_77802_desc_234_buck(2), + regulator_77802_desc_234_buck(3), + regulator_77802_desc_234_buck(4), + regulator_77802_desc_buck5(5), + regulator_77802_desc_16_buck(6), + regulator_77802_desc_buck7_10(7), + regulator_77802_desc_buck7_10(8), + regulator_77802_desc_buck7_10(9), + regulator_77802_desc_buck7_10(10), + regulator_77802_desc_n_ldo(1, 10, 2), + regulator_77802_desc_n_ldo(2, 10, 1), + regulator_77802_desc_p_ldo(3, 3, 2), + regulator_77802_desc_p_ldo(4, 6, 1), + regulator_77802_desc_p_ldo(5, 3, 1), + regulator_77802_desc_p_ldo(6, 3, 1), + regulator_77802_desc_p_ldo(7, 3, 1), + regulator_77802_desc_n_ldo(8, 1, 1), + regulator_77802_desc_p_ldo(9, 5, 1), + regulator_77802_desc_p_ldo(10, 4, 1), + regulator_77802_desc_p_ldo(11, 4, 1), + regulator_77802_desc_p_ldo(12, 9, 1), + regulator_77802_desc_p_ldo(13, 4, 1), + regulator_77802_desc_p_ldo(14, 4, 1), + regulator_77802_desc_n_ldo(15, 1, 1), + regulator_77802_desc_n_ldo(17, 2, 1), + regulator_77802_desc_p_ldo(18, 7, 1), + regulator_77802_desc_p_ldo(19, 5, 1), + regulator_77802_desc_p_ldo(20, 7, 2), + regulator_77802_desc_p_ldo(21, 6, 2), + regulator_77802_desc_p_ldo(23, 9, 1), + regulator_77802_desc_p_ldo(24, 6, 1), + regulator_77802_desc_p_ldo(25, 9, 1), + regulator_77802_desc_p_ldo(26, 9, 1), + regulator_77802_desc_n_ldo(27, 2, 1), + regulator_77802_desc_p_ldo(28, 7, 1), + regulator_77802_desc_p_ldo(29, 7, 1), + regulator_77802_desc_n_ldo(30, 2, 1), + regulator_77802_desc_p_ldo(32, 9, 1), + regulator_77802_desc_p_ldo(33, 6, 1), + regulator_77802_desc_p_ldo(34, 9, 1), + regulator_77802_desc_n_ldo(35, 2, 1), +}; + +#ifdef CONFIG_OF +static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev, + struct max77686_platform_data *pdata) +{ + struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct device_node *pmic_np, *regulators_np; + struct max77686_regulator_data *rdata; + struct of_regulator_match rmatch; + unsigned int i; + + pmic_np = iodev->dev->of_node; + regulators_np = of_get_child_by_name(pmic_np, "regulators"); + if (!regulators_np) { + dev_err(&pdev->dev, "could not find regulators sub-node\n"); + return -EINVAL; + } + + pdata->num_regulators = ARRAY_SIZE(regulators); + rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * + pdata->num_regulators, GFP_KERNEL); + if (!rdata) { + of_node_put(regulators_np); + return -ENOMEM; + } + + for (i = 0; i < pdata->num_regulators; i++) { + rmatch.name = regulators[i].name; + rmatch.init_data = NULL; + rmatch.of_node = NULL; + if (of_regulator_match(&pdev->dev, regulators_np, &rmatch, + 1) != 1) { + dev_warn(&pdev->dev, "No matching regulator for '%s'\n", + rmatch.name); + continue; + } + rdata[i].initdata = rmatch.init_data; + rdata[i].of_node = rmatch.of_node; + rdata[i].id = regulators[i].id; + } + + pdata->regulators = rdata; + of_node_put(regulators_np); + + return 0; +} +#else +static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev, + struct max77686_platform_data *pdata) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static int max77802_pmic_probe(struct platform_device *pdev) +{ + struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev); + struct max77802_regulator_prv *max77802; + int i, ret = 0, val; + struct regulator_config config = { }; + + /* This is allocated by the MFD driver */ + if (!pdata) { + dev_err(&pdev->dev, "no platform data found for regulator\n"); + return -ENODEV; + } + + max77802 = devm_kzalloc(&pdev->dev, + sizeof(struct max77802_regulator_prv), + GFP_KERNEL); + if (!max77802) + return -ENOMEM; + + if (iodev->dev->of_node) { + ret = max77802_pmic_dt_parse_pdata(pdev, pdata); + if (ret) + return ret; + } + + config.dev = iodev->dev; + config.regmap = iodev->regmap; + config.driver_data = max77802; + platform_set_drvdata(pdev, max77802); + + for (i = 0; i < MAX77802_REG_MAX; i++) { + struct regulator_dev *rdev; + int id = pdata->regulators[i].id; + int shift = max77802_get_opmode_shift(id); + + config.init_data = pdata->regulators[i].initdata; + config.of_node = pdata->regulators[i].of_node; + + ret = regmap_read(iodev->regmap, regulators[i].enable_reg, &val); + val = val >> shift & MAX77802_OPMODE_MASK; + + /* + * If the regulator is disabled and the system warm rebooted, + * the hardware reports OFF as the regulator operating mode. + * Default to operating mode NORMAL in that case. + */ + if (val == MAX77802_OPMODE_OFF) + max77802->opmode[id] = MAX77802_OPMODE_NORMAL; + else + max77802->opmode[id] = val; + + rdev = devm_regulator_register(&pdev->dev, + ®ulators[i], &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "regulator init failed for %d\n", i); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id max77802_pmic_id[] = { + {"max77802-pmic", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, max77802_pmic_id); + +static struct platform_driver max77802_pmic_driver = { + .driver = { + .name = "max77802-pmic", + .owner = THIS_MODULE, + }, + .probe = max77802_pmic_probe, + .id_table = max77802_pmic_id, +}; + +module_platform_driver(max77802_pmic_driver); + +MODULE_DESCRIPTION("MAXIM 77802 Regulator Driver"); +MODULE_AUTHOR("Simon Glass <sjg@chromium.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index f374fa57220..793b662a196 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -526,6 +526,7 @@ static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) return REGULATOR_MODE_NORMAL; } +static struct regulator_ops mc13892_vcam_ops; static int mc13892_regulator_probe(struct platform_device *pdev) { @@ -582,10 +583,12 @@ static int mc13892_regulator_probe(struct platform_device *pdev) } mc13xxx_unlock(mc13892); - mc13892_regulators[MC13892_VCAM].desc.ops->set_mode - = mc13892_vcam_set_mode; - mc13892_regulators[MC13892_VCAM].desc.ops->get_mode - = mc13892_vcam_get_mode; + /* update mc13892_vcam ops */ + memcpy(&mc13892_vcam_ops, mc13892_regulators[MC13892_VCAM].desc.ops, + sizeof(struct regulator_ops)); + mc13892_vcam_ops.set_mode = mc13892_vcam_set_mode, + mc13892_vcam_ops.get_mode = mc13892_vcam_get_mode, + mc13892_regulators[MC13892_VCAM].desc.ops = &mc13892_vcam_ops; mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators, ARRAY_SIZE(mc13892_regulators)); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index ee5e67bc8d5..7a51814abdc 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -14,8 +14,11 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> +#include "internal.h" + static void of_get_regulation_constraints(struct device_node *np, struct regulator_init_data **init_data) { @@ -189,3 +192,51 @@ int of_regulator_match(struct device *dev, struct device_node *node, return count; } EXPORT_SYMBOL_GPL(of_regulator_match); + +struct regulator_init_data *regulator_of_get_init_data(struct device *dev, + const struct regulator_desc *desc, + struct device_node **node) +{ + struct device_node *search, *child; + struct regulator_init_data *init_data = NULL; + const char *name; + + if (!dev->of_node || !desc->of_match) + return NULL; + + if (desc->regulators_node) + search = of_get_child_by_name(dev->of_node, + desc->regulators_node); + else + search = dev->of_node; + + if (!search) { + dev_err(dev, "Failed to find regulator container node\n"); + return NULL; + } + + for_each_child_of_node(search, child) { + name = of_get_property(child, "regulator-compatible", NULL); + if (!name) + name = child->name; + + if (strcmp(desc->of_match, name)) + continue; + + init_data = of_get_regulator_init_data(dev, child); + if (!init_data) { + dev_err(dev, + "failed to parse DT for regulator %s\n", + child->name); + break; + } + + of_node_get(child); + *node = child; + break; + } + + of_node_put(search); + + return init_data; +} diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c new file mode 100644 index 00000000000..d3f55eaea05 --- /dev/null +++ b/drivers/regulator/pwm-regulator.c @@ -0,0 +1,197 @@ +/* + * Regulator driver for PWM Regulators + * + * Copyright (C) 2014 - STMicroelectronics Inc. + * + * Author: Lee Jones <lee.jones@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pwm.h> + +struct pwm_regulator_data { + struct regulator_desc desc; + struct pwm_voltages *duty_cycle_table; + struct pwm_device *pwm; + bool enabled; + int state; +}; + +struct pwm_voltages { + unsigned int uV; + unsigned int dutycycle; +}; + +static int pwm_regulator_get_voltage_sel(struct regulator_dev *dev) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + + return drvdata->state; +} + +static int pwm_regulator_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + unsigned int pwm_reg_period; + int dutycycle; + int ret; + + pwm_reg_period = pwm_get_period(drvdata->pwm); + + dutycycle = (pwm_reg_period * + drvdata->duty_cycle_table[selector].dutycycle) / 100; + + ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period); + if (ret) { + dev_err(&dev->dev, "Failed to configure PWM\n"); + return ret; + } + + drvdata->state = selector; + + if (!drvdata->enabled) { + ret = pwm_enable(drvdata->pwm); + if (ret) { + dev_err(&dev->dev, "Failed to enable PWM\n"); + return ret; + } + drvdata->enabled = true; + } + + return 0; +} + +static int pwm_regulator_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + + if (selector >= drvdata->desc.n_voltages) + return -EINVAL; + + return drvdata->duty_cycle_table[selector].uV; +} + +static struct regulator_ops pwm_regulator_voltage_ops = { + .set_voltage_sel = pwm_regulator_set_voltage_sel, + .get_voltage_sel = pwm_regulator_get_voltage_sel, + .list_voltage = pwm_regulator_list_voltage, + .map_voltage = regulator_map_voltage_iterate, +}; + +static const struct regulator_desc pwm_regulator_desc = { + .name = "pwm-regulator", + .ops = &pwm_regulator_voltage_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .supply_name = "pwm", +}; + +static int pwm_regulator_probe(struct platform_device *pdev) +{ + struct pwm_regulator_data *drvdata; + struct property *prop; + struct regulator_dev *regulator; + struct regulator_config config = { }; + struct device_node *np = pdev->dev.of_node; + int length, ret; + + if (!np) { + dev_err(&pdev->dev, "Device Tree node missing\n"); + return -EINVAL; + } + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(pwm_regulator_desc)); + + /* determine the number of voltage-table */ + prop = of_find_property(np, "voltage-table", &length); + if (!prop) { + dev_err(&pdev->dev, "No voltage-table\n"); + return -EINVAL; + } + + if ((length < sizeof(*drvdata->duty_cycle_table)) || + (length % sizeof(*drvdata->duty_cycle_table))) { + dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n", + length); + return -EINVAL; + } + + drvdata->desc.n_voltages = length / sizeof(*drvdata->duty_cycle_table); + + drvdata->duty_cycle_table = devm_kzalloc(&pdev->dev, + length, GFP_KERNEL); + if (!drvdata->duty_cycle_table) + return -ENOMEM; + + /* read voltage table from DT property */ + ret = of_property_read_u32_array(np, "voltage-table", + (u32 *)drvdata->duty_cycle_table, + length / sizeof(u32)); + if (ret < 0) { + dev_err(&pdev->dev, "read voltage-table failed\n"); + return ret; + } + + config.init_data = of_get_regulator_init_data(&pdev->dev, np); + if (!config.init_data) + return -ENOMEM; + + config.of_node = np; + config.dev = &pdev->dev; + config.driver_data = drvdata; + + drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); + if (IS_ERR(drvdata->pwm)) { + dev_err(&pdev->dev, "Failed to get PWM\n"); + return PTR_ERR(drvdata->pwm); + } + + regulator = devm_regulator_register(&pdev->dev, + &drvdata->desc, &config); + if (IS_ERR(regulator)) { + dev_err(&pdev->dev, "Failed to register regulator %s\n", + drvdata->desc.name); + return PTR_ERR(regulator); + } + + return 0; +} + +static const struct of_device_id pwm_of_match[] = { + { .compatible = "pwm-regulator" }, + { }, +}; +MODULE_DEVICE_TABLE(of, pwm_of_match); + +static struct platform_driver pwm_regulator_driver = { + .driver = { + .name = "pwm-regulator", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pwm_of_match), + }, + .probe = pwm_regulator_probe, +}; + +module_platform_driver(pwm_regulator_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); +MODULE_DESCRIPTION("PWM Regulator Driver"); +MODULE_ALIAS("platform:pwm-regulator"); diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c new file mode 100644 index 00000000000..b55cd5b50eb --- /dev/null +++ b/drivers/regulator/qcom_rpm-regulator.c @@ -0,0 +1,798 @@ +/* + * Copyright (c) 2014, Sony Mobile Communications AB. + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/mfd/qcom_rpm.h> + +#include <dt-bindings/mfd/qcom-rpm.h> + +#define MAX_REQUEST_LEN 2 + +struct request_member { + int word; + unsigned int mask; + int shift; +}; + +struct rpm_reg_parts { + struct request_member mV; /* used if voltage is in mV */ + struct request_member uV; /* used if voltage is in uV */ + struct request_member ip; /* peak current in mA */ + struct request_member pd; /* pull down enable */ + struct request_member ia; /* average current in mA */ + struct request_member fm; /* force mode */ + struct request_member pm; /* power mode */ + struct request_member pc; /* pin control */ + struct request_member pf; /* pin function */ + struct request_member enable_state; /* NCP and switch */ + struct request_member comp_mode; /* NCP */ + struct request_member freq; /* frequency: NCP and SMPS */ + struct request_member freq_clk_src; /* clock source: SMPS */ + struct request_member hpm; /* switch: control OCP and SS */ + int request_len; +}; + +#define FORCE_MODE_IS_2_BITS(reg) \ + (((reg)->parts->fm.mask >> (reg)->parts->fm.shift) == 3) + +struct qcom_rpm_reg { + struct qcom_rpm *rpm; + + struct mutex lock; + struct device *dev; + struct regulator_desc desc; + const struct rpm_reg_parts *parts; + + int resource; + u32 val[MAX_REQUEST_LEN]; + + int uV; + int is_enabled; + + bool supports_force_mode_auto; + bool supports_force_mode_bypass; +}; + +static const struct rpm_reg_parts rpm8660_ldo_parts = { + .request_len = 2, + .mV = { 0, 0x00000FFF, 0 }, + .ip = { 0, 0x00FFF000, 12 }, + .fm = { 0, 0x03000000, 24 }, + .pc = { 0, 0x3C000000, 26 }, + .pf = { 0, 0xC0000000, 30 }, + .pd = { 1, 0x00000001, 0 }, + .ia = { 1, 0x00001FFE, 1 }, +}; + +static const struct rpm_reg_parts rpm8660_smps_parts = { + .request_len = 2, + .mV = { 0, 0x00000FFF, 0 }, + .ip = { 0, 0x00FFF000, 12 }, + .fm = { 0, 0x03000000, 24 }, + .pc = { 0, 0x3C000000, 26 }, + .pf = { 0, 0xC0000000, 30 }, + .pd = { 1, 0x00000001, 0 }, + .ia = { 1, 0x00001FFE, 1 }, + .freq = { 1, 0x001FE000, 13 }, + .freq_clk_src = { 1, 0x00600000, 21 }, +}; + +static const struct rpm_reg_parts rpm8660_switch_parts = { + .request_len = 1, + .enable_state = { 0, 0x00000001, 0 }, + .pd = { 0, 0x00000002, 1 }, + .pc = { 0, 0x0000003C, 2 }, + .pf = { 0, 0x000000C0, 6 }, + .hpm = { 0, 0x00000300, 8 }, +}; + +static const struct rpm_reg_parts rpm8660_ncp_parts = { + .request_len = 1, + .mV = { 0, 0x00000FFF, 0 }, + .enable_state = { 0, 0x00001000, 12 }, + .comp_mode = { 0, 0x00002000, 13 }, + .freq = { 0, 0x003FC000, 14 }, +}; + +static const struct rpm_reg_parts rpm8960_ldo_parts = { + .request_len = 2, + .uV = { 0, 0x007FFFFF, 0 }, + .pd = { 0, 0x00800000, 23 }, + .pc = { 0, 0x0F000000, 24 }, + .pf = { 0, 0xF0000000, 28 }, + .ip = { 1, 0x000003FF, 0 }, + .ia = { 1, 0x000FFC00, 10 }, + .fm = { 1, 0x00700000, 20 }, +}; + +static const struct rpm_reg_parts rpm8960_smps_parts = { + .request_len = 2, + .uV = { 0, 0x007FFFFF, 0 }, + .pd = { 0, 0x00800000, 23 }, + .pc = { 0, 0x0F000000, 24 }, + .pf = { 0, 0xF0000000, 28 }, + .ip = { 1, 0x000003FF, 0 }, + .ia = { 1, 0x000FFC00, 10 }, + .fm = { 1, 0x00700000, 20 }, + .pm = { 1, 0x00800000, 23 }, + .freq = { 1, 0x1F000000, 24 }, + .freq_clk_src = { 1, 0x60000000, 29 }, +}; + +static const struct rpm_reg_parts rpm8960_switch_parts = { + .request_len = 1, + .enable_state = { 0, 0x00000001, 0 }, + .pd = { 0, 0x00000002, 1 }, + .pc = { 0, 0x0000003C, 2 }, + .pf = { 0, 0x000003C0, 6 }, + .hpm = { 0, 0x00000C00, 10 }, +}; + +static const struct rpm_reg_parts rpm8960_ncp_parts = { + .request_len = 1, + .uV = { 0, 0x007FFFFF, 0 }, + .enable_state = { 0, 0x00800000, 23 }, + .comp_mode = { 0, 0x01000000, 24 }, + .freq = { 0, 0x3E000000, 25 }, +}; + +/* + * Physically available PMIC regulator voltage ranges + */ +static const struct regulator_linear_range pldo_ranges[] = { + REGULATOR_LINEAR_RANGE( 750000, 0, 59, 12500), + REGULATOR_LINEAR_RANGE(1500000, 60, 123, 25000), + REGULATOR_LINEAR_RANGE(3100000, 124, 160, 50000), +}; + +static const struct regulator_linear_range nldo_ranges[] = { + REGULATOR_LINEAR_RANGE( 750000, 0, 63, 12500), +}; + +static const struct regulator_linear_range nldo1200_ranges[] = { + REGULATOR_LINEAR_RANGE( 375000, 0, 59, 6250), + REGULATOR_LINEAR_RANGE( 750000, 60, 123, 12500), +}; + +static const struct regulator_linear_range smps_ranges[] = { + REGULATOR_LINEAR_RANGE( 375000, 0, 29, 12500), + REGULATOR_LINEAR_RANGE( 750000, 30, 89, 12500), + REGULATOR_LINEAR_RANGE(1500000, 90, 153, 25000), +}; + +static const struct regulator_linear_range ftsmps_ranges[] = { + REGULATOR_LINEAR_RANGE( 350000, 0, 6, 50000), + REGULATOR_LINEAR_RANGE( 700000, 7, 63, 12500), + REGULATOR_LINEAR_RANGE(1500000, 64, 100, 50000), +}; + +static const struct regulator_linear_range ncp_ranges[] = { + REGULATOR_LINEAR_RANGE(1500000, 0, 31, 50000), +}; + +static int rpm_reg_write(struct qcom_rpm_reg *vreg, + const struct request_member *req, + const int value) +{ + if (WARN_ON((value << req->shift) & ~req->mask)) + return -EINVAL; + + vreg->val[req->word] &= ~req->mask; + vreg->val[req->word] |= value << req->shift; + + return qcom_rpm_write(vreg->rpm, + vreg->resource, + vreg->val, + vreg->parts->request_len); +} + +static int rpm_reg_set_mV_sel(struct regulator_dev *rdev, + unsigned selector) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + const struct rpm_reg_parts *parts = vreg->parts; + const struct request_member *req = &parts->mV; + int ret = 0; + int uV; + + if (req->mask == 0) + return -EINVAL; + + uV = regulator_list_voltage_linear_range(rdev, selector); + if (uV < 0) + return uV; + + mutex_lock(&vreg->lock); + vreg->uV = uV; + if (vreg->is_enabled) + ret = rpm_reg_write(vreg, req, vreg->uV / 1000); + mutex_unlock(&vreg->lock); + + return ret; +} + +static int rpm_reg_set_uV_sel(struct regulator_dev *rdev, + unsigned selector) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + const struct rpm_reg_parts *parts = vreg->parts; + const struct request_member *req = &parts->uV; + int ret = 0; + int uV; + + if (req->mask == 0) + return -EINVAL; + + uV = regulator_list_voltage_linear_range(rdev, selector); + if (uV < 0) + return uV; + + mutex_lock(&vreg->lock); + vreg->uV = uV; + if (vreg->is_enabled) + ret = rpm_reg_write(vreg, req, vreg->uV); + mutex_unlock(&vreg->lock); + + return ret; +} + +static int rpm_reg_get_voltage(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + + return vreg->uV; +} + +static int rpm_reg_mV_enable(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + const struct rpm_reg_parts *parts = vreg->parts; + const struct request_member *req = &parts->mV; + int ret; + + if (req->mask == 0) + return -EINVAL; + + mutex_lock(&vreg->lock); + ret = rpm_reg_write(vreg, req, vreg->uV / 1000); + if (!ret) + vreg->is_enabled = 1; + mutex_unlock(&vreg->lock); + + return ret; +} + +static int rpm_reg_uV_enable(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + const struct rpm_reg_parts *parts = vreg->parts; + const struct request_member *req = &parts->uV; + int ret; + + if (req->mask == 0) + return -EINVAL; + + mutex_lock(&vreg->lock); + ret = rpm_reg_write(vreg, req, vreg->uV); + if (!ret) + vreg->is_enabled = 1; + mutex_unlock(&vreg->lock); + + return ret; +} + +static int rpm_reg_switch_enable(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + const struct rpm_reg_parts *parts = vreg->parts; + const struct request_member *req = &parts->enable_state; + int ret; + + if (req->mask == 0) + return -EINVAL; + + mutex_lock(&vreg->lock); + ret = rpm_reg_write(vreg, req, 1); + if (!ret) + vreg->is_enabled = 1; + mutex_unlock(&vreg->lock); + + return ret; +} + +static int rpm_reg_mV_disable(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + const struct rpm_reg_parts *parts = vreg->parts; + const struct request_member *req = &parts->mV; + int ret; + + if (req->mask == 0) + return -EINVAL; + + mutex_lock(&vreg->lock); + ret = rpm_reg_write(vreg, req, 0); + if (!ret) + vreg->is_enabled = 0; + mutex_unlock(&vreg->lock); + + return ret; +} + +static int rpm_reg_uV_disable(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + const struct rpm_reg_parts *parts = vreg->parts; + const struct request_member *req = &parts->uV; + int ret; + + if (req->mask == 0) + return -EINVAL; + + mutex_lock(&vreg->lock); + ret = rpm_reg_write(vreg, req, 0); + if (!ret) + vreg->is_enabled = 0; + mutex_unlock(&vreg->lock); + + return ret; +} + +static int rpm_reg_switch_disable(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + const struct rpm_reg_parts *parts = vreg->parts; + const struct request_member *req = &parts->enable_state; + int ret; + + if (req->mask == 0) + return -EINVAL; + + mutex_lock(&vreg->lock); + ret = rpm_reg_write(vreg, req, 0); + if (!ret) + vreg->is_enabled = 0; + mutex_unlock(&vreg->lock); + + return ret; +} + +static int rpm_reg_is_enabled(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + + return vreg->is_enabled; +} + +static struct regulator_ops uV_ops = { + .list_voltage = regulator_list_voltage_linear_range, + + .set_voltage_sel = rpm_reg_set_uV_sel, + .get_voltage = rpm_reg_get_voltage, + + .enable = rpm_reg_uV_enable, + .disable = rpm_reg_uV_disable, + .is_enabled = rpm_reg_is_enabled, +}; + +static struct regulator_ops mV_ops = { + .list_voltage = regulator_list_voltage_linear_range, + + .set_voltage_sel = rpm_reg_set_mV_sel, + .get_voltage = rpm_reg_get_voltage, + + .enable = rpm_reg_mV_enable, + .disable = rpm_reg_mV_disable, + .is_enabled = rpm_reg_is_enabled, +}; + +static struct regulator_ops switch_ops = { + .enable = rpm_reg_switch_enable, + .disable = rpm_reg_switch_disable, + .is_enabled = rpm_reg_is_enabled, +}; + +/* + * PM8058 regulators + */ +static const struct qcom_rpm_reg pm8058_pldo = { + .desc.linear_ranges = pldo_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges), + .desc.n_voltages = 161, + .desc.ops = &mV_ops, + .parts = &rpm8660_ldo_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = false, +}; + +static const struct qcom_rpm_reg pm8058_nldo = { + .desc.linear_ranges = nldo_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges), + .desc.n_voltages = 64, + .desc.ops = &mV_ops, + .parts = &rpm8660_ldo_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = false, +}; + +static const struct qcom_rpm_reg pm8058_smps = { + .desc.linear_ranges = smps_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges), + .desc.n_voltages = 154, + .desc.ops = &mV_ops, + .parts = &rpm8660_smps_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = false, +}; + +static const struct qcom_rpm_reg pm8058_ncp = { + .desc.linear_ranges = ncp_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges), + .desc.n_voltages = 32, + .desc.ops = &mV_ops, + .parts = &rpm8660_ncp_parts, +}; + +static const struct qcom_rpm_reg pm8058_switch = { + .desc.ops = &switch_ops, + .parts = &rpm8660_switch_parts, +}; + +/* + * PM8901 regulators + */ +static const struct qcom_rpm_reg pm8901_pldo = { + .desc.linear_ranges = pldo_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges), + .desc.n_voltages = 161, + .desc.ops = &mV_ops, + .parts = &rpm8660_ldo_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = true, +}; + +static const struct qcom_rpm_reg pm8901_nldo = { + .desc.linear_ranges = nldo_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges), + .desc.n_voltages = 64, + .desc.ops = &mV_ops, + .parts = &rpm8660_ldo_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = true, +}; + +static const struct qcom_rpm_reg pm8901_ftsmps = { + .desc.linear_ranges = ftsmps_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(ftsmps_ranges), + .desc.n_voltages = 101, + .desc.ops = &mV_ops, + .parts = &rpm8660_smps_parts, + .supports_force_mode_auto = true, + .supports_force_mode_bypass = false, +}; + +static const struct qcom_rpm_reg pm8901_switch = { + .desc.ops = &switch_ops, + .parts = &rpm8660_switch_parts, +}; + +/* + * PM8921 regulators + */ +static const struct qcom_rpm_reg pm8921_pldo = { + .desc.linear_ranges = pldo_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges), + .desc.n_voltages = 161, + .desc.ops = &uV_ops, + .parts = &rpm8960_ldo_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = true, +}; + +static const struct qcom_rpm_reg pm8921_nldo = { + .desc.linear_ranges = nldo_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges), + .desc.n_voltages = 64, + .desc.ops = &uV_ops, + .parts = &rpm8960_ldo_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = true, +}; + +static const struct qcom_rpm_reg pm8921_nldo1200 = { + .desc.linear_ranges = nldo1200_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(nldo1200_ranges), + .desc.n_voltages = 124, + .desc.ops = &uV_ops, + .parts = &rpm8960_ldo_parts, + .supports_force_mode_auto = false, + .supports_force_mode_bypass = true, +}; + +static const struct qcom_rpm_reg pm8921_smps = { + .desc.linear_ranges = smps_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges), + .desc.n_voltages = 154, + .desc.ops = &uV_ops, + .parts = &rpm8960_smps_parts, + .supports_force_mode_auto = true, + .supports_force_mode_bypass = false, +}; + +static const struct qcom_rpm_reg pm8921_ftsmps = { + .desc.linear_ranges = ftsmps_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(ftsmps_ranges), + .desc.n_voltages = 101, + .desc.ops = &uV_ops, + .parts = &rpm8960_smps_parts, + .supports_force_mode_auto = true, + .supports_force_mode_bypass = false, +}; + +static const struct qcom_rpm_reg pm8921_ncp = { + .desc.linear_ranges = ncp_ranges, + .desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges), + .desc.n_voltages = 32, + .desc.ops = &uV_ops, + .parts = &rpm8960_ncp_parts, +}; + +static const struct qcom_rpm_reg pm8921_switch = { + .desc.ops = &switch_ops, + .parts = &rpm8960_switch_parts, +}; + +static const struct of_device_id rpm_of_match[] = { + { .compatible = "qcom,rpm-pm8058-pldo", .data = &pm8058_pldo }, + { .compatible = "qcom,rpm-pm8058-nldo", .data = &pm8058_nldo }, + { .compatible = "qcom,rpm-pm8058-smps", .data = &pm8058_smps }, + { .compatible = "qcom,rpm-pm8058-ncp", .data = &pm8058_ncp }, + { .compatible = "qcom,rpm-pm8058-switch", .data = &pm8058_switch }, + + { .compatible = "qcom,rpm-pm8901-pldo", .data = &pm8901_pldo }, + { .compatible = "qcom,rpm-pm8901-nldo", .data = &pm8901_nldo }, + { .compatible = "qcom,rpm-pm8901-ftsmps", .data = &pm8901_ftsmps }, + { .compatible = "qcom,rpm-pm8901-switch", .data = &pm8901_switch }, + + { .compatible = "qcom,rpm-pm8921-pldo", .data = &pm8921_pldo }, + { .compatible = "qcom,rpm-pm8921-nldo", .data = &pm8921_nldo }, + { .compatible = "qcom,rpm-pm8921-nldo1200", .data = &pm8921_nldo1200 }, + { .compatible = "qcom,rpm-pm8921-smps", .data = &pm8921_smps }, + { .compatible = "qcom,rpm-pm8921-ftsmps", .data = &pm8921_ftsmps }, + { .compatible = "qcom,rpm-pm8921-ncp", .data = &pm8921_ncp }, + { .compatible = "qcom,rpm-pm8921-switch", .data = &pm8921_switch }, + { } +}; +MODULE_DEVICE_TABLE(of, rpm_of_match); + +static int rpm_reg_set(struct qcom_rpm_reg *vreg, + const struct request_member *req, + const int value) +{ + if (req->mask == 0 || (value << req->shift) & ~req->mask) + return -EINVAL; + + vreg->val[req->word] &= ~req->mask; + vreg->val[req->word] |= value << req->shift; + + return 0; +} + +static int rpm_reg_of_parse_freq(struct device *dev, struct qcom_rpm_reg *vreg) +{ + static const int freq_table[] = { + 19200000, 9600000, 6400000, 4800000, 3840000, 3200000, 2740000, + 2400000, 2130000, 1920000, 1750000, 1600000, 1480000, 1370000, + 1280000, 1200000, + + }; + const char *key; + u32 freq; + int ret; + int i; + + key = "qcom,switch-mode-frequency"; + ret = of_property_read_u32(dev->of_node, key, &freq); + if (ret) { + dev_err(dev, "regulator requires %s property\n", key); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(freq_table); i++) { + if (freq == freq_table[i]) { + rpm_reg_set(vreg, &vreg->parts->freq, i + 1); + return 0; + } + } + + dev_err(dev, "invalid frequency %d\n", freq); + return -EINVAL; +} + +static int rpm_reg_probe(struct platform_device *pdev) +{ + struct regulator_init_data *initdata; + const struct qcom_rpm_reg *template; + const struct of_device_id *match; + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct qcom_rpm_reg *vreg; + const char *key; + u32 force_mode; + bool pwm; + u32 val; + int ret; + + match = of_match_device(rpm_of_match, &pdev->dev); + template = match->data; + + initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); + if (!initdata) + return -EINVAL; + + vreg = devm_kmalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); + if (!vreg) { + dev_err(&pdev->dev, "failed to allocate vreg\n"); + return -ENOMEM; + } + memcpy(vreg, template, sizeof(*vreg)); + mutex_init(&vreg->lock); + vreg->dev = &pdev->dev; + vreg->desc.id = -1; + vreg->desc.owner = THIS_MODULE; + vreg->desc.type = REGULATOR_VOLTAGE; + vreg->desc.name = pdev->dev.of_node->name; + + vreg->rpm = dev_get_drvdata(pdev->dev.parent); + if (!vreg->rpm) { + dev_err(&pdev->dev, "unable to retrieve handle to rpm\n"); + return -ENODEV; + } + + key = "reg"; + ret = of_property_read_u32(pdev->dev.of_node, key, &val); + if (ret) { + dev_err(&pdev->dev, "failed to read %s\n", key); + return ret; + } + vreg->resource = val; + + if ((vreg->parts->uV.mask || vreg->parts->mV.mask) && + (!initdata->constraints.min_uV || !initdata->constraints.max_uV)) { + dev_err(&pdev->dev, "no voltage specified for regulator\n"); + return -EINVAL; + } + + key = "bias-pull-down"; + if (of_property_read_bool(pdev->dev.of_node, key)) { + ret = rpm_reg_set(vreg, &vreg->parts->pd, 1); + if (ret) { + dev_err(&pdev->dev, "%s is invalid", key); + return ret; + } + } + + if (vreg->parts->freq.mask) { + ret = rpm_reg_of_parse_freq(&pdev->dev, vreg); + if (ret < 0) + return ret; + } + + if (vreg->parts->pm.mask) { + key = "qcom,power-mode-hysteretic"; + pwm = !of_property_read_bool(pdev->dev.of_node, key); + + ret = rpm_reg_set(vreg, &vreg->parts->pm, pwm); + if (ret) { + dev_err(&pdev->dev, "failed to set power mode\n"); + return ret; + } + } + + if (vreg->parts->fm.mask) { + force_mode = -1; + + key = "qcom,force-mode"; + ret = of_property_read_u32(pdev->dev.of_node, key, &val); + if (ret == -EINVAL) { + val = QCOM_RPM_FORCE_MODE_NONE; + } else if (ret < 0) { + dev_err(&pdev->dev, "failed to read %s\n", key); + return ret; + } + + /* + * If force-mode is encoded as 2 bits then the + * possible register values are: + * NONE, LPM, HPM + * otherwise: + * NONE, LPM, AUTO, HPM, BYPASS + */ + switch (val) { + case QCOM_RPM_FORCE_MODE_NONE: + force_mode = 0; + break; + case QCOM_RPM_FORCE_MODE_LPM: + force_mode = 1; + break; + case QCOM_RPM_FORCE_MODE_HPM: + if (FORCE_MODE_IS_2_BITS(vreg)) + force_mode = 2; + else + force_mode = 3; + break; + case QCOM_RPM_FORCE_MODE_AUTO: + if (vreg->supports_force_mode_auto) + force_mode = 2; + break; + case QCOM_RPM_FORCE_MODE_BYPASS: + if (vreg->supports_force_mode_bypass) + force_mode = 4; + break; + } + + if (force_mode < 0) { + dev_err(&pdev->dev, "invalid force mode\n"); + return -EINVAL; + } + + ret = rpm_reg_set(vreg, &vreg->parts->fm, force_mode); + if (ret) { + dev_err(&pdev->dev, "failed to set force mode\n"); + return ret; + } + } + + config.dev = &pdev->dev; + config.init_data = initdata; + config.driver_data = vreg; + config.of_node = pdev->dev.of_node; + rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "can't register regulator\n"); + return PTR_ERR(rdev); + } + + return 0; +} + +static struct platform_driver rpm_reg_driver = { + .probe = rpm_reg_probe, + .driver = { + .name = "qcom_rpm_reg", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rpm_of_match), + }, +}; + +static int __init rpm_reg_init(void) +{ + return platform_driver_register(&rpm_reg_driver); +} +subsys_initcall(rpm_reg_init); + +static void __exit rpm_reg_exit(void) +{ + platform_driver_unregister(&rpm_reg_driver); +} +module_exit(rpm_reg_exit) + +MODULE_DESCRIPTION("Qualcomm RPM regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c new file mode 100644 index 00000000000..e305416d769 --- /dev/null +++ b/drivers/regulator/rk808-regulator.c @@ -0,0 +1,381 @@ +/* + * Regulator driver for Rockchip RK808 + * + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd + * + * Author: Chris Zhong <zyw@rock-chips.com> + * Author: Zhang Qing <zhangqing@rock-chips.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/mfd/rk808.h> +#include <linux/of_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +/* Field Definitions */ +#define RK808_BUCK_VSEL_MASK 0x3f +#define RK808_BUCK4_VSEL_MASK 0xf +#define RK808_LDO_VSEL_MASK 0x1f + +/* Ramp rate definitions for buck1 / buck2 only */ +#define RK808_RAMP_RATE_OFFSET 3 +#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET) +#define RK808_RAMP_RATE_2MV_PER_US (0 << RK808_RAMP_RATE_OFFSET) +#define RK808_RAMP_RATE_4MV_PER_US (1 << RK808_RAMP_RATE_OFFSET) +#define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET) +#define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET) + +static const int rk808_buck_config_regs[] = { + RK808_BUCK1_CONFIG_REG, + RK808_BUCK2_CONFIG_REG, + RK808_BUCK3_CONFIG_REG, + RK808_BUCK4_CONFIG_REG, +}; + +static const struct regulator_linear_range rk808_buck_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(700000, 0, 63, 12500), +}; + +static const struct regulator_linear_range rk808_buck4_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(1800000, 0, 15, 100000), +}; + +static const struct regulator_linear_range rk808_ldo_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(1800000, 0, 16, 100000), +}; + +static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000), + REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0), +}; + +static const struct regulator_linear_range rk808_ldo6_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(800000, 0, 17, 100000), +}; + +static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + unsigned int ramp_value = RK808_RAMP_RATE_10MV_PER_US; + unsigned int reg = rk808_buck_config_regs[rdev->desc->id - + RK808_ID_DCDC1]; + + switch (ramp_delay) { + case 1 ... 2000: + ramp_value = RK808_RAMP_RATE_2MV_PER_US; + break; + case 2001 ... 4000: + ramp_value = RK808_RAMP_RATE_4MV_PER_US; + break; + case 4001 ... 6000: + ramp_value = RK808_RAMP_RATE_6MV_PER_US; + break; + case 6001 ... 10000: + break; + default: + pr_warn("%s ramp_delay: %d not supported, setting 10000\n", + rdev->desc->name, ramp_delay); + } + + return regmap_update_bits(rdev->regmap, reg, + RK808_RAMP_RATE_MASK, ramp_value); +} + +static struct regulator_ops rk808_buck1_2_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_ramp_delay = rk808_set_ramp_delay, +}; + +static struct regulator_ops rk808_reg_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static struct regulator_ops rk808_switch_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_desc rk808_reg[] = { + { + .name = "DCDC_REG1", + .supply_name = "vcc1", + .id = RK808_ID_DCDC1, + .ops = &rk808_buck1_2_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 64, + .linear_ranges = rk808_buck_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges), + .vsel_reg = RK808_BUCK1_ON_VSEL_REG, + .vsel_mask = RK808_BUCK_VSEL_MASK, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(0), + .owner = THIS_MODULE, + }, { + .name = "DCDC_REG2", + .supply_name = "vcc2", + .id = RK808_ID_DCDC2, + .ops = &rk808_buck1_2_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 64, + .linear_ranges = rk808_buck_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges), + .vsel_reg = RK808_BUCK2_ON_VSEL_REG, + .vsel_mask = RK808_BUCK_VSEL_MASK, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(1), + .owner = THIS_MODULE, + }, { + .name = "DCDC_REG3", + .supply_name = "vcc3", + .id = RK808_ID_DCDC3, + .ops = &rk808_switch_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(2), + .owner = THIS_MODULE, + }, { + .name = "DCDC_REG4", + .supply_name = "vcc4", + .id = RK808_ID_DCDC4, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 16, + .linear_ranges = rk808_buck4_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_buck4_voltage_ranges), + .vsel_reg = RK808_BUCK4_ON_VSEL_REG, + .vsel_mask = RK808_BUCK4_VSEL_MASK, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(3), + .owner = THIS_MODULE, + }, { + .name = "LDO_REG1", + .supply_name = "vcc6", + .id = RK808_ID_LDO1, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 17, + .linear_ranges = rk808_ldo_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), + .vsel_reg = RK808_LDO1_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(0), + .owner = THIS_MODULE, + }, { + .name = "LDO_REG2", + .supply_name = "vcc6", + .id = RK808_ID_LDO2, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 17, + .linear_ranges = rk808_ldo_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), + .vsel_reg = RK808_LDO2_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(1), + .owner = THIS_MODULE, + }, { + .name = "LDO_REG3", + .supply_name = "vcc7", + .id = RK808_ID_LDO3, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 16, + .linear_ranges = rk808_ldo3_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges), + .vsel_reg = RK808_LDO3_ON_VSEL_REG, + .vsel_mask = RK808_BUCK4_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(2), + .owner = THIS_MODULE, + }, { + .name = "LDO_REG4", + .supply_name = "vcc9", + .id = RK808_ID_LDO4, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 17, + .linear_ranges = rk808_ldo_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), + .vsel_reg = RK808_LDO4_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(3), + .owner = THIS_MODULE, + }, { + .name = "LDO_REG5", + .supply_name = "vcc9", + .id = RK808_ID_LDO5, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 17, + .linear_ranges = rk808_ldo_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), + .vsel_reg = RK808_LDO5_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(4), + .owner = THIS_MODULE, + }, { + .name = "LDO_REG6", + .supply_name = "vcc10", + .id = RK808_ID_LDO6, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 18, + .linear_ranges = rk808_ldo6_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges), + .vsel_reg = RK808_LDO6_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(5), + .owner = THIS_MODULE, + }, { + .name = "LDO_REG7", + .supply_name = "vcc7", + .id = RK808_ID_LDO7, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 18, + .linear_ranges = rk808_ldo6_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges), + .vsel_reg = RK808_LDO7_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(6), + .owner = THIS_MODULE, + }, { + .name = "LDO_REG8", + .supply_name = "vcc11", + .id = RK808_ID_LDO8, + .ops = &rk808_reg_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 17, + .linear_ranges = rk808_ldo_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges), + .vsel_reg = RK808_LDO8_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(7), + .owner = THIS_MODULE, + }, { + .name = "SWITCH_REG1", + .supply_name = "vcc8", + .id = RK808_ID_SWITCH1, + .ops = &rk808_switch_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(5), + .owner = THIS_MODULE, + }, { + .name = "SWITCH_REG2", + .supply_name = "vcc12", + .id = RK808_ID_SWITCH2, + .ops = &rk808_switch_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(6), + .owner = THIS_MODULE, + }, +}; + +static struct of_regulator_match rk808_reg_matches[] = { + [RK808_ID_DCDC1] = { .name = "DCDC_REG1" }, + [RK808_ID_DCDC2] = { .name = "DCDC_REG2" }, + [RK808_ID_DCDC3] = { .name = "DCDC_REG3" }, + [RK808_ID_DCDC4] = { .name = "DCDC_REG4" }, + [RK808_ID_LDO1] = { .name = "LDO_REG1" }, + [RK808_ID_LDO2] = { .name = "LDO_REG2" }, + [RK808_ID_LDO3] = { .name = "LDO_REG3" }, + [RK808_ID_LDO4] = { .name = "LDO_REG4" }, + [RK808_ID_LDO5] = { .name = "LDO_REG5" }, + [RK808_ID_LDO6] = { .name = "LDO_REG6" }, + [RK808_ID_LDO7] = { .name = "LDO_REG7" }, + [RK808_ID_LDO8] = { .name = "LDO_REG8" }, + [RK808_ID_SWITCH1] = { .name = "SWITCH_REG1" }, + [RK808_ID_SWITCH2] = { .name = "SWITCH_REG2" }, +}; + +static int rk808_regulator_probe(struct platform_device *pdev) +{ + struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); + struct i2c_client *client = rk808->i2c; + struct device_node *reg_np; + struct regulator_config config = {}; + struct regulator_dev *rk808_rdev; + int ret, i; + + reg_np = of_get_child_by_name(client->dev.of_node, "regulators"); + if (!reg_np) + return -ENXIO; + + ret = of_regulator_match(&pdev->dev, reg_np, rk808_reg_matches, + RK808_NUM_REGULATORS); + of_node_put(reg_np); + if (ret < 0) + return ret; + + /* Instantiate the regulators */ + for (i = 0; i < RK808_NUM_REGULATORS; i++) { + if (!rk808_reg_matches[i].init_data || + !rk808_reg_matches[i].of_node) + continue; + + config.dev = &client->dev; + config.driver_data = rk808; + config.regmap = rk808->regmap; + config.of_node = rk808_reg_matches[i].of_node; + config.init_data = rk808_reg_matches[i].init_data; + + rk808_rdev = devm_regulator_register(&pdev->dev, + &rk808_reg[i], &config); + if (IS_ERR(rk808_rdev)) { + dev_err(&client->dev, + "failed to register %d regulator\n", i); + return PTR_ERR(rk808_rdev); + } + } + + return 0; +} + +static struct platform_driver rk808_regulator_driver = { + .probe = rk808_regulator_probe, + .driver = { + .name = "rk808-regulator", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(rk808_regulator_driver); + +MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs"); +MODULE_AUTHOR("Chris Zhong<zyw@rock-chips.com>"); +MODULE_AUTHOR("Zhang Qing<zhangqing@rock-chips.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rk808-regulator"); diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c new file mode 100644 index 00000000000..e58d79aeb39 --- /dev/null +++ b/drivers/regulator/rn5t618-regulator.c @@ -0,0 +1,143 @@ +/* + * Regulator driver for Ricoh RN5T618 PMIC + * + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/mfd/rn5t618.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +static struct regulator_ops rn5t618_reg_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, +}; + +#define REG(rid, ereg, emask, vreg, vmask, min, max, step) \ + [RN5T618_##rid] = { \ + .name = #rid, \ + .id = RN5T618_##rid, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .ops = &rn5t618_reg_ops, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .min_uV = (min), \ + .uV_step = (step), \ + .enable_reg = RN5T618_##ereg, \ + .enable_mask = (emask), \ + .vsel_reg = RN5T618_##vreg, \ + .vsel_mask = (vmask), \ + } + +static struct regulator_desc rn5t618_regulators[] = { + /* DCDC */ + REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC2, DC2CTL, BIT(0), DC2DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC3, DC3CTL, BIT(0), DC3DAC, 0xff, 600000, 3500000, 12500), + /* LDO */ + REG(LDO1, LDOEN1, BIT(0), LDO1DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO2, LDOEN1, BIT(1), LDO2DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO3, LDOEN1, BIT(2), LDO3DAC, 0x7f, 600000, 3500000, 25000), + REG(LDO4, LDOEN1, BIT(3), LDO4DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO5, LDOEN1, BIT(4), LDO5DAC, 0x7f, 900000, 3500000, 25000), + /* LDO RTC */ + REG(LDORTC1, LDOEN2, BIT(4), LDORTCDAC, 0x7f, 1700000, 3500000, 25000), + REG(LDORTC2, LDOEN2, BIT(5), LDORTC2DAC, 0x7f, 900000, 3500000, 25000), +}; + +static struct of_regulator_match rn5t618_matches[] = { + [RN5T618_DCDC1] = { .name = "DCDC1" }, + [RN5T618_DCDC2] = { .name = "DCDC2" }, + [RN5T618_DCDC3] = { .name = "DCDC3" }, + [RN5T618_LDO1] = { .name = "LDO1" }, + [RN5T618_LDO2] = { .name = "LDO2" }, + [RN5T618_LDO3] = { .name = "LDO3" }, + [RN5T618_LDO4] = { .name = "LDO4" }, + [RN5T618_LDO5] = { .name = "LDO5" }, + [RN5T618_LDORTC1] = { .name = "LDORTC1" }, + [RN5T618_LDORTC2] = { .name = "LDORTC2" }, +}; + +static int rn5t618_regulator_parse_dt(struct platform_device *pdev) +{ + struct device_node *np, *regulators; + int ret; + + np = of_node_get(pdev->dev.parent->of_node); + if (!np) + return 0; + + regulators = of_get_child_by_name(np, "regulators"); + if (!regulators) { + dev_err(&pdev->dev, "regulators node not found\n"); + return -EINVAL; + } + + ret = of_regulator_match(&pdev->dev, regulators, rn5t618_matches, + ARRAY_SIZE(rn5t618_matches)); + of_node_put(regulators); + if (ret < 0) { + dev_err(&pdev->dev, "error parsing regulator init data: %d\n", + ret); + } + + return 0; +} + +static int rn5t618_regulator_probe(struct platform_device *pdev) +{ + struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; + struct regulator_dev *rdev; + int ret, i; + + ret = rn5t618_regulator_parse_dt(pdev); + if (ret) + return ret; + + for (i = 0; i < RN5T618_REG_NUM; i++) { + config.dev = &pdev->dev; + config.init_data = rn5t618_matches[i].init_data; + config.of_node = rn5t618_matches[i].of_node; + config.regmap = rn5t618->regmap; + + rdev = devm_regulator_register(&pdev->dev, + &rn5t618_regulators[i], + &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s regulator\n", + rn5t618_regulators[i].name); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static struct platform_driver rn5t618_regulator_driver = { + .probe = rn5t618_regulator_probe, + .driver = { + .name = "rn5t618-regulator", + }, +}; + +module_platform_driver(rn5t618_regulator_driver); + +MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); +MODULE_DESCRIPTION("RN5T618 regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c index ee83b487642..4acefa6b462 100644 --- a/drivers/regulator/s2mpa01.c +++ b/drivers/regulator/s2mpa01.c @@ -235,28 +235,14 @@ static struct regulator_ops s2mpa01_buck_ops = { .set_ramp_delay = s2mpa01_set_ramp_delay, }; -#define regulator_desc_ldo1(num) { \ +#define regulator_desc_ldo(num, step) { \ .name = "LDO"#num, \ .id = S2MPA01_LDO##num, \ .ops = &s2mpa01_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPA01_LDO_MIN, \ - .uV_step = S2MPA01_LDO_STEP1, \ - .n_voltages = S2MPA01_LDO_N_VOLTAGES, \ - .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \ - .vsel_mask = S2MPA01_LDO_VSEL_MASK, \ - .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \ - .enable_mask = S2MPA01_ENABLE_MASK \ -} -#define regulator_desc_ldo2(num) { \ - .name = "LDO"#num, \ - .id = S2MPA01_LDO##num, \ - .ops = &s2mpa01_ldo_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPA01_LDO_MIN, \ - .uV_step = S2MPA01_LDO_STEP2, \ + .min_uV = MIN_800_MV, \ + .uV_step = step, \ .n_voltages = S2MPA01_LDO_N_VOLTAGES, \ .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \ .vsel_mask = S2MPA01_LDO_VSEL_MASK, \ @@ -270,8 +256,8 @@ static struct regulator_ops s2mpa01_buck_ops = { .ops = &s2mpa01_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPA01_BUCK_MIN1, \ - .uV_step = S2MPA01_BUCK_STEP1, \ + .min_uV = MIN_600_MV, \ + .uV_step = STEP_6_25_MV, \ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ .ramp_delay = S2MPA01_RAMP_DELAY, \ .vsel_reg = S2MPA01_REG_B1CTRL2 + (num - 1) * 2, \ @@ -286,8 +272,8 @@ static struct regulator_ops s2mpa01_buck_ops = { .ops = &s2mpa01_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPA01_BUCK_MIN2, \ - .uV_step = S2MPA01_BUCK_STEP1, \ + .min_uV = MIN_800_MV, \ + .uV_step = STEP_6_25_MV, \ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ .ramp_delay = S2MPA01_RAMP_DELAY, \ .vsel_reg = S2MPA01_REG_B5CTRL2, \ @@ -296,14 +282,14 @@ static struct regulator_ops s2mpa01_buck_ops = { .enable_mask = S2MPA01_ENABLE_MASK \ } -#define regulator_desc_buck6_7(num) { \ +#define regulator_desc_buck6_10(num, min, step) { \ .name = "BUCK"#num, \ .id = S2MPA01_BUCK##num, \ .ops = &s2mpa01_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPA01_BUCK_MIN1, \ - .uV_step = S2MPA01_BUCK_STEP1, \ + .min_uV = min, \ + .uV_step = step, \ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ .ramp_delay = S2MPA01_RAMP_DELAY, \ .vsel_reg = S2MPA01_REG_B6CTRL2 + (num - 6) * 2, \ @@ -312,91 +298,43 @@ static struct regulator_ops s2mpa01_buck_ops = { .enable_mask = S2MPA01_ENABLE_MASK \ } -#define regulator_desc_buck8 { \ - .name = "BUCK8", \ - .id = S2MPA01_BUCK8, \ - .ops = &s2mpa01_buck_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPA01_BUCK_MIN2, \ - .uV_step = S2MPA01_BUCK_STEP2, \ - .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ - .ramp_delay = S2MPA01_RAMP_DELAY, \ - .vsel_reg = S2MPA01_REG_B8CTRL2, \ - .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ - .enable_reg = S2MPA01_REG_B8CTRL1, \ - .enable_mask = S2MPA01_ENABLE_MASK \ -} - -#define regulator_desc_buck9 { \ - .name = "BUCK9", \ - .id = S2MPA01_BUCK9, \ - .ops = &s2mpa01_buck_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPA01_BUCK_MIN4, \ - .uV_step = S2MPA01_BUCK_STEP2, \ - .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ - .ramp_delay = S2MPA01_RAMP_DELAY, \ - .vsel_reg = S2MPA01_REG_B9CTRL2, \ - .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ - .enable_reg = S2MPA01_REG_B9CTRL1, \ - .enable_mask = S2MPA01_ENABLE_MASK \ -} - -#define regulator_desc_buck10 { \ - .name = "BUCK10", \ - .id = S2MPA01_BUCK10, \ - .ops = &s2mpa01_buck_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPA01_BUCK_MIN3, \ - .uV_step = S2MPA01_BUCK_STEP2, \ - .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ - .ramp_delay = S2MPA01_RAMP_DELAY, \ - .vsel_reg = S2MPA01_REG_B10CTRL2, \ - .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ - .enable_reg = S2MPA01_REG_B10CTRL1, \ - .enable_mask = S2MPA01_ENABLE_MASK \ -} - static struct regulator_desc regulators[] = { - regulator_desc_ldo2(1), - regulator_desc_ldo1(2), - regulator_desc_ldo1(3), - regulator_desc_ldo1(4), - regulator_desc_ldo1(5), - regulator_desc_ldo2(6), - regulator_desc_ldo1(7), - regulator_desc_ldo1(8), - regulator_desc_ldo1(9), - regulator_desc_ldo1(10), - regulator_desc_ldo2(11), - regulator_desc_ldo1(12), - regulator_desc_ldo1(13), - regulator_desc_ldo1(14), - regulator_desc_ldo1(15), - regulator_desc_ldo1(16), - regulator_desc_ldo1(17), - regulator_desc_ldo1(18), - regulator_desc_ldo1(19), - regulator_desc_ldo1(20), - regulator_desc_ldo1(21), - regulator_desc_ldo2(22), - regulator_desc_ldo2(23), - regulator_desc_ldo1(24), - regulator_desc_ldo1(25), - regulator_desc_ldo1(26), + regulator_desc_ldo(1, STEP_25_MV), + regulator_desc_ldo(2, STEP_50_MV), + regulator_desc_ldo(3, STEP_50_MV), + regulator_desc_ldo(4, STEP_50_MV), + regulator_desc_ldo(5, STEP_50_MV), + regulator_desc_ldo(6, STEP_25_MV), + regulator_desc_ldo(7, STEP_50_MV), + regulator_desc_ldo(8, STEP_50_MV), + regulator_desc_ldo(9, STEP_50_MV), + regulator_desc_ldo(10, STEP_50_MV), + regulator_desc_ldo(11, STEP_25_MV), + regulator_desc_ldo(12, STEP_50_MV), + regulator_desc_ldo(13, STEP_50_MV), + regulator_desc_ldo(14, STEP_50_MV), + regulator_desc_ldo(15, STEP_50_MV), + regulator_desc_ldo(16, STEP_50_MV), + regulator_desc_ldo(17, STEP_50_MV), + regulator_desc_ldo(18, STEP_50_MV), + regulator_desc_ldo(19, STEP_50_MV), + regulator_desc_ldo(20, STEP_50_MV), + regulator_desc_ldo(21, STEP_50_MV), + regulator_desc_ldo(22, STEP_25_MV), + regulator_desc_ldo(23, STEP_25_MV), + regulator_desc_ldo(24, STEP_50_MV), + regulator_desc_ldo(25, STEP_50_MV), + regulator_desc_ldo(26, STEP_50_MV), regulator_desc_buck1_4(1), regulator_desc_buck1_4(2), regulator_desc_buck1_4(3), regulator_desc_buck1_4(4), regulator_desc_buck5, - regulator_desc_buck6_7(6), - regulator_desc_buck6_7(7), - regulator_desc_buck8, - regulator_desc_buck9, - regulator_desc_buck10, + regulator_desc_buck6_10(6, MIN_600_MV, STEP_6_25_MV), + regulator_desc_buck6_10(7, MIN_600_MV, STEP_6_25_MV), + regulator_desc_buck6_10(8, MIN_800_MV, STEP_12_5_MV), + regulator_desc_buck6_10(9, MIN_1500_MV, STEP_12_5_MV), + regulator_desc_buck6_10(10, MIN_1000_MV, STEP_12_5_MV), }; static int s2mpa01_pmic_probe(struct platform_device *pdev) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index b16c53a8272..adab82d5279 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -255,28 +255,14 @@ static struct regulator_ops s2mps11_buck_ops = { .set_ramp_delay = s2mps11_set_ramp_delay, }; -#define regulator_desc_s2mps11_ldo1(num) { \ +#define regulator_desc_s2mps11_ldo(num, step) { \ .name = "LDO"#num, \ .id = S2MPS11_LDO##num, \ .ops = &s2mps11_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPS11_LDO_MIN, \ - .uV_step = S2MPS11_LDO_STEP1, \ - .n_voltages = S2MPS11_LDO_N_VOLTAGES, \ - .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \ - .vsel_mask = S2MPS11_LDO_VSEL_MASK, \ - .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \ - .enable_mask = S2MPS11_ENABLE_MASK \ -} -#define regulator_desc_s2mps11_ldo2(num) { \ - .name = "LDO"#num, \ - .id = S2MPS11_LDO##num, \ - .ops = &s2mps11_ldo_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPS11_LDO_MIN, \ - .uV_step = S2MPS11_LDO_STEP2, \ + .min_uV = MIN_800_MV, \ + .uV_step = step, \ .n_voltages = S2MPS11_LDO_N_VOLTAGES, \ .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \ .vsel_mask = S2MPS11_LDO_VSEL_MASK, \ @@ -290,8 +276,8 @@ static struct regulator_ops s2mps11_buck_ops = { .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPS11_BUCK_MIN1, \ - .uV_step = S2MPS11_BUCK_STEP1, \ + .min_uV = MIN_600_MV, \ + .uV_step = STEP_6_25_MV, \ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ .ramp_delay = S2MPS11_RAMP_DELAY, \ .vsel_reg = S2MPS11_REG_B1CTRL2 + (num - 1) * 2, \ @@ -306,8 +292,8 @@ static struct regulator_ops s2mps11_buck_ops = { .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPS11_BUCK_MIN1, \ - .uV_step = S2MPS11_BUCK_STEP1, \ + .min_uV = MIN_600_MV, \ + .uV_step = STEP_6_25_MV, \ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ .ramp_delay = S2MPS11_RAMP_DELAY, \ .vsel_reg = S2MPS11_REG_B5CTRL2, \ @@ -316,14 +302,14 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_s2mps11_buck6_8(num) { \ +#define regulator_desc_s2mps11_buck6_10(num, min, step) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPS11_BUCK_MIN1, \ - .uV_step = S2MPS11_BUCK_STEP1, \ + .min_uV = min, \ + .uV_step = step, \ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ .ramp_delay = S2MPS11_RAMP_DELAY, \ .vsel_reg = S2MPS11_REG_B6CTRL2 + (num - 6) * 2, \ @@ -332,87 +318,55 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_s2mps11_buck9 { \ - .name = "BUCK9", \ - .id = S2MPS11_BUCK9, \ - .ops = &s2mps11_buck_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPS11_BUCK_MIN3, \ - .uV_step = S2MPS11_BUCK_STEP3, \ - .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ - .ramp_delay = S2MPS11_RAMP_DELAY, \ - .vsel_reg = S2MPS11_REG_B9CTRL2, \ - .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ - .enable_reg = S2MPS11_REG_B9CTRL1, \ - .enable_mask = S2MPS11_ENABLE_MASK \ -} - -#define regulator_desc_s2mps11_buck10 { \ - .name = "BUCK10", \ - .id = S2MPS11_BUCK10, \ - .ops = &s2mps11_buck_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPS11_BUCK_MIN2, \ - .uV_step = S2MPS11_BUCK_STEP2, \ - .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ - .ramp_delay = S2MPS11_RAMP_DELAY, \ - .vsel_reg = S2MPS11_REG_B10CTRL2, \ - .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ - .enable_reg = S2MPS11_REG_B10CTRL1, \ - .enable_mask = S2MPS11_ENABLE_MASK \ -} - static const struct regulator_desc s2mps11_regulators[] = { - regulator_desc_s2mps11_ldo2(1), - regulator_desc_s2mps11_ldo1(2), - regulator_desc_s2mps11_ldo1(3), - regulator_desc_s2mps11_ldo1(4), - regulator_desc_s2mps11_ldo1(5), - regulator_desc_s2mps11_ldo2(6), - regulator_desc_s2mps11_ldo1(7), - regulator_desc_s2mps11_ldo1(8), - regulator_desc_s2mps11_ldo1(9), - regulator_desc_s2mps11_ldo1(10), - regulator_desc_s2mps11_ldo2(11), - regulator_desc_s2mps11_ldo1(12), - regulator_desc_s2mps11_ldo1(13), - regulator_desc_s2mps11_ldo1(14), - regulator_desc_s2mps11_ldo1(15), - regulator_desc_s2mps11_ldo1(16), - regulator_desc_s2mps11_ldo1(17), - regulator_desc_s2mps11_ldo1(18), - regulator_desc_s2mps11_ldo1(19), - regulator_desc_s2mps11_ldo1(20), - regulator_desc_s2mps11_ldo1(21), - regulator_desc_s2mps11_ldo2(22), - regulator_desc_s2mps11_ldo2(23), - regulator_desc_s2mps11_ldo1(24), - regulator_desc_s2mps11_ldo1(25), - regulator_desc_s2mps11_ldo1(26), - regulator_desc_s2mps11_ldo2(27), - regulator_desc_s2mps11_ldo1(28), - regulator_desc_s2mps11_ldo1(29), - regulator_desc_s2mps11_ldo1(30), - regulator_desc_s2mps11_ldo1(31), - regulator_desc_s2mps11_ldo1(32), - regulator_desc_s2mps11_ldo1(33), - regulator_desc_s2mps11_ldo1(34), - regulator_desc_s2mps11_ldo1(35), - regulator_desc_s2mps11_ldo1(36), - regulator_desc_s2mps11_ldo1(37), - regulator_desc_s2mps11_ldo1(38), + regulator_desc_s2mps11_ldo(1, STEP_25_MV), + regulator_desc_s2mps11_ldo(2, STEP_50_MV), + regulator_desc_s2mps11_ldo(3, STEP_50_MV), + regulator_desc_s2mps11_ldo(4, STEP_50_MV), + regulator_desc_s2mps11_ldo(5, STEP_50_MV), + regulator_desc_s2mps11_ldo(6, STEP_25_MV), + regulator_desc_s2mps11_ldo(7, STEP_50_MV), + regulator_desc_s2mps11_ldo(8, STEP_50_MV), + regulator_desc_s2mps11_ldo(9, STEP_50_MV), + regulator_desc_s2mps11_ldo(10, STEP_50_MV), + regulator_desc_s2mps11_ldo(11, STEP_25_MV), + regulator_desc_s2mps11_ldo(12, STEP_50_MV), + regulator_desc_s2mps11_ldo(13, STEP_50_MV), + regulator_desc_s2mps11_ldo(14, STEP_50_MV), + regulator_desc_s2mps11_ldo(15, STEP_50_MV), + regulator_desc_s2mps11_ldo(16, STEP_50_MV), + regulator_desc_s2mps11_ldo(17, STEP_50_MV), + regulator_desc_s2mps11_ldo(18, STEP_50_MV), + regulator_desc_s2mps11_ldo(19, STEP_50_MV), + regulator_desc_s2mps11_ldo(20, STEP_50_MV), + regulator_desc_s2mps11_ldo(21, STEP_50_MV), + regulator_desc_s2mps11_ldo(22, STEP_25_MV), + regulator_desc_s2mps11_ldo(23, STEP_25_MV), + regulator_desc_s2mps11_ldo(24, STEP_50_MV), + regulator_desc_s2mps11_ldo(25, STEP_50_MV), + regulator_desc_s2mps11_ldo(26, STEP_50_MV), + regulator_desc_s2mps11_ldo(27, STEP_25_MV), + regulator_desc_s2mps11_ldo(28, STEP_50_MV), + regulator_desc_s2mps11_ldo(29, STEP_50_MV), + regulator_desc_s2mps11_ldo(30, STEP_50_MV), + regulator_desc_s2mps11_ldo(31, STEP_50_MV), + regulator_desc_s2mps11_ldo(32, STEP_50_MV), + regulator_desc_s2mps11_ldo(33, STEP_50_MV), + regulator_desc_s2mps11_ldo(34, STEP_50_MV), + regulator_desc_s2mps11_ldo(35, STEP_50_MV), + regulator_desc_s2mps11_ldo(36, STEP_50_MV), + regulator_desc_s2mps11_ldo(37, STEP_50_MV), + regulator_desc_s2mps11_ldo(38, STEP_50_MV), regulator_desc_s2mps11_buck1_4(1), regulator_desc_s2mps11_buck1_4(2), regulator_desc_s2mps11_buck1_4(3), regulator_desc_s2mps11_buck1_4(4), regulator_desc_s2mps11_buck5, - regulator_desc_s2mps11_buck6_8(6), - regulator_desc_s2mps11_buck6_8(7), - regulator_desc_s2mps11_buck6_8(8), - regulator_desc_s2mps11_buck9, - regulator_desc_s2mps11_buck10, + regulator_desc_s2mps11_buck6_10(6, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps11_buck6_10(7, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps11_buck6_10(8, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps11_buck6_10(9, MIN_3000_MV, STEP_25_MV), + regulator_desc_s2mps11_buck6_10(10, MIN_750_MV, STEP_12_5_MV), }; static int s2mps14_regulator_enable(struct regulator_dev *rdev) @@ -510,56 +464,29 @@ static struct regulator_ops s2mps14_reg_ops = { .set_suspend_disable = s2mps14_regulator_set_suspend_disable, }; -#define regulator_desc_s2mps14_ldo1(num) { \ - .name = "LDO"#num, \ - .id = S2MPS14_LDO##num, \ - .ops = &s2mps14_reg_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPS14_LDO_MIN_800MV, \ - .uV_step = S2MPS14_LDO_STEP_25MV, \ - .n_voltages = S2MPS14_LDO_N_VOLTAGES, \ - .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \ - .vsel_mask = S2MPS14_LDO_VSEL_MASK, \ - .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \ - .enable_mask = S2MPS14_ENABLE_MASK \ -} -#define regulator_desc_s2mps14_ldo2(num) { \ - .name = "LDO"#num, \ - .id = S2MPS14_LDO##num, \ - .ops = &s2mps14_reg_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPS14_LDO_MIN_1800MV, \ - .uV_step = S2MPS14_LDO_STEP_25MV, \ - .n_voltages = S2MPS14_LDO_N_VOLTAGES, \ - .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \ - .vsel_mask = S2MPS14_LDO_VSEL_MASK, \ - .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \ - .enable_mask = S2MPS14_ENABLE_MASK \ -} -#define regulator_desc_s2mps14_ldo3(num) { \ +#define regulator_desc_s2mps14_ldo(num, min, step) { \ .name = "LDO"#num, \ .id = S2MPS14_LDO##num, \ .ops = &s2mps14_reg_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPS14_LDO_MIN_800MV, \ - .uV_step = S2MPS14_LDO_STEP_12_5MV, \ + .min_uV = min, \ + .uV_step = step, \ .n_voltages = S2MPS14_LDO_N_VOLTAGES, \ .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \ .vsel_mask = S2MPS14_LDO_VSEL_MASK, \ .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \ .enable_mask = S2MPS14_ENABLE_MASK \ } -#define regulator_desc_s2mps14_buck1235(num) { \ + +#define regulator_desc_s2mps14_buck(num, min, step) { \ .name = "BUCK"#num, \ .id = S2MPS14_BUCK##num, \ .ops = &s2mps14_reg_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = S2MPS14_BUCK1235_MIN_600MV, \ - .uV_step = S2MPS14_BUCK1235_STEP_6_25MV, \ + .min_uV = min, \ + .uV_step = step, \ .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \ .linear_min_sel = S2MPS14_BUCK1235_START_SEL, \ .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \ @@ -568,54 +495,38 @@ static struct regulator_ops s2mps14_reg_ops = { .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \ .enable_mask = S2MPS14_ENABLE_MASK \ } -#define regulator_desc_s2mps14_buck4(num) { \ - .name = "BUCK"#num, \ - .id = S2MPS14_BUCK##num, \ - .ops = &s2mps14_reg_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .min_uV = S2MPS14_BUCK4_MIN_1400MV, \ - .uV_step = S2MPS14_BUCK4_STEP_12_5MV, \ - .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \ - .linear_min_sel = S2MPS14_BUCK4_START_SEL, \ - .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \ - .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \ - .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \ - .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \ - .enable_mask = S2MPS14_ENABLE_MASK \ -} static const struct regulator_desc s2mps14_regulators[] = { - regulator_desc_s2mps14_ldo3(1), - regulator_desc_s2mps14_ldo3(2), - regulator_desc_s2mps14_ldo1(3), - regulator_desc_s2mps14_ldo1(4), - regulator_desc_s2mps14_ldo3(5), - regulator_desc_s2mps14_ldo3(6), - regulator_desc_s2mps14_ldo1(7), - regulator_desc_s2mps14_ldo2(8), - regulator_desc_s2mps14_ldo3(9), - regulator_desc_s2mps14_ldo3(10), - regulator_desc_s2mps14_ldo1(11), - regulator_desc_s2mps14_ldo2(12), - regulator_desc_s2mps14_ldo2(13), - regulator_desc_s2mps14_ldo2(14), - regulator_desc_s2mps14_ldo2(15), - regulator_desc_s2mps14_ldo2(16), - regulator_desc_s2mps14_ldo2(17), - regulator_desc_s2mps14_ldo2(18), - regulator_desc_s2mps14_ldo1(19), - regulator_desc_s2mps14_ldo1(20), - regulator_desc_s2mps14_ldo1(21), - regulator_desc_s2mps14_ldo3(22), - regulator_desc_s2mps14_ldo1(23), - regulator_desc_s2mps14_ldo2(24), - regulator_desc_s2mps14_ldo2(25), - regulator_desc_s2mps14_buck1235(1), - regulator_desc_s2mps14_buck1235(2), - regulator_desc_s2mps14_buck1235(3), - regulator_desc_s2mps14_buck4(4), - regulator_desc_s2mps14_buck1235(5), + regulator_desc_s2mps14_ldo(1, MIN_800_MV, STEP_12_5_MV), + regulator_desc_s2mps14_ldo(2, MIN_800_MV, STEP_12_5_MV), + regulator_desc_s2mps14_ldo(3, MIN_800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(4, MIN_800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(5, MIN_800_MV, STEP_12_5_MV), + regulator_desc_s2mps14_ldo(6, MIN_800_MV, STEP_12_5_MV), + regulator_desc_s2mps14_ldo(7, MIN_800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(8, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(9, MIN_800_MV, STEP_12_5_MV), + regulator_desc_s2mps14_ldo(10, MIN_800_MV, STEP_12_5_MV), + regulator_desc_s2mps14_ldo(11, MIN_800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(12, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(13, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(14, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(15, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(16, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(17, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(18, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(19, MIN_800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(20, MIN_800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(21, MIN_800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(22, MIN_800_MV, STEP_12_5_MV), + regulator_desc_s2mps14_ldo(23, MIN_800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(24, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_ldo(25, MIN_1800_MV, STEP_25_MV), + regulator_desc_s2mps14_buck(1, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps14_buck(2, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps14_buck(3, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps14_buck(4, MIN_1400_MV, STEP_12_5_MV), + regulator_desc_s2mps14_buck(5, MIN_600_MV, STEP_6_25_MV), }; static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, diff --git a/drivers/regulator/sky81452-regulator.c b/drivers/regulator/sky81452-regulator.c new file mode 100644 index 00000000000..97aff0ccd65 --- /dev/null +++ b/drivers/regulator/sky81452-regulator.c @@ -0,0 +1,130 @@ +/* + * sky81452-regulator.c SKY81452 regulator driver + * + * Copyright 2014 Skyworks Solutions Inc. + * Author : Gyungoh Yoo <jack.yoo@skyworksinc.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +/* registers */ +#define SKY81452_REG1 0x01 +#define SKY81452_REG3 0x03 + +/* bit mask */ +#define SKY81452_LEN 0x40 +#define SKY81452_LOUT 0x1F + +static struct regulator_ops sky81452_reg_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_linear_range sky81452_reg_ranges[] = { + REGULATOR_LINEAR_RANGE(4500000, 0, 14, 250000), + REGULATOR_LINEAR_RANGE(9000000, 15, 31, 1000000), +}; + +static const struct regulator_desc sky81452_reg = { + .name = "LOUT", + .ops = &sky81452_reg_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = SKY81452_LOUT + 1, + .linear_ranges = sky81452_reg_ranges, + .n_linear_ranges = ARRAY_SIZE(sky81452_reg_ranges), + .vsel_reg = SKY81452_REG3, + .vsel_mask = SKY81452_LOUT, + .enable_reg = SKY81452_REG1, + .enable_mask = SKY81452_LEN, +}; + +#ifdef CONFIG_OF +static struct regulator_init_data *sky81452_reg_parse_dt(struct device *dev) +{ + struct regulator_init_data *init_data; + struct device_node *np; + + np = of_get_child_by_name(dev->parent->of_node, "regulator"); + if (unlikely(!np)) { + dev_err(dev, "regulator node not found"); + return NULL; + } + + init_data = of_get_regulator_init_data(dev, np); + + of_node_put(np); + return init_data; +} +#else +static struct regulator_init_data *sky81452_reg_parse_dt(struct device *dev) +{ + return ERR_PTR(-EINVAL); +} +#endif + +static int sky81452_reg_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct regulator_init_data *init_data = dev_get_platdata(dev); + struct regulator_config config = { }; + struct regulator_dev *rdev; + + if (!init_data) { + init_data = sky81452_reg_parse_dt(dev); + if (IS_ERR(init_data)) + return PTR_ERR(init_data); + } + + config.dev = dev; + config.init_data = init_data; + config.of_node = dev->of_node; + config.regmap = dev_get_drvdata(dev->parent); + + rdev = devm_regulator_register(dev, &sky81452_reg, &config); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + platform_set_drvdata(pdev, rdev); + + return 0; +} + +static struct platform_driver sky81452_reg_driver = { + .driver = { + .name = "sky81452-regulator", + }, + .probe = sky81452_reg_probe, +}; + +module_platform_driver(sky81452_reg_driver); + +MODULE_DESCRIPTION("Skyworks SKY81452 Regulator driver"); +MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@skyworksinc.com>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c deleted file mode 100644 index 5ea78df449f..00000000000 --- a/drivers/regulator/st-pwm.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Regulator driver for ST's PWM Regulators - * - * Copyright (C) 2014 - STMicroelectronics Inc. - * - * Author: Lee Jones <lee.jones@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/err.h> -#include <linux/regulator/driver.h> -#include <linux/regulator/machine.h> -#include <linux/regulator/of_regulator.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/pwm.h> - -#define ST_PWM_REG_PERIOD 8448 - -struct st_pwm_regulator_pdata { - const struct regulator_desc *desc; - struct st_pwm_voltages *duty_cycle_table; -}; - -struct st_pwm_regulator_data { - const struct st_pwm_regulator_pdata *pdata; - struct pwm_device *pwm; - bool enabled; - int state; -}; - -struct st_pwm_voltages { - unsigned int uV; - unsigned int dutycycle; -}; - -static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev) -{ - struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); - - return drvdata->state; -} - -static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev, - unsigned selector) -{ - struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); - int dutycycle; - int ret; - - dutycycle = (ST_PWM_REG_PERIOD / 100) * - drvdata->pdata->duty_cycle_table[selector].dutycycle; - - ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD); - if (ret) { - dev_err(&dev->dev, "Failed to configure PWM\n"); - return ret; - } - - drvdata->state = selector; - - if (!drvdata->enabled) { - ret = pwm_enable(drvdata->pwm); - if (ret) { - dev_err(&dev->dev, "Failed to enable PWM\n"); - return ret; - } - drvdata->enabled = true; - } - - return 0; -} - -static int st_pwm_regulator_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); - - if (selector >= dev->desc->n_voltages) - return -EINVAL; - - return drvdata->pdata->duty_cycle_table[selector].uV; -} - -static struct regulator_ops st_pwm_regulator_voltage_ops = { - .set_voltage_sel = st_pwm_regulator_set_voltage_sel, - .get_voltage_sel = st_pwm_regulator_get_voltage_sel, - .list_voltage = st_pwm_regulator_list_voltage, - .map_voltage = regulator_map_voltage_iterate, -}; - -static struct st_pwm_voltages b2105_duty_cycle_table[] = { - { .uV = 1114000, .dutycycle = 0, }, - { .uV = 1095000, .dutycycle = 10, }, - { .uV = 1076000, .dutycycle = 20, }, - { .uV = 1056000, .dutycycle = 30, }, - { .uV = 1036000, .dutycycle = 40, }, - { .uV = 1016000, .dutycycle = 50, }, - /* WARNING: Values above 50% duty-cycle cause boot failures. */ -}; - -static const struct regulator_desc b2105_desc = { - .name = "b2105-pwm-regulator", - .ops = &st_pwm_regulator_voltage_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(b2105_duty_cycle_table), - .supply_name = "pwm", -}; - -static const struct st_pwm_regulator_pdata b2105_info = { - .desc = &b2105_desc, - .duty_cycle_table = b2105_duty_cycle_table, -}; - -static const struct of_device_id st_pwm_of_match[] = { - { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, }, - { }, -}; -MODULE_DEVICE_TABLE(of, st_pwm_of_match); - -static int st_pwm_regulator_probe(struct platform_device *pdev) -{ - struct st_pwm_regulator_data *drvdata; - struct regulator_dev *regulator; - struct regulator_config config = { }; - struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_match; - - if (!np) { - dev_err(&pdev->dev, "Device Tree node missing\n"); - return -EINVAL; - } - - drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - of_match = of_match_device(st_pwm_of_match, &pdev->dev); - if (!of_match) { - dev_err(&pdev->dev, "failed to match of device\n"); - return -ENODEV; - } - drvdata->pdata = of_match->data; - - config.init_data = of_get_regulator_init_data(&pdev->dev, np); - if (!config.init_data) - return -ENOMEM; - - config.of_node = np; - config.dev = &pdev->dev; - config.driver_data = drvdata; - - drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); - if (IS_ERR(drvdata->pwm)) { - dev_err(&pdev->dev, "Failed to get PWM\n"); - return PTR_ERR(drvdata->pwm); - } - - regulator = devm_regulator_register(&pdev->dev, - drvdata->pdata->desc, &config); - if (IS_ERR(regulator)) { - dev_err(&pdev->dev, "Failed to register regulator %s\n", - drvdata->pdata->desc->name); - return PTR_ERR(regulator); - } - - return 0; -} - -static struct platform_driver st_pwm_regulator_driver = { - .driver = { - .name = "st-pwm-regulator", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(st_pwm_of_match), - }, - .probe = st_pwm_regulator_probe, -}; - -module_platform_driver(st_pwm_regulator_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); -MODULE_DESCRIPTION("ST PWM Regulator Driver"); -MODULE_ALIAS("platform:st_pwm-regulator"); diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 3ef67a86115..7380af8bd50 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -211,9 +211,6 @@ static int tps_65023_probe(struct i2c_client *client, int i; int error; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - /** * init_data points to array of regulator_init structures * coming from the board-evm file. diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index d58db72a63b..adbe4fc5cf0 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -27,10 +27,13 @@ #include <linux/regulator/machine.h> #include <linux/mfd/tps65217.h> -#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t, _lr, _nlr) \ +#define TPS65217_REGULATOR(_name, _id, _of_match, _ops, _n, _vr, _vm, _em, \ + _t, _lr, _nlr) \ { \ .name = _name, \ .id = _id, \ + .of_match = of_match_ptr(_of_match), \ + .regulators_node= of_match_ptr("regulators"), \ .ops = &_ops, \ .n_voltages = _n, \ .type = REGULATOR_VOLTAGE, \ @@ -138,87 +141,40 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = { }; static const struct regulator_desc regulators[] = { - TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64, - TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK, - TPS65217_ENABLE_DC1_EN, NULL, tps65217_uv1_ranges, - 2), /* DCDC1 voltage range: 900000 ~ 1800000 */ - TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64, - TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK, - TPS65217_ENABLE_DC2_EN, NULL, tps65217_uv1_ranges, + TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, "dcdc1", + tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC1, + TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC1_EN, + NULL, tps65217_uv1_ranges, 2), + TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, "dcdc2", + tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC2, + TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC2_EN, + NULL, tps65217_uv1_ranges, ARRAY_SIZE(tps65217_uv1_ranges)), - TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64, - TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK, - TPS65217_ENABLE_DC3_EN, NULL, tps65217_uv1_ranges, - 1), /* DCDC3 voltage range: 900000 ~ 1500000 */ - TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16, - TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK, - TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table, NULL, 0), - TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64, - TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK, - TPS65217_ENABLE_LDO2_EN, NULL, tps65217_uv1_ranges, + TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, "dcdc3", + tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC3, + TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC3_EN, + NULL, tps65217_uv1_ranges, 1), + TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, "ldo1", + tps65217_pmic_ldo1_ops, 16, TPS65217_REG_DEFLDO1, + TPS65217_DEFLDO1_LDO1_MASK, TPS65217_ENABLE_LDO1_EN, + LDO1_VSEL_table, NULL, 0), + TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, "ldo2", tps65217_pmic_ops, + 64, TPS65217_REG_DEFLDO2, + TPS65217_DEFLDO2_LDO2_MASK, TPS65217_ENABLE_LDO2_EN, + NULL, tps65217_uv1_ranges, ARRAY_SIZE(tps65217_uv1_ranges)), - TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32, - TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK, + TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, "ldo3", tps65217_pmic_ops, + 32, TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK, TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN, NULL, tps65217_uv2_ranges, ARRAY_SIZE(tps65217_uv2_ranges)), - TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32, - TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK, + TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, "ldo4", tps65217_pmic_ops, + 32, TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK, TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN, NULL, tps65217_uv2_ranges, ARRAY_SIZE(tps65217_uv2_ranges)), }; -#ifdef CONFIG_OF -static struct of_regulator_match reg_matches[] = { - { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 }, - { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 }, - { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 }, - { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 }, - { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 }, - { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 }, - { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 }, -}; - -static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) -{ - struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); - struct device_node *node = tps->dev->of_node; - struct tps65217_board *pdata; - struct device_node *regs; - int i, count; - - regs = of_get_child_by_name(node, "regulators"); - if (!regs) - return NULL; - - count = of_regulator_match(&pdev->dev, regs, reg_matches, - TPS65217_NUM_REGULATOR); - of_node_put(regs); - if ((count < 0) || (count > TPS65217_NUM_REGULATOR)) - return NULL; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - - for (i = 0; i < count; i++) { - if (!reg_matches[i].of_node) - continue; - - pdata->tps65217_init_data[i] = reg_matches[i].init_data; - pdata->of_node[i] = reg_matches[i].of_node; - } - - return pdata; -} -#else -static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) -{ - return NULL; -} -#endif - static int tps65217_regulator_probe(struct platform_device *pdev) { struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); @@ -227,14 +183,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev) struct regulator_config config = { }; int i; - if (tps->dev->of_node) - pdata = tps65217_parse_dt(pdev); - - if (!pdata) { - dev_err(&pdev->dev, "Platform data not found\n"); - return -EINVAL; - } - if (tps65217_chip_id(tps) != TPS65217) { dev_err(&pdev->dev, "Invalid tps chip version\n"); return -ENODEV; @@ -245,11 +193,10 @@ static int tps65217_regulator_probe(struct platform_device *pdev) for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { /* Register the regulators */ config.dev = tps->dev; - config.init_data = pdata->tps65217_init_data[i]; + if (pdata) + config.init_data = pdata->tps65217_init_data[i]; config.driver_data = tps; config.regmap = tps->regmap; - if (tps->dev->of_node) - config.of_node = pdata->of_node[i]; rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); @@ -259,6 +206,7 @@ static int tps65217_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } } + return 0; } diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index e584c998b55..18fc991175b 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -1047,7 +1047,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data( *tps65910_reg_matches = matches; for (idx = 0; idx < count; idx++) { - if (!matches[idx].init_data || !matches[idx].of_node) + if (!matches[idx].of_node) continue; pmic_plat_data->tps65910_pmic_init_data[idx] = @@ -1077,7 +1077,6 @@ static int tps65910_probe(struct platform_device *pdev) struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; struct tps_info *info; - struct regulator_init_data *reg_data; struct regulator_dev *rdev; struct tps65910_reg *pmic; struct tps65910_board *pmic_plat_data; @@ -1140,14 +1139,6 @@ static int tps65910_probe(struct platform_device *pdev) for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS; i++, info++) { - - reg_data = pmic_plat_data->tps65910_pmic_init_data[i]; - - /* Regulator API handles empty constraints but not NULL - * constraints */ - if (!reg_data) - continue; - /* Register the regulators */ pmic->info[i] = info; @@ -1199,7 +1190,7 @@ static int tps65910_probe(struct platform_device *pdev) pmic->desc[i].enable_mask = TPS65910_SUPPLY_STATE_ENABLED; config.dev = tps65910->dev; - config.init_data = reg_data; + config.init_data = pmic_plat_data->tps65910_pmic_init_data[i]; config.driver_data = pmic; config.regmap = tps65910->regmap; diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 8225b89de81..c384fec6d17 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -232,6 +232,7 @@ static struct platform_driver efi_rtc_driver = { module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe); +MODULE_ALIAS("platform:rtc-efi"); MODULE_AUTHOR("dann frazier <dannf@hp.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("EFI RTC driver"); diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 79788a12712..02e69e7ee4a 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1647,7 +1647,7 @@ static int cxgbi_inet6addr_handler(struct notifier_block *this, if (event_dev->priv_flags & IFF_802_1Q_VLAN) event_dev = vlan_dev_real_dev(event_dev); - cdev = cxgbi_device_find_by_netdev(event_dev, NULL); + cdev = cxgbi_device_find_by_netdev_rcu(event_dev, NULL); if (!cdev) return ret; diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index d65df6dc106..addd1dddce1 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -57,6 +57,9 @@ MODULE_PARM_DESC(dbg_level, "libiscsi debug level (default=0)"); static LIST_HEAD(cdev_list); static DEFINE_MUTEX(cdev_mutex); +static LIST_HEAD(cdev_rcu_list); +static DEFINE_SPINLOCK(cdev_rcu_lock); + int cxgbi_device_portmap_create(struct cxgbi_device *cdev, unsigned int base, unsigned int max_conn) { @@ -142,6 +145,10 @@ struct cxgbi_device *cxgbi_device_register(unsigned int extra, list_add_tail(&cdev->list_head, &cdev_list); mutex_unlock(&cdev_mutex); + spin_lock(&cdev_rcu_lock); + list_add_tail_rcu(&cdev->rcu_node, &cdev_rcu_list); + spin_unlock(&cdev_rcu_lock); + log_debug(1 << CXGBI_DBG_DEV, "cdev 0x%p, p# %u.\n", cdev, nports); return cdev; @@ -153,9 +160,16 @@ void cxgbi_device_unregister(struct cxgbi_device *cdev) log_debug(1 << CXGBI_DBG_DEV, "cdev 0x%p, p# %u,%s.\n", cdev, cdev->nports, cdev->nports ? cdev->ports[0]->name : ""); + mutex_lock(&cdev_mutex); list_del(&cdev->list_head); mutex_unlock(&cdev_mutex); + + spin_lock(&cdev_rcu_lock); + list_del_rcu(&cdev->rcu_node); + spin_unlock(&cdev_rcu_lock); + synchronize_rcu(); + cxgbi_device_destroy(cdev); } EXPORT_SYMBOL_GPL(cxgbi_device_unregister); @@ -167,12 +181,9 @@ void cxgbi_device_unregister_all(unsigned int flag) mutex_lock(&cdev_mutex); list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { if ((cdev->flags & flag) == flag) { - log_debug(1 << CXGBI_DBG_DEV, - "cdev 0x%p, p# %u,%s.\n", - cdev, cdev->nports, cdev->nports ? - cdev->ports[0]->name : ""); - list_del(&cdev->list_head); - cxgbi_device_destroy(cdev); + mutex_unlock(&cdev_mutex); + cxgbi_device_unregister(cdev); + mutex_lock(&cdev_mutex); } } mutex_unlock(&cdev_mutex); @@ -191,6 +202,7 @@ struct cxgbi_device *cxgbi_device_find_by_lldev(void *lldev) } } mutex_unlock(&cdev_mutex); + log_debug(1 << CXGBI_DBG_DEV, "lldev 0x%p, NO match found.\n", lldev); return NULL; @@ -230,6 +242,39 @@ struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, } EXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev); +struct cxgbi_device *cxgbi_device_find_by_netdev_rcu(struct net_device *ndev, + int *port) +{ + struct net_device *vdev = NULL; + struct cxgbi_device *cdev; + int i; + + if (ndev->priv_flags & IFF_802_1Q_VLAN) { + vdev = ndev; + ndev = vlan_dev_real_dev(ndev); + pr_info("vlan dev %s -> %s.\n", vdev->name, ndev->name); + } + + rcu_read_lock(); + list_for_each_entry_rcu(cdev, &cdev_rcu_list, rcu_node) { + for (i = 0; i < cdev->nports; i++) { + if (ndev == cdev->ports[i]) { + cdev->hbas[i]->vdev = vdev; + rcu_read_unlock(); + if (port) + *port = i; + return cdev; + } + } + } + rcu_read_unlock(); + + log_debug(1 << CXGBI_DBG_DEV, + "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); + return NULL; +} +EXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev_rcu); + static struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev, int *port) { diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index b3e6e7541cc..1d98fad6a0a 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -527,6 +527,7 @@ struct cxgbi_ports_map { #define CXGBI_FLAG_IPV4_SET 0x10 struct cxgbi_device { struct list_head list_head; + struct list_head rcu_node; unsigned int flags; struct net_device **ports; void *lldev; @@ -709,6 +710,8 @@ void cxgbi_device_unregister(struct cxgbi_device *); void cxgbi_device_unregister_all(unsigned int flag); struct cxgbi_device *cxgbi_device_find_by_lldev(void *); struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *, int *); +struct cxgbi_device *cxgbi_device_find_by_netdev_rcu(struct net_device *, + int *); int cxgbi_hbas_add(struct cxgbi_device *, u64, unsigned int, struct scsi_host_template *, struct scsi_transport_template *); diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c index 447458e696a..7e1f120f2b3 100644 --- a/drivers/soc/qcom/qcom_gsbi.c +++ b/drivers/soc/qcom/qcom_gsbi.c @@ -22,44 +22,63 @@ #define GSBI_CTRL_REG 0x0000 #define GSBI_PROTOCOL_SHIFT 4 +struct gsbi_info { + struct clk *hclk; + u32 mode; + u32 crci; +}; + static int gsbi_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct resource *res; void __iomem *base; - struct clk *hclk; - u32 mode, crci = 0; + struct gsbi_info *gsbi; + + gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL); + + if (!gsbi) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); - if (of_property_read_u32(node, "qcom,mode", &mode)) { + if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) { dev_err(&pdev->dev, "missing mode configuration\n"); return -EINVAL; } /* not required, so default to 0 if not present */ - of_property_read_u32(node, "qcom,crci", &crci); + of_property_read_u32(node, "qcom,crci", &gsbi->crci); - dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n", mode, crci); + dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n", + gsbi->mode, gsbi->crci); + gsbi->hclk = devm_clk_get(&pdev->dev, "iface"); + if (IS_ERR(gsbi->hclk)) + return PTR_ERR(gsbi->hclk); - hclk = devm_clk_get(&pdev->dev, "iface"); - if (IS_ERR(hclk)) - return PTR_ERR(hclk); + clk_prepare_enable(gsbi->hclk); - clk_prepare_enable(hclk); - - writel_relaxed((mode << GSBI_PROTOCOL_SHIFT) | crci, + writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci, base + GSBI_CTRL_REG); /* make sure the gsbi control write is not reordered */ wmb(); - clk_disable_unprepare(hclk); + platform_set_drvdata(pdev, gsbi); + + return of_platform_populate(node, NULL, NULL, &pdev->dev); +} + +static int gsbi_remove(struct platform_device *pdev) +{ + struct gsbi_info *gsbi = platform_get_drvdata(pdev); + + clk_disable_unprepare(gsbi->hclk); - return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + return 0; } static const struct of_device_id gsbi_dt_match[] = { @@ -76,6 +95,7 @@ static struct platform_driver gsbi_driver = { .of_match_table = gsbi_dt_match, }, .probe = gsbi_probe, + .remove = gsbi_remove, }; module_platform_driver(gsbi_driver); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 62e2242ad7e..84e7c9e6cce 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -69,6 +69,7 @@ config SPI_ATH79 config SPI_ATMEL tristate "Atmel SPI Controller" + depends on HAS_DMA depends on (ARCH_AT91 || AVR32 || COMPILE_TEST) help This selects a driver for the Atmel SPI Controller, present on @@ -112,6 +113,14 @@ config SPI_AU1550 If you say yes to this option, support will be included for the PSC SPI controller found on Au1550, Au1200 and Au1300 series. +config SPI_BCM53XX + tristate "Broadcom BCM53xx SPI controller" + depends on ARCH_BCM_5301X + depends on BCMA_POSSIBLE + select BCMA + help + Enable support for the SPI controller on Broadcom BCM53xx ARM SoCs. + config SPI_BCM63XX tristate "Broadcom BCM63xx SPI controller" depends on BCM63XX @@ -185,6 +194,7 @@ config SPI_EFM32 config SPI_EP93XX tristate "Cirrus Logic EP93xx SPI controller" + depends on HAS_DMA depends on ARCH_EP93XX || COMPILE_TEST help This enables using the Cirrus EP93xx SPI controller in master @@ -314,6 +324,7 @@ config SPI_OMAP_UWIRE config SPI_OMAP24XX tristate "McSPI driver for OMAP" + depends on HAS_DMA depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH depends on ARCH_OMAP2PLUS || COMPILE_TEST help @@ -380,7 +391,7 @@ config SPI_PXA2XX additional documentation can be found a Documentation/spi/pxa2xx. config SPI_PXA2XX_PCI - def_tristate SPI_PXA2XX && PCI + def_tristate SPI_PXA2XX && PCI && COMMON_CLK config SPI_ROCKCHIP tristate "Rockchip SPI controller driver" @@ -500,7 +511,7 @@ config SPI_MXS config SPI_TEGRA114 tristate "NVIDIA Tegra114 SPI Controller" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST - depends on RESET_CONTROLLER + depends on RESET_CONTROLLER && HAS_DMA help SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller is different than the older SoCs SPI controller and also register interface @@ -518,7 +529,7 @@ config SPI_TEGRA20_SFLASH config SPI_TEGRA20_SLINK tristate "Nvidia Tegra20/Tegra30 SLINK Controller" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST - depends on RESET_CONTROLLER + depends on RESET_CONTROLLER && HAS_DMA help SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. @@ -591,7 +602,7 @@ config SPI_DW_PCI depends on SPI_DESIGNWARE && PCI config SPI_DW_MID_DMA - bool "DMA support for DW SPI controller on Intel Moorestown platform" + bool "DMA support for DW SPI controller on Intel MID platform" depends on SPI_DW_PCI && INTEL_MID_DMAC config SPI_DW_MMIO diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 762da074114..78f24ca36fc 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o obj-$(CONFIG_SPI_ATH79) += spi-ath79.o obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o +obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c new file mode 100644 index 00000000000..17b34cbadc0 --- /dev/null +++ b/drivers/spi/spi-bcm53xx.c @@ -0,0 +1,299 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/bcma/bcma.h> +#include <linux/spi/spi.h> + +#include "spi-bcm53xx.h" + +#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */ + +/* The longest observed required wait was 19 ms */ +#define BCM53XXSPI_SPE_TIMEOUT_MS 80 + +struct bcm53xxspi { + struct bcma_device *core; + struct spi_master *master; + + size_t read_offset; +}; + +static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset) +{ + return bcma_read32(b53spi->core, offset); +} + +static inline void bcm53xxspi_write(struct bcm53xxspi *b53spi, u16 offset, + u32 value) +{ + bcma_write32(b53spi->core, offset, value); +} + +static inline unsigned int bcm53xxspi_calc_timeout(size_t len) +{ + /* Do some magic calculation based on length and buad. Add 10% and 1. */ + return (len * 9000 / BCM53XXSPI_MAX_SPI_BAUD * 110 / 100) + 1; +} + +static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms) +{ + unsigned long deadline; + u32 tmp; + + /* SPE bit has to be 0 before we read MSPI STATUS */ + deadline = jiffies + BCM53XXSPI_SPE_TIMEOUT_MS * HZ / 1000; + do { + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); + if (!(tmp & B53SPI_MSPI_SPCR2_SPE)) + break; + udelay(5); + } while (!time_after_eq(jiffies, deadline)); + + if (tmp & B53SPI_MSPI_SPCR2_SPE) + goto spi_timeout; + + /* Check status */ + deadline = jiffies + timeout_ms * HZ / 1000; + do { + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS); + if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) { + bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0); + return 0; + } + + cpu_relax(); + udelay(100); + } while (!time_after_eq(jiffies, deadline)); + +spi_timeout: + bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0); + + pr_err("Timeout waiting for SPI to be ready!\n"); + + return -EBUSY; +} + +static void bcm53xxspi_buf_write(struct bcm53xxspi *b53spi, u8 *w_buf, + size_t len, bool cont) +{ + u32 tmp; + int i; + + for (i = 0; i < len; i++) { + /* Transmit Register File MSB */ + bcm53xxspi_write(b53spi, B53SPI_MSPI_TXRAM + 4 * (i * 2), + (unsigned int)w_buf[i]); + } + + for (i = 0; i < len; i++) { + tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL | + B53SPI_CDRAM_PCS_DSCK; + if (!cont && i == len - 1) + tmp &= ~B53SPI_CDRAM_CONT; + tmp &= ~0x1; + /* Command Register File */ + bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp); + } + + /* Set queue pointers */ + bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0); + bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1); + + if (cont) + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1); + + /* Start SPI transfer */ + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); + tmp |= B53SPI_MSPI_SPCR2_SPE; + if (cont) + tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD; + bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp); + + /* Wait for SPI to finish */ + bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len)); + + if (!cont) + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0); + + b53spi->read_offset = len; +} + +static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf, + size_t len, bool cont) +{ + u32 tmp; + int i; + + for (i = 0; i < b53spi->read_offset + len; i++) { + tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL | + B53SPI_CDRAM_PCS_DSCK; + if (!cont && i == b53spi->read_offset + len - 1) + tmp &= ~B53SPI_CDRAM_CONT; + tmp &= ~0x1; + /* Command Register File */ + bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp); + } + + /* Set queue pointers */ + bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0); + bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, + b53spi->read_offset + len - 1); + + if (cont) + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1); + + /* Start SPI transfer */ + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); + tmp |= B53SPI_MSPI_SPCR2_SPE; + if (cont) + tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD; + bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp); + + /* Wait for SPI to finish */ + bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len)); + + if (!cont) + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0); + + for (i = 0; i < len; ++i) { + int offset = b53spi->read_offset + i; + + /* Data stored in the transmit register file LSB */ + r_buf[i] = (u8)bcm53xxspi_read(b53spi, B53SPI_MSPI_RXRAM + 4 * (1 + offset * 2)); + } + + b53spi->read_offset = 0; +} + +static int bcm53xxspi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct bcm53xxspi *b53spi = spi_master_get_devdata(master); + u8 *buf; + size_t left; + + if (t->tx_buf) { + buf = (u8 *)t->tx_buf; + left = t->len; + while (left) { + size_t to_write = min_t(size_t, 16, left); + bool cont = left - to_write > 0; + + bcm53xxspi_buf_write(b53spi, buf, to_write, cont); + left -= to_write; + buf += to_write; + } + } + + if (t->rx_buf) { + buf = (u8 *)t->rx_buf; + left = t->len; + while (left) { + size_t to_read = min_t(size_t, 16 - b53spi->read_offset, + left); + bool cont = left - to_read > 0; + + bcm53xxspi_buf_read(b53spi, buf, to_read, cont); + left -= to_read; + buf += to_read; + } + } + + return 0; +} + +/************************************************** + * BCMA + **************************************************/ + +static struct spi_board_info bcm53xx_info = { + .modalias = "bcm53xxspiflash", +}; + +static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = { + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS), + BCMA_CORETABLE_END +}; +MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl); + +static int bcm53xxspi_bcma_probe(struct bcma_device *core) +{ + struct bcm53xxspi *b53spi; + struct spi_master *master; + int err; + + if (core->bus->drv_cc.core->id.rev != 42) { + pr_err("SPI on SoC with unsupported ChipCommon rev\n"); + return -ENOTSUPP; + } + + master = spi_alloc_master(&core->dev, sizeof(*b53spi)); + if (!master) + return -ENOMEM; + + b53spi = spi_master_get_devdata(master); + b53spi->master = master; + b53spi->core = core; + + master->transfer_one = bcm53xxspi_transfer_one; + + bcma_set_drvdata(core, b53spi); + + err = devm_spi_register_master(&core->dev, master); + if (err) { + spi_master_put(master); + bcma_set_drvdata(core, NULL); + goto out; + } + + /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */ + spi_new_device(master, &bcm53xx_info); + +out: + return err; +} + +static void bcm53xxspi_bcma_remove(struct bcma_device *core) +{ + struct bcm53xxspi *b53spi = bcma_get_drvdata(core); + + spi_unregister_master(b53spi->master); +} + +static struct bcma_driver bcm53xxspi_bcma_driver = { + .name = KBUILD_MODNAME, + .id_table = bcm53xxspi_bcma_tbl, + .probe = bcm53xxspi_bcma_probe, + .remove = bcm53xxspi_bcma_remove, +}; + +/************************************************** + * Init & exit + **************************************************/ + +static int __init bcm53xxspi_module_init(void) +{ + int err = 0; + + err = bcma_driver_register(&bcm53xxspi_bcma_driver); + if (err) + pr_err("Failed to register bcma driver: %d\n", err); + + return err; +} + +static void __exit bcm53xxspi_module_exit(void) +{ + bcma_driver_unregister(&bcm53xxspi_bcma_driver); +} + +module_init(bcm53xxspi_module_init); +module_exit(bcm53xxspi_module_exit); + +MODULE_DESCRIPTION("Broadcom BCM53xx SPI Controller driver"); +MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-bcm53xx.h b/drivers/spi/spi-bcm53xx.h new file mode 100644 index 00000000000..73575dfe691 --- /dev/null +++ b/drivers/spi/spi-bcm53xx.h @@ -0,0 +1,72 @@ +#ifndef SPI_BCM53XX_H +#define SPI_BCM53XX_H + +#define B53SPI_BSPI_REVISION_ID 0x000 +#define B53SPI_BSPI_SCRATCH 0x004 +#define B53SPI_BSPI_MAST_N_BOOT_CTRL 0x008 +#define B53SPI_BSPI_BUSY_STATUS 0x00c +#define B53SPI_BSPI_INTR_STATUS 0x010 +#define B53SPI_BSPI_B0_STATUS 0x014 +#define B53SPI_BSPI_B0_CTRL 0x018 +#define B53SPI_BSPI_B1_STATUS 0x01c +#define B53SPI_BSPI_B1_CTRL 0x020 +#define B53SPI_BSPI_STRAP_OVERRIDE_CTRL 0x024 +#define B53SPI_BSPI_FLEX_MODE_ENABLE 0x028 +#define B53SPI_BSPI_BITS_PER_CYCLE 0x02c +#define B53SPI_BSPI_BITS_PER_PHASE 0x030 +#define B53SPI_BSPI_CMD_AND_MODE_BYTE 0x034 +#define B53SPI_BSPI_BSPI_FLASH_UPPER_ADDR_BYTE 0x038 +#define B53SPI_BSPI_BSPI_XOR_VALUE 0x03c +#define B53SPI_BSPI_BSPI_XOR_ENABLE 0x040 +#define B53SPI_BSPI_BSPI_PIO_MODE_ENABLE 0x044 +#define B53SPI_BSPI_BSPI_PIO_IODIR 0x048 +#define B53SPI_BSPI_BSPI_PIO_DATA 0x04c + +/* RAF */ +#define B53SPI_RAF_START_ADDR 0x100 +#define B53SPI_RAF_NUM_WORDS 0x104 +#define B53SPI_RAF_CTRL 0x108 +#define B53SPI_RAF_FULLNESS 0x10c +#define B53SPI_RAF_WATERMARK 0x110 +#define B53SPI_RAF_STATUS 0x114 +#define B53SPI_RAF_READ_DATA 0x118 +#define B53SPI_RAF_WORD_CNT 0x11c +#define B53SPI_RAF_CURR_ADDR 0x120 + +/* MSPI */ +#define B53SPI_MSPI_SPCR0_LSB 0x200 +#define B53SPI_MSPI_SPCR0_MSB 0x204 +#define B53SPI_MSPI_SPCR1_LSB 0x208 +#define B53SPI_MSPI_SPCR1_MSB 0x20c +#define B53SPI_MSPI_NEWQP 0x210 +#define B53SPI_MSPI_ENDQP 0x214 +#define B53SPI_MSPI_SPCR2 0x218 +#define B53SPI_MSPI_SPCR2_SPE 0x00000040 +#define B53SPI_MSPI_SPCR2_CONT_AFTER_CMD 0x00000080 +#define B53SPI_MSPI_MSPI_STATUS 0x220 +#define B53SPI_MSPI_MSPI_STATUS_SPIF 0x00000001 +#define B53SPI_MSPI_CPTQP 0x224 +#define B53SPI_MSPI_TXRAM 0x240 /* 32 registers, up to 0x2b8 */ +#define B53SPI_MSPI_RXRAM 0x2c0 /* 32 registers, up to 0x33c */ +#define B53SPI_MSPI_CDRAM 0x340 /* 16 registers, up to 0x37c */ +#define B53SPI_CDRAM_PCS_PCS0 0x00000001 +#define B53SPI_CDRAM_PCS_PCS1 0x00000002 +#define B53SPI_CDRAM_PCS_PCS2 0x00000004 +#define B53SPI_CDRAM_PCS_PCS3 0x00000008 +#define B53SPI_CDRAM_PCS_DISABLE_ALL 0x0000000f +#define B53SPI_CDRAM_PCS_DSCK 0x00000010 +#define B53SPI_CDRAM_BITSE 0x00000040 +#define B53SPI_CDRAM_CONT 0x00000080 +#define B53SPI_MSPI_WRITE_LOCK 0x380 +#define B53SPI_MSPI_DISABLE_FLUSH_GEN 0x384 + +/* Interrupt */ +#define B53SPI_INTR_RAF_LR_FULLNESS_REACHED 0x3a0 +#define B53SPI_INTR_RAF_LR_TRUNCATED 0x3a4 +#define B53SPI_INTR_RAF_LR_IMPATIENT 0x3a8 +#define B53SPI_INTR_RAF_LR_SESSION_DONE 0x3ac +#define B53SPI_INTR_RAF_LR_OVERREAD 0x3b0 +#define B53SPI_INTR_MSPI_DONE 0x3b4 +#define B53SPI_INTR_MSPI_HALT_SET_TRANSACTION_DONE 0x3b8 + +#endif /* SPI_BCM53XX_H */ diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 562ff83debd..7b811e38c7a 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -677,7 +677,6 @@ static struct platform_driver cdns_spi_driver = { .remove = cdns_spi_remove, .driver = { .name = CDNS_SPI_NAME, - .owner = THIS_MODULE, .of_match_table = cdns_spi_of_match, .pm = &cdns_spi_dev_pm_ops, }, diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index ce538dad526..181cf226200 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -30,7 +30,6 @@ struct spi_clps711x_data { void __iomem *syncio; struct regmap *syscon; - struct regmap *syscon1; struct clk *spi_clk; u8 *tx_buf; @@ -47,27 +46,6 @@ static int spi_clps711x_setup(struct spi_device *spi) return 0; } -static void spi_clps711x_setup_xfer(struct spi_device *spi, - struct spi_transfer *xfer) -{ - struct spi_master *master = spi->master; - struct spi_clps711x_data *hw = spi_master_get_devdata(master); - - /* Setup SPI frequency divider */ - if (xfer->speed_hz >= master->max_speed_hz) - regmap_update_bits(hw->syscon1, SYSCON_OFFSET, - SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3)); - else if (xfer->speed_hz >= (master->max_speed_hz / 2)) - regmap_update_bits(hw->syscon1, SYSCON_OFFSET, - SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2)); - else if (xfer->speed_hz >= (master->max_speed_hz / 8)) - regmap_update_bits(hw->syscon1, SYSCON_OFFSET, - SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1)); - else - regmap_update_bits(hw->syscon1, SYSCON_OFFSET, - SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0)); -} - static int spi_clps711x_prepare_message(struct spi_master *master, struct spi_message *msg) { @@ -87,7 +65,7 @@ static int spi_clps711x_transfer_one(struct spi_master *master, struct spi_clps711x_data *hw = spi_master_get_devdata(master); u8 data; - spi_clps711x_setup_xfer(spi, xfer); + clk_set_rate(hw->spi_clk, xfer->speed_hz ? : spi->max_speed_hz); hw->len = xfer->len; hw->bpw = xfer->bits_per_word; @@ -176,13 +154,11 @@ static int spi_clps711x_probe(struct platform_device *pdev) } } - hw->spi_clk = devm_clk_get(&pdev->dev, "spi"); + hw->spi_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(hw->spi_clk)) { - dev_err(&pdev->dev, "Can't get clocks\n"); ret = PTR_ERR(hw->spi_clk); goto err_out; } - master->max_speed_hz = clk_get_rate(hw->spi_clk); hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3"); if (IS_ERR(hw->syscon)) { @@ -190,12 +166,6 @@ static int spi_clps711x_probe(struct platform_device *pdev) goto err_out; } - hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1"); - if (IS_ERR(hw->syscon1)) { - ret = PTR_ERR(hw->syscon1); - goto err_out; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hw->syncio = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hw->syncio)) { diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 134fb6eb7b1..63700ab7bd9 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -65,6 +65,7 @@ /* SPIDAT1 (upper 16 bit defines) */ #define SPIDAT1_CSHOLD_MASK BIT(12) +#define SPIDAT1_WDEL BIT(10) /* SPIGCR1 */ #define SPIGCR1_CLKMOD_MASK BIT(1) @@ -167,8 +168,10 @@ static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *dspi) static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi) { u32 data = 0; + if (dspi->tx) { const u8 *tx = dspi->tx; + data = *tx++; dspi->tx = tx; } @@ -178,8 +181,10 @@ static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi) static u32 davinci_spi_tx_buf_u16(struct davinci_spi *dspi) { u32 data = 0; + if (dspi->tx) { const u16 *tx = dspi->tx; + data = *tx++; dspi->tx = tx; } @@ -209,6 +214,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) { struct davinci_spi *dspi; struct davinci_spi_platform_data *pdata; + struct davinci_spi_config *spicfg = spi->controller_data; u8 chip_sel = spi->chip_select; u16 spidat1 = CS_DEFAULT; bool gpio_chipsel = false; @@ -223,6 +229,10 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) gpio = spi->cs_gpio; } + /* program delay transfers if tx_delay is non zero */ + if (spicfg->wdelay) + spidat1 |= SPIDAT1_WDEL; + /* * Board specific chip select logic decides the polarity and cs * line for the controller @@ -237,9 +247,9 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) spidat1 |= SPIDAT1_CSHOLD_MASK; spidat1 &= ~(0x1 << chip_sel); } - - iowrite16(spidat1, dspi->base + SPIDAT1 + 2); } + + iowrite16(spidat1, dspi->base + SPIDAT1 + 2); } /** @@ -285,7 +295,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, int prescale; dspi = spi_master_get_devdata(spi->master); - spicfg = (struct davinci_spi_config *)spi->controller_data; + spicfg = spi->controller_data; if (!spicfg) spicfg = &davinci_spi_default_cfg; @@ -333,6 +343,14 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, spifmt |= SPIFMT_PHASE_MASK; /* + * Assume wdelay is used only on SPI peripherals that has this field + * in SPIFMTn register and when it's configured from board file or DT. + */ + if (spicfg->wdelay) + spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT) + & SPIFMT_WDELAY_MASK); + + /* * Version 1 hardware supports two basic SPI modes: * - Standard SPI mode uses 4 pins, with chipselect * - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS) @@ -349,9 +367,6 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, u32 delay = 0; - spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT) - & SPIFMT_WDELAY_MASK); - if (spicfg->odd_parity) spifmt |= SPIFMT_ODD_PARITY_MASK; @@ -383,6 +398,26 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, return 0; } +static int davinci_spi_of_setup(struct spi_device *spi) +{ + struct davinci_spi_config *spicfg = spi->controller_data; + struct device_node *np = spi->dev.of_node; + u32 prop; + + if (spicfg == NULL && np) { + spicfg = kzalloc(sizeof(*spicfg), GFP_KERNEL); + if (!spicfg) + return -ENOMEM; + *spicfg = davinci_spi_default_cfg; + /* override with dt configured values */ + if (!of_property_read_u32(np, "ti,spi-wdelay", &prop)) + spicfg->wdelay = (u8)prop; + spi->controller_data = spicfg; + } + + return 0; +} + /** * davinci_spi_setup - This functions will set default transfer method * @spi: spi device on which data transfer to be done @@ -433,7 +468,16 @@ static int davinci_spi_setup(struct spi_device *spi) else clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK); - return retval; + return davinci_spi_of_setup(spi); +} + +static void davinci_spi_cleanup(struct spi_device *spi) +{ + struct davinci_spi_config *spicfg = spi->controller_data; + + spi->controller_data = NULL; + if (spi->dev.of_node) + kfree(spicfg); } static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) @@ -947,6 +991,7 @@ static int davinci_spi_probe(struct platform_device *pdev) master->num_chipselect = pdata->num_chipselect; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); master->setup = davinci_spi_setup; + master->cleanup = davinci_spi_cleanup; dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; @@ -996,8 +1041,8 @@ static int davinci_spi_probe(struct platform_device *pdev) goto free_clk; dev_info(&pdev->dev, "DMA: supported\n"); - dev_info(&pdev->dev, "DMA: RX channel: %pa, TX channel: %pa, " - "event queue: %d\n", &dma_rx_chan, &dma_tx_chan, + dev_info(&pdev->dev, "DMA: RX channel: %pa, TX channel: %pa, event queue: %d\n", + &dma_rx_chan, &dma_tx_chan, pdata->dma_event_q); } diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index 6d207afec8c..46c6d58e1fd 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -1,7 +1,7 @@ /* * Special handling for DW core on Intel MID platform * - * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2009, 2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -11,10 +11,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include <linux/dma-mapping.h> @@ -39,22 +35,25 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param) { struct dw_spi *dws = param; - return dws->dmac && (&dws->dmac->dev == chan->device->dev); + return dws->dma_dev == chan->device->dev; } static int mid_spi_dma_init(struct dw_spi *dws) { struct mid_dma *dw_dma = dws->dma_priv; + struct pci_dev *dma_dev; struct intel_mid_dma_slave *rxs, *txs; dma_cap_mask_t mask; /* * Get pci device for DMA controller, currently it could only - * be the DMA controller of either Moorestown or Medfield + * be the DMA controller of Medfield */ - dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL); - if (!dws->dmac) - dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL); + dma_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL); + if (!dma_dev) + return -ENODEV; + + dws->dma_dev = &dma_dev->dev; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -83,13 +82,18 @@ static int mid_spi_dma_init(struct dw_spi *dws) free_rxchan: dma_release_channel(dws->rxchan); err_exit: - return -1; - + return -EBUSY; } static void mid_spi_dma_exit(struct dw_spi *dws) { + if (!dws->dma_inited) + return; + + dmaengine_terminate_all(dws->txchan); dma_release_channel(dws->txchan); + + dmaengine_terminate_all(dws->rxchan); dma_release_channel(dws->rxchan); } @@ -109,8 +113,7 @@ static void dw_spi_dma_done(void *arg) static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) { - struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL; - struct dma_chan *txchan, *rxchan; + struct dma_async_tx_descriptor *txdesc, *rxdesc; struct dma_slave_config txconf, rxconf; u16 dma_ctrl = 0; @@ -120,37 +123,34 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) dw_writew(dws, DW_SPI_DMARDLR, 0xf); dw_writew(dws, DW_SPI_DMATDLR, 0x10); if (dws->tx_dma) - dma_ctrl |= 0x2; + dma_ctrl |= SPI_DMA_TDMAE; if (dws->rx_dma) - dma_ctrl |= 0x1; + dma_ctrl |= SPI_DMA_RDMAE; dw_writew(dws, DW_SPI_DMACR, dma_ctrl); spi_enable_chip(dws, 1); } dws->dma_chan_done = 0; - txchan = dws->txchan; - rxchan = dws->rxchan; /* 2. Prepare the TX dma transfer */ txconf.direction = DMA_MEM_TO_DEV; txconf.dst_addr = dws->dma_addr; txconf.dst_maxburst = LNW_DMA_MSIZE_16; txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + txconf.dst_addr_width = dws->dma_width; txconf.device_fc = false; - txchan->device->device_control(txchan, DMA_SLAVE_CONFIG, - (unsigned long) &txconf); + dmaengine_slave_config(dws->txchan, &txconf); memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl)); dws->tx_sgl.dma_address = dws->tx_dma; dws->tx_sgl.length = dws->len; - txdesc = dmaengine_prep_slave_sg(txchan, + txdesc = dmaengine_prep_slave_sg(dws->txchan, &dws->tx_sgl, 1, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT); + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); txdesc->callback = dw_spi_dma_done; txdesc->callback_param = dws; @@ -159,27 +159,30 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) rxconf.src_addr = dws->dma_addr; rxconf.src_maxburst = LNW_DMA_MSIZE_16; rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + rxconf.src_addr_width = dws->dma_width; rxconf.device_fc = false; - rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG, - (unsigned long) &rxconf); + dmaengine_slave_config(dws->rxchan, &rxconf); memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl)); dws->rx_sgl.dma_address = dws->rx_dma; dws->rx_sgl.length = dws->len; - rxdesc = dmaengine_prep_slave_sg(rxchan, + rxdesc = dmaengine_prep_slave_sg(dws->rxchan, &dws->rx_sgl, 1, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); rxdesc->callback = dw_spi_dma_done; rxdesc->callback_param = dws; /* rx must be started before tx due to spi instinct */ - rxdesc->tx_submit(rxdesc); - txdesc->tx_submit(txdesc); + dmaengine_submit(rxdesc); + dma_async_issue_pending(dws->rxchan); + + dmaengine_submit(txdesc); + dma_async_issue_pending(dws->txchan); + return 0; } @@ -190,7 +193,7 @@ static struct dw_spi_dma_ops mid_dma_ops = { }; #endif -/* Some specific info for SPI0 controller on Moorestown */ +/* Some specific info for SPI0 controller on Intel MID */ /* HW info for MRST CLk Control Unit, one 32b reg */ #define MRST_SPI_CLK_BASE 100000000 /* 100m */ diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index e14960470d8..ba68da12cdf 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -1,7 +1,7 @@ /* * PCI interface driver for DW SPI Core * - * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2009, 2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -11,10 +11,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include <linux/interrupt.h> @@ -32,17 +28,22 @@ struct dw_spi_pci { struct dw_spi dws; }; -static int spi_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +struct spi_pci_desc { + int (*setup)(struct dw_spi *); +}; + +static struct spi_pci_desc spi_pci_mid_desc = { + .setup = dw_spi_mid_init, +}; + +static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct dw_spi_pci *dwpci; struct dw_spi *dws; + struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data; int pci_bar = 0; int ret; - dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", - pdev->vendor, pdev->device); - ret = pcim_enable_device(pdev); if (ret) return ret; @@ -58,7 +59,7 @@ static int spi_pci_probe(struct pci_dev *pdev, /* Get basic io resource and map it */ dws->paddr = pci_resource_start(pdev, pci_bar); - ret = pcim_iomap_regions(pdev, 1, dev_name(&pdev->dev)); + ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev)); if (ret) return ret; @@ -69,11 +70,11 @@ static int spi_pci_probe(struct pci_dev *pdev, dws->irq = pdev->irq; /* - * Specific handling for Intel MID paltforms, like dma setup, + * Specific handling for paltforms, like dma setup, * clock rate, FIFO depth. */ - if (pdev->device == 0x0800) { - ret = dw_spi_mid_init(dws); + if (desc && desc->setup) { + ret = desc->setup(dws); if (ret) return ret; } @@ -85,6 +86,9 @@ static int spi_pci_probe(struct pci_dev *pdev, /* PCI hook and SPI hook use the same drv data */ pci_set_drvdata(pdev, dwpci); + dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", + pdev->vendor, pdev->device); + return 0; } @@ -95,41 +99,29 @@ static void spi_pci_remove(struct pci_dev *pdev) dw_spi_remove_host(&dwpci->dws); } -#ifdef CONFIG_PM -static int spi_suspend(struct pci_dev *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int spi_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); - int ret; - ret = dw_spi_suspend_host(&dwpci->dws); - if (ret) - return ret; - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return ret; + return dw_spi_suspend_host(&dwpci->dws); } -static int spi_resume(struct pci_dev *pdev) +static int spi_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); - int ret; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) - return ret; return dw_spi_resume_host(&dwpci->dws); } -#else -#define spi_suspend NULL -#define spi_resume NULL #endif +static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume); + static const struct pci_device_id pci_ids[] = { /* Intel MID platform SPI controller 0 */ - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) }, + { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc}, {}, }; @@ -138,8 +130,9 @@ static struct pci_driver dw_spi_driver = { .id_table = pci_ids, .probe = spi_pci_probe, .remove = spi_pci_remove, - .suspend = spi_suspend, - .resume = spi_resume, + .driver = { + .pm = &dw_spi_pm_ops, + }, }; module_pci_driver(dw_spi_driver); diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 0dd0623319b..72921588525 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -11,10 +11,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include <linux/dma-mapping.h> @@ -59,22 +55,20 @@ struct chip_data { #ifdef CONFIG_DEBUG_FS #define SPI_REGS_BUFSIZE 1024 -static ssize_t spi_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t dw_spi_show_regs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { - struct dw_spi *dws; + struct dw_spi *dws = file->private_data; char *buf; u32 len = 0; ssize_t ret; - dws = file->private_data; - buf = kzalloc(SPI_REGS_BUFSIZE, GFP_KERNEL); if (!buf) return 0; len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, - "MRST SPI0 registers:\n"); + "%s registers:\n", dev_name(&dws->master->dev)); len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, "=================================\n"); len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, @@ -110,42 +104,41 @@ static ssize_t spi_show_regs(struct file *file, char __user *user_buf, len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, "=================================\n"); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return ret; } -static const struct file_operations mrst_spi_regs_ops = { +static const struct file_operations dw_spi_regs_ops = { .owner = THIS_MODULE, .open = simple_open, - .read = spi_show_regs, + .read = dw_spi_show_regs, .llseek = default_llseek, }; -static int mrst_spi_debugfs_init(struct dw_spi *dws) +static int dw_spi_debugfs_init(struct dw_spi *dws) { - dws->debugfs = debugfs_create_dir("mrst_spi", NULL); + dws->debugfs = debugfs_create_dir("dw_spi", NULL); if (!dws->debugfs) return -ENOMEM; debugfs_create_file("registers", S_IFREG | S_IRUGO, - dws->debugfs, (void *)dws, &mrst_spi_regs_ops); + dws->debugfs, (void *)dws, &dw_spi_regs_ops); return 0; } -static void mrst_spi_debugfs_remove(struct dw_spi *dws) +static void dw_spi_debugfs_remove(struct dw_spi *dws) { - if (dws->debugfs) - debugfs_remove_recursive(dws->debugfs); + debugfs_remove_recursive(dws->debugfs); } #else -static inline int mrst_spi_debugfs_init(struct dw_spi *dws) +static inline int dw_spi_debugfs_init(struct dw_spi *dws) { return 0; } -static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) +static inline void dw_spi_debugfs_remove(struct dw_spi *dws) { } #endif /* CONFIG_DEBUG_FS */ @@ -177,7 +170,7 @@ static inline u32 rx_max(struct dw_spi *dws) { u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes; - return min(rx_left, (u32)dw_readw(dws, DW_SPI_RXFLR)); + return min_t(u32, rx_left, dw_readw(dws, DW_SPI_RXFLR)); } static void dw_writer(struct dw_spi *dws) @@ -228,8 +221,9 @@ static void *next_transfer(struct dw_spi *dws) struct spi_transfer, transfer_list); return RUNNING_STATE; - } else - return DONE_STATE; + } + + return DONE_STATE; } /* @@ -396,7 +390,7 @@ static void pump_transfers(unsigned long data) goto early_exit; } - /* Delay if requested at end of transfer*/ + /* Delay if requested at end of transfer */ if (message->state == RUNNING_STATE) { previous = list_entry(transfer->transfer_list.prev, struct spi_transfer, @@ -471,10 +465,12 @@ static void pump_transfers(unsigned long data) */ if (!dws->dma_mapped && !chip->poll_mode) { int templen = dws->len / dws->n_bytes; + txint_level = dws->fifo_len / 2; txint_level = (templen > txint_level) ? txint_level : templen; - imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI; + imask |= SPI_INT_TXEI | SPI_INT_TXOI | + SPI_INT_RXUI | SPI_INT_RXOI; dws->transfer_handler = interrupt_transfer; } @@ -515,7 +511,6 @@ static void pump_transfers(unsigned long data) early_exit: giveback(dws); - return; } static int dw_spi_transfer_one_message(struct spi_master *master, @@ -524,7 +519,7 @@ static int dw_spi_transfer_one_message(struct spi_master *master, struct dw_spi *dws = spi_master_get_devdata(master); dws->cur_msg = msg; - /* Initial message state*/ + /* Initial message state */ dws->cur_msg->state = START_STATE; dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, struct spi_transfer, @@ -595,6 +590,9 @@ static int dw_spi_setup(struct spi_device *spi) | (spi->mode << SPI_MODE_OFFSET) | (chip->tmode << SPI_TMOD_OFFSET); + if (spi->mode & SPI_LOOP) + chip->cr0 |= 1 << SPI_SRL_OFFSET; + if (gpio_is_valid(spi->cs_gpio)) { ret = gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); @@ -626,6 +624,7 @@ static void spi_hw_init(struct dw_spi *dws) */ if (!dws->fifo_len) { u32 fifo; + for (fifo = 2; fifo <= 257; fifo++) { dw_writew(dws, DW_SPI_TXFLTR, fifo); if (fifo != dw_readw(dws, DW_SPI_TXFLTR)) @@ -653,8 +652,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->prev_chip = NULL; dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60); - snprintf(dws->name, sizeof(dws->name), "dw_spi%d", - dws->bus_num); + snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num); ret = devm_request_irq(dev, dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, dws); @@ -663,7 +661,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) goto err_free_master; } - master->mode_bits = SPI_CPOL | SPI_CPHA; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bus_num = dws->bus_num; master->num_chipselect = dws->num_cs; @@ -692,7 +690,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) goto err_dma_exit; } - mrst_spi_debugfs_init(dws); + dw_spi_debugfs_init(dws); return 0; err_dma_exit: @@ -709,7 +707,7 @@ void dw_spi_remove_host(struct dw_spi *dws) { if (!dws) return; - mrst_spi_debugfs_remove(dws); + dw_spi_debugfs_remove(dws); if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 6d2acad34f6..83a103a7648 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -74,6 +74,10 @@ #define SPI_INT_RXFI (1 << 4) #define SPI_INT_MSTI (1 << 5) +/* Bit fields in DMACR */ +#define SPI_DMA_RDMAE (1 << 0) +#define SPI_DMA_TDMAE (1 << 1) + /* TX RX interrupt level threshold, max can be 256 */ #define SPI_INT_THRESHOLD 32 @@ -140,7 +144,6 @@ struct dw_spi { dma_addr_t dma_addr; /* phy address of the Data register */ struct dw_spi_dma_ops *dma_ops; void *dma_priv; /* platform relate info */ - struct pci_dev *dmac; /* Bus interface info */ void *priv; @@ -217,11 +220,11 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) * Each SPI slave device to work with dw_api controller should * has such a structure claiming its working mode (PIO/DMA etc), * which can be save in the "controller_data" member of the - * struct spi_device + * struct spi_device. */ struct dw_spi_chip { - u8 poll_mode; /* 0 for contoller polling mode */ - u8 type; /* SPI/SSP/Micrwire */ + u8 poll_mode; /* 1 for controller polling mode */ + u8 type; /* SPI/SSP/MicroWire */ u8 enable_dma; void (*cs_control)(u32 command); }; diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 2f675d32df0..bf972877324 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -266,6 +266,7 @@ static int ep93xx_spi_setup(struct spi_device *spi) if (chip->ops && chip->ops->setup) { int ret = chip->ops->setup(spi); + if (ret) { kfree(chip); return ret; diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index 54b06376f03..c5dd20beee2 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -15,17 +15,17 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/fsl_devices.h> -#include <linux/dma-mapping.h> -#include <linux/of_address.h> #include <asm/cpm.h> #include <asm/qe.h> +#include <linux/dma-mapping.h> +#include <linux/fsl_devices.h> +#include <linux/kernel.h> +#include <linux/of_address.h> +#include <linux/spi/spi.h> +#include <linux/types.h> -#include "spi-fsl-lib.h" #include "spi-fsl-cpm.h" +#include "spi-fsl-lib.h" #include "spi-fsl-spi.h" /* CPM1 and CPM2 are mutually exclusive. */ diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 5021ddf03f6..448216025ce 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -13,22 +13,22 @@ * */ +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/errno.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/sched.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/err.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> -#include <linux/pm_runtime.h> -#include <linux/of.h> -#include <linux/of_device.h> #define DRIVER_NAME "fsl-dspi" @@ -493,9 +493,6 @@ static int dspi_probe(struct platform_device *pdev) } dspi_regmap_config.lock_arg = dspi; - dspi_regmap_config.val_format_endian = - of_property_read_bool(np, "big-endian") - ? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT; dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base, &dspi_regmap_config); if (IS_ERR(dspi->regmap)) { @@ -535,7 +532,6 @@ static int dspi_probe(struct platform_device *pdev) goto out_clk_put; } - pr_info(KERN_INFO "Freescale DSPI master initialized\n"); return ret; out_clk_put: diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 429e1119026..a7f94b6a9e7 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -8,19 +8,19 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#include <linux/module.h> #include <linux/delay.h> -#include <linux/irq.h> -#include <linux/spi/spi.h> -#include <linux/platform_device.h> +#include <linux/err.h> #include <linux/fsl_devices.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/module.h> #include <linux/mm.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> -#include <linux/interrupt.h> -#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> #include <sysdev/fsl_soc.h> #include "spi-fsl-lib.h" diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index e0b773fc29c..5ddb5b098e4 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -16,10 +16,10 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/fsl_devices.h> #include <linux/dma-mapping.h> +#include <linux/fsl_devices.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> #include <linux/mm.h> #include <linux/of_platform.h> #include <linux/spi/spi.h> diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 590f31bc0ab..ed792880c9d 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -19,25 +19,25 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/interrupt.h> #include <linux/delay.h> -#include <linux/irq.h> -#include <linux/spi/spi.h> -#include <linux/spi/spi_bitbang.h> -#include <linux/platform_device.h> -#include <linux/fsl_devices.h> #include <linux/dma-mapping.h> +#include <linux/fsl_devices.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> -#include <linux/of_platform.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/gpio.h> #include <linux/of_gpio.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> +#include <linux/types.h> #include "spi-fsl-lib.h" #include "spi-fsl-cpm.h" diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 5daff2054ae..3637847b537 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -21,6 +21,8 @@ #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/interrupt.h> @@ -37,6 +39,7 @@ #include <linux/of_device.h> #include <linux/of_gpio.h> +#include <linux/platform_data/dma-imx.h> #include <linux/platform_data/spi-imx.h> #define DRIVER_NAME "spi_imx" @@ -51,6 +54,9 @@ #define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */ #define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */ +/* The maximum bytes that a sdma BD can transfer.*/ +#define MAX_SDMA_BD_BYTES (1 << 15) +#define IMX_DMA_TIMEOUT (msecs_to_jiffies(3000)) struct spi_imx_config { unsigned int speed_hz; unsigned int bpw; @@ -95,6 +101,16 @@ struct spi_imx_data { const void *tx_buf; unsigned int txfifo; /* number of words pushed in tx FIFO */ + /* DMA */ + unsigned int dma_is_inited; + unsigned int dma_finished; + bool usedma; + u32 rx_wml; + u32 tx_wml; + u32 rxt_wml; + struct completion dma_rx_completion; + struct completion dma_tx_completion; + const struct spi_imx_devtype_data *devtype_data; int chipselect[0]; }; @@ -181,9 +197,21 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, return 7; } +static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct spi_imx_data *spi_imx = spi_master_get_devdata(master); + + if (spi_imx->dma_is_inited && (transfer->len > spi_imx->rx_wml) + && (transfer->len > spi_imx->tx_wml)) + return true; + return false; +} + #define MX51_ECSPI_CTRL 0x08 #define MX51_ECSPI_CTRL_ENABLE (1 << 0) #define MX51_ECSPI_CTRL_XCH (1 << 2) +#define MX51_ECSPI_CTRL_SMC (1 << 3) #define MX51_ECSPI_CTRL_MODE_MASK (0xf << 4) #define MX51_ECSPI_CTRL_POSTDIV_OFFSET 8 #define MX51_ECSPI_CTRL_PREDIV_OFFSET 12 @@ -201,6 +229,18 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, #define MX51_ECSPI_INT_TEEN (1 << 0) #define MX51_ECSPI_INT_RREN (1 << 3) +#define MX51_ECSPI_DMA 0x14 +#define MX51_ECSPI_DMA_TX_WML_OFFSET 0 +#define MX51_ECSPI_DMA_TX_WML_MASK 0x3F +#define MX51_ECSPI_DMA_RX_WML_OFFSET 16 +#define MX51_ECSPI_DMA_RX_WML_MASK (0x3F << 16) +#define MX51_ECSPI_DMA_RXT_WML_OFFSET 24 +#define MX51_ECSPI_DMA_RXT_WML_MASK (0x3F << 24) + +#define MX51_ECSPI_DMA_TEDEN_OFFSET 7 +#define MX51_ECSPI_DMA_RXDEN_OFFSET 23 +#define MX51_ECSPI_DMA_RXTDEN_OFFSET 31 + #define MX51_ECSPI_STAT 0x18 #define MX51_ECSPI_STAT_RR (1 << 3) @@ -257,17 +297,22 @@ static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx) { - u32 reg; - - reg = readl(spi_imx->base + MX51_ECSPI_CTRL); - reg |= MX51_ECSPI_CTRL_XCH; + u32 reg = readl(spi_imx->base + MX51_ECSPI_CTRL); + + if (!spi_imx->usedma) + reg |= MX51_ECSPI_CTRL_XCH; + else if (!spi_imx->dma_finished) + reg |= MX51_ECSPI_CTRL_SMC; + else + reg &= ~MX51_ECSPI_CTRL_SMC; writel(reg, spi_imx->base + MX51_ECSPI_CTRL); } static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, struct spi_imx_config *config) { - u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0; + u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0, dma = 0; + u32 tx_wml_cfg, rx_wml_cfg, rxt_wml_cfg; u32 clk = config->speed_hz, delay; /* @@ -319,6 +364,30 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, else /* SCLK is _very_ slow */ usleep_range(delay, delay + 10); + /* + * Configure the DMA register: setup the watermark + * and enable DMA request. + */ + if (spi_imx->dma_is_inited) { + dma = readl(spi_imx->base + MX51_ECSPI_DMA); + + spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2; + spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2; + spi_imx->rxt_wml = spi_imx_get_fifosize(spi_imx) / 2; + rx_wml_cfg = spi_imx->rx_wml << MX51_ECSPI_DMA_RX_WML_OFFSET; + tx_wml_cfg = spi_imx->tx_wml << MX51_ECSPI_DMA_TX_WML_OFFSET; + rxt_wml_cfg = spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET; + dma = (dma & ~MX51_ECSPI_DMA_TX_WML_MASK + & ~MX51_ECSPI_DMA_RX_WML_MASK + & ~MX51_ECSPI_DMA_RXT_WML_MASK) + | rx_wml_cfg | tx_wml_cfg | rxt_wml_cfg + |(1 << MX51_ECSPI_DMA_TEDEN_OFFSET) + |(1 << MX51_ECSPI_DMA_RXDEN_OFFSET) + |(1 << MX51_ECSPI_DMA_RXTDEN_OFFSET); + + writel(dma, spi_imx->base + MX51_ECSPI_DMA); + } + return 0; } @@ -730,7 +799,186 @@ static int spi_imx_setupxfer(struct spi_device *spi, return 0; } -static int spi_imx_transfer(struct spi_device *spi, +static void spi_imx_sdma_exit(struct spi_imx_data *spi_imx) +{ + struct spi_master *master = spi_imx->bitbang.master; + + if (master->dma_rx) { + dma_release_channel(master->dma_rx); + master->dma_rx = NULL; + } + + if (master->dma_tx) { + dma_release_channel(master->dma_tx); + master->dma_tx = NULL; + } + + spi_imx->dma_is_inited = 0; +} + +static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, + struct spi_master *master, + const struct resource *res) +{ + struct dma_slave_config slave_config = {}; + int ret; + + /* Prepare for TX DMA: */ + master->dma_tx = dma_request_slave_channel(dev, "tx"); + if (!master->dma_tx) { + dev_err(dev, "cannot get the TX DMA channel!\n"); + ret = -EINVAL; + goto err; + } + + slave_config.direction = DMA_MEM_TO_DEV; + slave_config.dst_addr = res->start + MXC_CSPITXDATA; + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_maxburst = spi_imx_get_fifosize(spi_imx) / 2; + ret = dmaengine_slave_config(master->dma_tx, &slave_config); + if (ret) { + dev_err(dev, "error in TX dma configuration.\n"); + goto err; + } + + /* Prepare for RX : */ + master->dma_rx = dma_request_slave_channel(dev, "rx"); + if (!master->dma_rx) { + dev_dbg(dev, "cannot get the DMA channel.\n"); + ret = -EINVAL; + goto err; + } + + slave_config.direction = DMA_DEV_TO_MEM; + slave_config.src_addr = res->start + MXC_CSPIRXDATA; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_maxburst = spi_imx_get_fifosize(spi_imx) / 2; + ret = dmaengine_slave_config(master->dma_rx, &slave_config); + if (ret) { + dev_err(dev, "error in RX dma configuration.\n"); + goto err; + } + + init_completion(&spi_imx->dma_rx_completion); + init_completion(&spi_imx->dma_tx_completion); + master->can_dma = spi_imx_can_dma; + master->max_dma_len = MAX_SDMA_BD_BYTES; + spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX | + SPI_MASTER_MUST_TX; + spi_imx->dma_is_inited = 1; + + return 0; +err: + spi_imx_sdma_exit(spi_imx); + return ret; +} + +static void spi_imx_dma_rx_callback(void *cookie) +{ + struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie; + + complete(&spi_imx->dma_rx_completion); +} + +static void spi_imx_dma_tx_callback(void *cookie) +{ + struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie; + + complete(&spi_imx->dma_tx_completion); +} + +static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, + struct spi_transfer *transfer) +{ + struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL; + int ret; + u32 dma; + int left; + struct spi_master *master = spi_imx->bitbang.master; + struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg; + + if (tx) { + desc_tx = dmaengine_prep_slave_sg(master->dma_tx, + tx->sgl, tx->nents, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_tx) + goto no_dma; + + desc_tx->callback = spi_imx_dma_tx_callback; + desc_tx->callback_param = (void *)spi_imx; + dmaengine_submit(desc_tx); + } + + if (rx) { + desc_rx = dmaengine_prep_slave_sg(master->dma_rx, + rx->sgl, rx->nents, DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_rx) + goto no_dma; + + desc_rx->callback = spi_imx_dma_rx_callback; + desc_rx->callback_param = (void *)spi_imx; + dmaengine_submit(desc_rx); + } + + reinit_completion(&spi_imx->dma_rx_completion); + reinit_completion(&spi_imx->dma_tx_completion); + + /* Trigger the cspi module. */ + spi_imx->dma_finished = 0; + + dma = readl(spi_imx->base + MX51_ECSPI_DMA); + dma = dma & (~MX51_ECSPI_DMA_RXT_WML_MASK); + /* Change RX_DMA_LENGTH trigger dma fetch tail data */ + left = transfer->len % spi_imx->rxt_wml; + if (left) + writel(dma | (left << MX51_ECSPI_DMA_RXT_WML_OFFSET), + spi_imx->base + MX51_ECSPI_DMA); + spi_imx->devtype_data->trigger(spi_imx); + + dma_async_issue_pending(master->dma_tx); + dma_async_issue_pending(master->dma_rx); + /* Wait SDMA to finish the data transfer.*/ + ret = wait_for_completion_timeout(&spi_imx->dma_tx_completion, + IMX_DMA_TIMEOUT); + if (!ret) { + pr_warn("%s %s: I/O Error in DMA TX\n", + dev_driver_string(&master->dev), + dev_name(&master->dev)); + dmaengine_terminate_all(master->dma_tx); + } else { + ret = wait_for_completion_timeout(&spi_imx->dma_rx_completion, + IMX_DMA_TIMEOUT); + if (!ret) { + pr_warn("%s %s: I/O Error in DMA RX\n", + dev_driver_string(&master->dev), + dev_name(&master->dev)); + spi_imx->devtype_data->reset(spi_imx); + dmaengine_terminate_all(master->dma_rx); + } + writel(dma | + spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET, + spi_imx->base + MX51_ECSPI_DMA); + } + + spi_imx->dma_finished = 1; + spi_imx->devtype_data->trigger(spi_imx); + + if (!ret) + ret = -ETIMEDOUT; + else if (ret > 0) + ret = transfer->len; + + return ret; + +no_dma: + pr_warn_once("%s %s: DMA not available, falling back to PIO\n", + dev_driver_string(&master->dev), + dev_name(&master->dev)); + return -EAGAIN; +} + +static int spi_imx_pio_transfer(struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); @@ -751,6 +999,24 @@ static int spi_imx_transfer(struct spi_device *spi, return transfer->len; } +static int spi_imx_transfer(struct spi_device *spi, + struct spi_transfer *transfer) +{ + int ret; + struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); + + if (spi_imx->bitbang.master->can_dma && + spi_imx_can_dma(spi_imx->bitbang.master, spi, transfer)) { + spi_imx->usedma = true; + ret = spi_imx_dma_transfer(spi_imx, transfer); + if (ret != -EAGAIN) + return ret; + } + spi_imx->usedma = false; + + return spi_imx_pio_transfer(spi, transfer); +} + static int spi_imx_setup(struct spi_device *spi) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); @@ -911,6 +1177,13 @@ static int spi_imx_probe(struct platform_device *pdev) goto out_put_per; spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per); + /* + * Only validated on i.mx6 now, can remove the constrain if validated on + * other chips. + */ + if (spi_imx->devtype_data == &imx51_ecspi_devtype_data + && spi_imx_sdma_init(&pdev->dev, spi_imx, master, res)) + dev_err(&pdev->dev, "dma setup error,use pio instead\n"); spi_imx->devtype_data->reset(spi_imx); @@ -949,6 +1222,7 @@ static int spi_imx_remove(struct platform_device *pdev) writel(0, spi_imx->base + MXC_CSPICTRL); clk_unprepare(spi_imx->clk_ipg); clk_unprepare(spi_imx->clk_per); + spi_imx_sdma_exit(spi_imx); spi_master_put(master); return 0; diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 2884f0c2f5f..51460878af0 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -85,7 +85,7 @@ static int mxs_spi_setup_transfer(struct spi_device *dev, mxs_ssp_set_clk_rate(ssp, hz); /* * Save requested rate, hz, rather than the actual rate, - * ssp->clk_rate. Otherwise we would set the rate every trasfer + * ssp->clk_rate. Otherwise we would set the rate every transfer * when the actual rate is not quite the same as requested rate. */ spi->sck = hz; @@ -154,12 +154,14 @@ static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set) static void mxs_ssp_dma_irq_callback(void *param) { struct mxs_spi *spi = param; + complete(&spi->c); } static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id) { struct mxs_ssp *ssp = dev_id; + dev_err(ssp->dev, "%s[%i] CTRL1=%08x STATUS=%08x\n", __func__, __LINE__, readl(ssp->base + HW_SSP_CTRL1(ssp)), @@ -189,7 +191,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, if (!len) return -EINVAL; - dma_xfer = kzalloc(sizeof(*dma_xfer) * sgs, GFP_KERNEL); + dma_xfer = kcalloc(sgs, sizeof(*dma_xfer), GFP_KERNEL); if (!dma_xfer) return -ENOMEM; diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 5e91858f6f0..fb522765ce5 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -70,10 +70,6 @@ #define SPI_STATUS_WE (1UL << 1) #define SPI_STATUS_RD (1UL << 0) -#define WRITE 0 -#define READ 1 - - /* use PIO for small transfers, avoiding DMA setup/teardown overhead and * cache operations; better heuristics consider wordsize and bitrate. */ diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index c4675fa8b64..835cdda6f4f 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/clk.h> #include <linux/sizes.h> #include <asm/unaligned.h> @@ -40,13 +41,27 @@ #define ORION_SPI_MODE_CPHA (1 << 12) #define ORION_SPI_IF_8_16_BIT_MODE (1 << 5) #define ORION_SPI_CLK_PRESCALE_MASK 0x1F +#define ARMADA_SPI_CLK_PRESCALE_MASK 0xDF #define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \ ORION_SPI_MODE_CPHA) +enum orion_spi_type { + ORION_SPI, + ARMADA_SPI, +}; + +struct orion_spi_dev { + enum orion_spi_type typ; + unsigned int min_divisor; + unsigned int max_divisor; + u32 prescale_mask; +}; + struct orion_spi { struct spi_master *master; void __iomem *base; struct clk *clk; + const struct orion_spi_dev *devdata; }; static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg) @@ -83,30 +98,66 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) u32 prescale; u32 reg; struct orion_spi *orion_spi; + const struct orion_spi_dev *devdata; orion_spi = spi_master_get_devdata(spi->master); + devdata = orion_spi->devdata; tclk_hz = clk_get_rate(orion_spi->clk); - /* - * the supported rates are: 4,6,8...30 - * round up as we look for equal or less speed - */ - rate = DIV_ROUND_UP(tclk_hz, speed); - rate = roundup(rate, 2); + if (devdata->typ == ARMADA_SPI) { + unsigned int clk, spr, sppr, sppr2, err; + unsigned int best_spr, best_sppr, best_err; - /* check if requested speed is too small */ - if (rate > 30) - return -EINVAL; + best_err = speed; + best_spr = 0; + best_sppr = 0; - if (rate < 4) - rate = 4; + /* Iterate over the valid range looking for best fit */ + for (sppr = 0; sppr < 8; sppr++) { + sppr2 = 0x1 << sppr; + + spr = tclk_hz / sppr2; + spr = DIV_ROUND_UP(spr, speed); + if ((spr == 0) || (spr > 15)) + continue; + + clk = tclk_hz / (spr * sppr2); + err = speed - clk; + + if (err < best_err) { + best_spr = spr; + best_sppr = sppr; + best_err = err; + } + } - /* Convert the rate to SPI clock divisor value. */ - prescale = 0x10 + rate/2; + if ((best_sppr == 0) && (best_spr == 0)) + return -EINVAL; + + prescale = ((best_sppr & 0x6) << 5) | + ((best_sppr & 0x1) << 4) | best_spr; + } else { + /* + * the supported rates are: 4,6,8...30 + * round up as we look for equal or less speed + */ + rate = DIV_ROUND_UP(tclk_hz, speed); + rate = roundup(rate, 2); + + /* check if requested speed is too small */ + if (rate > 30) + return -EINVAL; + + if (rate < 4) + rate = 4; + + /* Convert the rate to SPI clock divisor value. */ + prescale = 0x10 + rate/2; + } reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); - reg = ((reg & ~ORION_SPI_CLK_PRESCALE_MASK) | prescale); + reg = ((reg & ~devdata->prescale_mask) | prescale); writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); return 0; @@ -179,8 +230,8 @@ static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi) for (i = 0; i < ORION_SPI_WAIT_RDY_MAX_LOOP; i++) { if (readl(spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG))) return 1; - else - udelay(1); + + udelay(1); } return -1; @@ -342,8 +393,31 @@ static int orion_spi_reset(struct orion_spi *orion_spi) return 0; } +static const struct orion_spi_dev orion_spi_dev_data = { + .typ = ORION_SPI, + .min_divisor = 4, + .max_divisor = 30, + .prescale_mask = ORION_SPI_CLK_PRESCALE_MASK, +}; + +static const struct orion_spi_dev armada_spi_dev_data = { + .typ = ARMADA_SPI, + .min_divisor = 1, + .max_divisor = 1920, + .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK, +}; + +static const struct of_device_id orion_spi_of_match_table[] = { + { .compatible = "marvell,orion-spi", .data = &orion_spi_dev_data, }, + { .compatible = "marvell,armada-370-spi", .data = &armada_spi_dev_data, }, + {} +}; +MODULE_DEVICE_TABLE(of, orion_spi_of_match_table); + static int orion_spi_probe(struct platform_device *pdev) { + const struct of_device_id *of_id; + const struct orion_spi_dev *devdata; struct spi_master *master; struct orion_spi *spi; struct resource *r; @@ -360,6 +434,7 @@ static int orion_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; if (pdev->dev.of_node) { u32 cell_index; + if (!of_property_read_u32(pdev->dev.of_node, "cell-index", &cell_index)) master->bus_num = cell_index; @@ -378,6 +453,10 @@ static int orion_spi_probe(struct platform_device *pdev) spi = spi_master_get_devdata(master); spi->master = master; + of_id = of_match_device(orion_spi_of_match_table, &pdev->dev); + devdata = of_id->data; + spi->devdata = devdata; + spi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(spi->clk)) { status = PTR_ERR(spi->clk); @@ -389,8 +468,8 @@ static int orion_spi_probe(struct platform_device *pdev) goto out; tclk_hz = clk_get_rate(spi->clk); - master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4); - master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30); + master->max_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->min_divisor); + master->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); spi->base = devm_ioremap_resource(&pdev->dev, r); @@ -469,12 +548,6 @@ static const struct dev_pm_ops orion_spi_pm_ops = { NULL) }; -static const struct of_device_id orion_spi_of_match_table[] = { - { .compatible = "marvell,orion-spi", }, - {} -}; -MODULE_DEVICE_TABLE(of, orion_spi_of_match_table); - static struct platform_driver orion_spi_driver = { .driver = { .name = DRIVER_NAME, diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index f1f0a587e4f..f35f723816e 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -82,6 +82,7 @@ #define SSP_MIS(r) (r + 0x01C) #define SSP_ICR(r) (r + 0x020) #define SSP_DMACR(r) (r + 0x024) +#define SSP_CSR(r) (r + 0x030) /* vendor extension */ #define SSP_ITCR(r) (r + 0x080) #define SSP_ITIP(r) (r + 0x084) #define SSP_ITOP(r) (r + 0x088) @@ -198,6 +199,12 @@ #define SSP_DMACR_MASK_TXDMAE (0x1UL << 1) /* + * SSP Chip Select Control Register - SSP_CSR + * (vendor extension) + */ +#define SSP_CSR_CSVALUE_MASK (0x1FUL << 0) + +/* * SSP Integration Test control Register - SSP_ITCR */ #define SSP_ITCR_MASK_ITEN (0x1UL << 0) @@ -313,6 +320,7 @@ enum ssp_writing { * @extended_cr: 32 bit wide control register 0 with extra * features and extra features in CR1 as found in the ST variants * @pl023: supports a subset of the ST extensions called "PL023" + * @internal_cs_ctrl: supports chip select control register */ struct vendor_data { int fifodepth; @@ -321,6 +329,7 @@ struct vendor_data { bool extended_cr; bool pl023; bool loopback; + bool internal_cs_ctrl; }; /** @@ -440,9 +449,32 @@ static void null_cs_control(u32 command) pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); } +/** + * internal_cs_control - Control chip select signals via SSP_CSR. + * @pl022: SSP driver private data structure + * @command: select/delect the chip + * + * Used on controller with internal chip select control via SSP_CSR register + * (vendor extension). Each of the 5 LSB in the register controls one chip + * select signal. + */ +static void internal_cs_control(struct pl022 *pl022, u32 command) +{ + u32 tmp; + + tmp = readw(SSP_CSR(pl022->virtbase)); + if (command == SSP_CHIP_SELECT) + tmp &= ~BIT(pl022->cur_cs); + else + tmp |= BIT(pl022->cur_cs); + writew(tmp, SSP_CSR(pl022->virtbase)); +} + static void pl022_cs_control(struct pl022 *pl022, u32 command) { - if (gpio_is_valid(pl022->cur_cs)) + if (pl022->vendor->internal_cs_ctrl) + internal_cs_control(pl022, command); + else if (gpio_is_valid(pl022->cur_cs)) gpio_set_value(pl022->cur_cs, command); else pl022->cur_chip->cs_control(command); @@ -2100,6 +2132,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) pl022->vendor = id->data; pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int), GFP_KERNEL); + if (!pl022->chipselects) { + status = -ENOMEM; + goto err_no_mem; + } /* * Bus Number Which has been Assigned to this SSP controller @@ -2118,6 +2154,9 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) if (platform_info->num_chipselect && platform_info->chipselects) { for (i = 0; i < num_cs; i++) pl022->chipselects[i] = platform_info->chipselects[i]; + } else if (pl022->vendor->internal_cs_ctrl) { + for (i = 0; i < num_cs; i++) + pl022->chipselects[i] = i; } else if (IS_ENABLED(CONFIG_OF)) { for (i = 0; i < num_cs; i++) { int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); @@ -2241,6 +2280,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) amba_release_regions(adev); err_no_ioregion: err_no_gpio: + err_no_mem: spi_master_put(master); return status; } @@ -2347,6 +2387,7 @@ static struct vendor_data vendor_arm = { .extended_cr = false, .pl023 = false, .loopback = true, + .internal_cs_ctrl = false, }; static struct vendor_data vendor_st = { @@ -2356,6 +2397,7 @@ static struct vendor_data vendor_st = { .extended_cr = true, .pl023 = false, .loopback = true, + .internal_cs_ctrl = false, }; static struct vendor_data vendor_st_pl023 = { @@ -2365,6 +2407,17 @@ static struct vendor_data vendor_st_pl023 = { .extended_cr = true, .pl023 = true, .loopback = false, + .internal_cs_ctrl = false, +}; + +static struct vendor_data vendor_lsi = { + .fifodepth = 8, + .max_bpw = 16, + .unidir = false, + .extended_cr = false, + .pl023 = false, + .loopback = true, + .internal_cs_ctrl = true, }; static struct amba_id pl022_ids[] = { @@ -2398,6 +2451,15 @@ static struct amba_id pl022_ids[] = { .mask = 0xffffffff, .data = &vendor_st_pl023, }, + { + /* + * PL022 variant that has a chip select control register whih + * allows control of 5 output signals nCS[0:4]. + */ + .id = 0x000b6022, + .mask = 0x000fffff, + .data = &vendor_lsi, + }, { 0, 0 }, }; diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index c1865c92ccb..536c863bebf 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -7,6 +7,8 @@ #include <linux/of_device.h> #include <linux/module.h> #include <linux/spi/pxa2xx_spi.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> enum { PORT_CE4100, @@ -21,6 +23,7 @@ struct pxa_spi_info { int tx_chan_id; int rx_slave_id; int rx_chan_id; + unsigned long max_clk_rate; }; static struct pxa_spi_info spi_info_configs[] = { @@ -32,6 +35,7 @@ static struct pxa_spi_info spi_info_configs[] = { .tx_chan_id = -1, .rx_slave_id = -1, .rx_chan_id = -1, + .max_clk_rate = 3686400, }, [PORT_BYT] = { .type = LPSS_SSP, @@ -41,6 +45,7 @@ static struct pxa_spi_info spi_info_configs[] = { .tx_chan_id = 0, .rx_slave_id = 1, .rx_chan_id = 1, + .max_clk_rate = 50000000, }, }; @@ -53,6 +58,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, struct pxa2xx_spi_master spi_pdata; struct ssp_device *ssp; struct pxa_spi_info *c; + char buf[40]; ret = pcim_enable_device(dev); if (ret) @@ -84,6 +90,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn; ssp->type = c->type; + snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id); + ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL, + CLK_IS_ROOT, c->max_clk_rate); + if (IS_ERR(ssp->clk)) + return PTR_ERR(ssp->clk); + memset(&pi, 0, sizeof(pi)); pi.parent = &dev->dev; pi.name = "pxa2xx-spi"; @@ -92,8 +104,10 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, pi.size_data = sizeof(spi_pdata); pdev = platform_device_register_full(&pi); - if (IS_ERR(pdev)) + if (IS_ERR(pdev)) { + clk_unregister(ssp->clk); return PTR_ERR(pdev); + } pci_set_drvdata(dev, pdev); @@ -103,8 +117,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, static void pxa2xx_spi_pci_remove(struct pci_dev *dev) { struct platform_device *pdev = pci_get_drvdata(dev); + struct pxa2xx_spi_master *spi_pdata; + + spi_pdata = dev_get_platdata(&pdev->dev); platform_device_unregister(pdev); + clk_unregister(spi_pdata->ssp.clk); } static const struct pci_device_id pxa2xx_spi_pci_devices[] = { diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 3afc266b666..f96ea8a38d6 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -415,7 +415,7 @@ static void rockchip_spi_dma_txcb(void *data) spin_unlock_irqrestore(&rs->lock, flags); } -static int rockchip_spi_dma_transfer(struct rockchip_spi *rs) +static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) { unsigned long flags; struct dma_slave_config rxconf, txconf; @@ -474,8 +474,6 @@ static int rockchip_spi_dma_transfer(struct rockchip_spi *rs) dmaengine_submit(txdesc); dma_async_issue_pending(rs->dma_tx.ch); } - - return 1; } static void rockchip_spi_config(struct rockchip_spi *rs) @@ -557,16 +555,17 @@ static int rockchip_spi_transfer_one( else if (rs->rx) rs->tmode = CR0_XFM_RO; - if (master->can_dma && master->can_dma(master, spi, xfer)) + /* we need prepare dma before spi was enabled */ + if (master->can_dma && master->can_dma(master, spi, xfer)) { rs->use_dma = 1; - else + rockchip_spi_prepare_dma(rs); + } else { rs->use_dma = 0; + } rockchip_spi_config(rs); - if (rs->use_dma) - ret = rockchip_spi_dma_transfer(rs); - else + if (!rs->use_dma) ret = rockchip_spi_pio_transfer(rs); return ret; diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index ad87a98f8f6..54bb0faec15 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -87,7 +87,7 @@ /* RSPI on SH only */ #define SPCR_TXMD 0x02 /* TX Only Mode (vs. Full Duplex) */ #define SPCR_SPMS 0x01 /* 3-wire Mode (vs. 4-wire) */ -/* QSPI on R-Car M2 only */ +/* QSPI on R-Car Gen2 only */ #define SPCR_WSWAP 0x02 /* Word Swap of read-data for DMAC */ #define SPCR_BSWAP 0x01 /* Byte Swap of read-data for DMAC */ @@ -909,20 +909,24 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev, dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - chan = dma_request_channel(mask, shdma_chan_filter, - (void *)(unsigned long)id); + chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, + (void *)(unsigned long)id, dev, + dir == DMA_MEM_TO_DEV ? "tx" : "rx"); if (!chan) { - dev_warn(dev, "dma_request_channel failed\n"); + dev_warn(dev, "dma_request_slave_channel_compat failed\n"); return NULL; } memset(&cfg, 0, sizeof(cfg)); cfg.slave_id = id; cfg.direction = dir; - if (dir == DMA_MEM_TO_DEV) + if (dir == DMA_MEM_TO_DEV) { cfg.dst_addr = port_addr; - else + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + } else { cfg.src_addr = port_addr; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + } ret = dmaengine_slave_config(chan, &cfg); if (ret) { @@ -938,22 +942,30 @@ static int rspi_request_dma(struct device *dev, struct spi_master *master, const struct resource *res) { const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev); + unsigned int dma_tx_id, dma_rx_id; + + if (dev->of_node) { + /* In the OF case we will get the slave IDs from the DT */ + dma_tx_id = 0; + dma_rx_id = 0; + } else if (rspi_pd && rspi_pd->dma_tx_id && rspi_pd->dma_rx_id) { + dma_tx_id = rspi_pd->dma_tx_id; + dma_rx_id = rspi_pd->dma_rx_id; + } else { + /* The driver assumes no error. */ + return 0; + } - if (!rspi_pd || !rspi_pd->dma_rx_id || !rspi_pd->dma_tx_id) - return 0; /* The driver assumes no error. */ - - master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, - rspi_pd->dma_rx_id, + master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, dma_tx_id, res->start + RSPI_SPDR); - if (!master->dma_rx) + if (!master->dma_tx) return -ENODEV; - master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, - rspi_pd->dma_tx_id, + master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, dma_rx_id, res->start + RSPI_SPDR); - if (!master->dma_tx) { - dma_release_channel(master->dma_rx); - master->dma_rx = NULL; + if (!master->dma_rx) { + dma_release_channel(master->dma_tx); + master->dma_tx = NULL; return -ENODEV; } @@ -1046,12 +1058,11 @@ static int rspi_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, const char *suffix, void *dev_id) { - const char *base = dev_name(dev); - size_t len = strlen(base) + strlen(suffix) + 2; - char *name = devm_kzalloc(dev, len, GFP_KERNEL); + const char *name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", + dev_name(dev), suffix); if (!name) return -ENOMEM; - snprintf(name, len, "%s:%s", base, suffix); + return devm_request_irq(dev, irq, handler, 0, name, dev_id); } @@ -1084,7 +1095,7 @@ static int rspi_probe(struct platform_device *pdev) master->num_chipselect = rspi_pd->num_chipselect; else master->num_chipselect = 2; /* default */ - }; + } /* ops parameter check */ if (!ops->set_config_register) { diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 543075b80f1..3f365402fcc 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -642,18 +642,14 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, desc_rx = dmaengine_prep_slave_single(p->master->dma_rx, p->rx_dma_addr, len, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_rx) { - ret = -EAGAIN; - goto no_dma_rx; - } + if (!desc_rx) + return -EAGAIN; desc_rx->callback = sh_msiof_dma_complete; desc_rx->callback_param = p; cookie = dmaengine_submit(desc_rx); - if (dma_submit_error(cookie)) { - ret = cookie; - goto no_dma_rx; - } + if (dma_submit_error(cookie)) + return cookie; } if (tx) { @@ -738,7 +734,6 @@ no_dma_tx: if (rx) dmaengine_terminate_all(p->master->dma_rx); sh_msiof_write(p, IER, 0); -no_dma_rx: return ret; } @@ -933,6 +928,9 @@ static const struct of_device_id sh_msiof_match[] = { { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data }, + { .compatible = "renesas,msiof-r8a7792", .data = &r8a779x_data }, + { .compatible = "renesas,msiof-r8a7793", .data = &r8a779x_data }, + { .compatible = "renesas,msiof-r8a7794", .data = &r8a779x_data }, {}, }; MODULE_DEVICE_TABLE(of, sh_msiof_match); @@ -977,20 +975,24 @@ static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev, dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - chan = dma_request_channel(mask, shdma_chan_filter, - (void *)(unsigned long)id); + chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, + (void *)(unsigned long)id, dev, + dir == DMA_MEM_TO_DEV ? "tx" : "rx"); if (!chan) { - dev_warn(dev, "dma_request_channel failed\n"); + dev_warn(dev, "dma_request_slave_channel_compat failed\n"); return NULL; } memset(&cfg, 0, sizeof(cfg)); cfg.slave_id = id; cfg.direction = dir; - if (dir == DMA_MEM_TO_DEV) + if (dir == DMA_MEM_TO_DEV) { cfg.dst_addr = port_addr; - else + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + } else { cfg.src_addr = port_addr; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + } ret = dmaengine_slave_config(chan, &cfg); if (ret) { @@ -1007,12 +1009,22 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p) struct platform_device *pdev = p->pdev; struct device *dev = &pdev->dev; const struct sh_msiof_spi_info *info = dev_get_platdata(dev); + unsigned int dma_tx_id, dma_rx_id; const struct resource *res; struct spi_master *master; struct device *tx_dev, *rx_dev; - if (!info || !info->dma_tx_id || !info->dma_rx_id) - return 0; /* The driver assumes no error */ + if (dev->of_node) { + /* In the OF case we will get the slave IDs from the DT */ + dma_tx_id = 0; + dma_rx_id = 0; + } else if (info && info->dma_tx_id && info->dma_rx_id) { + dma_tx_id = info->dma_tx_id; + dma_rx_id = info->dma_rx_id; + } else { + /* The driver assumes no error */ + return 0; + } /* The DMA engine uses the second register set, if present */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); @@ -1021,13 +1033,13 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p) master = p->master; master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV, - info->dma_tx_id, + dma_tx_id, res->start + TFDR); if (!master->dma_tx) return -ENODEV; master->dma_rx = sh_msiof_request_dma_chan(dev, DMA_DEV_TO_MEM, - info->dma_rx_id, + dma_rx_id, res->start + RFDR); if (!master->dma_rx) goto free_tx_chan; @@ -1210,6 +1222,9 @@ static struct platform_device_id spi_driver_ids[] = { { "spi_sh_msiof", (kernel_ulong_t)&sh_data }, { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data }, { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data }, + { "spi_r8a7792_msiof", (kernel_ulong_t)&r8a779x_data }, + { "spi_r8a7793_msiof", (kernel_ulong_t)&r8a779x_data }, + { "spi_r8a7794_msiof", (kernel_ulong_t)&r8a779x_data }, {}, }; MODULE_DEVICE_TABLE(platform, spi_driver_ids); diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 6f0602fd740..39e2c0a55a2 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -62,15 +62,15 @@ #define SIRFSOC_SPI_TRAN_DAT_FORMAT_12 (1 << 26) #define SIRFSOC_SPI_TRAN_DAT_FORMAT_16 (2 << 26) #define SIRFSOC_SPI_TRAN_DAT_FORMAT_32 (3 << 26) -#define SIRFSOC_SPI_CMD_BYTE_NUM(x) ((x & 3) << 28) -#define SIRFSOC_SPI_ENA_AUTO_CLR BIT(30) -#define SIRFSOC_SPI_MUL_DAT_MODE BIT(31) +#define SIRFSOC_SPI_CMD_BYTE_NUM(x) ((x & 3) << 28) +#define SIRFSOC_SPI_ENA_AUTO_CLR BIT(30) +#define SIRFSOC_SPI_MUL_DAT_MODE BIT(31) /* Interrupt Enable */ -#define SIRFSOC_SPI_RX_DONE_INT_EN BIT(0) -#define SIRFSOC_SPI_TX_DONE_INT_EN BIT(1) -#define SIRFSOC_SPI_RX_OFLOW_INT_EN BIT(2) -#define SIRFSOC_SPI_TX_UFLOW_INT_EN BIT(3) +#define SIRFSOC_SPI_RX_DONE_INT_EN BIT(0) +#define SIRFSOC_SPI_TX_DONE_INT_EN BIT(1) +#define SIRFSOC_SPI_RX_OFLOW_INT_EN BIT(2) +#define SIRFSOC_SPI_TX_UFLOW_INT_EN BIT(3) #define SIRFSOC_SPI_RX_IO_DMA_INT_EN BIT(4) #define SIRFSOC_SPI_TX_IO_DMA_INT_EN BIT(5) #define SIRFSOC_SPI_RXFIFO_FULL_INT_EN BIT(6) @@ -79,7 +79,7 @@ #define SIRFSOC_SPI_TXFIFO_THD_INT_EN BIT(9) #define SIRFSOC_SPI_FRM_END_INT_EN BIT(10) -#define SIRFSOC_SPI_INT_MASK_ALL 0x1FFF +#define SIRFSOC_SPI_INT_MASK_ALL 0x1FFF /* Interrupt status */ #define SIRFSOC_SPI_RX_DONE BIT(0) @@ -170,8 +170,7 @@ struct sirfsoc_spi { * command model */ bool tx_by_cmd; - - int chipselect[0]; + bool hw_cs; }; static void spi_sirfsoc_rx_word_u8(struct sirfsoc_spi *sspi) @@ -304,7 +303,7 @@ static void spi_sirfsoc_dma_fini_callback(void *data) complete(dma_complete); } -static int spi_sirfsoc_cmd_transfer(struct spi_device *spi, +static void spi_sirfsoc_cmd_transfer(struct spi_device *spi, struct spi_transfer *t) { struct sirfsoc_spi *sspi; @@ -328,10 +327,9 @@ static int spi_sirfsoc_cmd_transfer(struct spi_device *spi, sspi->base + SIRFSOC_SPI_TX_RX_EN); if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { dev_err(&spi->dev, "cmd transfer timeout\n"); - return 0; + return; } - - return t->len; + sspi->left_rx_word -= t->len; } static void spi_sirfsoc_dma_transfer(struct spi_device *spi, @@ -487,7 +485,7 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value) { struct sirfsoc_spi *sspi = spi_master_get_devdata(spi->master); - if (sspi->chipselect[spi->chip_select] == 0) { + if (sspi->hw_cs) { u32 regval = readl(sspi->base + SIRFSOC_SPI_CTRL); switch (value) { case BITBANG_CS_ACTIVE: @@ -505,14 +503,13 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value) } writel(regval, sspi->base + SIRFSOC_SPI_CTRL); } else { - int gpio = sspi->chipselect[spi->chip_select]; switch (value) { case BITBANG_CS_ACTIVE: - gpio_direction_output(gpio, + gpio_direction_output(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0); break; case BITBANG_CS_INACTIVE: - gpio_direction_output(gpio, + gpio_direction_output(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); break; } @@ -606,8 +603,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) sspi->tx_by_cmd = false; } /* - * set spi controller in RISC chipselect mode, we are controlling CS by - * software BITBANG_CS_ACTIVE and BITBANG_CS_INACTIVE. + * it should never set to hardware cs mode because in hardware cs mode, + * cs signal can't controlled by driver. */ regval |= SIRFSOC_SPI_CS_IO_MODE; writel(regval, sspi->base + SIRFSOC_SPI_CTRL); @@ -630,9 +627,17 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) static int spi_sirfsoc_setup(struct spi_device *spi) { + struct sirfsoc_spi *sspi; + if (!spi->max_speed_hz) return -EINVAL; + sspi = spi_master_get_devdata(spi->master); + + if (spi->cs_gpio == -ENOENT) + sspi->hw_cs = true; + else + sspi->hw_cs = false; return spi_sirfsoc_setup_transfer(spi, NULL); } @@ -641,19 +646,10 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) struct sirfsoc_spi *sspi; struct spi_master *master; struct resource *mem_res; - int num_cs, cs_gpio, irq; - int i; - int ret; - - ret = of_property_read_u32(pdev->dev.of_node, - "sirf,spi-num-chipselects", &num_cs); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to get chip select number\n"); - goto err_cs; - } + int irq; + int i, ret; - master = spi_alloc_master(&pdev->dev, - sizeof(*sspi) + sizeof(int) * num_cs); + master = spi_alloc_master(&pdev->dev, sizeof(*sspi)); if (!master) { dev_err(&pdev->dev, "Unable to allocate SPI master\n"); return -ENOMEM; @@ -661,32 +657,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); sspi = spi_master_get_devdata(master); - master->num_chipselect = num_cs; - - for (i = 0; i < master->num_chipselect; i++) { - cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i); - if (cs_gpio < 0) { - dev_err(&pdev->dev, "can't get cs gpio from DT\n"); - ret = -ENODEV; - goto free_master; - } - - sspi->chipselect[i] = cs_gpio; - if (cs_gpio == 0) - continue; /* use cs from spi controller */ - - ret = gpio_request(cs_gpio, DRIVER_NAME); - if (ret) { - while (i > 0) { - i--; - if (sspi->chipselect[i] > 0) - gpio_free(sspi->chipselect[i]); - } - dev_err(&pdev->dev, "fail to request cs gpios\n"); - goto free_master; - } - } - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sspi->base = devm_ioremap_resource(&pdev->dev, mem_res); if (IS_ERR(sspi->base)) { @@ -756,7 +726,21 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) ret = spi_bitbang_start(&sspi->bitbang); if (ret) goto free_dummypage; - + for (i = 0; master->cs_gpios && i < master->num_chipselect; i++) { + if (master->cs_gpios[i] == -ENOENT) + continue; + if (!gpio_is_valid(master->cs_gpios[i])) { + dev_err(&pdev->dev, "no valid gpio\n"); + ret = -EINVAL; + goto free_dummypage; + } + ret = devm_gpio_request(&pdev->dev, + master->cs_gpios[i], DRIVER_NAME); + if (ret) { + dev_err(&pdev->dev, "failed to request gpio\n"); + goto free_dummypage; + } + } dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num); return 0; @@ -771,7 +755,7 @@ free_rx_dma: dma_release_channel(sspi->rx_chan); free_master: spi_master_put(master); -err_cs: + return ret; } @@ -779,16 +763,11 @@ static int spi_sirfsoc_remove(struct platform_device *pdev) { struct spi_master *master; struct sirfsoc_spi *sspi; - int i; master = platform_get_drvdata(pdev); sspi = spi_master_get_devdata(master); spi_bitbang_stop(&sspi->bitbang); - for (i = 0; i < master->num_chipselect; i++) { - if (sspi->chipselect[i] > 0) - gpio_free(sspi->chipselect[i]); - } kfree(sspi->dummypage); clk_disable_unprepare(sspi->clk); clk_put(sspi->clk); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e4a85ada861..795bcbc0131 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -302,6 +302,7 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( max_n_32bit = DIV_ROUND_UP(nbytes, 4); for (count = 0; count < max_n_32bit; count++) { u32 x = 0; + for (i = 0; (i < 4) && nbytes; i++, nbytes--) x |= (u32)(*tx_buf++) << (i * 8); tegra_spi_writel(tspi, x, SPI_TX_FIFO); @@ -312,6 +313,7 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( nbytes = written_words * tspi->bytes_per_word; for (count = 0; count < max_n_32bit; count++) { u32 x = 0; + for (i = 0; nbytes && (i < tspi->bytes_per_word); i++, nbytes--) x |= (u32)(*tx_buf++) << (i * 8); @@ -338,6 +340,7 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( len = tspi->curr_dma_words * tspi->bytes_per_word; for (count = 0; count < rx_full_count; count++) { u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO); + for (i = 0; len && (i < 4); i++, len--) *rx_buf++ = (x >> i*8) & 0xFF; } @@ -345,8 +348,10 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( read_words += tspi->curr_dma_words; } else { u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; + for (count = 0; count < rx_full_count; count++) { u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask; + for (i = 0; (i < tspi->bytes_per_word); i++) *rx_buf++ = (x >> (i*8)) & 0xFF; } @@ -365,6 +370,7 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( if (tspi->is_packed) { unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; + memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len); } else { unsigned int i; @@ -374,6 +380,7 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( for (count = 0; count < tspi->curr_dma_words; count++) { u32 x = 0; + for (i = 0; consume && (i < tspi->bytes_per_word); i++, consume--) x |= (u32)(*tx_buf++) << (i * 8); @@ -396,6 +403,7 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf( if (tspi->is_packed) { unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; + memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len); } else { unsigned int i; @@ -405,6 +413,7 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf( for (count = 0; count < tspi->curr_dma_words; count++) { u32 x = tspi->rx_dma_buf[count] & rx_mask; + for (i = 0; (i < tspi->bytes_per_word); i++) *rx_buf++ = (x >> (i*8)) & 0xFF; } diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 3548ce25c08..cd66fe7b78a 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -99,7 +99,7 @@ #define SPI_TX_TRIG_MASK (0x3 << 16) #define SPI_TX_TRIG_1W (0x0 << 16) #define SPI_TX_TRIG_4W (0x1 << 16) -#define SPI_DMA_BLK_COUNT(count) (((count) - 1) & 0xFFFF); +#define SPI_DMA_BLK_COUNT(count) (((count) - 1) & 0xFFFF) #define SPI_TX_FIFO 0x10 #define SPI_RX_FIFO 0x20 @@ -221,6 +221,7 @@ static int tegra_sflash_read_rx_fifo_to_client_rxbuf( while (!(status & SPI_RXF_EMPTY)) { int i; u32 x = tegra_sflash_readl(tsd, SPI_RX_FIFO); + for (i = 0; (i < tsd->bytes_per_word); i++) *rx_buf++ = (x >> (i*8)) & 0xFF; read_words++; diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 5f183baa91a..2501a8373e8 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -97,6 +97,7 @@ static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c, int on, unsigned int cs_delay) { int val = (spi->mode & SPI_CS_HIGH) ? on : !on; + if (on) { /* deselect the chip with cs_change hint in last transfer */ if (c->last_chipselect >= 0) @@ -188,6 +189,7 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m) if (prev_speed_hz != speed_hz || prev_bits_per_word != bits_per_word) { int n = DIV_ROUND_UP(c->baseclk, speed_hz) - 1; + n = clamp(n, SPI_MIN_DIVIDER, SPI_MAX_DIVIDER); /* enter config mode */ txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 4d8efb16573..79bd84f4343 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -471,7 +471,6 @@ static struct platform_driver xilinx_spi_driver = { .remove = xilinx_spi_remove, .driver = { .name = XILINX_SPI_NAME, - .owner = THIS_MODULE, .of_match_table = xilinx_spi_of_match, }, }; diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c index 41e158187f9..0dc5df5233a 100644 --- a/drivers/spi/spi-xtensa-xtfpga.c +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -46,6 +46,7 @@ static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi, static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi) { unsigned i; + for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) && i < BUSY_WAIT_US; ++i) udelay(1); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ca935df80c8..e19512ffc40 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -552,6 +552,9 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) struct boardinfo *bi; int i; + if (!n) + return -EINVAL; + bi = kzalloc(n * sizeof(*bi), GFP_KERNEL); if (!bi) return -ENOMEM; @@ -789,27 +792,35 @@ static int spi_transfer_one_message(struct spi_master *master, list_for_each_entry(xfer, &msg->transfers, transfer_list) { trace_spi_transfer_start(msg, xfer); - reinit_completion(&master->xfer_completion); + if (xfer->tx_buf || xfer->rx_buf) { + reinit_completion(&master->xfer_completion); - ret = master->transfer_one(master, msg->spi, xfer); - if (ret < 0) { - dev_err(&msg->spi->dev, - "SPI transfer failed: %d\n", ret); - goto out; - } + ret = master->transfer_one(master, msg->spi, xfer); + if (ret < 0) { + dev_err(&msg->spi->dev, + "SPI transfer failed: %d\n", ret); + goto out; + } - if (ret > 0) { - ret = 0; - ms = xfer->len * 8 * 1000 / xfer->speed_hz; - ms += ms + 100; /* some tolerance */ + if (ret > 0) { + ret = 0; + ms = xfer->len * 8 * 1000 / xfer->speed_hz; + ms += ms + 100; /* some tolerance */ - ms = wait_for_completion_timeout(&master->xfer_completion, - msecs_to_jiffies(ms)); - } + ms = wait_for_completion_timeout(&master->xfer_completion, + msecs_to_jiffies(ms)); + } - if (ms == 0) { - dev_err(&msg->spi->dev, "SPI transfer timed out\n"); - msg->status = -ETIMEDOUT; + if (ms == 0) { + dev_err(&msg->spi->dev, + "SPI transfer timed out\n"); + msg->status = -ETIMEDOUT; + } + } else { + if (xfer->len) + dev_err(&msg->spi->dev, + "Bufferless transfer has length %u\n", + xfer->len); } trace_spi_transfer_stop(msg, xfer); diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 1d42dba6121..bd672948f2f 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -3587,7 +3587,7 @@ static void __used s8250_options(void) #ifdef CONFIG_SERIAL_8250_RSA __module_param_call(MODULE_PARAM_PREFIX, probe_rsa, ¶m_array_ops, .arr = &__param_arr_probe_rsa, - 0444, -1); + 0444, -1, 0); #endif } #else diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 3f42785f653..9bfa7252f7f 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -970,6 +970,13 @@ static struct scsi_host_template uas_host_template = { .cmd_per_lun = 1, /* until we override it */ .skip_settle_delay = 1, .ordered_tag = 1, + + /* + * The uas drivers expects tags not to be bigger than the maximum + * per-device queue depth, which is not true with the blk-mq tag + * allocator. + */ + .disable_blk_mq = true, }; #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c index d749731dc0e..fbb08e97438 100644 --- a/fs/cachefiles/bind.c +++ b/fs/cachefiles/bind.c @@ -50,18 +50,18 @@ int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args) cache->brun_percent < 100); if (*args) { - pr_err("'bind' command doesn't take an argument"); + pr_err("'bind' command doesn't take an argument\n"); return -EINVAL; } if (!cache->rootdirname) { - pr_err("No cache directory specified"); + pr_err("No cache directory specified\n"); return -EINVAL; } /* don't permit already bound caches to be re-bound */ if (test_bit(CACHEFILES_READY, &cache->flags)) { - pr_err("Cache already bound"); + pr_err("Cache already bound\n"); return -EBUSY; } @@ -248,7 +248,7 @@ error_open_root: kmem_cache_free(cachefiles_object_jar, fsdef); error_root_object: cachefiles_end_secure(cache, saved_cred); - pr_err("Failed to register: %d", ret); + pr_err("Failed to register: %d\n", ret); return ret; } diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c index b078d3081d6..ce1b115dcc2 100644 --- a/fs/cachefiles/daemon.c +++ b/fs/cachefiles/daemon.c @@ -315,7 +315,7 @@ static unsigned int cachefiles_daemon_poll(struct file *file, static int cachefiles_daemon_range_error(struct cachefiles_cache *cache, char *args) { - pr_err("Free space limits must be in range 0%%<=stop<cull<run<100%%"); + pr_err("Free space limits must be in range 0%%<=stop<cull<run<100%%\n"); return -EINVAL; } @@ -475,12 +475,12 @@ static int cachefiles_daemon_dir(struct cachefiles_cache *cache, char *args) _enter(",%s", args); if (!*args) { - pr_err("Empty directory specified"); + pr_err("Empty directory specified\n"); return -EINVAL; } if (cache->rootdirname) { - pr_err("Second cache directory specified"); + pr_err("Second cache directory specified\n"); return -EEXIST; } @@ -503,12 +503,12 @@ static int cachefiles_daemon_secctx(struct cachefiles_cache *cache, char *args) _enter(",%s", args); if (!*args) { - pr_err("Empty security context specified"); + pr_err("Empty security context specified\n"); return -EINVAL; } if (cache->secctx) { - pr_err("Second security context specified"); + pr_err("Second security context specified\n"); return -EINVAL; } @@ -531,7 +531,7 @@ static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args) _enter(",%s", args); if (!*args) { - pr_err("Empty tag specified"); + pr_err("Empty tag specified\n"); return -EINVAL; } @@ -562,12 +562,12 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) goto inval; if (!test_bit(CACHEFILES_READY, &cache->flags)) { - pr_err("cull applied to unready cache"); + pr_err("cull applied to unready cache\n"); return -EIO; } if (test_bit(CACHEFILES_DEAD, &cache->flags)) { - pr_err("cull applied to dead cache"); + pr_err("cull applied to dead cache\n"); return -EIO; } @@ -587,11 +587,11 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) notdir: path_put(&path); - pr_err("cull command requires dirfd to be a directory"); + pr_err("cull command requires dirfd to be a directory\n"); return -ENOTDIR; inval: - pr_err("cull command requires dirfd and filename"); + pr_err("cull command requires dirfd and filename\n"); return -EINVAL; } @@ -614,7 +614,7 @@ static int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args) return 0; inval: - pr_err("debug command requires mask"); + pr_err("debug command requires mask\n"); return -EINVAL; } @@ -634,12 +634,12 @@ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) goto inval; if (!test_bit(CACHEFILES_READY, &cache->flags)) { - pr_err("inuse applied to unready cache"); + pr_err("inuse applied to unready cache\n"); return -EIO; } if (test_bit(CACHEFILES_DEAD, &cache->flags)) { - pr_err("inuse applied to dead cache"); + pr_err("inuse applied to dead cache\n"); return -EIO; } @@ -659,11 +659,11 @@ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) notdir: path_put(&path); - pr_err("inuse command requires dirfd to be a directory"); + pr_err("inuse command requires dirfd to be a directory\n"); return -ENOTDIR; inval: - pr_err("inuse command requires dirfd and filename"); + pr_err("inuse command requires dirfd and filename\n"); return -EINVAL; } diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index 3d50998abf5..8c52472d2ef 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h @@ -255,7 +255,7 @@ extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache, #define cachefiles_io_error(___cache, FMT, ...) \ do { \ - pr_err("I/O Error: " FMT, ##__VA_ARGS__); \ + pr_err("I/O Error: " FMT"\n", ##__VA_ARGS__); \ fscache_io_error(&(___cache)->cache); \ set_bit(CACHEFILES_DEAD, &(___cache)->flags); \ } while (0) diff --git a/fs/cachefiles/main.c b/fs/cachefiles/main.c index 180edfb45f6..711f13d8c2d 100644 --- a/fs/cachefiles/main.c +++ b/fs/cachefiles/main.c @@ -84,7 +84,7 @@ error_proc: error_object_jar: misc_deregister(&cachefiles_dev); error_dev: - pr_err("failed to register: %d", ret); + pr_err("failed to register: %d\n", ret); return ret; } diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 83e9c94ca2c..dad7d9542a2 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -543,7 +543,7 @@ lookup_again: next, next->d_inode, next->d_inode->i_ino); } else if (!S_ISDIR(next->d_inode->i_mode)) { - pr_err("inode %lu is not a directory", + pr_err("inode %lu is not a directory\n", next->d_inode->i_ino); ret = -ENOBUFS; goto error; @@ -574,7 +574,7 @@ lookup_again: } else if (!S_ISDIR(next->d_inode->i_mode) && !S_ISREG(next->d_inode->i_mode) ) { - pr_err("inode %lu is not a file or directory", + pr_err("inode %lu is not a file or directory\n", next->d_inode->i_ino); ret = -ENOBUFS; goto error; @@ -768,7 +768,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, ASSERT(subdir->d_inode); if (!S_ISDIR(subdir->d_inode->i_mode)) { - pr_err("%s is not a directory", dirname); + pr_err("%s is not a directory\n", dirname); ret = -EIO; goto check_error; } @@ -796,13 +796,13 @@ check_error: mkdir_error: mutex_unlock(&dir->d_inode->i_mutex); dput(subdir); - pr_err("mkdir %s failed with error %d", dirname, ret); + pr_err("mkdir %s failed with error %d\n", dirname, ret); return ERR_PTR(ret); lookup_error: mutex_unlock(&dir->d_inode->i_mutex); ret = PTR_ERR(subdir); - pr_err("Lookup %s failed with error %d", dirname, ret); + pr_err("Lookup %s failed with error %d\n", dirname, ret); return ERR_PTR(ret); nomem_d_alloc: @@ -892,7 +892,7 @@ lookup_error: if (ret == -EIO) { cachefiles_io_error(cache, "Lookup failed"); } else if (ret != -ENOMEM) { - pr_err("Internal error: %d", ret); + pr_err("Internal error: %d\n", ret); ret = -EIO; } @@ -951,7 +951,7 @@ error: } if (ret != -ENOMEM) { - pr_err("Internal error: %d", ret); + pr_err("Internal error: %d\n", ret); ret = -EIO; } diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c index 1ad51ffbb27..acbc1f094fb 100644 --- a/fs/cachefiles/xattr.c +++ b/fs/cachefiles/xattr.c @@ -51,7 +51,7 @@ int cachefiles_check_object_type(struct cachefiles_object *object) } if (ret != -EEXIST) { - pr_err("Can't set xattr on %*.*s [%lu] (err %d)", + pr_err("Can't set xattr on %*.*s [%lu] (err %d)\n", dentry->d_name.len, dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino, -ret); @@ -64,7 +64,7 @@ int cachefiles_check_object_type(struct cachefiles_object *object) if (ret == -ERANGE) goto bad_type_length; - pr_err("Can't read xattr on %*.*s [%lu] (err %d)", + pr_err("Can't read xattr on %*.*s [%lu] (err %d)\n", dentry->d_name.len, dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino, -ret); @@ -85,14 +85,14 @@ error: return ret; bad_type_length: - pr_err("Cache object %lu type xattr length incorrect", + pr_err("Cache object %lu type xattr length incorrect\n", dentry->d_inode->i_ino); ret = -EIO; goto error; bad_type: xtype[2] = 0; - pr_err("Cache object %*.*s [%lu] type %s not %s", + pr_err("Cache object %*.*s [%lu] type %s not %s\n", dentry->d_name.len, dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino, xtype, type); @@ -293,7 +293,7 @@ error: return ret; bad_type_length: - pr_err("Cache object %lu xattr length incorrect", + pr_err("Cache object %lu xattr length incorrect\n", dentry->d_inode->i_ino); ret = -EIO; goto error; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 7c018a1c52f..5f29354b072 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -3568,15 +3568,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, lru_cache_add_file(page); unlock_page(page); page_cache_release(page); - if (rc == -EAGAIN) - list_add_tail(&page->lru, &tmplist); } + /* Fallback to the readpage in error/reconnect cases */ kref_put(&rdata->refcount, cifs_readdata_release); - if (rc == -EAGAIN) { - /* Re-add pages to the page_list and retry */ - list_splice(&tmplist, page_list); - continue; - } break; } diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 1a6df4b03f6..52131d8cb4d 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -586,7 +586,7 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, tmprc = CIFS_open(xid, &oparms, &oplock, NULL); if (tmprc == -EOPNOTSUPP) *symlink = true; - else + else if (tmprc == 0) CIFSSMBClose(xid, tcon, fid.netfid); } diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index af59d03db49..8257a5a97cc 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -256,6 +256,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = { {STATUS_DLL_MIGHT_BE_INCOMPATIBLE, -EIO, "STATUS_DLL_MIGHT_BE_INCOMPATIBLE"}, {STATUS_STOPPED_ON_SYMLINK, -EOPNOTSUPP, "STATUS_STOPPED_ON_SYMLINK"}, + {STATUS_IO_REPARSE_TAG_NOT_HANDLED, -EOPNOTSUPP, + "STATUS_REPARSE_NOT_HANDLED"}, {STATUS_DEVICE_REQUIRES_CLEANING, -EIO, "STATUS_DEVICE_REQUIRES_CLEANING"}, {STATUS_DEVICE_DOOR_OPEN, -EIO, "STATUS_DEVICE_DOOR_OPEN"}, diff --git a/fs/dcache.c b/fs/dcache.c index 7a5b51440af..cb25a1a5e30 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2372,7 +2372,8 @@ void dentry_update_name_case(struct dentry *dentry, struct qstr *name) } EXPORT_SYMBOL(dentry_update_name_case); -static void switch_names(struct dentry *dentry, struct dentry *target) +static void switch_names(struct dentry *dentry, struct dentry *target, + bool exchange) { if (dname_external(target)) { if (dname_external(dentry)) { @@ -2406,13 +2407,19 @@ static void switch_names(struct dentry *dentry, struct dentry *target) */ unsigned int i; BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long))); + if (!exchange) { + memcpy(dentry->d_iname, target->d_name.name, + target->d_name.len + 1); + dentry->d_name.hash_len = target->d_name.hash_len; + return; + } for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) { swap(((long *) &dentry->d_iname)[i], ((long *) &target->d_iname)[i]); } } } - swap(dentry->d_name.len, target->d_name.len); + swap(dentry->d_name.hash_len, target->d_name.hash_len); } static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) @@ -2442,25 +2449,29 @@ static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) } } -static void dentry_unlock_parents_for_move(struct dentry *dentry, - struct dentry *target) +static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target) { if (target->d_parent != dentry->d_parent) spin_unlock(&dentry->d_parent->d_lock); if (target->d_parent != target) spin_unlock(&target->d_parent->d_lock); + spin_unlock(&target->d_lock); + spin_unlock(&dentry->d_lock); } /* * When switching names, the actual string doesn't strictly have to * be preserved in the target - because we're dropping the target * anyway. As such, we can just do a simple memcpy() to copy over - * the new name before we switch. - * - * Note that we have to be a lot more careful about getting the hash - * switched - we have to switch the hash value properly even if it - * then no longer matches the actual (corrupted) string of the target. - * The hash value has to match the hash queue that the dentry is on.. + * the new name before we switch, unless we are going to rehash + * it. Note that if we *do* unhash the target, we are not allowed + * to rehash it without giving it a new name/hash key - whether + * we swap or overwrite the names here, resulting name won't match + * the reality in filesystem; it's only there for d_path() purposes. + * Note that all of this is happening under rename_lock, so the + * any hash lookup seeing it in the middle of manipulations will + * be discarded anyway. So we do not care what happens to the hash + * key in that case. */ /* * __d_move - move a dentry @@ -2506,36 +2517,30 @@ static void __d_move(struct dentry *dentry, struct dentry *target, d_hash(dentry->d_parent, dentry->d_name.hash)); } - list_del(&dentry->d_u.d_child); - list_del(&target->d_u.d_child); - /* Switch the names.. */ - switch_names(dentry, target); - swap(dentry->d_name.hash, target->d_name.hash); + switch_names(dentry, target, exchange); - /* ... and switch the parents */ + /* ... and switch them in the tree */ if (IS_ROOT(dentry)) { + /* splicing a tree */ dentry->d_parent = target->d_parent; target->d_parent = target; - INIT_LIST_HEAD(&target->d_u.d_child); + list_del_init(&target->d_u.d_child); + list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); } else { + /* swapping two dentries */ swap(dentry->d_parent, target->d_parent); - - /* And add them back to the (new) parent lists */ - list_add(&target->d_u.d_child, &target->d_parent->d_subdirs); + list_move(&target->d_u.d_child, &target->d_parent->d_subdirs); + list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); + if (exchange) + fsnotify_d_move(target); + fsnotify_d_move(dentry); } - list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); - write_seqcount_end(&target->d_seq); write_seqcount_end(&dentry->d_seq); - dentry_unlock_parents_for_move(dentry, target); - if (exchange) - fsnotify_d_move(target); - spin_unlock(&target->d_lock); - fsnotify_d_move(dentry); - spin_unlock(&dentry->d_lock); + dentry_unlock_for_move(dentry, target); } /* @@ -2633,45 +2638,6 @@ out_err: return ret; } -/* - * Prepare an anonymous dentry for life in the superblock's dentry tree as a - * named dentry in place of the dentry to be replaced. - * returns with anon->d_lock held! - */ -static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) -{ - struct dentry *dparent; - - dentry_lock_for_move(anon, dentry); - - write_seqcount_begin(&dentry->d_seq); - write_seqcount_begin_nested(&anon->d_seq, DENTRY_D_LOCK_NESTED); - - dparent = dentry->d_parent; - - switch_names(dentry, anon); - swap(dentry->d_name.hash, anon->d_name.hash); - - dentry->d_parent = dentry; - list_del_init(&dentry->d_u.d_child); - anon->d_parent = dparent; - if (likely(!d_unhashed(anon))) { - hlist_bl_lock(&anon->d_sb->s_anon); - __hlist_bl_del(&anon->d_hash); - anon->d_hash.pprev = NULL; - hlist_bl_unlock(&anon->d_sb->s_anon); - } - list_move(&anon->d_u.d_child, &dparent->d_subdirs); - - write_seqcount_end(&dentry->d_seq); - write_seqcount_end(&anon->d_seq); - - dentry_unlock_parents_for_move(anon, dentry); - spin_unlock(&dentry->d_lock); - - /* anon->d_lock still locked, returns locked */ -} - /** * d_splice_alias - splice a disconnected dentry into the tree if one exists * @inode: the inode which may have a disconnected dentry @@ -2717,10 +2683,8 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) return ERR_PTR(-EIO); } write_seqlock(&rename_lock); - __d_materialise_dentry(dentry, new); + __d_move(new, dentry, false); write_sequnlock(&rename_lock); - _d_rehash(new); - spin_unlock(&new->d_lock); spin_unlock(&inode->i_lock); security_d_instantiate(new, inode); iput(inode); @@ -2780,7 +2744,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) } else if (IS_ROOT(alias)) { /* Is this an anonymous mountpoint that we * could splice into our tree? */ - __d_materialise_dentry(dentry, alias); + __d_move(alias, dentry, false); write_sequnlock(&rename_lock); goto found; } else { @@ -2807,13 +2771,9 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) actual = __d_instantiate_unique(dentry, inode); if (!actual) actual = dentry; - else - BUG_ON(!d_unhashed(actual)); - spin_lock(&actual->d_lock); + d_rehash(actual); found: - _d_rehash(actual); - spin_unlock(&actual->d_lock); spin_unlock(&inode->i_lock); out_nolock: if (actual == dentry) { diff --git a/fs/direct-io.c b/fs/direct-io.c index c3116404ab4..e181b6b2e29 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -158,7 +158,7 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio) { ssize_t ret; - ret = iov_iter_get_pages(sdio->iter, dio->pages, DIO_PAGES, + ret = iov_iter_get_pages(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES, &sdio->from); if (ret < 0 && sdio->blocks_available && (dio->rw & WRITE)) { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 912061ac4ba..caa8d95b24e 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1305,6 +1305,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, size_t start; ssize_t ret = iov_iter_get_pages(ii, &req->pages[req->num_pages], + *nbytesp - nbytes, req->max_pages - req->num_pages, &start); if (ret < 0) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index e94457c33ad..b01f6e100ee 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3104,7 +3104,8 @@ static __be32 nfsd4_encode_splice_read( buf->page_len = maxcount; buf->len += maxcount; - xdr->page_ptr += (maxcount + PAGE_SIZE - 1) / PAGE_SIZE; + xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1) + / PAGE_SIZE; /* Use rest of head for padding and remaining ops: */ buf->tail[0].iov_base = xdr->p; diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 6252b173a46..d071e7f23de 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -24,6 +24,7 @@ #include <linux/buffer_head.h> #include <linux/gfp.h> #include <linux/mpage.h> +#include <linux/pagemap.h> #include <linux/writeback.h> #include <linux/aio.h> #include "nilfs.h" @@ -219,10 +220,10 @@ static int nilfs_writepage(struct page *page, struct writeback_control *wbc) static int nilfs_set_page_dirty(struct page *page) { + struct inode *inode = page->mapping->host; int ret = __set_page_dirty_nobuffers(page); if (page_has_buffers(page)) { - struct inode *inode = page->mapping->host; unsigned nr_dirty = 0; struct buffer_head *bh, *head; @@ -245,6 +246,10 @@ static int nilfs_set_page_dirty(struct page *page) if (nr_dirty) nilfs_set_file_dirty(inode, nr_dirty); + } else if (ret) { + unsigned nr_dirty = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits); + + nilfs_set_file_dirty(inode, nr_dirty); } return ret; } diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 3ec906ef5d9..12ba682fc53 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -655,12 +655,9 @@ void dlm_lockres_clear_refmap_bit(struct dlm_ctxt *dlm, clear_bit(bit, res->refmap); } - -void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, +static void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) { - assert_spin_locked(&res->spinlock); - res->inflight_locks++; mlog(0, "%s: res %.*s, inflight++: now %u, %ps()\n", dlm->name, @@ -668,6 +665,13 @@ void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, __builtin_return_address(0)); } +void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res) +{ + assert_spin_locked(&res->spinlock); + __dlm_lockres_grab_inflight_ref(dlm, res); +} + void dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) { @@ -894,10 +898,8 @@ lookup: /* finally add the lockres to its hash bucket */ __dlm_insert_lockres(dlm, res); - /* Grab inflight ref to pin the resource */ - spin_lock(&res->spinlock); - dlm_lockres_grab_inflight_ref(dlm, res); - spin_unlock(&res->spinlock); + /* since this lockres is new it doesn't not require the spinlock */ + __dlm_lockres_grab_inflight_ref(dlm, res); /* get an extra ref on the mle in case this is a BLOCK * if so, the creator of the BLOCK may try to put the last @@ -2037,6 +2039,10 @@ kill: "and killing the other node now! This node is OK and can continue.\n"); __dlm_print_one_lock_resource(res); spin_unlock(&res->spinlock); + spin_lock(&dlm->master_lock); + if (mle) + __dlm_put_mle(mle); + spin_unlock(&dlm->master_lock); spin_unlock(&dlm->spinlock); *ret_data = (void *)res; dlm_put(dlm); diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index ddb662b3244..4142546aeda 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -2532,6 +2532,7 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb) kfree(osb->journal); kfree(osb->local_alloc_copy); kfree(osb->uuid_str); + kfree(osb->vol_label); ocfs2_put_dlm_debug(osb->osb_dlm_debug); memset(osb, 0, sizeof(struct ocfs2_super)); } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index dfc791c42d6..c34156888d7 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -931,23 +931,32 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, while (addr < end) { struct vm_area_struct *vma = find_vma(walk->mm, addr); pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); - unsigned long vm_end; + /* End of address space hole, which we mark as non-present. */ + unsigned long hole_end; - if (!vma) { - vm_end = end; - } else { - vm_end = min(end, vma->vm_end); - if (vma->vm_flags & VM_SOFTDIRTY) - pme.pme |= PM_STATUS2(pm->v2, __PM_SOFT_DIRTY); + if (vma) + hole_end = min(end, vma->vm_start); + else + hole_end = end; + + for (; addr < hole_end; addr += PAGE_SIZE) { + err = add_to_pagemap(addr, &pme, pm); + if (err) + goto out; } - for (; addr < vm_end; addr += PAGE_SIZE) { + if (!vma) + break; + + /* Addresses in the VMA. */ + if (vma->vm_flags & VM_SOFTDIRTY) + pme.pme |= PM_STATUS2(pm->v2, __PM_SOFT_DIRTY); + for (; addr < min(end, vma->vm_end); addr += PAGE_SIZE) { err = add_to_pagemap(addr, &pme, pm); if (err) goto out; } } - out: return err; } diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index a9cc75ffa92..7caa0165288 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -298,7 +298,10 @@ cg_found: ufsi->i_oeftflag = 0; ufsi->i_dir_start_lookup = 0; memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1)); - insert_inode_hash(inode); + if (insert_inode_locked(inode) < 0) { + err = -EIO; + goto failed; + } mark_inode_dirty(inode); if (uspi->fs_magic == UFS2_MAGIC) { @@ -337,6 +340,7 @@ cg_found: fail_remove_inode: unlock_ufs(sb); clear_nlink(inode); + unlock_new_inode(inode); iput(inode); UFSD("EXIT (FAILED): err %d\n", err); return ERR_PTR(err); diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 2df62a73f20..fd65deb4b5f 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -38,10 +38,12 @@ static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode) { int err = ufs_add_link(dentry, inode); if (!err) { + unlock_new_inode(inode); d_instantiate(dentry, inode); return 0; } inode_dec_link_count(inode); + unlock_new_inode(inode); iput(inode); return err; } @@ -155,6 +157,7 @@ out_notlocked: out_fail: inode_dec_link_count(inode); + unlock_new_inode(inode); iput(inode); goto out; } @@ -210,6 +213,7 @@ out: out_fail: inode_dec_link_count(inode); inode_dec_link_count(inode); + unlock_new_inode(inode); iput (inode); inode_dec_link_count(dir); unlock_ufs(dir->i_sb); diff --git a/include/dt-bindings/pinctrl/at91.h b/include/dt-bindings/pinctrl/at91.h index 0fee6ff77ff..bbca3d03890 100644 --- a/include/dt-bindings/pinctrl/at91.h +++ b/include/dt-bindings/pinctrl/at91.h @@ -20,6 +20,11 @@ #define AT91_PINCTRL_PULL_UP_DEGLITCH (AT91_PINCTRL_PULL_UP | AT91_PINCTRL_DEGLITCH) +#define AT91_PINCTRL_DRIVE_STRENGTH_DEFAULT (0x0 << 5) +#define AT91_PINCTRL_DRIVE_STRENGTH_LOW (0x1 << 5) +#define AT91_PINCTRL_DRIVE_STRENGTH_MED (0x2 << 5) +#define AT91_PINCTRL_DRIVE_STRENGTH_HI (0x3 << 5) + #define AT91_PIOA 0 #define AT91_PIOB 1 #define AT91_PIOC 2 diff --git a/include/dt-bindings/pinctrl/rockchip.h b/include/dt-bindings/pinctrl/rockchip.h index cd5788be82c..743e66a95e1 100644 --- a/include/dt-bindings/pinctrl/rockchip.h +++ b/include/dt-bindings/pinctrl/rockchip.h @@ -28,5 +28,7 @@ #define RK_FUNC_GPIO 0 #define RK_FUNC_1 1 #define RK_FUNC_2 2 +#define RK_FUNC_3 3 +#define RK_FUNC_4 4 #endif diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h index fdd7e1b61f6..c324f5700d1 100644 --- a/include/linux/amba/bus.h +++ b/include/linux/amba/bus.h @@ -44,10 +44,15 @@ struct amba_driver { const struct amba_id *id_table; }; +/* + * Constants for the designer field of the Peripheral ID register. When bit 7 + * is set to '1', bits [6:0] should be the JEP106 manufacturer identity code. + */ enum amba_vendor { AMBA_VENDOR_ARM = 0x41, AMBA_VENDOR_ST = 0x80, AMBA_VENDOR_QCOM = 0x51, + AMBA_VENDOR_LSI = 0xb6, }; extern struct bus_type amba_bustype; diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index ade2390ffe9..6e39c9bb0da 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -93,12 +93,12 @@ extern int cpuset_slab_spread_node(void); static inline int cpuset_do_page_mem_spread(void) { - return current->flags & PF_SPREAD_PAGE; + return task_spread_page(current); } static inline int cpuset_do_slab_mem_spread(void) { - return current->flags & PF_SPREAD_SLAB; + return task_spread_slab(current); } extern int current_cpuset_is_being_rebound(void); diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 1f9e642c66a..212c5b9ac10 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -900,18 +900,6 @@ static inline void dmaengine_put(void) } #endif -#ifdef CONFIG_NET_DMA -#define net_dmaengine_get() dmaengine_get() -#define net_dmaengine_put() dmaengine_put() -#else -static inline void net_dmaengine_get(void) -{ -} -static inline void net_dmaengine_put(void) -{ -} -#endif - #ifdef CONFIG_ASYNC_TX_DMA #define async_dmaengine_get() dmaengine_get() #define async_dmaengine_put() dmaengine_put() @@ -933,16 +921,8 @@ async_dma_find_channel(enum dma_transaction_type type) return NULL; } #endif /* CONFIG_ASYNC_TX_DMA */ - -dma_cookie_t dma_async_memcpy_buf_to_buf(struct dma_chan *chan, - void *dest, void *src, size_t len); -dma_cookie_t dma_async_memcpy_buf_to_pg(struct dma_chan *chan, - struct page *page, unsigned int offset, void *kdata, size_t len); -dma_cookie_t dma_async_memcpy_pg_to_pg(struct dma_chan *chan, - struct page *dest_pg, unsigned int dest_off, struct page *src_pg, - unsigned int src_off, size_t len); void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, - struct dma_chan *chan); + struct dma_chan *chan); static inline void async_tx_ack(struct dma_async_tx_descriptor *tx) { diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index b5f73de81aa..1825edacbda 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -14,6 +14,27 @@ #ifndef __LINUX_MFD_SEC_CORE_H #define __LINUX_MFD_SEC_CORE_H +/* Macros to represent minimum voltages for LDO/BUCK */ +#define MIN_3000_MV 3000000 +#define MIN_2500_MV 2500000 +#define MIN_2000_MV 2000000 +#define MIN_1800_MV 1800000 +#define MIN_1500_MV 1500000 +#define MIN_1400_MV 1400000 +#define MIN_1000_MV 1000000 + +#define MIN_900_MV 900000 +#define MIN_850_MV 850000 +#define MIN_800_MV 800000 +#define MIN_750_MV 750000 +#define MIN_600_MV 600000 + +/* Macros to represent steps for LDO/BUCK */ +#define STEP_50_MV 50000 +#define STEP_25_MV 25000 +#define STEP_12_5_MV 12500 +#define STEP_6_25_MV 6250 + enum sec_device_type { S5M8751X, S5M8763X, diff --git a/include/linux/mfd/samsung/s2mpa01.h b/include/linux/mfd/samsung/s2mpa01.h index fbc63bc0d6a..2766108bca2 100644 --- a/include/linux/mfd/samsung/s2mpa01.h +++ b/include/linux/mfd/samsung/s2mpa01.h @@ -155,18 +155,6 @@ enum s2mpa01_regulators { S2MPA01_REGULATOR_MAX, }; -#define S2MPA01_BUCK_MIN1 600000 -#define S2MPA01_BUCK_MIN2 800000 -#define S2MPA01_BUCK_MIN3 1000000 -#define S2MPA01_BUCK_MIN4 1500000 -#define S2MPA01_LDO_MIN 800000 - -#define S2MPA01_BUCK_STEP1 6250 -#define S2MPA01_BUCK_STEP2 12500 - -#define S2MPA01_LDO_STEP1 50000 -#define S2MPA01_LDO_STEP2 25000 - #define S2MPA01_LDO_VSEL_MASK 0x3F #define S2MPA01_BUCK_VSEL_MASK 0xFF #define S2MPA01_ENABLE_MASK (0x03 << S2MPA01_ENABLE_SHIFT) diff --git a/include/linux/mfd/samsung/s2mps11.h b/include/linux/mfd/samsung/s2mps11.h index b3ddf98dec3..7981a9d77d3 100644 --- a/include/linux/mfd/samsung/s2mps11.h +++ b/include/linux/mfd/samsung/s2mps11.h @@ -171,15 +171,6 @@ enum s2mps11_regulators { S2MPS11_REGULATOR_MAX, }; -#define S2MPS11_BUCK_MIN1 600000 -#define S2MPS11_BUCK_MIN2 750000 -#define S2MPS11_BUCK_MIN3 3000000 -#define S2MPS11_LDO_MIN 800000 -#define S2MPS11_BUCK_STEP1 6250 -#define S2MPS11_BUCK_STEP2 12500 -#define S2MPS11_BUCK_STEP3 25000 -#define S2MPS11_LDO_STEP1 50000 -#define S2MPS11_LDO_STEP2 25000 #define S2MPS11_LDO_VSEL_MASK 0x3F #define S2MPS11_BUCK_VSEL_MASK 0xFF #define S2MPS11_ENABLE_MASK (0x03 << S2MPS11_ENABLE_SHIFT) diff --git a/include/linux/mfd/samsung/s2mps14.h b/include/linux/mfd/samsung/s2mps14.h index 900cd7a0431..c92f4782afb 100644 --- a/include/linux/mfd/samsung/s2mps14.h +++ b/include/linux/mfd/samsung/s2mps14.h @@ -123,10 +123,6 @@ enum s2mps14_regulators { }; /* Regulator constraints for BUCKx */ -#define S2MPS14_BUCK1235_MIN_600MV 600000 -#define S2MPS14_BUCK4_MIN_1400MV 1400000 -#define S2MPS14_BUCK1235_STEP_6_25MV 6250 -#define S2MPS14_BUCK4_STEP_12_5MV 12500 #define S2MPS14_BUCK1235_START_SEL 0x20 #define S2MPS14_BUCK4_START_SEL 0x40 /* @@ -136,12 +132,6 @@ enum s2mps14_regulators { */ #define S2MPS14_BUCK_RAMP_DELAY 12500 -/* Regulator constraints for different types of LDOx */ -#define S2MPS14_LDO_MIN_800MV 800000 -#define S2MPS14_LDO_MIN_1800MV 1800000 -#define S2MPS14_LDO_STEP_12_5MV 12500 -#define S2MPS14_LDO_STEP_25MV 25000 - #define S2MPS14_LDO_VSEL_MASK 0x3F #define S2MPS14_BUCK_VSEL_MASK 0xFF #define S2MPS14_ENABLE_MASK (0x03 << S2MPS14_ENABLE_SHIFT) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 494f99e852d..b43f4752304 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -42,7 +42,7 @@ struct kernel_param; * NOARG - the parameter allows for no argument (foo instead of foo=1) */ enum { - KERNEL_PARAM_FL_NOARG = (1 << 0) + KERNEL_PARAM_OPS_FL_NOARG = (1 << 0) }; struct kernel_param_ops { @@ -56,11 +56,21 @@ struct kernel_param_ops { void (*free)(void *arg); }; +/* + * Flags available for kernel_param + * + * UNSAFE - the parameter is dangerous and setting it will taint the kernel + */ +enum { + KERNEL_PARAM_FL_UNSAFE = (1 << 0) +}; + struct kernel_param { const char *name; const struct kernel_param_ops *ops; u16 perm; - s16 level; + s8 level; + u8 flags; union { void *arg; const struct kparam_string *str; @@ -113,6 +123,12 @@ struct kparam_array module_param_named(name, name, type, perm) /** + * module_param_unsafe - same as module_param but taints kernel + */ +#define module_param_unsafe(name, type, perm) \ + module_param_named_unsafe(name, name, type, perm) + +/** * module_param_named - typesafe helper for a renamed module/cmdline parameter * @name: a valid C identifier which is the parameter name. * @value: the actual lvalue to alter. @@ -129,6 +145,14 @@ struct kparam_array __MODULE_PARM_TYPE(name, #type) /** + * module_param_named_unsafe - same as module_param_named but taints kernel + */ +#define module_param_named_unsafe(name, value, type, perm) \ + param_check_##type(name, &(value)); \ + module_param_cb_unsafe(name, ¶m_ops_##type, &value, perm); \ + __MODULE_PARM_TYPE(name, #type) + +/** * module_param_cb - general callback for a module/cmdline parameter * @name: a valid C identifier which is the parameter name. * @ops: the set & get operations for this parameter. @@ -137,7 +161,11 @@ struct kparam_array * The ops can have NULL set or get functions. */ #define module_param_cb(name, ops, arg, perm) \ - __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1) + __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0) + +#define module_param_cb_unsafe(name, ops, arg, perm) \ + __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, \ + KERNEL_PARAM_FL_UNSAFE) /** * <level>_param_cb - general callback for a module/cmdline parameter @@ -149,7 +177,7 @@ struct kparam_array * The ops can have NULL set or get functions. */ #define __level_param_cb(name, ops, arg, perm, level) \ - __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, level) + __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, level, 0) #define core_param_cb(name, ops, arg, perm) \ __level_param_cb(name, ops, arg, perm, 1) @@ -184,22 +212,22 @@ struct kparam_array /* This is the fundamental function for registering boot/module parameters. */ -#define __module_param_call(prefix, name, ops, arg, perm, level) \ +#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \ /* Default value instead of permissions? */ \ static const char __param_str_##name[] = prefix #name; \ static struct kernel_param __moduleparam_const __param_##name \ __used \ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ = { __param_str_##name, ops, VERIFY_OCTAL_PERMISSIONS(perm), \ - level, { arg } } + level, flags, { arg } } /* Obsolete - use module_param_cb() */ #define module_param_call(name, set, get, arg, perm) \ static struct kernel_param_ops __param_ops_##name = \ - { 0, (void *)set, (void *)get }; \ + { .flags = 0, (void *)set, (void *)get }; \ __module_param_call(MODULE_PARAM_PREFIX, \ name, &__param_ops_##name, arg, \ - (perm) + sizeof(__check_old_set_param(set))*0, -1) + (perm) + sizeof(__check_old_set_param(set))*0, -1, 0) /* We don't get oldget: it's often a new-style param_get_uint, etc. */ static inline int @@ -279,7 +307,7 @@ static inline void __kernel_param_unlock(void) */ #define core_param(name, var, type, perm) \ param_check_##type(name, &(var)); \ - __module_param_call("", name, ¶m_ops_##type, &var, perm, -1) + __module_param_call("", name, ¶m_ops_##type, &var, perm, -1, 0) #endif /* !MODULE */ /** @@ -297,7 +325,7 @@ static inline void __kernel_param_unlock(void) = { len, string }; \ __module_param_call(MODULE_PARAM_PREFIX, name, \ ¶m_ops_string, \ - .str = &__param_string_##name, perm, -1); \ + .str = &__param_string_##name, perm, -1, 0);\ __MODULE_PARM_TYPE(name, "string") /** @@ -444,7 +472,7 @@ extern int param_set_bint(const char *val, const struct kernel_param *kp); __module_param_call(MODULE_PARAM_PREFIX, name, \ ¶m_array_ops, \ .arr = &__param_arr_##name, \ - perm, -1); \ + perm, -1, 0); \ __MODULE_PARM_TYPE(name, "array of " #type) extern struct kernel_param_ops param_array_ops; diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index a15f10727eb..d578a60eff2 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -57,7 +57,7 @@ * which are then pulled up with an external resistor. Setting this * config will enable open drain mode, the argument is ignored. * @PIN_CONFIG_DRIVE_OPEN_SOURCE: the pin will be driven with open source - * (open emitter). Setting this config will enable open drain mode, the + * (open emitter). Setting this config will enable open source mode, the * argument is ignored. * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current * passed as argument. The argument is in mA. diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h index 3097aafbeb2..511bda9ed4b 100644 --- a/include/linux/pinctrl/pinmux.h +++ b/include/linux/pinctrl/pinmux.h @@ -39,13 +39,12 @@ struct pinctrl_dev; * name can be used with the generic @pinctrl_ops to retrieve the * actual pins affected. The applicable groups will be returned in * @groups and the number of groups in @num_groups - * @enable: enable a certain muxing function with a certain pin group. The + * @set_mux: enable a certain muxing function with a certain pin group. The * driver does not need to figure out whether enabling this function * conflicts some other use of the pins in that group, such collisions * are handled by the pinmux subsystem. The @func_selector selects a * certain function whereas @group_selector selects a certain set of pins * to be used. On simple controllers the latter argument may be ignored - * @disable: disable a certain muxing selector with a certain pin group * @gpio_request_enable: requests and enables GPIO on a certain pin. * Implement this only if you can mux every pin individually as GPIO. The * affected GPIO range is passed along with an offset(pin number) into that @@ -68,8 +67,8 @@ struct pinmux_ops { unsigned selector, const char * const **groups, unsigned * const num_groups); - int (*enable) (struct pinctrl_dev *pctldev, unsigned func_selector, - unsigned group_selector); + int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector, + unsigned group_selector); int (*gpio_request_enable) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset); diff --git a/include/linux/platform_data/isl9305.h b/include/linux/platform_data/isl9305.h new file mode 100644 index 00000000000..1419133fa69 --- /dev/null +++ b/include/linux/platform_data/isl9305.h @@ -0,0 +1,30 @@ +/* + * isl9305 - Intersil ISL9305 DCDC regulator + * + * Copyright 2014 Linaro Ltd + * + * Author: Mark Brown <broonie@kernel.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ISL9305_H +#define __ISL9305_H + +#define ISL9305_DCD1 0 +#define ISL9305_DCD2 1 +#define ISL9305_LDO1 2 +#define ISL9305_LDO2 3 + +#define ISL9305_MAX_REGULATOR ISL9305_LDO2 + +struct regulator_init_data; + +struct isl9305_pdata { + struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR]; +}; + +#endif diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index f8a8733068a..d347c805f92 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -93,7 +93,12 @@ struct regmap; * OVER_TEMP Regulator over temp. * FORCE_DISABLE Regulator forcibly shut down by software. * VOLTAGE_CHANGE Regulator voltage changed. + * Data passed is old voltage cast to (void *). * DISABLE Regulator was disabled. + * PRE_VOLTAGE_CHANGE Regulator is about to have voltage changed. + * Data passed is "struct pre_voltage_change_data" + * ABORT_VOLTAGE_CHANGE Regulator voltage change failed for some reason. + * Data passed is old voltage cast to (void *). * * NOTE: These events can be OR'ed together when passed into handler. */ @@ -106,6 +111,21 @@ struct regmap; #define REGULATOR_EVENT_FORCE_DISABLE 0x20 #define REGULATOR_EVENT_VOLTAGE_CHANGE 0x40 #define REGULATOR_EVENT_DISABLE 0x80 +#define REGULATOR_EVENT_PRE_VOLTAGE_CHANGE 0x100 +#define REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE 0x200 + +/** + * struct pre_voltage_change_data - Data sent with PRE_VOLTAGE_CHANGE event + * + * @old_uV: Current voltage before change. + * @min_uV: Min voltage we'll change to. + * @max_uV: Max voltage we'll change to. + */ +struct pre_voltage_change_data { + unsigned long old_uV; + unsigned long min_uV; + unsigned long max_uV; +}; struct regulator; diff --git a/include/linux/regulator/da9211.h b/include/linux/regulator/da9211.h index 0981ce0e72c..5479394fefc 100644 --- a/include/linux/regulator/da9211.h +++ b/include/linux/regulator/da9211.h @@ -1,5 +1,5 @@ /* - * da9211.h - Regulator device driver for DA9211 + * da9211.h - Regulator device driver for DA9211/DA9213 * Copyright (C) 2014 Dialog Semiconductor Ltd. * * This library is free software; you can redistribute it and/or @@ -20,6 +20,11 @@ #define DA9211_MAX_REGULATORS 2 +enum da9211_chip_id { + DA9211, + DA9213, +}; + struct da9211_pdata { /* * Number of buck @@ -27,6 +32,6 @@ struct da9211_pdata { * 2 : 2 phase 2 buck */ int num_buck; - struct regulator_init_data *init_data; + struct regulator_init_data *init_data[DA9211_MAX_REGULATORS]; }; #endif diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4efa1ed8a2b..fc0ee0ce832 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -203,6 +203,8 @@ enum regulator_type { * * @name: Identifying name for the regulator. * @supply_name: Identifying the regulator supply + * @of_match: Name used to identify regulator in DT. + * @regulators_node: Name of node containing regulator definitions in DT. * @id: Numerical identifier for the regulator. * @ops: Regulator operations table. * @irq: Interrupt number for the regulator. @@ -240,14 +242,17 @@ enum regulator_type { * @bypass_val_off: Disabling value for control when using regmap set_bypass * * @enable_time: Time taken for initial enable of regulator (in uS). + * @off_on_delay: guard time (in uS), before re-enabling a regulator */ struct regulator_desc { const char *name; const char *supply_name; + const char *of_match; + const char *regulators_node; int id; bool continuous_voltage_range; unsigned n_voltages; - struct regulator_ops *ops; + const struct regulator_ops *ops; int irq; enum regulator_type type; struct module *owner; @@ -278,6 +283,8 @@ struct regulator_desc { unsigned int bypass_val_off; unsigned int enable_time; + + unsigned int off_on_delay; }; /** @@ -350,6 +357,9 @@ struct regulator_dev { struct regulator_enable_gpio *ena_pin; unsigned int ena_gpio_state:1; + + /* time when this regulator was disabled last time */ + unsigned long last_off_jiffy; }; struct regulator_dev * diff --git a/include/linux/regulator/max1586.h b/include/linux/regulator/max1586.h index de9a7fae20b..cedd0febe88 100644 --- a/include/linux/regulator/max1586.h +++ b/include/linux/regulator/max1586.h @@ -40,7 +40,7 @@ */ struct max1586_subdev_data { int id; - char *name; + const char *name; struct regulator_init_data *platform_data; }; diff --git a/include/linux/sched.h b/include/linux/sched.h index 5c2c885ee52..b867a4dab38 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1903,8 +1903,6 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, #define PF_KTHREAD 0x00200000 /* I am a kernel thread */ #define PF_RANDOMIZE 0x00400000 /* randomize virtual address space */ #define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */ -#define PF_SPREAD_PAGE 0x01000000 /* Spread page cache over cpuset */ -#define PF_SPREAD_SLAB 0x02000000 /* Spread some slab caches over cpuset */ #define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */ #define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */ #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ @@ -1957,17 +1955,31 @@ static inline void memalloc_noio_restore(unsigned int flags) } /* Per-process atomic flags. */ -#define PFA_NO_NEW_PRIVS 0x00000001 /* May not gain new privileges. */ +#define PFA_NO_NEW_PRIVS 0 /* May not gain new privileges. */ +#define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */ +#define PFA_SPREAD_SLAB 2 /* Spread some slab caches over cpuset */ -static inline bool task_no_new_privs(struct task_struct *p) -{ - return test_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags); -} -static inline void task_set_no_new_privs(struct task_struct *p) -{ - set_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags); -} +#define TASK_PFA_TEST(name, func) \ + static inline bool task_##func(struct task_struct *p) \ + { return test_bit(PFA_##name, &p->atomic_flags); } +#define TASK_PFA_SET(name, func) \ + static inline void task_set_##func(struct task_struct *p) \ + { set_bit(PFA_##name, &p->atomic_flags); } +#define TASK_PFA_CLEAR(name, func) \ + static inline void task_clear_##func(struct task_struct *p) \ + { clear_bit(PFA_##name, &p->atomic_flags); } + +TASK_PFA_TEST(NO_NEW_PRIVS, no_new_privs) +TASK_PFA_SET(NO_NEW_PRIVS, no_new_privs) + +TASK_PFA_TEST(SPREAD_PAGE, spread_page) +TASK_PFA_SET(SPREAD_PAGE, spread_page) +TASK_PFA_CLEAR(SPREAD_PAGE, spread_page) + +TASK_PFA_TEST(SPREAD_SLAB, spread_slab) +TASK_PFA_SET(SPREAD_SLAB, spread_slab) +TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab) /* * task->jobctl flags @@ -2608,9 +2620,22 @@ static inline void setup_thread_stack(struct task_struct *p, struct task_struct task_thread_info(p)->task = p; } +/* + * Return the address of the last usable long on the stack. + * + * When the stack grows down, this is just above the thread + * info struct. Going any lower will corrupt the threadinfo. + * + * When the stack grows up, this is the highest address. + * Beyond that position, we corrupt data on the next page. + */ static inline unsigned long *end_of_stack(struct task_struct *p) { +#ifdef CONFIG_STACK_GROWSUP + return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1; +#else return (unsigned long *)(task_thread_info(p) + 1); +#endif } #endif diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index abde271c18a..a17ba0881af 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -28,7 +28,6 @@ #include <linux/textsearch.h> #include <net/checksum.h> #include <linux/rcupdate.h> -#include <linux/dmaengine.h> #include <linux/hrtimer.h> #include <linux/dma-mapping.h> #include <linux/netdev_features.h> @@ -581,11 +580,8 @@ struct sk_buff { /* 2/4 bit hole (depending on ndisc_nodetype presence) */ kmemcheck_bitfield_end(flags2); -#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL - union { - unsigned int napi_id; - dma_cookie_t dma_cookie; - }; +#ifdef CONFIG_NET_RX_BUSY_POLL + unsigned int napi_id; #endif #ifdef CONFIG_NETWORK_SECMARK __u32 secmark; diff --git a/include/linux/tcp.h b/include/linux/tcp.h index fa5258f322e..ac82c5ea955 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -19,7 +19,6 @@ #include <linux/skbuff.h> -#include <linux/dmaengine.h> #include <net/sock.h> #include <net/inet_connection_sock.h> #include <net/inet_timewait_sock.h> @@ -166,13 +165,6 @@ struct tcp_sock { struct iovec *iov; int memory; int len; -#ifdef CONFIG_NET_DMA - /* members for async copy */ - struct dma_chan *dma_chan; - int wakeup; - struct dma_pinned_list *pinned_list; - dma_cookie_t dma_cookie; -#endif } ucopy; u32 snd_wl1; /* Sequence for window update */ diff --git a/include/linux/uio.h b/include/linux/uio.h index 48d64e6ab29..290fbf0b6b8 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -84,7 +84,7 @@ unsigned long iov_iter_alignment(const struct iov_iter *i); void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, unsigned long nr_segs, size_t count); ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, - unsigned maxpages, size_t *start); + size_t maxsize, unsigned maxpages, size_t *start); ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, size_t maxsize, size_t *start); int iov_iter_npages(const struct iov_iter *i, int maxpages); diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 9bcb220bd4a..cf485f9aa56 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -114,16 +114,13 @@ struct rt6_info { u32 rt6i_flags; struct rt6key rt6i_src; struct rt6key rt6i_prefsrc; - u32 rt6i_metric; struct inet6_dev *rt6i_idev; unsigned long _rt6i_peer; - u32 rt6i_genid; - + u32 rt6i_metric; /* more non-fragment space at head required */ unsigned short rt6i_nfheader_len; - u8 rt6i_protocol; }; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 361d2607719..e0d64667a4b 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -352,26 +352,12 @@ static inline void rt_genid_bump_ipv4(struct net *net) atomic_inc(&net->ipv4.rt_genid); } -#if IS_ENABLED(CONFIG_IPV6) -static inline int rt_genid_ipv6(struct net *net) -{ - return atomic_read(&net->ipv6.rt_genid); -} - -static inline void rt_genid_bump_ipv6(struct net *net) -{ - atomic_inc(&net->ipv6.rt_genid); -} -#else -static inline int rt_genid_ipv6(struct net *net) -{ - return 0; -} - +extern void (*__fib6_flush_trees)(struct net *net); static inline void rt_genid_bump_ipv6(struct net *net) { + if (__fib6_flush_trees) + __fib6_flush_trees(net); } -#endif #if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) static inline struct netns_ieee802154_lowpan * diff --git a/include/net/netdma.h b/include/net/netdma.h deleted file mode 100644 index 8ba8ce284ee..00000000000 --- a/include/net/netdma.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ -#ifndef NETDMA_H -#define NETDMA_H -#ifdef CONFIG_NET_DMA -#include <linux/dmaengine.h> -#include <linux/skbuff.h> - -int dma_skb_copy_datagram_iovec(struct dma_chan* chan, - struct sk_buff *skb, int offset, struct iovec *to, - size_t len, struct dma_pinned_list *pinned_list); - -#endif /* CONFIG_NET_DMA */ -#endif /* NETDMA_H */ diff --git a/include/net/sock.h b/include/net/sock.h index b9a5bd0ed9f..591e607cca3 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -233,7 +233,6 @@ struct cg_proto; * @sk_receive_queue: incoming packets * @sk_wmem_alloc: transmit queue bytes committed * @sk_write_queue: Packet sending queue - * @sk_async_wait_queue: DMA copied packets * @sk_omem_alloc: "o" is "option" or "other" * @sk_wmem_queued: persistent queue size * @sk_forward_alloc: space allocated forward @@ -362,10 +361,6 @@ struct sock { struct sk_filter __rcu *sk_filter; struct socket_wq __rcu *sk_wq; -#ifdef CONFIG_NET_DMA - struct sk_buff_head sk_async_wait_queue; -#endif - #ifdef CONFIG_XFRM struct xfrm_policy *sk_policy[2]; #endif @@ -2206,27 +2201,15 @@ void sock_tx_timestamp(const struct sock *sk, __u8 *tx_flags); * sk_eat_skb - Release a skb if it is no longer needed * @sk: socket to eat this skb from * @skb: socket buffer to eat - * @copied_early: flag indicating whether DMA operations copied this data early * * This routine must be called with interrupts disabled or with the socket * locked so that the sk_buff queue operation is ok. */ -#ifdef CONFIG_NET_DMA -static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, bool copied_early) -{ - __skb_unlink(skb, &sk->sk_receive_queue); - if (!copied_early) - __kfree_skb(skb); - else - __skb_queue_tail(&sk->sk_async_wait_queue, skb); -} -#else -static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, bool copied_early) +static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb) { __skb_unlink(skb, &sk->sk_receive_queue); __kfree_skb(skb); } -#endif static inline struct net *sock_net(const struct sock *sk) diff --git a/include/net/tcp.h b/include/net/tcp.h index 590e01a476a..7523c325673 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -27,7 +27,6 @@ #include <linux/cache.h> #include <linux/percpu.h> #include <linux/skbuff.h> -#include <linux/dmaengine.h> #include <linux/crypto.h> #include <linux/cryptohash.h> #include <linux/kref.h> @@ -262,7 +261,6 @@ extern int sysctl_tcp_adv_win_scale; extern int sysctl_tcp_tw_reuse; extern int sysctl_tcp_frto; extern int sysctl_tcp_low_latency; -extern int sysctl_tcp_dma_copybreak; extern int sysctl_tcp_nometrics_save; extern int sysctl_tcp_moderate_rcvbuf; extern int sysctl_tcp_tso_win_divisor; @@ -368,7 +366,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, const struct tcphdr *th, unsigned int len); void tcp_rcv_space_adjust(struct sock *sk); -void tcp_cleanup_rbuf(struct sock *sk, int copied); int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp); void tcp_twsk_destructor(struct sock *sk); ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, @@ -1031,12 +1028,6 @@ static inline void tcp_prequeue_init(struct tcp_sock *tp) tp->ucopy.len = 0; tp->ucopy.memory = 0; skb_queue_head_init(&tp->ucopy.prequeue); -#ifdef CONFIG_NET_DMA - tp->ucopy.dma_chan = NULL; - tp->ucopy.wakeup = 0; - tp->ucopy.pinned_list = NULL; - tp->ucopy.dma_cookie = 0; -#endif } bool tcp_prequeue(struct sock *sk, struct sk_buff *skb); diff --git a/init/Kconfig b/init/Kconfig index e84c6423a2e..e25a82a291a 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -811,6 +811,7 @@ config LOG_BUF_SHIFT int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" range 12 21 default 17 + depends on PRINTK help Select the minimal kernel log buffer size as a power of 2. The final size is affected by LOG_CPU_MAX_BUF_SHIFT config @@ -830,6 +831,7 @@ config LOG_CPU_MAX_BUF_SHIFT range 0 21 default 12 if !BASE_SMALL default 0 if BASE_SMALL + depends on PRINTK help This option allows to increase the default ring buffer size according to the number of CPUs. The value defines the contribution @@ -1475,6 +1477,7 @@ config FUTEX config HAVE_FUTEX_CMPXCHG bool + depends on FUTEX help Architectures should select this if futex_atomic_cmpxchg_inatomic() is implemented and always working. This removes a couple of runtime @@ -1537,6 +1540,16 @@ config AIO by some high performance threaded applications. Disabling this option saves about 7k. +config ADVISE_SYSCALLS + bool "Enable madvise/fadvise syscalls" if EXPERT + default y + help + This option enables the madvise and fadvise syscalls, used by + applications to advise the kernel about their future memory or file + usage, improving performance. If building an embedded system where no + applications use these syscalls, you can disable this option to save + space. + config PCI_QUIRKS default y bool "Enable PCI quirk workarounds" if EXPERT @@ -1906,6 +1919,49 @@ config MODULE_SIG_HASH default "sha384" if MODULE_SIG_SHA384 default "sha512" if MODULE_SIG_SHA512 +config MODULE_COMPRESS + bool "Compress modules on installation" + depends on MODULES + help + This option compresses the kernel modules when 'make + modules_install' is run. + + The modules will be compressed either using gzip or xz depend on the + choice made in "Compression algorithm". + + module-init-tools has support for gzip format while kmod handle gzip + and xz compressed modules. + + When a kernel module is installed from outside of the main kernel + source and uses the Kbuild system for installing modules then that + kernel module will also be compressed when it is installed. + + This option provides little benefit when the modules are to be used inside + an initrd or initramfs, it generally is more efficient to compress the whole + initrd or initramfs instead. + + This is fully compatible with signed modules while the signed module is + compressed. module-init-tools or kmod handles decompression and provide to + other layer the uncompressed but signed payload. + +choice + prompt "Compression algorithm" + depends on MODULE_COMPRESS + default MODULE_COMPRESS_GZIP + help + This determines which sort of compression will be used during + 'make modules_install'. + + GZIP (default) and XZ are supported. + +config MODULE_COMPRESS_GZIP + bool "GZIP" + +config MODULE_COMPRESS_XZ + bool "XZ" + +endchoice + endif # MODULES config INIT_ALL_POSSIBLE diff --git a/kernel/configs/tiny.config b/kernel/configs/tiny.config new file mode 100644 index 00000000000..c2de56ab0fc --- /dev/null +++ b/kernel/configs/tiny.config @@ -0,0 +1,4 @@ +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KERNEL_XZ=y +CONFIG_OPTIMIZE_INLINING=y +CONFIG_SLOB=y diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 22874d7cf2c..52cb04c993b 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -365,13 +365,14 @@ static void cpuset_update_task_spread_flag(struct cpuset *cs, struct task_struct *tsk) { if (is_spread_page(cs)) - tsk->flags |= PF_SPREAD_PAGE; + task_set_spread_page(tsk); else - tsk->flags &= ~PF_SPREAD_PAGE; + task_clear_spread_page(tsk); + if (is_spread_slab(cs)) - tsk->flags |= PF_SPREAD_SLAB; + task_set_spread_slab(tsk); else - tsk->flags &= ~PF_SPREAD_SLAB; + task_clear_spread_slab(tsk); } /* diff --git a/kernel/events/core.c b/kernel/events/core.c index d640a8b4dcb..963bf139e2b 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7948,8 +7948,10 @@ int perf_event_init_task(struct task_struct *child) for_each_task_context_nr(ctxn) { ret = perf_event_init_context(child, ctxn); - if (ret) + if (ret) { + perf_event_free_task(child); return ret; + } } return 0; diff --git a/kernel/fork.c b/kernel/fork.c index 0cf9cdb6e49..a91e47d86de 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1360,7 +1360,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, goto bad_fork_cleanup_policy; retval = audit_alloc(p); if (retval) - goto bad_fork_cleanup_policy; + goto bad_fork_cleanup_perf; /* copy all the process information */ shm_init_task(p); retval = copy_semundo(clone_flags, p); @@ -1566,8 +1566,9 @@ bad_fork_cleanup_semundo: exit_sem(p); bad_fork_cleanup_audit: audit_free(p); -bad_fork_cleanup_policy: +bad_fork_cleanup_perf: perf_event_free_task(p); +bad_fork_cleanup_policy: #ifdef CONFIG_NUMA mpol_put(p->mempolicy); bad_fork_cleanup_threadgroup_lock: diff --git a/kernel/module.c b/kernel/module.c index 03214bd288e..8a0dc91eddb 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -135,7 +135,7 @@ static int param_set_bool_enable_only(const char *val, } static const struct kernel_param_ops param_ops_bool_enable_only = { - .flags = KERNEL_PARAM_FL_NOARG, + .flags = KERNEL_PARAM_OPS_FL_NOARG, .set = param_set_bool_enable_only, .get = param_get_bool, }; diff --git a/kernel/params.c b/kernel/params.c index 34f52702379..041b5899d5e 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -83,6 +83,15 @@ bool parameq(const char *a, const char *b) return parameqn(a, b, strlen(a)+1); } +static void param_check_unsafe(const struct kernel_param *kp) +{ + if (kp->flags & KERNEL_PARAM_FL_UNSAFE) { + pr_warn("Setting dangerous option %s - tainting kernel\n", + kp->name); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } +} + static int parse_one(char *param, char *val, const char *doing, @@ -104,11 +113,12 @@ static int parse_one(char *param, return 0; /* No one handled NULL, so do it here. */ if (!val && - !(params[i].ops->flags & KERNEL_PARAM_FL_NOARG)) + !(params[i].ops->flags & KERNEL_PARAM_OPS_FL_NOARG)) return -EINVAL; pr_debug("handling %s with %p\n", param, params[i].ops->set); mutex_lock(¶m_lock); + param_check_unsafe(¶ms[i]); err = params[i].ops->set(val, ¶ms[i]); mutex_unlock(¶m_lock); return err; @@ -318,7 +328,7 @@ int param_get_bool(char *buffer, const struct kernel_param *kp) EXPORT_SYMBOL(param_get_bool); struct kernel_param_ops param_ops_bool = { - .flags = KERNEL_PARAM_FL_NOARG, + .flags = KERNEL_PARAM_OPS_FL_NOARG, .set = param_set_bool, .get = param_get_bool, }; @@ -369,7 +379,7 @@ int param_set_bint(const char *val, const struct kernel_param *kp) EXPORT_SYMBOL(param_set_bint); struct kernel_param_ops param_ops_bint = { - .flags = KERNEL_PARAM_FL_NOARG, + .flags = KERNEL_PARAM_OPS_FL_NOARG, .set = param_set_bint, .get = param_get_int, }; @@ -552,6 +562,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr, return -EPERM; mutex_lock(¶m_lock); + param_check_unsafe(attribute->param); err = attribute->param->ops->set(buf, attribute->param); mutex_unlock(¶m_lock); if (!err) diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 391d4ddb6f4..d4709d48105 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -156,6 +156,9 @@ cond_syscall(sys_process_vm_writev); cond_syscall(compat_sys_process_vm_readv); cond_syscall(compat_sys_process_vm_writev); cond_syscall(sys_uselib); +cond_syscall(sys_fadvise64); +cond_syscall(sys_fadvise64_64); +cond_syscall(sys_madvise); /* arch-specific weak syscall entries */ cond_syscall(sys_pciconfig_read); diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c index e4ba9a5a5cc..9a4f750a296 100644 --- a/kernel/sysctl_binary.c +++ b/kernel/sysctl_binary.c @@ -390,7 +390,6 @@ static const struct bin_table bin_net_ipv4_table[] = { { CTL_INT, NET_TCP_MTU_PROBING, "tcp_mtu_probing" }, { CTL_INT, NET_TCP_BASE_MSS, "tcp_base_mss" }, { CTL_INT, NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS, "tcp_workaround_signed_windows" }, - { CTL_INT, NET_TCP_DMA_COPYBREAK, "tcp_dma_copybreak" }, { CTL_INT, NET_TCP_SLOW_START_AFTER_IDLE, "tcp_slow_start_after_idle" }, { CTL_INT, NET_CIPSOV4_CACHE_ENABLE, "cipso_cache_enable" }, { CTL_INT, NET_CIPSOV4_CACHE_BUCKET_SIZE, "cipso_cache_bucket_size" }, diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index b38fb2b9e23..2d75c94ae87 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3359,7 +3359,7 @@ static void rb_iter_reset(struct ring_buffer_iter *iter) iter->head = cpu_buffer->reader_page->read; iter->cache_reader_page = iter->head_page; - iter->cache_read = iter->head; + iter->cache_read = cpu_buffer->read; if (iter->head) iter->read_stamp = cpu_buffer->read_stamp; diff --git a/lib/genalloc.c b/lib/genalloc.c index bdb9a456bcb..38d2db82228 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -588,6 +588,7 @@ struct gen_pool *of_get_named_gen_pool(struct device_node *np, if (!np_pool) return NULL; pdev = of_find_device_by_node(np_pool); + of_node_put(np_pool); if (!pdev) return NULL; return dev_get_gen_pool(&pdev->dev); diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 7b36e4d40ed..16d02639d33 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -588,13 +588,13 @@ EXPORT_SYMBOL_GPL(rhashtable_init); * rhashtable_destroy - destroy hash table * @ht: the hash table to destroy * - * Frees the bucket array. + * Frees the bucket array. This function is not rcu safe, therefore the caller + * has to make sure that no resizing may happen by unpublishing the hashtable + * and waiting for the quiescent cycle before releasing the bucket array. */ void rhashtable_destroy(const struct rhashtable *ht) { - const struct bucket_table *tbl = rht_dereference(ht->tbl, ht); - - bucket_table_free(tbl); + bucket_table_free(ht->tbl); } EXPORT_SYMBOL_GPL(rhashtable_destroy); diff --git a/mm/Makefile b/mm/Makefile index 632ae77e607..fe7a053c0f4 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -3,7 +3,7 @@ # mmu-y := nommu.o -mmu-$(CONFIG_MMU) := fremap.o gup.o highmem.o madvise.o memory.o mincore.o \ +mmu-$(CONFIG_MMU) := fremap.o gup.o highmem.o memory.o mincore.o \ mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \ vmalloc.o pagewalk.o pgtable-generic.o @@ -11,7 +11,7 @@ ifdef CONFIG_CROSS_MEMORY_ATTACH mmu-$(CONFIG_MMU) += process_vm_access.o endif -obj-y := filemap.o mempool.o oom_kill.o fadvise.o \ +obj-y := filemap.o mempool.o oom_kill.o \ maccess.o page_alloc.o page-writeback.o \ readahead.o swap.o truncate.o vmscan.o shmem.o \ util.o mmzone.o vmstat.o backing-dev.o \ @@ -28,6 +28,9 @@ else obj-y += bootmem.o endif +ifdef CONFIG_MMU + obj-$(CONFIG_ADVISE_SYSCALLS) += fadvise.o madvise.o +endif obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o diff --git a/mm/huge_memory.c b/mm/huge_memory.c index d9a21d06b86..f8ffd9412ec 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1795,14 +1795,17 @@ static int __split_huge_page_map(struct page *page, for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) { pte_t *pte, entry; BUG_ON(PageCompound(page+i)); + /* + * Note that pmd_numa is not transferred deliberately + * to avoid any possibility that pte_numa leaks to + * a PROT_NONE VMA by accident. + */ entry = mk_pte(page + i, vma->vm_page_prot); entry = maybe_mkwrite(pte_mkdirty(entry), vma); if (!pmd_write(*pmd)) entry = pte_wrprotect(entry); if (!pmd_young(*pmd)) entry = pte_mkold(entry); - if (pmd_numa(*pmd)) - entry = pte_mknuma(entry); pte = pte_offset_map(&_pmd, haddr); BUG_ON(!pte_none(*pte)); set_pte_at(mm, haddr, pte, entry); diff --git a/mm/iov_iter.c b/mm/iov_iter.c index ab88dc0ea1d..9a09f2034fc 100644 --- a/mm/iov_iter.c +++ b/mm/iov_iter.c @@ -310,7 +310,7 @@ void iov_iter_init(struct iov_iter *i, int direction, EXPORT_SYMBOL(iov_iter_init); static ssize_t get_pages_iovec(struct iov_iter *i, - struct page **pages, unsigned maxpages, + struct page **pages, size_t maxsize, unsigned maxpages, size_t *start) { size_t offset = i->iov_offset; @@ -323,6 +323,8 @@ static ssize_t get_pages_iovec(struct iov_iter *i, len = iov->iov_len - offset; if (len > i->count) len = i->count; + if (len > maxsize) + len = maxsize; addr = (unsigned long)iov->iov_base + offset; len += *start = addr & (PAGE_SIZE - 1); if (len > maxpages * PAGE_SIZE) @@ -588,13 +590,15 @@ static unsigned long alignment_bvec(const struct iov_iter *i) } static ssize_t get_pages_bvec(struct iov_iter *i, - struct page **pages, unsigned maxpages, + struct page **pages, size_t maxsize, unsigned maxpages, size_t *start) { const struct bio_vec *bvec = i->bvec; size_t len = bvec->bv_len - i->iov_offset; if (len > i->count) len = i->count; + if (len > maxsize) + len = maxsize; /* can't be more than PAGE_SIZE */ *start = bvec->bv_offset + i->iov_offset; @@ -711,13 +715,13 @@ unsigned long iov_iter_alignment(const struct iov_iter *i) EXPORT_SYMBOL(iov_iter_alignment); ssize_t iov_iter_get_pages(struct iov_iter *i, - struct page **pages, unsigned maxpages, + struct page **pages, size_t maxsize, unsigned maxpages, size_t *start) { if (i->type & ITER_BVEC) - return get_pages_bvec(i, pages, maxpages, start); + return get_pages_bvec(i, pages, maxsize, maxpages, start); else - return get_pages_iovec(i, pages, maxpages, start); + return get_pages_iovec(i, pages, maxsize, maxpages, start); } EXPORT_SYMBOL(iov_iter_get_pages); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 085dc6d2f87..28928ce9b07 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -292,6 +292,9 @@ struct mem_cgroup { /* vmpressure notifications */ struct vmpressure vmpressure; + /* css_online() has been completed */ + int initialized; + /* * the counter to account for mem+swap usage. */ @@ -1099,10 +1102,21 @@ skip_node: * skipping css reference should be safe. */ if (next_css) { - if ((next_css == &root->css) || - ((next_css->flags & CSS_ONLINE) && - css_tryget_online(next_css))) - return mem_cgroup_from_css(next_css); + struct mem_cgroup *memcg = mem_cgroup_from_css(next_css); + + if (next_css == &root->css) + return memcg; + + if (css_tryget_online(next_css)) { + /* + * Make sure the memcg is initialized: + * mem_cgroup_css_online() orders the the + * initialization against setting the flag. + */ + if (smp_load_acquire(&memcg->initialized)) + return memcg; + css_put(next_css); + } prev_css = next_css; goto skip_node; @@ -5549,6 +5563,7 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup *parent = mem_cgroup_from_css(css->parent); + int ret; if (css->id > MEM_CGROUP_ID_MAX) return -ENOSPC; @@ -5585,7 +5600,18 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css) } mutex_unlock(&memcg_create_mutex); - return memcg_init_kmem(memcg, &memory_cgrp_subsys); + ret = memcg_init_kmem(memcg, &memory_cgrp_subsys); + if (ret) + return ret; + + /* + * Make sure the memcg is initialized: mem_cgroup_iter() + * orders reading memcg->initialized against its callers + * reading the memcg members. + */ + smp_store_release(&memcg->initialized, 1); + + return 0; } /* diff --git a/mm/memory.c b/mm/memory.c index d17f1bcd2a9..e229970e422 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1127,7 +1127,7 @@ again: addr) != page->index) { pte_t ptfile = pgoff_to_pte(page->index); if (pte_soft_dirty(ptent)) - pte_file_mksoft_dirty(ptfile); + ptfile = pte_file_mksoft_dirty(ptfile); set_pte_at(mm, addr, pte, ptfile); } if (PageAnon(page)) diff --git a/mm/migrate.c b/mm/migrate.c index f78ec9bd454..2740360cd21 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -146,8 +146,11 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma, pte = pte_mkold(mk_pte(new, vma->vm_page_prot)); if (pte_swp_soft_dirty(*ptep)) pte = pte_mksoft_dirty(pte); + + /* Recheck VMA as permissions can change since migration started */ if (is_write_migration_entry(entry)) - pte = pte_mkwrite(pte); + pte = maybe_mkwrite(pte, vma); + #ifdef CONFIG_HUGETLB_PAGE if (PageHuge(new)) { pte = pte_mkhuge(pte); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 18cee0d4c8a..eee96195802 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1612,7 +1612,7 @@ again: } __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order)); - if (zone_page_state(zone, NR_ALLOC_BATCH) == 0 && + if (atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]) <= 0 && !zone_is_fair_depleted(zone)) zone_set_flag(zone, ZONE_FAIR_DEPLETED); @@ -5701,9 +5701,8 @@ static void __setup_per_zone_wmarks(void) zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1); __mod_zone_page_state(zone, NR_ALLOC_BATCH, - high_wmark_pages(zone) - - low_wmark_pages(zone) - - zone_page_state(zone, NR_ALLOC_BATCH)); + high_wmark_pages(zone) - low_wmark_pages(zone) - + atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH])); setup_zone_migrate_reserve(zone); spin_unlock_irqrestore(&zone->lock, flags); diff --git a/mm/shmem.c b/mm/shmem.c index 0e5fb225007..469f90d5605 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2367,8 +2367,10 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc if (new_dentry->d_inode) { (void) shmem_unlink(new_dir, new_dentry); - if (they_are_dirs) + if (they_are_dirs) { + drop_nlink(new_dentry->d_inode); drop_nlink(old_dir); + } } else if (they_are_dirs) { drop_nlink(old_dir); inc_nlink(new_dir); diff --git a/mm/slab.c b/mm/slab.c index a467b308c68..7c52b3890d2 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2124,7 +2124,8 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp) int __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) { - size_t left_over, freelist_size, ralign; + size_t left_over, freelist_size; + size_t ralign = BYTES_PER_WORD; gfp_t gfp; int err; size_t size = cachep->size; @@ -2157,14 +2158,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) size &= ~(BYTES_PER_WORD - 1); } - /* - * Redzoning and user store require word alignment or possibly larger. - * Note this will be overridden by architecture or caller mandated - * alignment if either is greater than BYTES_PER_WORD. - */ - if (flags & SLAB_STORE_USER) - ralign = BYTES_PER_WORD; - if (flags & SLAB_RED_ZONE) { ralign = REDZONE_ALIGN; /* If redzoning, ensure that the second redzone is suitably @@ -2994,7 +2987,7 @@ out: #ifdef CONFIG_NUMA /* - * Try allocating on another node if PF_SPREAD_SLAB is a mempolicy is set. + * Try allocating on another node if PFA_SPREAD_SLAB is a mempolicy is set. * * If we are in_interrupt, then process context, including cpusets and * mempolicy, may not apply and should not be used for allocation policy. @@ -3226,7 +3219,7 @@ __do_cache_alloc(struct kmem_cache *cache, gfp_t flags) { void *objp; - if (current->mempolicy || unlikely(current->flags & PF_SPREAD_SLAB)) { + if (current->mempolicy || cpuset_do_slab_mem_spread()) { objp = alternate_node_alloc(cache, flags); if (objp) goto out; diff --git a/net/core/Makefile b/net/core/Makefile index 71093d94ad2..235e6c50708 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -16,7 +16,6 @@ obj-y += net-sysfs.o obj-$(CONFIG_PROC_FS) += net-procfs.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_NETPOLL) += netpoll.o -obj-$(CONFIG_NET_DMA) += user_dma.o obj-$(CONFIG_FIB_RULES) += fib_rules.o obj-$(CONFIG_TRACEPOINTS) += net-traces.o obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o diff --git a/net/core/dev.c b/net/core/dev.c index cf8a95f48cf..130d6422022 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1284,7 +1284,6 @@ static int __dev_open(struct net_device *dev) clear_bit(__LINK_STATE_START, &dev->state); else { dev->flags |= IFF_UP; - net_dmaengine_get(); dev_set_rx_mode(dev); dev_activate(dev); add_device_randomness(dev->dev_addr, dev->addr_len); @@ -1363,7 +1362,6 @@ static int __dev_close_many(struct list_head *head) ops->ndo_stop(dev); dev->flags &= ~IFF_UP; - net_dmaengine_put(); netpoll_poll_enable(dev); } @@ -4505,14 +4503,6 @@ static void net_rx_action(struct softirq_action *h) out: net_rps_action_and_irq_enable(sd); -#ifdef CONFIG_NET_DMA - /* - * There may not be any more sk_buffs coming right now, so push - * any pending DMA copies to hardware - */ - dma_issue_pending_all(); -#endif - return; softnet_break: diff --git a/net/core/skbuff.c b/net/core/skbuff.c index da1378a3e2c..8d289697cc7 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3152,6 +3152,9 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD; goto done; } + /* switch back to head shinfo */ + pinfo = skb_shinfo(p); + if (pinfo->frag_list) goto merge; if (skb_gro_len(p) != pinfo->gso_size) diff --git a/net/core/sock.c b/net/core/sock.c index 9c3f823e76a..611f424fb76 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1489,9 +1489,6 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) atomic_set(&newsk->sk_omem_alloc, 0); skb_queue_head_init(&newsk->sk_receive_queue); skb_queue_head_init(&newsk->sk_write_queue); -#ifdef CONFIG_NET_DMA - skb_queue_head_init(&newsk->sk_async_wait_queue); -#endif spin_lock_init(&newsk->sk_dst_lock); rwlock_init(&newsk->sk_callback_lock); @@ -2308,9 +2305,6 @@ void sock_init_data(struct socket *sock, struct sock *sk) skb_queue_head_init(&sk->sk_receive_queue); skb_queue_head_init(&sk->sk_write_queue); skb_queue_head_init(&sk->sk_error_queue); -#ifdef CONFIG_NET_DMA - skb_queue_head_init(&sk->sk_async_wait_queue); -#endif sk->sk_send_head = NULL; diff --git a/net/core/user_dma.c b/net/core/user_dma.c deleted file mode 100644 index 1b5fefdb819..00000000000 --- a/net/core/user_dma.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. - * Portions based on net/core/datagram.c and copyrighted by their authors. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -/* - * This code allows the net stack to make use of a DMA engine for - * skb to iovec copies. - */ - -#include <linux/dmaengine.h> -#include <linux/socket.h> -#include <linux/export.h> -#include <net/tcp.h> -#include <net/netdma.h> - -#define NET_DMA_DEFAULT_COPYBREAK 4096 - -int sysctl_tcp_dma_copybreak = NET_DMA_DEFAULT_COPYBREAK; -EXPORT_SYMBOL(sysctl_tcp_dma_copybreak); - -/** - * dma_skb_copy_datagram_iovec - Copy a datagram to an iovec. - * @skb - buffer to copy - * @offset - offset in the buffer to start copying from - * @iovec - io vector to copy to - * @len - amount of data to copy from buffer to iovec - * @pinned_list - locked iovec buffer data - * - * Note: the iovec is modified during the copy. - */ -int dma_skb_copy_datagram_iovec(struct dma_chan *chan, - struct sk_buff *skb, int offset, struct iovec *to, - size_t len, struct dma_pinned_list *pinned_list) -{ - int start = skb_headlen(skb); - int i, copy = start - offset; - struct sk_buff *frag_iter; - dma_cookie_t cookie = 0; - - /* Copy header. */ - if (copy > 0) { - if (copy > len) - copy = len; - cookie = dma_memcpy_to_iovec(chan, to, pinned_list, - skb->data + offset, copy); - if (cookie < 0) - goto fault; - len -= copy; - if (len == 0) - goto end; - offset += copy; - } - - /* Copy paged appendix. Hmm... why does this look so complicated? */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int end; - const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - WARN_ON(start > offset + len); - - end = start + skb_frag_size(frag); - copy = end - offset; - if (copy > 0) { - struct page *page = skb_frag_page(frag); - - if (copy > len) - copy = len; - - cookie = dma_memcpy_pg_to_iovec(chan, to, pinned_list, page, - frag->page_offset + offset - start, copy); - if (cookie < 0) - goto fault; - len -= copy; - if (len == 0) - goto end; - offset += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - copy = end - offset; - if (copy > 0) { - if (copy > len) - copy = len; - cookie = dma_skb_copy_datagram_iovec(chan, frag_iter, - offset - start, - to, copy, - pinned_list); - if (cookie < 0) - goto fault; - len -= copy; - if (len == 0) - goto end; - offset += copy; - } - start = end; - } - -end: - if (!len) { - skb->dma_cookie = cookie; - return cookie; - } - -fault: - return -EFAULT; -} diff --git a/net/dccp/proto.c b/net/dccp/proto.c index de2c1e71930..f440cc7c9f7 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -848,7 +848,7 @@ int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, default: dccp_pr_debug("packet_type=%s\n", dccp_packet_name(dh->dccph_type)); - sk_eat_skb(sk, skb, false); + sk_eat_skb(sk, skb); } verify_sock_status: if (sock_flag(sk, SOCK_DONE)) { @@ -905,7 +905,7 @@ verify_sock_status: len = skb->len; found_fin_ok: if (!(flags & MSG_PEEK)) - sk_eat_skb(sk, skb, false); + sk_eat_skb(sk, skb); break; } while (1); out: diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index bd41dd1948b..bda4bb8ae26 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -764,9 +764,14 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); - if (!t && (cmd == SIOCADDTUNNEL)) { - t = ip_tunnel_create(net, itn, p); - err = PTR_ERR_OR_ZERO(t); + if (cmd == SIOCADDTUNNEL) { + if (!t) { + t = ip_tunnel_create(net, itn, p); + err = PTR_ERR_OR_ZERO(t); + break; + } + + err = -EEXIST; break; } if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 173e7ea54c7..cbadb942c33 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -746,7 +746,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow } n = ipv4_neigh_lookup(&rt->dst, NULL, &new_gw); - if (n) { + if (!IS_ERR(n)) { if (!(n->nud_state & NUD_VALID)) { neigh_event_send(n, NULL); } else { diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 79a007c5255..a9fde0eef77 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -628,15 +628,6 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, -#ifdef CONFIG_NET_DMA - { - .procname = "tcp_dma_copybreak", - .data = &sysctl_tcp_dma_copybreak, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, -#endif { .procname = "tcp_slow_start_after_idle", .data = &sysctl_tcp_slow_start_after_idle, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 541f26a67ba..8ee43ae9039 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -274,7 +274,6 @@ #include <net/tcp.h> #include <net/xfrm.h> #include <net/ip.h> -#include <net/netdma.h> #include <net/sock.h> #include <asm/uaccess.h> @@ -1394,7 +1393,7 @@ static int tcp_peek_sndq(struct sock *sk, struct msghdr *msg, int len) * calculation of whether or not we must ACK for the sake of * a window update. */ -void tcp_cleanup_rbuf(struct sock *sk, int copied) +static void tcp_cleanup_rbuf(struct sock *sk, int copied) { struct tcp_sock *tp = tcp_sk(sk); bool time_to_ack = false; @@ -1470,39 +1469,6 @@ static void tcp_prequeue_process(struct sock *sk) tp->ucopy.memory = 0; } -#ifdef CONFIG_NET_DMA -static void tcp_service_net_dma(struct sock *sk, bool wait) -{ - dma_cookie_t done, used; - dma_cookie_t last_issued; - struct tcp_sock *tp = tcp_sk(sk); - - if (!tp->ucopy.dma_chan) - return; - - last_issued = tp->ucopy.dma_cookie; - dma_async_issue_pending(tp->ucopy.dma_chan); - - do { - if (dma_async_is_tx_complete(tp->ucopy.dma_chan, - last_issued, &done, - &used) == DMA_COMPLETE) { - /* Safe to free early-copied skbs now */ - __skb_queue_purge(&sk->sk_async_wait_queue); - break; - } else { - struct sk_buff *skb; - while ((skb = skb_peek(&sk->sk_async_wait_queue)) && - (dma_async_is_complete(skb->dma_cookie, done, - used) == DMA_COMPLETE)) { - __skb_dequeue(&sk->sk_async_wait_queue); - kfree_skb(skb); - } - } - } while (wait); -} -#endif - static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) { struct sk_buff *skb; @@ -1520,7 +1486,7 @@ static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) * splitted a fat GRO packet, while we released socket lock * in skb_splice_bits() */ - sk_eat_skb(sk, skb, false); + sk_eat_skb(sk, skb); } return NULL; } @@ -1586,11 +1552,11 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, continue; } if (tcp_hdr(skb)->fin) { - sk_eat_skb(sk, skb, false); + sk_eat_skb(sk, skb); ++seq; break; } - sk_eat_skb(sk, skb, false); + sk_eat_skb(sk, skb); if (!desc->count) break; tp->copied_seq = seq; @@ -1628,7 +1594,6 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int target; /* Read at least this many bytes */ long timeo; struct task_struct *user_recv = NULL; - bool copied_early = false; struct sk_buff *skb; u32 urg_hole = 0; @@ -1674,28 +1639,6 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); -#ifdef CONFIG_NET_DMA - tp->ucopy.dma_chan = NULL; - preempt_disable(); - skb = skb_peek_tail(&sk->sk_receive_queue); - { - int available = 0; - - if (skb) - available = TCP_SKB_CB(skb)->seq + skb->len - (*seq); - if ((available < target) && - (len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) && - !sysctl_tcp_low_latency && - net_dma_find_channel()) { - preempt_enable(); - tp->ucopy.pinned_list = - dma_pin_iovec_pages(msg->msg_iov, len); - } else { - preempt_enable(); - } - } -#endif - do { u32 offset; @@ -1826,16 +1769,6 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* __ Set realtime policy in scheduler __ */ } -#ifdef CONFIG_NET_DMA - if (tp->ucopy.dma_chan) { - if (tp->rcv_wnd == 0 && - !skb_queue_empty(&sk->sk_async_wait_queue)) { - tcp_service_net_dma(sk, true); - tcp_cleanup_rbuf(sk, copied); - } else - dma_async_issue_pending(tp->ucopy.dma_chan); - } -#endif if (copied >= target) { /* Do not sleep, just process backlog. */ release_sock(sk); @@ -1843,11 +1776,6 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } else sk_wait_data(sk, &timeo); -#ifdef CONFIG_NET_DMA - tcp_service_net_dma(sk, false); /* Don't block */ - tp->ucopy.wakeup = 0; -#endif - if (user_recv) { int chunk; @@ -1905,43 +1833,13 @@ do_prequeue: } if (!(flags & MSG_TRUNC)) { -#ifdef CONFIG_NET_DMA - if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = net_dma_find_channel(); - - if (tp->ucopy.dma_chan) { - tp->ucopy.dma_cookie = dma_skb_copy_datagram_iovec( - tp->ucopy.dma_chan, skb, offset, - msg->msg_iov, used, - tp->ucopy.pinned_list); - - if (tp->ucopy.dma_cookie < 0) { - - pr_alert("%s: dma_cookie < 0\n", - __func__); - - /* Exception. Bailout! */ - if (!copied) - copied = -EFAULT; - break; - } - - dma_async_issue_pending(tp->ucopy.dma_chan); - - if ((offset + used) == skb->len) - copied_early = true; - - } else -#endif - { - err = skb_copy_datagram_iovec(skb, offset, - msg->msg_iov, used); - if (err) { - /* Exception. Bailout! */ - if (!copied) - copied = -EFAULT; - break; - } + err = skb_copy_datagram_iovec(skb, offset, + msg->msg_iov, used); + if (err) { + /* Exception. Bailout! */ + if (!copied) + copied = -EFAULT; + break; } } @@ -1961,19 +1859,15 @@ skip_copy: if (tcp_hdr(skb)->fin) goto found_fin_ok; - if (!(flags & MSG_PEEK)) { - sk_eat_skb(sk, skb, copied_early); - copied_early = false; - } + if (!(flags & MSG_PEEK)) + sk_eat_skb(sk, skb); continue; found_fin_ok: /* Process the FIN. */ ++*seq; - if (!(flags & MSG_PEEK)) { - sk_eat_skb(sk, skb, copied_early); - copied_early = false; - } + if (!(flags & MSG_PEEK)) + sk_eat_skb(sk, skb); break; } while (len > 0); @@ -1996,16 +1890,6 @@ skip_copy: tp->ucopy.len = 0; } -#ifdef CONFIG_NET_DMA - tcp_service_net_dma(sk, true); /* Wait for queue to drain */ - tp->ucopy.dma_chan = NULL; - - if (tp->ucopy.pinned_list) { - dma_unpin_iovec_pages(tp->ucopy.pinned_list); - tp->ucopy.pinned_list = NULL; - } -#endif - /* According to UNIX98, msg_name/msg_namelen are ignored * on connected socket. I was just happy when found this 8) --ANK */ @@ -2349,9 +2233,6 @@ int tcp_disconnect(struct sock *sk, int flags) __skb_queue_purge(&sk->sk_receive_queue); tcp_write_queue_purge(sk); __skb_queue_purge(&tp->out_of_order_queue); -#ifdef CONFIG_NET_DMA - __skb_queue_purge(&sk->sk_async_wait_queue); -#endif inet->inet_dport = 0; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a906e0200ff..0185eea5934 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -73,7 +73,6 @@ #include <net/inet_common.h> #include <linux/ipsec.h> #include <asm/unaligned.h> -#include <net/netdma.h> #include <linux/errqueue.h> int sysctl_tcp_timestamps __read_mostly = 1; @@ -4951,53 +4950,6 @@ static inline bool tcp_checksum_complete_user(struct sock *sk, __tcp_checksum_complete_user(sk, skb); } -#ifdef CONFIG_NET_DMA -static bool tcp_dma_try_early_copy(struct sock *sk, struct sk_buff *skb, - int hlen) -{ - struct tcp_sock *tp = tcp_sk(sk); - int chunk = skb->len - hlen; - int dma_cookie; - bool copied_early = false; - - if (tp->ucopy.wakeup) - return false; - - if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = net_dma_find_channel(); - - if (tp->ucopy.dma_chan && skb_csum_unnecessary(skb)) { - - dma_cookie = dma_skb_copy_datagram_iovec(tp->ucopy.dma_chan, - skb, hlen, - tp->ucopy.iov, chunk, - tp->ucopy.pinned_list); - - if (dma_cookie < 0) - goto out; - - tp->ucopy.dma_cookie = dma_cookie; - copied_early = true; - - tp->ucopy.len -= chunk; - tp->copied_seq += chunk; - tcp_rcv_space_adjust(sk); - - if ((tp->ucopy.len == 0) || - (tcp_flag_word(tcp_hdr(skb)) & TCP_FLAG_PSH) || - (atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1))) { - tp->ucopy.wakeup = 1; - sk->sk_data_ready(sk); - } - } else if (chunk > 0) { - tp->ucopy.wakeup = 1; - sk->sk_data_ready(sk); - } -out: - return copied_early; -} -#endif /* CONFIG_NET_DMA */ - /* Does PAWS and seqno based validation of an incoming segment, flags will * play significant role here. */ @@ -5177,27 +5129,15 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, } } else { int eaten = 0; - int copied_early = 0; bool fragstolen = false; - if (tp->copied_seq == tp->rcv_nxt && - len - tcp_header_len <= tp->ucopy.len) { -#ifdef CONFIG_NET_DMA - if (tp->ucopy.task == current && - sock_owned_by_user(sk) && - tcp_dma_try_early_copy(sk, skb, tcp_header_len)) { - copied_early = 1; - eaten = 1; - } -#endif - if (tp->ucopy.task == current && - sock_owned_by_user(sk) && !copied_early) { - __set_current_state(TASK_RUNNING); + if (tp->ucopy.task == current && + tp->copied_seq == tp->rcv_nxt && + len - tcp_header_len <= tp->ucopy.len && + sock_owned_by_user(sk)) { + __set_current_state(TASK_RUNNING); - if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) - eaten = 1; - } - if (eaten) { + if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) { /* Predicted packet is in window by definition. * seq == rcv_nxt and rcv_wup <= rcv_nxt. * Hence, check seq<=rcv_wup reduces to: @@ -5213,9 +5153,8 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, __skb_pull(skb, tcp_header_len); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITSTOUSER); + eaten = 1; } - if (copied_early) - tcp_cleanup_rbuf(sk, skb->len); } if (!eaten) { if (tcp_checksum_complete_user(sk, skb)) @@ -5252,14 +5191,8 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, goto no_ack; } - if (!copied_early || tp->rcv_nxt != tp->rcv_wup) - __tcp_ack_snd_check(sk, 0); + __tcp_ack_snd_check(sk, 0); no_ack: -#ifdef CONFIG_NET_DMA - if (copied_early) - __skb_queue_tail(&sk->sk_async_wait_queue, skb); - else -#endif if (eaten) kfree_skb_partial(skb, fragstolen); sk->sk_data_ready(sk); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index cd17f009aed..fbea536cf5c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -72,7 +72,6 @@ #include <net/inet_common.h> #include <net/timewait_sock.h> #include <net/xfrm.h> -#include <net/netdma.h> #include <net/secure_seq.h> #include <net/tcp_memcontrol.h> #include <net/busy_poll.h> @@ -1670,18 +1669,8 @@ process: bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { -#ifdef CONFIG_NET_DMA - struct tcp_sock *tp = tcp_sk(sk); - if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = net_dma_find_channel(); - if (tp->ucopy.dma_chan) + if (!tcp_prequeue(sk, skb)) ret = tcp_v4_do_rcv(sk, skb); - else -#endif - { - if (!tcp_prequeue(sk, skb)) - ret = tcp_v4_do_rcv(sk, skb); - } } else if (unlikely(sk_add_backlog(sk, skb, sk->sk_rcvbuf + sk->sk_sndbuf))) { bh_unlock_sock(sk); @@ -1841,11 +1830,6 @@ void tcp_v4_destroy_sock(struct sock *sk) } #endif -#ifdef CONFIG_NET_DMA - /* Cleans up our sk_async_wait_queue */ - __skb_queue_purge(&sk->sk_async_wait_queue); -#endif - /* Clean prequeue, it must be empty really */ __skb_queue_purge(&tp->ucopy.prequeue); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3342ee64f2e..3e118dfddd0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4780,10 +4780,11 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) if (ip6_del_rt(ifp->rt)) dst_free(&ifp->rt->dst); + + rt_genid_bump_ipv6(net); break; } atomic_inc(&net->ipv6.dev_addr_genid); - rt_genid_bump_ipv6(net); } static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index e6960457f62..98cc4cd570e 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c @@ -8,6 +8,13 @@ #include <net/addrconf.h> #include <net/ip.h> +/* if ipv6 module registers this function is used by xfrm to force all + * sockets to relookup their nodes - this is fairly expensive, be + * careful + */ +void (*__fib6_flush_trees)(struct net *); +EXPORT_SYMBOL(__fib6_flush_trees); + #define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16) static inline unsigned int ipv6_addr_scope2type(unsigned int scope) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 76b7f5ee8f4..97b9fa8de37 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1605,6 +1605,24 @@ static void fib6_prune_clones(struct net *net, struct fib6_node *fn) fib6_clean_tree(net, fn, fib6_prune_clone, 1, NULL); } +static int fib6_update_sernum(struct rt6_info *rt, void *arg) +{ + __u32 sernum = *(__u32 *)arg; + + if (rt->rt6i_node && + rt->rt6i_node->fn_sernum != sernum) + rt->rt6i_node->fn_sernum = sernum; + + return 0; +} + +static void fib6_flush_trees(struct net *net) +{ + __u32 new_sernum = fib6_new_sernum(); + + fib6_clean_all(net, fib6_update_sernum, &new_sernum); +} + /* * Garbage collection */ @@ -1788,6 +1806,8 @@ int __init fib6_init(void) NULL); if (ret) goto out_unregister_subsys; + + __fib6_flush_trees = fib6_flush_trees; out: return ret; diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 5f19dfbc4c6..f304471477d 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -314,6 +314,8 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); t = ip6gre_tunnel_find(net, parms, ARPHRD_IP6GRE); + if (t && create) + return NULL; if (t || !create) return t; @@ -1724,4 +1726,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); MODULE_DESCRIPTION("GRE over IPv6 tunneling device"); MODULE_ALIAS_RTNL_LINK("ip6gre"); +MODULE_ALIAS_RTNL_LINK("ip6gretap"); MODULE_ALIAS_NETDEV("ip6gre0"); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index f9de5a69507..69a84b46400 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -364,8 +364,12 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net, (t = rtnl_dereference(*tp)) != NULL; tp = &t->next) { if (ipv6_addr_equal(local, &t->parms.laddr) && - ipv6_addr_equal(remote, &t->parms.raddr)) + ipv6_addr_equal(remote, &t->parms.raddr)) { + if (create) + return NULL; + return t; + } } if (!create) return NULL; diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 7f52fd9fa7b..5833a224446 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -253,8 +253,12 @@ static struct ip6_tnl *vti6_locate(struct net *net, struct __ip6_tnl_parm *p, (t = rtnl_dereference(*tp)) != NULL; tp = &t->next) { if (ipv6_addr_equal(local, &t->parms.laddr) && - ipv6_addr_equal(remote, &t->parms.raddr)) + ipv6_addr_equal(remote, &t->parms.raddr)) { + if (create) + return NULL; + return t; + } } if (!create) return NULL; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f23fbd28a50..bafde82324c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -314,7 +314,6 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net, memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers); - rt->rt6i_genid = rt_genid_ipv6(net); INIT_LIST_HEAD(&rt->rt6i_siblings); } return rt; @@ -1098,9 +1097,6 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) * DST_OBSOLETE_FORCE_CHK which forces validation calls down * into this function always. */ - if (rt->rt6i_genid != rt_genid_ipv6(dev_net(rt->dst.dev))) - return NULL; - if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie)) return NULL; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 29964c3d363..03a5d1ed334 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -59,7 +59,6 @@ #include <net/snmp.h> #include <net/dsfield.h> #include <net/timewait_sock.h> -#include <net/netdma.h> #include <net/inet_common.h> #include <net/secure_seq.h> #include <net/tcp_memcontrol.h> @@ -1446,18 +1445,8 @@ process: bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { -#ifdef CONFIG_NET_DMA - struct tcp_sock *tp = tcp_sk(sk); - if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = net_dma_find_channel(); - if (tp->ucopy.dma_chan) + if (!tcp_prequeue(sk, skb)) ret = tcp_v6_do_rcv(sk, skb); - else -#endif - { - if (!tcp_prequeue(sk, skb)) - ret = tcp_v6_do_rcv(sk, skb); - } } else if (unlikely(sk_add_backlog(sk, skb, sk->sk_rcvbuf + sk->sk_sndbuf))) { bh_unlock_sock(sk); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 0080d2b0a8a..bb9cbc17d92 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -839,7 +839,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, if (!(flags & MSG_PEEK)) { spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); - sk_eat_skb(sk, skb, false); + sk_eat_skb(sk, skb); spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); *seq = 0; } @@ -861,10 +861,10 @@ copy_uaddr: llc_cmsg_rcv(msg, skb); if (!(flags & MSG_PEEK)) { - spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); - sk_eat_skb(sk, skb, false); - spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); - *seq = 0; + spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); + sk_eat_skb(sk, skb); + spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); + *seq = 0; } goto out; diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index b5c1d3aadb4..6d77cce481d 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -847,6 +847,7 @@ config NETFILTER_XT_TARGET_TPROXY tristate '"TPROXY" target transparent proxying support' depends on NETFILTER_XTABLES depends on NETFILTER_ADVANCED + depends on (IPV6 || IPV6=n) depends on IP_NF_MANGLE select NF_DEFRAG_IPV4 select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index c138b8fbe28..f37f0716a9f 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -222,6 +222,51 @@ replay: } } +struct nfnl_err { + struct list_head head; + struct nlmsghdr *nlh; + int err; +}; + +static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err) +{ + struct nfnl_err *nfnl_err; + + nfnl_err = kmalloc(sizeof(struct nfnl_err), GFP_KERNEL); + if (nfnl_err == NULL) + return -ENOMEM; + + nfnl_err->nlh = nlh; + nfnl_err->err = err; + list_add_tail(&nfnl_err->head, list); + + return 0; +} + +static void nfnl_err_del(struct nfnl_err *nfnl_err) +{ + list_del(&nfnl_err->head); + kfree(nfnl_err); +} + +static void nfnl_err_reset(struct list_head *err_list) +{ + struct nfnl_err *nfnl_err, *next; + + list_for_each_entry_safe(nfnl_err, next, err_list, head) + nfnl_err_del(nfnl_err); +} + +static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb) +{ + struct nfnl_err *nfnl_err, *next; + + list_for_each_entry_safe(nfnl_err, next, err_list, head) { + netlink_ack(skb, nfnl_err->nlh, nfnl_err->err); + nfnl_err_del(nfnl_err); + } +} + static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, u_int16_t subsys_id) { @@ -230,6 +275,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, const struct nfnetlink_subsystem *ss; const struct nfnl_callback *nc; bool success = true, done = false; + static LIST_HEAD(err_list); int err; if (subsys_id >= NFNL_SUBSYS_COUNT) @@ -287,6 +333,7 @@ replay: type = nlh->nlmsg_type; if (type == NFNL_MSG_BATCH_BEGIN) { /* Malformed: Batch begin twice */ + nfnl_err_reset(&err_list); success = false; goto done; } else if (type == NFNL_MSG_BATCH_END) { @@ -333,6 +380,7 @@ replay: * original skb. */ if (err == -EAGAIN) { + nfnl_err_reset(&err_list); ss->abort(skb); nfnl_unlock(subsys_id); kfree_skb(nskb); @@ -341,11 +389,24 @@ replay: } ack: if (nlh->nlmsg_flags & NLM_F_ACK || err) { + /* Errors are delivered once the full batch has been + * processed, this avoids that the same error is + * reported several times when replaying the batch. + */ + if (nfnl_err_add(&err_list, nlh, err) < 0) { + /* We failed to enqueue an error, reset the + * list of errors and send OOM to userspace + * pointing to the batch header. + */ + nfnl_err_reset(&err_list); + netlink_ack(skb, nlmsg_hdr(oskb), -ENOMEM); + success = false; + goto done; + } /* We don't stop processing the batch on errors, thus, * userspace gets all the errors that the batch * triggers. */ - netlink_ack(skb, nlh, err); if (err) success = false; } @@ -361,6 +422,7 @@ done: else ss->abort(skb); + nfnl_err_deliver(&err_list, oskb); nfnl_unlock(subsys_id); kfree_skb(nskb); } diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 28fb8f38e6b..8892b7b6184 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c @@ -180,15 +180,17 @@ static int nft_hash_init(const struct nft_set *set, static void nft_hash_destroy(const struct nft_set *set) { const struct rhashtable *priv = nft_set_priv(set); - const struct bucket_table *tbl; + const struct bucket_table *tbl = priv->tbl; struct nft_hash_elem *he, *next; unsigned int i; - tbl = rht_dereference(priv->tbl, priv); - for (i = 0; i < tbl->size; i++) - rht_for_each_entry_safe(he, next, tbl->buckets[i], priv, node) + for (i = 0; i < tbl->size; i++) { + for (he = rht_entry(tbl->buckets[i], struct nft_hash_elem, node); + he != NULL; he = next) { + next = rht_entry(he->node.next, struct nft_hash_elem, node); nft_hash_elem_destroy(set, he); - + } + } rhashtable_destroy(priv); } diff --git a/net/netfilter/nft_rbtree.c b/net/netfilter/nft_rbtree.c index e1836ff8819..46214f24566 100644 --- a/net/netfilter/nft_rbtree.c +++ b/net/netfilter/nft_rbtree.c @@ -234,13 +234,11 @@ static void nft_rbtree_destroy(const struct nft_set *set) struct nft_rbtree_elem *rbe; struct rb_node *node; - spin_lock_bh(&nft_rbtree_lock); while ((node = priv->root.rb_node) != NULL) { rb_erase(node, &priv->root); rbe = rb_entry(node, struct nft_rbtree_elem, node); nft_rbtree_elem_destroy(set, rbe); } - spin_unlock_bh(&nft_rbtree_lock); } static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, diff --git a/net/sched/ematch.c b/net/sched/ematch.c index 3a633debb6d..ad57f4444b9 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -526,9 +526,11 @@ pop_stack: match_idx = stack[--stackp]; cur_match = tcf_em_get_match(tree, match_idx); - if (tcf_em_early_end(cur_match, res)) + if (tcf_em_early_end(cur_match, res)) { + if (tcf_em_is_inverted(cur_match)) + res = !res; goto pop_stack; - else { + } else { match_idx++; goto proceed; } diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index 95ec7b35e8b..e48a4e9d886 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -18,7 +18,12 @@ __modinst: $(modules) # Don't stop modules_install if we can't sign external modules. quiet_cmd_modules_install = INSTALL $@ - cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) ; $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) + cmd_modules_install = \ + mkdir -p $(2) ; \ + cp $@ $(2) ; \ + $(mod_strip_cmd) $(2)/$(notdir $@) ; \ + $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) ; \ + $(mod_compress_cmd) $(2)/$(notdir $@) # Modules built outside the kernel source tree go into extra by default INSTALL_MOD_DIR ?= extra diff --git a/scripts/Makefile.modsign b/scripts/Makefile.modsign index abfda626dba..b6ac7084da7 100644 --- a/scripts/Makefile.modsign +++ b/scripts/Makefile.modsign @@ -7,7 +7,7 @@ __modsign: include scripts/Kbuild.include -__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) +__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod))) modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) PHONY += $(modules) diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter index 549d0ab8c66..23e78dcd12b 100755 --- a/scripts/bloat-o-meter +++ b/scripts/bloat-o-meter @@ -20,6 +20,8 @@ def getsizes(file): if type in "tTdDbBrR": # strip generated symbols if name.startswith("__mod_"): continue + if name.startswith("SyS_"): continue + if name.startswith("compat_SyS_"): continue if name == "linux_banner": continue # statics and some other optimizations adds random .NUMBER name = re.sub(r'\.[0-9]+', '', name) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 9c4d2412fb7..ebf40f6edb4 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -104,6 +104,23 @@ endif %_defconfig: $(obj)/conf $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) +configfiles=$(wildcard $(srctree)/kernel/configs/$(1).config $(srctree)/arch/$(SRCARCH)/configs/$(1).config) + +define mergeconfig +$(if $(wildcard $(objtree)/.config),, $(error You need an existing .config for this target)) +$(if $(call configfiles,$(1)),, $(error No configuration exists for this target on this architecture)) +$(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m -O $(objtree) $(objtree)/.config $(call configfiles,$(1)) +$(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig +endef + +PHONY += kvmconfig +kvmconfig: + $(call mergeconfig,kvm_guest) + +PHONY += tinyconfig +tinyconfig: allnoconfig + $(call mergeconfig,tiny) + # Help text used by make help help: @echo ' config - Update current config utilising a line-oriented program' @@ -124,6 +141,8 @@ help: @echo ' randconfig - New config with random answer to all options' @echo ' listnewconfig - List new options' @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value' + @echo ' kvmconfig - Enable additional options for guest kernel support' + @echo ' tinyconfig - Configure the tiniest possible kernel' # lxdialog stuff check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 091d90573b6..3b405c726ec 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -24,9 +24,9 @@ #include "../../include/linux/export.h" /* Are we using CONFIG_MODVERSIONS? */ -int modversions = 0; +static int modversions = 0; /* Warn about undefined symbols? (do so if we have vmlinux) */ -int have_vmlinux = 0; +static int have_vmlinux = 0; /* Is CONFIG_MODULE_SRCVERSION_ALL set? */ static int all_versions = 0; /* If we are modposting external module set to 1 */ @@ -229,7 +229,7 @@ static struct symbol *find_symbol(const char *name) return NULL; } -static struct { +static const struct { const char *str; enum export export; } export_list[] = { @@ -805,7 +805,7 @@ static int match(const char *sym, const char * const pat[]) } /* sections that we do not want to do full section mismatch check on */ -static const char *section_white_list[] = +static const char *const section_white_list[] = { ".comment*", ".debug*", @@ -882,17 +882,18 @@ static void check_section(const char *modname, struct elf_info *elf, #define MEM_EXIT_SECTIONS ".memexit.*" /* init data sections */ -static const char *init_data_sections[] = { ALL_INIT_DATA_SECTIONS, NULL }; +static const char *const init_data_sections[] = + { ALL_INIT_DATA_SECTIONS, NULL }; /* all init sections */ -static const char *init_sections[] = { ALL_INIT_SECTIONS, NULL }; +static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; /* All init and exit sections (code + data) */ -static const char *init_exit_sections[] = +static const char *const init_exit_sections[] = {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; /* data section */ -static const char *data_sections[] = { DATA_SECTIONS, NULL }; +static const char *const data_sections[] = { DATA_SECTIONS, NULL }; /* symbols in .data that may refer to init/exit sections */ @@ -906,8 +907,8 @@ static const char *data_sections[] = { DATA_SECTIONS, NULL }; "*_probe_one", \ "*_console" -static const char *head_sections[] = { ".head.text*", NULL }; -static const char *linker_symbols[] = +static const char *const head_sections[] = { ".head.text*", NULL }; +static const char *const linker_symbols[] = { "__init_begin", "_sinittext", "_einittext", NULL }; enum mismatch { @@ -929,7 +930,7 @@ struct sectioncheck { const char *symbol_white_list[20]; }; -const struct sectioncheck sectioncheck[] = { +static const struct sectioncheck sectioncheck[] = { /* Do not reference init/exit code/data from * normal code and data */ @@ -2211,7 +2212,7 @@ int main(int argc, char **argv) err = 0; for (mod = modules; mod; mod = mod->next) { - char fname[strlen(mod->name) + 10]; + char fname[PATH_MAX]; if (mod->skip) continue; diff --git a/scripts/tags.sh b/scripts/tags.sh index cbfd269a601..293828bfd4a 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -197,6 +197,9 @@ exuberant() --regex-c++='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/' \ --regex-c++='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/' \ --regex-c++='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \ + --regex-c++='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/' \ + --regex-c++='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/' \ + --regex-c++='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/'\ --regex-c='/PCI_OP_READ\((\w*).*[1-4]\)/pci_bus_read_config_\1/' \ --regex-c='/PCI_OP_WRITE\((\w*).*[1-4]\)/pci_bus_write_config_\1/' \ --regex-c='/DEFINE_(MUTEX|SEMAPHORE|SPINLOCK)\((\w*)/\2/v/' \ @@ -260,6 +263,9 @@ emacs() --regex='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/' \ --regex='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/' \ --regex='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \ + --regex='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/' \ + --regex='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/' \ + --regex='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/' \ --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' \ --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \ --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 99810009333..65ca451a764 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -668,7 +668,7 @@ static int param_set_aabool(const char *val, const struct kernel_param *kp); static int param_get_aabool(char *buffer, const struct kernel_param *kp); #define param_check_aabool param_check_bool static struct kernel_param_ops param_ops_aabool = { - .flags = KERNEL_PARAM_FL_NOARG, + .flags = KERNEL_PARAM_OPS_FL_NOARG, .set = param_set_aabool, .get = param_get_aabool }; @@ -685,7 +685,7 @@ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp); #define param_check_aalockpolicy param_check_bool static struct kernel_param_ops param_ops_aalockpolicy = { - .flags = KERNEL_PARAM_FL_NOARG, + .flags = KERNEL_PARAM_OPS_FL_NOARG, .set = param_set_aalockpolicy, .get = param_get_aalockpolicy }; diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index e4f6102efc1..b86b426f159 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -51,7 +51,7 @@ static struct reg_default rt286_index_def[] = { { 0x04, 0xaf01 }, { 0x08, 0x000d }, { 0x09, 0xd810 }, - { 0x0a, 0x0060 }, + { 0x0a, 0x0120 }, { 0x0b, 0x0000 }, { 0x0d, 0x2800 }, { 0x0f, 0x0000 }, @@ -60,7 +60,7 @@ static struct reg_default rt286_index_def[] = { { 0x33, 0x0208 }, { 0x49, 0x0004 }, { 0x4f, 0x50e9 }, - { 0x50, 0x2c00 }, + { 0x50, 0x2000 }, { 0x63, 0x2902 }, { 0x67, 0x1111 }, { 0x68, 0x1016 }, @@ -104,7 +104,6 @@ static const struct reg_default rt286_reg[] = { { 0x02170700, 0x00000000 }, { 0x02270100, 0x00000000 }, { 0x02370100, 0x00000000 }, - { 0x02040000, 0x00004002 }, { 0x01870700, 0x00000020 }, { 0x00830000, 0x000000c3 }, { 0x00930000, 0x000000c3 }, @@ -192,7 +191,6 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) /*handle index registers*/ if (reg <= 0xff) { rt286_hw_write(client, RT286_COEF_INDEX, reg); - reg = RT286_PROC_COEF; for (i = 0; i < INDEX_CACHE_SIZE; i++) { if (reg == rt286->index_cache[i].reg) { rt286->index_cache[i].def = value; @@ -200,6 +198,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) } } + reg = RT286_PROC_COEF; } data[0] = (reg >> 24) & 0xff; diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 484b3bbe862..4021cd43574 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -647,7 +647,7 @@ int ssm2602_probe(struct device *dev, enum ssm2602_type type, return -ENOMEM; dev_set_drvdata(dev, ssm2602); - ssm2602->type = SSM2602; + ssm2602->type = type; ssm2602->regmap = regmap; return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602, diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 87eb5776a39..de6ab06f58a 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -748,8 +748,9 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, return 0; } -static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, - unsigned int fmt) +static int _fsl_ssi_set_dai_fmt(struct device *dev, + struct fsl_ssi_private *ssi_private, + unsigned int fmt) { struct regmap *regs = ssi_private->regs; u32 strcr = 0, stcr, srcr, scr, mask; @@ -758,7 +759,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, ssi_private->dai_fmt = fmt; if (fsl_ssi_is_i2s_master(ssi_private) && IS_ERR(ssi_private->baudclk)) { - dev_err(&ssi_private->pdev->dev, "baudclk is missing which is necessary for master mode\n"); + dev_err(dev, "baudclk is missing which is necessary for master mode\n"); return -EINVAL; } @@ -913,7 +914,7 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); - return _fsl_ssi_set_dai_fmt(ssi_private, fmt); + return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi_private, fmt); } /** @@ -1387,7 +1388,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) done: if (ssi_private->dai_fmt) - _fsl_ssi_set_dai_fmt(ssi_private, ssi_private->dai_fmt); + _fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private, + ssi_private->dai_fmt); return 0; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 3092b58fede..cecfab3cc94 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -102,13 +102,11 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) fe->dpcm[stream].runtime = fe_substream->runtime; ret = dpcm_path_get(fe, stream, &list); - if (ret < 0) { - mutex_unlock(&fe->card->mutex); + if (ret < 0) goto fe_err; - } else if (ret == 0) { + else if (ret == 0) dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", fe->dai_link->name, stream ? "capture" : "playback"); - } /* calculate valid and active FE <-> BE dpcms */ dpcm_process_paths(fe, stream, &list, 1); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 889f4e3d35d..d074aa91b02 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3203,7 +3203,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, unsigned int val, mask; void *data; - if (!component->regmap) + if (!component->regmap || !params->num_regs) return -EINVAL; len = params->num_regs * component->val_bytes; |