diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-07 13:51:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-07 13:51:13 -0700 |
commit | 968c61f7da3cf6d58a49587cfe00d899ca72c1ad (patch) | |
tree | b5f7adb38c01234d34e000f6f7ad9da432e663e5 | |
parent | 9d71941d39fb876271df72394518a98ae079e5a3 (diff) | |
parent | b01e9348e106544e50691252bf58cde239681f19 (diff) | |
download | lwn-968c61f7da3cf6d58a49587cfe00d899ca72c1ad.tar.gz lwn-968c61f7da3cf6d58a49587cfe00d899ca72c1ad.zip |
Merge tag 'mfd-next-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"New Drivers
- RK805 Power Management IC (PMIC)
- ROHM BD9571MWV-M MFD Power Management IC (PMIC)
- Texas Instruments TPS68470 Power Management IC (PMIC) & LEDs
New Device Support:
- Add support for HiSilicon Hi6421v530 to hi6421-pmic-core
- Add support for X-Powers AXP806 to axp20x
- Add support for X-Powers AXP813 to axp20x
- Add support for Intel Sunrise Point LPSS to intel-lpss-pci
New Functionality:
- Amend API to provide register layout; atmel-smc
Fix-ups:
- DT re-work; omap, nokia
- Header file location change {I2C => MFD}; dm355evm_msp, tps65010
- Fix chip ID formatting issue(s); rk808
- Optionally register touchscreen devices; da9052-core
- Documentation improvements; twl-core
- Constification; rtsx_pcr, ab8500-core, da9055-i2c, da9052-spi
- Drop unnecessary static declaration; max8925-i2c
- Kconfig changes (missing deps and remove module support)
- Slim down oversized licence statement; hi6421-pmic-core
- Use managed resources (devm_*); lp87565
- Supply proper error checking/handling; t7l66xb
Bug Fixes:
- Fix counter duplication issue; da9052-core
- Fix potential NULL deference issue; max8998
- Leave SPI-NOR write-protection bit alone; lpc_ich
- Ensure device is put into reset during suspend; intel-lpss
- Correct register offset variable size; omap-usb-tll"
* tag 'mfd-next-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (61 commits)
mfd: intel_soc_pmic: Differentiate between Bay and Cherry Trail CRC variants
mfd: intel_soc_pmic: Export separate mfd-cell configs for BYT and CHT
dt-bindings: mfd: Add bindings for ZII RAVE devices
mfd: omap-usb-tll: Fix register offsets
mfd: da9052: Constify spi_device_id
mfd: intel-lpss: Put I2C and SPI controllers into reset state on suspend
mfd: da9055: Constify i2c_device_id
mfd: intel-lpss: Add missing PCI ID for Intel Sunrise Point LPSS devices
mfd: t7l66xb: Handle return value of clk_prepare_enable
mfd: Add ROHM BD9571MWV-M PMIC DT bindings
mfd: intel_soc_pmic_chtwc: Turn Kconfig option into a bool
mfd: lp87565: Convert to use devm_mfd_add_devices()
mfd: Add support for TPS68470 device
mfd: lpc_ich: Do not touch SPI-NOR write protection bit on Haswell/Broadwell
mfd: syscon: atmel-smc: Add helper to retrieve register layout
mfd: axp20x: Use correct platform device ID for many PEK
dt-bindings: mfd: axp20x: Introduce bindings for AXP813
mfd: axp20x: Add support for AXP813 PMIC
dt-bindings: mfd: axp20x: Add AXP806 to supported list of chips
mfd: Add ROHM BD9571MWV-M MFD PMIC driver
...
113 files changed, 3318 insertions, 182 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm32 new file mode 100644 index 000000000000..ad2cc63e4bf8 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm32 @@ -0,0 +1,57 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_count0_preset +KernelVersion: 4.13 +Contact: fabrice.gasnier@st.com +Description: + Reading returns the current preset value. Writing sets the + preset value. Encoder counts continuously from 0 to preset + value, depending on direction (up/down). + +What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available +KernelVersion: 4.13 +Contact: fabrice.gasnier@st.com +Description: + Reading returns the list possible quadrature modes. + +What: /sys/bus/iio/devices/iio:deviceX/in_count0_quadrature_mode +KernelVersion: 4.13 +Contact: fabrice.gasnier@st.com +Description: + Configure the device counter quadrature modes: + - non-quadrature: + Encoder IN1 input servers as the count input (up + direction). + - quadrature: + Encoder IN1 and IN2 inputs are mixed to get direction + and count. + +What: /sys/bus/iio/devices/iio:deviceX/in_count_polarity_available +KernelVersion: 4.13 +Contact: fabrice.gasnier@st.com +Description: + Reading returns the list possible active edges. + +What: /sys/bus/iio/devices/iio:deviceX/in_count0_polarity +KernelVersion: 4.13 +Contact: fabrice.gasnier@st.com +Description: + Configure the device encoder/counter active edge: + - rising-edge + - falling-edge + - both-edges + + In non-quadrature mode, device counts up on active edge. + In quadrature mode, encoder counting scenarios are as follows: + ---------------------------------------------------------------- + | Active | Level on | IN1 signal | IN2 signal | + | edge | opposite |------------------------------------------ + | | signal | Rising | Falling | Rising | Falling | + ---------------------------------------------------------------- + | Rising | High -> | Down | - | Up | - | + | edge | Low -> | Up | - | Down | - | + ---------------------------------------------------------------- + | Falling | High -> | - | Up | - | Down | + | edge | Low -> | - | Down | - | Up | + ---------------------------------------------------------------- + | Both | High -> | Down | Up | Up | Down | + | edges | Low -> | Up | Down | Down | Up | + ---------------------------------------------------------------- diff --git a/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt index 8ce9cd2855b5..c143948b2a37 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt @@ -20,8 +20,8 @@ i2c@0 { #address-cells = <1>; #size-cells = <0>; - retu-mfd: retu@1 { - compatible = "retu-mfd"; + retu: retu@1 { + compatible = "nokia,retu"; reg = <0x1>; }; }; diff --git a/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt new file mode 100644 index 000000000000..a04aa5c04103 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt @@ -0,0 +1,27 @@ +STMicroelectronics STM32 Low-Power Timer quadrature encoder and counter + +STM32 Low-Power Timer provides several counter modes. It can be used as: +- quadrature encoder to detect angular position and direction of rotary + elements, from IN1 and IN2 input signals. +- simple counter from IN1 input signal. + +Must be a sub-node of an STM32 Low-Power Timer device tree node. +See ../mfd/stm32-lptimer.txt for details about the parent node. + +Required properties: +- compatible: Must be "st,stm32-lptimer-counter". +- pinctrl-names: Set to "default". +- pinctrl-0: List of phandles pointing to pin configuration nodes, + to set IN1/IN2 pins in mode of operation for Low-Power + Timer input on external pin. + +Example: + timer@40002400 { + compatible = "st,stm32-lptimer"; + ... + counter { + compatible = "st,stm32-lptimer-counter"; + pinctrl-names = "default"; + pinctrl-0 = <&lptim1_in_pins>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-lptimer-trigger.txt b/Documentation/devicetree/bindings/iio/timer/stm32-lptimer-trigger.txt new file mode 100644 index 000000000000..85e6806b17d7 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/timer/stm32-lptimer-trigger.txt @@ -0,0 +1,23 @@ +STMicroelectronics STM32 Low-Power Timer Trigger + +STM32 Low-Power Timer provides trigger source (LPTIM output) that can be used +by STM32 internal ADC and/or DAC. + +Must be a sub-node of an STM32 Low-Power Timer device tree node. +See ../mfd/stm32-lptimer.txt for details about the parent node. + +Required properties: +- compatible: Must be "st,stm32-lptimer-trigger". +- reg: Identify trigger hardware block. Must be 0, 1 or 2 + respectively for lptimer1, lptimer2 or lptimer3 + trigger output. + +Example: + timer@40002400 { + compatible = "st,stm32-lptimer"; + ... + trigger@0 { + compatible = "st,stm32-lptimer-trigger"; + reg = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/atmel-smc.txt b/Documentation/devicetree/bindings/mfd/atmel-smc.txt index 26eeed373934..1103ce2030fb 100644 --- a/Documentation/devicetree/bindings/mfd/atmel-smc.txt +++ b/Documentation/devicetree/bindings/mfd/atmel-smc.txt @@ -8,6 +8,7 @@ Required properties: - compatible: Should be one of the following "atmel,at91sam9260-smc", "syscon" "atmel,sama5d3-smc", "syscon" + "atmel,sama5d2-smc", "syscon" - reg: Contains offset/length value of the SMC memory region. diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt index aca09af66514..9455503b0299 100644 --- a/Documentation/devicetree/bindings/mfd/axp20x.txt +++ b/Documentation/devicetree/bindings/mfd/axp20x.txt @@ -7,7 +7,14 @@ axp209 (X-Powers) axp221 (X-Powers) axp223 (X-Powers) axp803 (X-Powers) +axp806 (X-Powers) axp809 (X-Powers) +axp813 (X-Powers) + +The AXP813 is 2 chips packaged into 1. The 2 chips do not share anything +other than the packaging. Pins are routed separately. As such they should +be treated as separate entities. The other half is an AC100 RTC/codec +combo chip. Please see ./ac100.txt for its bindings. Required properties: - compatible: should be one of: @@ -19,6 +26,7 @@ Required properties: * "x-powers,axp803" * "x-powers,axp806" * "x-powers,axp809" + * "x-powers,axp813" - reg: The I2C slave address or RSB hardware address for the AXP chip - interrupt-parent: The parent interrupt controller - interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin @@ -28,12 +36,14 @@ Required properties: Optional properties: - x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz AXP152/20X: range: 750-1875, Default: 1.5 MHz - AXP22X/80X: range: 1800-4050, Default: 3 MHz + AXP22X/8XX: range: 1800-4050, Default: 3 MHz -- x-powers,drive-vbus-en: axp221 / axp223 only boolean, set this when the - N_VBUSEN pin is used as an output pin to control an external - regulator to drive the OTG VBus, rather then as an input pin - which signals whether the board is driving OTG VBus or not. +- x-powers,drive-vbus-en: boolean, set this when the N_VBUSEN pin is + used as an output pin to control an external + regulator to drive the OTG VBus, rather then + as an input pin which signals whether the + board is driving OTG VBus or not. + (axp221 / axp223 / axp813 only) - x-powers,master-mode: Boolean (axp806 only). Set this when the PMIC is wired for master mode. The default is slave mode. @@ -171,6 +181,36 @@ LDO_IO1 : LDO : ips-supply : GPIO 1 RTC_LDO : LDO : ips-supply : always on SW : On/Off Switch : swin-supply +AXP813 regulators, type, and corresponding input supply names: + +Regulator Type Supply Name Notes +--------- ---- ----------- ----- +DCDC1 : DC-DC buck : vin1-supply +DCDC2 : DC-DC buck : vin2-supply : poly-phase capable +DCDC3 : DC-DC buck : vin3-supply : poly-phase capable +DCDC4 : DC-DC buck : vin4-supply +DCDC5 : DC-DC buck : vin5-supply : poly-phase capable +DCDC6 : DC-DC buck : vin6-supply : poly-phase capable +DCDC7 : DC-DC buck : vin7-supply +ALDO1 : LDO : aldoin-supply : shared supply +ALDO2 : LDO : aldoin-supply : shared supply +ALDO3 : LDO : aldoin-supply : shared supply +DLDO1 : LDO : dldoin-supply : shared supply +DLDO2 : LDO : dldoin-supply : shared supply +DLDO3 : LDO : dldoin-supply : shared supply +DLDO4 : LDO : dldoin-supply : shared supply +ELDO1 : LDO : eldoin-supply : shared supply +ELDO2 : LDO : eldoin-supply : shared supply +ELDO3 : LDO : eldoin-supply : shared supply +FLDO1 : LDO : fldoin-supply : shared supply +FLDO2 : LDO : fldoin-supply : shared supply +FLDO3 : LDO : fldoin-supply : shared supply +LDO_IO0 : LDO : ips-supply : GPIO 0 +LDO_IO1 : LDO : ips-supply : GPIO 1 +RTC_LDO : LDO : ips-supply : always on +SW : On/Off Switch : swin-supply +DRIVEVBUS : Enable output : drivevbus-supply : external regulator + Example: axp209: pmic@34 { diff --git a/Documentation/devicetree/bindings/mfd/bd9571mwv.txt b/Documentation/devicetree/bindings/mfd/bd9571mwv.txt new file mode 100644 index 000000000000..9ab216a851d5 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/bd9571mwv.txt @@ -0,0 +1,49 @@ +* ROHM BD9571MWV Power Management Integrated Circuit (PMIC) bindings + +Required properties: + - compatible : Should be "rohm,bd9571mwv". + - reg : I2C slave address. + - interrupt-parent : Phandle to the parent interrupt controller. + - interrupts : The interrupt line the device is connected to. + - interrupt-controller : Marks the device node as an interrupt controller. + - #interrupt-cells : The number of cells to describe an IRQ, should be 2. + The first cell is the IRQ number. + The second cell is the flags, encoded as trigger + masks from ../interrupt-controller/interrupts.txt. + - gpio-controller : Marks the device node as a GPIO Controller. + - #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + - regulators: : List of child nodes that specify the regulator + initialization data. Child nodes must be named + after their hardware counterparts: + - vd09 + - vd18 + - vd25 + - vd33 + - dvfs + Each child node is defined using the standard + binding for regulators. + +Example: + + pmic: pmic@30 { + compatible = "rohm,bd9571mwv"; + reg = <0x30>; + interrupt-parent = <&gpio2>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + + regulators { + dvfs: dvfs { + regulator-name = "dvfs"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1030000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/da9052-i2c.txt b/Documentation/devicetree/bindings/mfd/da9052-i2c.txt index 9554292dc6cb..57fa74e65664 100644 --- a/Documentation/devicetree/bindings/mfd/da9052-i2c.txt +++ b/Documentation/devicetree/bindings/mfd/da9052-i2c.txt @@ -4,6 +4,14 @@ Required properties: - compatible : Should be "dlg,da9052", "dlg,da9053-aa", "dlg,da9053-ab", or "dlg,da9053-bb" +Optional properties: +- dlg,tsi-as-adc : Boolean, if set the X+, X-, Y+, Y- touchscreen + input lines are used as general purpose analogue + input. +- tsiref-supply: Phandle to the regulator, which provides the reference + voltage for the TSIREF pin. Must be provided when the + touchscreen pins are used for ADC purposes. + Sub-nodes: - regulators : Contain the regulator nodes. The DA9052/53 regulators are bound using their names as listed below: diff --git a/Documentation/devicetree/bindings/mfd/retu.txt b/Documentation/devicetree/bindings/mfd/retu.txt new file mode 100644 index 000000000000..876242394a16 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/retu.txt @@ -0,0 +1,25 @@ +* Device tree bindings for Nokia Retu and Tahvo multi-function device + +Retu and Tahvo are a multi-function devices found on Nokia Internet +Tablets (770, N800 and N810). The Retu chip provides watchdog timer +and power button control functionalities while Tahvo chip provides +USB transceiver functionality. + +Required properties: +- compatible: "nokia,retu" or "nokia,tahvo" +- reg: Specifies the CBUS slave address of the ASIC chip +- interrupts: The interrupt line the device is connected to +- interrupt-parent: The parent interrupt controller + +Example: + +cbus0 { + compatible = "i2c-cbus-gpio"; + ... + retu: retu@1 { + compatible = "nokia,retu"; + interrupt-parent = <&gpio4>; + interrupts = <12 IRQ_TYPE_EDGE_RISING>; + reg = <0x1>; + }; +}; diff --git a/Documentation/devicetree/bindings/mfd/rk808.txt b/Documentation/devicetree/bindings/mfd/rk808.txt index 9636ae8d8d41..91b65227afeb 100644 --- a/Documentation/devicetree/bindings/mfd/rk808.txt +++ b/Documentation/devicetree/bindings/mfd/rk808.txt @@ -1,11 +1,14 @@ RK8XX Power Management Integrated Circuit The rk8xx family current members: +rk805 rk808 rk818 Required properties: -- compatible: "rockchip,rk808", "rockchip,rk818" +- compatible: "rockchip,rk805" +- compatible: "rockchip,rk808" +- compatible: "rockchip,rk818" - reg: I2C slave address - interrupt-parent: The parent interrupt controller. - interrupts: the interrupt outputs of the controller. @@ -18,6 +21,14 @@ Optional properties: - rockchip,system-power-controller: Telling whether or not this pmic is controlling the system power. +Optional RK805 properties: +- vcc1-supply: The input supply for DCDC_REG1 +- vcc2-supply: The input supply for DCDC_REG2 +- vcc3-supply: The input supply for DCDC_REG3 +- vcc4-supply: The input supply for DCDC_REG4 +- vcc5-supply: The input supply for LDO_REG1 and LDO_REG2 +- vcc6-supply: The input supply for LDO_REG3 + Optional RK808 properties: - vcc1-supply: The input supply for DCDC_REG1 - vcc2-supply: The input supply for DCDC_REG2 @@ -56,6 +67,15 @@ by a child node of the 'regulators' node. /* standard regulator bindings here */ }; +Following regulators of the RK805 PMIC regulators are supported. Note that +the 'n' in regulator name, as in DCDC_REGn or LDOn, represents the DCDC or LDO +number as described in RK805 datasheet. + + - DCDC_REGn + - valid values for n are 1 to 4. + - LDO_REGn + - valid values for n are 1 to 3 + Following regulators of the RK808 PMIC block are supported. Note that the 'n' in regulator name, as in DCDC_REGn or LDOn, represents the DCDC or LDO number as described in RK808 datasheet. diff --git a/Documentation/devicetree/bindings/mfd/stm32-lptimer.txt b/Documentation/devicetree/bindings/mfd/stm32-lptimer.txt new file mode 100644 index 000000000000..2a9ff29db9c9 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/stm32-lptimer.txt @@ -0,0 +1,48 @@ +STMicroelectronics STM32 Low-Power Timer + +The STM32 Low-Power Timer (LPTIM) is a 16-bit timer that provides several +functions: +- PWM output (with programmable prescaler, configurable polarity) +- Quadrature encoder, counter +- Trigger source for STM32 ADC/DAC (LPTIM_OUT) + +Required properties: +- compatible: Must be "st,stm32-lptimer". +- reg: Offset and length of the device's register set. +- clocks: Phandle to the clock used by the LP Timer module. +- clock-names: Must be "mux". +- #address-cells: Should be '<1>'. +- #size-cells: Should be '<0>'. + +Optional subnodes: +- pwm: See ../pwm/pwm-stm32-lp.txt +- counter: See ../iio/timer/stm32-lptimer-cnt.txt +- trigger: See ../iio/timer/stm32-lptimer-trigger.txt + +Example: + + timer@40002400 { + compatible = "st,stm32-lptimer"; + reg = <0x40002400 0x400>; + clocks = <&timer_clk>; + clock-names = "mux"; + #address-cells = <1>; + #size-cells = <0>; + + pwm { + compatible = "st,stm32-pwm-lp"; + pinctrl-names = "default"; + pinctrl-0 = <&lppwm1_pins>; + }; + + trigger@0 { + compatible = "st,stm32-lptimer-trigger"; + reg = <0>; + }; + + counter { + compatible = "st,stm32-lptimer-counter"; + pinctrl-names = "default"; + pinctrl-0 = <&lptim1_in_pins>; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/tps6105x.txt b/Documentation/devicetree/bindings/mfd/tps6105x.txt new file mode 100644 index 000000000000..93602c7a19c8 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/tps6105x.txt @@ -0,0 +1,17 @@ +* Device tree bindings for TI TPS61050/61052 Boost Converters + +The TP61050/TPS61052 is a high-power "white LED driver". The +device provides LED, GPIO and regulator functionalities. + +Required properties: +- compatible: "ti,tps61050" or "ti,tps61052" +- reg: Specifies the I2C slave address + +Example: + +i2c0 { + tps61052@33 { + compatible = "ti,tps61052"; + reg = <0x33>; + }; +}; diff --git a/Documentation/devicetree/bindings/mfd/zii,rave-sp.txt b/Documentation/devicetree/bindings/mfd/zii,rave-sp.txt new file mode 100644 index 000000000000..088eff9ddb78 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/zii,rave-sp.txt @@ -0,0 +1,39 @@ +Zodiac Inflight Innovations RAVE Supervisory Processor + +RAVE Supervisory Processor communicates with SoC over UART. It is +expected that its Device Tree node is specified as a child of a node +corresponding to UART controller used for communication. + +Required parent device properties: + + - compatible: Should be one of: + - "zii,rave-sp-niu" + - "zii,rave-sp-mezz" + - "zii,rave-sp-esb" + - "zii,rave-sp-rdu1" + - "zii,rave-sp-rdu2" + + - current-speed: Should be set to baud rate SP device is using + +RAVE SP consists of the following sub-devices: + +Device Description +------ ----------- +rave-sp-wdt : Watchdog +rave-sp-nvmem : Interface to onborad EEPROM +rave-sp-backlight : Display backlight +rave-sp-hwmon : Interface to onboard hardware sensors +rave-sp-leds : Interface to onboard LEDs +rave-sp-input : Interface to onboard power button + +Example of usage: + + rdu { + compatible = "zii,rave-sp-rdu2"; + current-speed = <1000000>; + + watchdog { + compatible = "zii,rave-sp-watchdog"; + }; + }; + diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-rk805.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-rk805.txt new file mode 100644 index 000000000000..eee3dc260934 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-rk805.txt @@ -0,0 +1,63 @@ +Pincontrol driver for RK805 Power management IC. + +RK805 has 2 pins which can be configured as GPIO output only. + +Please refer file <devicetree/bindings/pinctrl/pinctrl-bindings.txt> +for details of the common pinctrl bindings used by client devices, +including the meaning of the phrase "pin configuration node". + +Optional Pinmux properties: +-------------------------- +Following properties are required if default setting of pins are required +at boot. +- pinctrl-names: A pinctrl state named per <pinctrl-binding.txt>. +- pinctrl[0...n]: Properties to contain the phandle for pinctrl states per + <pinctrl-binding.txt>. + +The pin configurations are defined as child of the pinctrl states node. Each +sub-node have following properties: + +Required properties: +------------------ +- #gpio-cells: Should be two. The first cell is the pin number and the + second is the GPIO flags. + +- gpio-controller: Marks the device node as a GPIO controller. + +- pins: List of pins. Valid values of pins properties are: gpio0, gpio1. + +First 2 properties must be added in the RK805 PMIC node, documented in +Documentation/devicetree/bindings/mfd/rk808.txt + +Optional properties: +------------------- +Following are optional properties defined as pinmux DT binding document +<pinctrl-bindings.txt>. Absence of properties will leave the configuration +on default. + function, + output-low, + output-high. + +Valid values for function properties are: gpio. + +Theres is also not customised properties for any GPIO. + +Example: +-------- +rk805: rk805@18 { + compatible = "rockchip,rk805"; + ... + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>, <&rk805_default>; + + rk805_default: pinmux { + gpio01 { + pins = "gpio0", "gpio1"; + function = "gpio"; + output-high; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt new file mode 100644 index 000000000000..f8338d11fd2b --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt @@ -0,0 +1,24 @@ +STMicroelectronics STM32 Low-Power Timer PWM + +STM32 Low-Power Timer provides single channel PWM. + +Must be a sub-node of an STM32 Low-Power Timer device tree node. +See ../mfd/stm32-lptimer.txt for details about the parent node. + +Required parameters: +- compatible: Must be "st,stm32-pwm-lp". + +Optional properties: +- pinctrl-names: Set to "default". +- pinctrl-0: Phandle pointing to pin configuration node for PWM. + +Example: + timer@40002400 { + compatible = "st,stm32-lptimer"; + ... + pwm { + compatible = "st,stm32-pwm-lp"; + pinctrl-names = "default"; + pinctrl-0 = <&lppwm1_pins>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index b07232679a66..ac2dfb26d899 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11432,6 +11432,17 @@ L: linux-serial@vger.kernel.org S: Odd Fixes F: drivers/tty/serial/rp2.* +ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS +M: Marek Vasut <marek.vasut+renesas@gmail.com> +L: linux-kernel@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +S: Supported +F: drivers/mfd/bd9571mwv.c +F: drivers/regulator/bd9571mwv-regulator.c +F: drivers/gpio/gpio-bd9571mwv.c +F: include/linux/mfd/bd9571mwv.h +F: Documentation/devicetree/bindings/mfd/bd9571mwv.txt + ROSE NETWORK LAYER M: Ralf Baechle <ralf@linux-mips.org> L: linux-hams@vger.kernel.org diff --git a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi index 7e5ffc583c90..91886231e5a8 100644 --- a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi +++ b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi @@ -15,8 +15,8 @@ >; #address-cells = <1>; #size-cells = <0>; - retu_mfd: retu@1 { - compatible = "retu-mfd"; + retu: retu@1 { + compatible = "nokia,retu"; interrupt-parent = <&gpio4>; interrupts = <12 IRQ_TYPE_EDGE_RISING>; reg = <0x1>; diff --git a/arch/arm/boot/dts/ste-hrefprev60.dtsi b/arch/arm/boot/dts/ste-hrefprev60.dtsi index 5882a2606ac3..3f14b4df69b4 100644 --- a/arch/arm/boot/dts/ste-hrefprev60.dtsi +++ b/arch/arm/boot/dts/ste-hrefprev60.dtsi @@ -30,7 +30,7 @@ i2c@80004000 { tps61052@33 { - compatible = "tps61052"; + compatible = "ti,tps61052"; reg = <0x33>; }; diff --git a/arch/arm/mach-omap1/board-h2-mmc.c b/arch/arm/mach-omap1/board-h2-mmc.c index 357be2debc9d..91bda9c802ff 100644 --- a/arch/arm/mach-omap1/board-h2-mmc.c +++ b/arch/arm/mach-omap1/board-h2-mmc.c @@ -14,7 +14,7 @@ #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/platform_data/gpio-omap.h> -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #include "board-h2.h" #include "mmc.h" diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 675254ee4b1e..dece47d76282 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -28,7 +28,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/physmap.h> #include <linux/input.h> -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #include <linux/smc91x.h> #include <linux/omapfb.h> #include <linux/platform_data/gpio-omap.h> diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c index 4f58bfa5e754..692c267a9a90 100644 --- a/arch/arm/mach-omap1/board-h3-mmc.c +++ b/arch/arm/mach-omap1/board-h3-mmc.c @@ -14,7 +14,7 @@ #include <linux/gpio.h> #include <linux/platform_device.h> -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #include "common.h" #include "board-h3.h" diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index e62f9d454f10..6d32beeb2d88 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -28,7 +28,7 @@ #include <linux/mtd/physmap.h> #include <linux/input.h> #include <linux/spi/spi.h> -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #include <linux/smc91x.h> #include <linux/omapfb.h> #include <linux/platform_data/gpio-omap.h> diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index ee8d9f553db4..06243c0b12d2 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -233,10 +233,10 @@ static struct platform_device nokia770_cbus_device = { static struct i2c_board_info nokia770_i2c_board_info_2[] __initdata = { { - I2C_BOARD_INFO("retu-mfd", 0x01), + I2C_BOARD_INFO("retu", 0x01), }, { - I2C_BOARD_INFO("tahvo-mfd", 0x02), + I2C_BOARD_INFO("tahvo", 0x02), }, }; diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 95ac1929aede..d579f4e04137 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -38,7 +38,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/mtd/physmap.h> -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #include <linux/platform_data/gpio-omap.h> #include <linux/platform_data/omap1_bl.h> diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 8cc6338fcb12..b5ad7fcb80ed 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -29,7 +29,7 @@ #include <linux/irq.h> #include <linux/delay.h> #include <linux/i2c.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/i2c-omap.h> #include <linux/reboot.h> #include <linux/irqchip/irq-omap-intc.h> diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index 1346b3ab34a5..295124b248ae 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -16,7 +16,7 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/kernel.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include "soc.h" #include "voltage.h" diff --git a/arch/arm/mach-s3c24xx/mach-osiris-dvs.c b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c index 262ab0744748..6cac7da15e2b 100644 --- a/arch/arm/mach-s3c24xx/mach-osiris-dvs.c +++ b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c @@ -17,7 +17,7 @@ #include <linux/cpufreq.h> #include <linux/gpio.h> -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #include <plat/cpu-freq.h> #include <mach/gpio-samsung.h> diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c index 70b0eb7d3134..64b1a0b7b803 100644 --- a/arch/arm/mach-s3c24xx/mach-osiris.c +++ b/arch/arm/mach-s3c24xx/mach-osiris.c @@ -24,7 +24,7 @@ #include <linux/io.h> #include <linux/platform_device.h> -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 24f388ed46d4..9b511df5450e 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -35,7 +35,7 @@ #include <linux/of.h> #include <linux/irqdomain.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> /* * The GPIO "subchip" supports 18 GPIOs which can be configured as diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 6bc602891f2f..e3c15f88075f 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -25,6 +25,7 @@ #include <linux/dmaengine.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> +#include <linux/iio/timer/stm32-lptim-trigger.h> #include <linux/iio/timer/stm32-timer-trigger.h> #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> @@ -185,6 +186,11 @@ enum stm32_adc_extsel { STM32_EXT13, STM32_EXT14, STM32_EXT15, + STM32_EXT16, + STM32_EXT17, + STM32_EXT18, + STM32_EXT19, + STM32_EXT20, }; /** @@ -526,6 +532,9 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = { { TIM4_TRGO, STM32_EXT12 }, { TIM6_TRGO, STM32_EXT13 }, { TIM3_CH4, STM32_EXT15 }, + { LPTIM1_OUT, STM32_EXT18 }, + { LPTIM2_OUT, STM32_EXT19 }, + { LPTIM3_OUT, STM32_EXT20 }, {}, }; @@ -1082,7 +1091,8 @@ static int stm32_adc_get_trig_extsel(struct iio_dev *indio_dev, * Checking both stm32 timer trigger type and trig name * should be safe against arbitrary trigger names. */ - if (is_stm32_timer_trigger(trig) && + if ((is_stm32_timer_trigger(trig) || + is_stm32_lptim_trigger(trig)) && !strcmp(adc->cfg->trigs[i].name, trig->name)) { return adc->cfg->trigs[i].extsel; } @@ -1764,7 +1774,7 @@ static int stm32_adc_probe(struct platform_device *pdev) indio_dev->dev.parent = &pdev->dev; indio_dev->dev.of_node = pdev->dev.of_node; indio_dev->info = &stm32_adc_iio_info; - indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_HARDWARE_TRIGGERED; platform_set_drvdata(pdev, adc); diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index bd3d37fc2144..1edd99f0c5e5 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -35,7 +35,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/module.h> #include <linux/stddef.h> #include <linux/mutex.h> diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index becbb0aef232..bc0e60b9da45 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -33,7 +33,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of_platform.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> diff --git a/drivers/iio/counter/Kconfig b/drivers/iio/counter/Kconfig index b37e5fc03149..474e1ac4e7c0 100644 --- a/drivers/iio/counter/Kconfig +++ b/drivers/iio/counter/Kconfig @@ -21,4 +21,13 @@ config 104_QUAD_8 The base port addresses for the devices may be configured via the base array module parameter. +config STM32_LPTIMER_CNT + tristate "STM32 LP Timer encoder counter driver" + depends on MFD_STM32_LPTIMER || COMPILE_TEST + help + Select this option to enable STM32 Low-Power Timer quadrature encoder + and counter driver. + + To compile this driver as a module, choose M here: the + module will be called stm32-lptimer-cnt. endmenu diff --git a/drivers/iio/counter/Makefile b/drivers/iio/counter/Makefile index 007e88411648..1b9a896eb488 100644 --- a/drivers/iio/counter/Makefile +++ b/drivers/iio/counter/Makefile @@ -5,3 +5,4 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o +obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o diff --git a/drivers/iio/counter/stm32-lptimer-cnt.c b/drivers/iio/counter/stm32-lptimer-cnt.c new file mode 100644 index 000000000000..1c5909bb1605 --- /dev/null +++ b/drivers/iio/counter/stm32-lptimer-cnt.c @@ -0,0 +1,383 @@ +/* + * STM32 Low-Power Timer Encoder and Counter driver + * + * Copyright (C) STMicroelectronics 2017 + * + * Author: Fabrice Gasnier <fabrice.gasnier@st.com> + * + * Inspired by 104-quad-8 and stm32-timer-trigger drivers. + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/bitfield.h> +#include <linux/iio/iio.h> +#include <linux/mfd/stm32-lptimer.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +struct stm32_lptim_cnt { + struct device *dev; + struct regmap *regmap; + struct clk *clk; + u32 preset; + u32 polarity; + u32 quadrature_mode; +}; + +static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv) +{ + u32 val; + int ret; + + ret = regmap_read(priv->regmap, STM32_LPTIM_CR, &val); + if (ret) + return ret; + + return FIELD_GET(STM32_LPTIM_ENABLE, val); +} + +static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, + int enable) +{ + int ret; + u32 val; + + val = FIELD_PREP(STM32_LPTIM_ENABLE, enable); + ret = regmap_write(priv->regmap, STM32_LPTIM_CR, val); + if (ret) + return ret; + + if (!enable) { + clk_disable(priv->clk); + return 0; + } + + /* LP timer must be enabled before writing CMP & ARR */ + ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, priv->preset); + if (ret) + return ret; + + ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, 0); + if (ret) + return ret; + + /* ensure CMP & ARR registers are properly written */ + ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, + (val & STM32_LPTIM_CMPOK_ARROK), + 100, 1000); + if (ret) + return ret; + + ret = regmap_write(priv->regmap, STM32_LPTIM_ICR, + STM32_LPTIM_CMPOKCF_ARROKCF); + if (ret) + return ret; + + ret = clk_enable(priv->clk); + if (ret) { + regmap_write(priv->regmap, STM32_LPTIM_CR, 0); + return ret; + } + + /* Start LP timer in continuous mode */ + return regmap_update_bits(priv->regmap, STM32_LPTIM_CR, + STM32_LPTIM_CNTSTRT, STM32_LPTIM_CNTSTRT); +} + +static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable) +{ + u32 mask = STM32_LPTIM_ENC | STM32_LPTIM_COUNTMODE | + STM32_LPTIM_CKPOL | STM32_LPTIM_PRESC; + u32 val; + + /* Setup LP timer encoder/counter and polarity, without prescaler */ + if (priv->quadrature_mode) + val = enable ? STM32_LPTIM_ENC : 0; + else + val = enable ? STM32_LPTIM_COUNTMODE : 0; + val |= FIELD_PREP(STM32_LPTIM_CKPOL, enable ? priv->polarity : 0); + + return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val); +} + +static int stm32_lptim_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct stm32_lptim_cnt *priv = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_ENABLE: + if (val < 0 || val > 1) + return -EINVAL; + + /* Check nobody uses the timer, or already disabled/enabled */ + ret = stm32_lptim_is_enabled(priv); + if ((ret < 0) || (!ret && !val)) + return ret; + if (val && ret) + return -EBUSY; + + ret = stm32_lptim_setup(priv, val); + if (ret) + return ret; + return stm32_lptim_set_enable_state(priv, val); + + default: + return -EINVAL; + } +} + +static int stm32_lptim_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct stm32_lptim_cnt *priv = iio_priv(indio_dev); + u32 dat; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &dat); + if (ret) + return ret; + *val = dat; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_ENABLE: + ret = stm32_lptim_is_enabled(priv); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + /* Non-quadrature mode: scale = 1 */ + *val = 1; + *val2 = 0; + if (priv->quadrature_mode) { + /* + * Quadrature encoder mode: + * - both edges, quarter cycle, scale is 0.25 + * - either rising/falling edge scale is 0.5 + */ + if (priv->polarity > 1) + *val2 = 2; + else + *val2 = 1; + } + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } +} + +static const struct iio_info stm32_lptim_cnt_iio_info = { + .read_raw = stm32_lptim_read_raw, + .write_raw = stm32_lptim_write_raw, + .driver_module = THIS_MODULE, +}; + +static const char *const stm32_lptim_quadrature_modes[] = { + "non-quadrature", + "quadrature", +}; + +static int stm32_lptim_get_quadrature_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct stm32_lptim_cnt *priv = iio_priv(indio_dev); + + return priv->quadrature_mode; +} + +static int stm32_lptim_set_quadrature_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int type) +{ + struct stm32_lptim_cnt *priv = iio_priv(indio_dev); + + if (stm32_lptim_is_enabled(priv)) + return -EBUSY; + + priv->quadrature_mode = type; + + return 0; +} + +static const struct iio_enum stm32_lptim_quadrature_mode_en = { + .items = stm32_lptim_quadrature_modes, + .num_items = ARRAY_SIZE(stm32_lptim_quadrature_modes), + .get = stm32_lptim_get_quadrature_mode, + .set = stm32_lptim_set_quadrature_mode, +}; + +static const char * const stm32_lptim_cnt_polarity[] = { + "rising-edge", "falling-edge", "both-edges", +}; + +static int stm32_lptim_cnt_get_polarity(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct stm32_lptim_cnt *priv = iio_priv(indio_dev); + + return priv->polarity; +} + +static int stm32_lptim_cnt_set_polarity(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int type) +{ + struct stm32_lptim_cnt *priv = iio_priv(indio_dev); + + if (stm32_lptim_is_enabled(priv)) + return -EBUSY; + + priv->polarity = type; + + return 0; +} + +static const struct iio_enum stm32_lptim_cnt_polarity_en = { + .items = stm32_lptim_cnt_polarity, + .num_items = ARRAY_SIZE(stm32_lptim_cnt_polarity), + .get = stm32_lptim_cnt_get_polarity, + .set = stm32_lptim_cnt_set_polarity, +}; + +static ssize_t stm32_lptim_cnt_get_preset(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct stm32_lptim_cnt *priv = iio_priv(indio_dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset); +} + +static ssize_t stm32_lptim_cnt_set_preset(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct stm32_lptim_cnt *priv = iio_priv(indio_dev); + int ret; + + if (stm32_lptim_is_enabled(priv)) + return -EBUSY; + + ret = kstrtouint(buf, 0, &priv->preset); + if (ret) + return ret; + + if (priv->preset > STM32_LPTIM_MAX_ARR) + return -EINVAL; + + return len; +} + +/* LP timer with encoder */ +static const struct iio_chan_spec_ext_info stm32_lptim_enc_ext_info[] = { + { + .name = "preset", + .shared = IIO_SEPARATE, + .read = stm32_lptim_cnt_get_preset, + .write = stm32_lptim_cnt_set_preset, + }, + IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), + IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), + IIO_ENUM("quadrature_mode", IIO_SEPARATE, + &stm32_lptim_quadrature_mode_en), + IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_lptim_quadrature_mode_en), + {} +}; + +static const struct iio_chan_spec stm32_lptim_enc_channels = { + .type = IIO_COUNT, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_ENABLE) | + BIT(IIO_CHAN_INFO_SCALE), + .ext_info = stm32_lptim_enc_ext_info, + .indexed = 1, +}; + +/* LP timer without encoder (counter only) */ +static const struct iio_chan_spec_ext_info stm32_lptim_cnt_ext_info[] = { + { + .name = "preset", + .shared = IIO_SEPARATE, + .read = stm32_lptim_cnt_get_preset, + .write = stm32_lptim_cnt_set_preset, + }, + IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), + IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), + {} +}; + +static const struct iio_chan_spec stm32_lptim_cnt_channels = { + .type = IIO_COUNT, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_ENABLE) | + BIT(IIO_CHAN_INFO_SCALE), + .ext_info = stm32_lptim_cnt_ext_info, + .indexed = 1, +}; + +static int stm32_lptim_cnt_probe(struct platform_device *pdev) +{ + struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); + struct stm32_lptim_cnt *priv; + struct iio_dev *indio_dev; + + if (IS_ERR_OR_NULL(ddata)) + return -EINVAL; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + priv = iio_priv(indio_dev); + priv->dev = &pdev->dev; + priv->regmap = ddata->regmap; + priv->clk = ddata->clk; + priv->preset = STM32_LPTIM_MAX_ARR; + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->info = &stm32_lptim_cnt_iio_info; + if (ddata->has_encoder) + indio_dev->channels = &stm32_lptim_enc_channels; + else + indio_dev->channels = &stm32_lptim_cnt_channels; + indio_dev->num_channels = 1; + + platform_set_drvdata(pdev, priv); + + return devm_iio_device_register(&pdev->dev, indio_dev); +} + +static const struct of_device_id stm32_lptim_cnt_of_match[] = { + { .compatible = "st,stm32-lptimer-counter", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_lptim_cnt_of_match); + +static struct platform_driver stm32_lptim_cnt_driver = { + .probe = stm32_lptim_cnt_probe, + .driver = { + .name = "stm32-lptimer-counter", + .of_match_table = stm32_lptim_cnt_of_match, + }, +}; +module_platform_driver(stm32_lptim_cnt_driver); + +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); +MODULE_ALIAS("platform:stm32-lptimer-counter"); +MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig index e4d4e63434db..a633d2c8e805 100644 --- a/drivers/iio/trigger/Kconfig +++ b/drivers/iio/trigger/Kconfig @@ -24,6 +24,17 @@ config IIO_INTERRUPT_TRIGGER To compile this driver as a module, choose M here: the module will be called iio-trig-interrupt. +config IIO_STM32_LPTIMER_TRIGGER + tristate "STM32 Low-Power Timer Trigger" + depends on MFD_STM32_LPTIMER || COMPILE_TEST + help + Select this option to enable STM32 Low-Power Timer Trigger. + This can be used as trigger source for STM32 internal ADC + and/or DAC. + + To compile this driver as a module, choose M here: the + module will be called stm32-lptimer-trigger. + config IIO_STM32_TIMER_TRIGGER tristate "STM32 Timer Trigger" depends on (ARCH_STM32 && OF && MFD_STM32_TIMERS) || COMPILE_TEST diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile index 5c4ecd380653..0a72a2a76cb2 100644 --- a/drivers/iio/trigger/Makefile +++ b/drivers/iio/trigger/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o +obj-$(CONFIG_IIO_STM32_LPTIMER_TRIGGER) += stm32-lptimer-trigger.o obj-$(CONFIG_IIO_STM32_TIMER_TRIGGER) += stm32-timer-trigger.o obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o obj-$(CONFIG_IIO_TIGHTLOOP_TRIGGER) += iio-trig-loop.o diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c new file mode 100644 index 000000000000..241eae6a4306 --- /dev/null +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c @@ -0,0 +1,118 @@ +/* + * STM32 Low-Power Timer Trigger driver + * + * Copyright (C) STMicroelectronics 2017 + * + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>. + * + * License terms: GNU General Public License (GPL), version 2 + * + * Inspired by Benjamin Gaignard's stm32-timer-trigger driver + */ + +#include <linux/iio/timer/stm32-lptim-trigger.h> +#include <linux/mfd/stm32-lptimer.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +/* List Low-Power Timer triggers */ +static const char * const stm32_lptim_triggers[] = { + LPTIM1_OUT, + LPTIM2_OUT, + LPTIM3_OUT, +}; + +struct stm32_lptim_trigger { + struct device *dev; + const char *trg; +}; + +static int stm32_lptim_validate_device(struct iio_trigger *trig, + struct iio_dev *indio_dev) +{ + if (indio_dev->modes & INDIO_HARDWARE_TRIGGERED) + return 0; + + return -EINVAL; +} + +static const struct iio_trigger_ops stm32_lptim_trigger_ops = { + .owner = THIS_MODULE, + .validate_device = stm32_lptim_validate_device, +}; + +/** + * is_stm32_lptim_trigger + * @trig: trigger to be checked + * + * return true if the trigger is a valid STM32 IIO Low-Power Timer Trigger + * either return false + */ +bool is_stm32_lptim_trigger(struct iio_trigger *trig) +{ + return (trig->ops == &stm32_lptim_trigger_ops); +} +EXPORT_SYMBOL(is_stm32_lptim_trigger); + +static int stm32_lptim_setup_trig(struct stm32_lptim_trigger *priv) +{ + struct iio_trigger *trig; + + trig = devm_iio_trigger_alloc(priv->dev, "%s", priv->trg); + if (!trig) + return -ENOMEM; + + trig->dev.parent = priv->dev->parent; + trig->ops = &stm32_lptim_trigger_ops; + iio_trigger_set_drvdata(trig, priv); + + return devm_iio_trigger_register(priv->dev, trig); +} + +static int stm32_lptim_trigger_probe(struct platform_device *pdev) +{ + struct stm32_lptim_trigger *priv; + u32 index; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + if (of_property_read_u32(pdev->dev.of_node, "reg", &index)) + return -EINVAL; + + if (index >= ARRAY_SIZE(stm32_lptim_triggers)) + return -EINVAL; + + priv->dev = &pdev->dev; + priv->trg = stm32_lptim_triggers[index]; + + ret = stm32_lptim_setup_trig(priv); + if (ret) + return ret; + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static const struct of_device_id stm32_lptim_trig_of_match[] = { + { .compatible = "st,stm32-lptimer-trigger", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_lptim_trig_of_match); + +static struct platform_driver stm32_lptim_trigger_driver = { + .probe = stm32_lptim_trigger_probe, + .driver = { + .name = "stm32-lptimer-trigger", + .of_match_table = stm32_lptim_trig_of_match, + }, +}; +module_platform_driver(stm32_lptim_trigger_driver); + +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); +MODULE_ALIAS("platform:stm32-lptimer-trigger"); +MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM trigger driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 39e72b3219d8..f9f98ef1d98e 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -30,7 +30,7 @@ #include <linux/interrupt.h> #include <linux/input.h> #include <linux/platform_device.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/slab.h> #include <linux/of.h> diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index bab256ef32b9..c803db64a376 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -15,7 +15,7 @@ #include <linux/platform_device.h> #include <linux/interrupt.h> -#include <linux/i2c/dm355evm_msp.h> +#include <linux/mfd/dm355evm_msp.h> #include <linux/module.h> diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index 1c13005b228f..b307cca17022 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -27,7 +27,7 @@ #include <linux/input.h> #include <linux/interrupt.h> #include <linux/platform_device.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #define PWR_PWRON_IRQ (1 << 0) diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index caa5a62c42fb..6c51d404874b 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -28,7 +28,7 @@ #include <linux/platform_device.h> #include <linux/of.h> #include <linux/workqueue.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/mfd/twl4030-audio.h> #include <linux/input.h> #include <linux/slab.h> diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index ebf69ff48ae2..c00a7c7f460a 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -51,6 +51,7 @@ struct atmel_ebi { struct { struct regmap *regmap; struct clk *clk; + const struct atmel_hsmc_reg_layout *layout; } smc; struct device *dev; @@ -84,8 +85,8 @@ static void at91sam9_ebi_get_config(struct atmel_ebi_dev *ebid, static void sama5_ebi_get_config(struct atmel_ebi_dev *ebid, struct atmel_ebi_dev_config *conf) { - atmel_hsmc_cs_conf_get(ebid->ebi->smc.regmap, conf->cs, - &conf->smcconf); + atmel_hsmc_cs_conf_get(ebid->ebi->smc.regmap, ebid->ebi->smc.layout, + conf->cs, &conf->smcconf); } static const struct atmel_smc_timing_xlate timings_xlate_table[] = { @@ -287,8 +288,8 @@ static void at91sam9_ebi_apply_config(struct atmel_ebi_dev *ebid, static void sama5_ebi_apply_config(struct atmel_ebi_dev *ebid, struct atmel_ebi_dev_config *conf) { - atmel_hsmc_cs_conf_apply(ebid->ebi->smc.regmap, conf->cs, - &conf->smcconf); + atmel_hsmc_cs_conf_apply(ebid->ebi->smc.regmap, ebid->ebi->smc.layout, + conf->cs, &conf->smcconf); } static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np, @@ -527,6 +528,10 @@ static int atmel_ebi_probe(struct platform_device *pdev) if (IS_ERR(ebi->smc.regmap)) return PTR_ERR(ebi->smc.regmap); + ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np); + if (IS_ERR(ebi->smc.layout)) + return PTR_ERR(ebi->smc.layout); + ebi->smc.clk = of_clk_get(smc_np, 0); if (IS_ERR(ebi->smc.clk)) { if (PTR_ERR(ebi->smc.clk) != -ENOENT) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 94ad2c1c3d90..fc5e4fef89d2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -133,6 +133,20 @@ config MFD_BCM590XX help Support for the BCM590xx PMUs from Broadcom +config MFD_BD9571MWV + tristate "ROHM BD9571MWV PMIC" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C + help + Support for the ROHM BD9571MWV PMIC, which contains single + voltage regulator, voltage sampling units, GPIO block and + watchdog block. + + This driver can also be built as a module. If so, the module + will be called bd9571mwv. + config MFD_AC100 tristate "X-Powers AC100" select MFD_CORE @@ -453,12 +467,12 @@ config LPC_SCH config INTEL_SOC_PMIC bool "Support for Crystal Cove PMIC" - depends on HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK + depends on ACPI && HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK depends on X86 || COMPILE_TEST select MFD_CORE select REGMAP_I2C select REGMAP_IRQ - select I2C_DESIGNWARE_PLATFORM if ACPI + select I2C_DESIGNWARE_PLATFORM help Select this option to enable support for Crystal Cove PMIC on some Intel SoC systems. The PMIC provides ADC, GPIO, @@ -481,7 +495,7 @@ config INTEL_SOC_PMIC_BXTWC on these systems. config INTEL_SOC_PMIC_CHTWC - tristate "Support for Intel Cherry Trail Whiskey Cove PMIC" + bool "Support for Intel Cherry Trail Whiskey Cove PMIC" depends on ACPI && HAS_IOMEM && I2C=y && COMMON_CLK depends on X86 || COMPILE_TEST select MFD_CORE @@ -951,13 +965,13 @@ config MFD_RC5T583 different functionality of the device. config MFD_RK808 - tristate "Rockchip RK808/RK818 Power Management Chip" + tristate "Rockchip RK805/RK808/RK818 Power Management Chip" depends on I2C && OF select MFD_CORE select REGMAP_I2C select REGMAP_IRQ help - If you say yes here you get support for the RK808 and RK818 + If you say yes here you get support for the RK805, RK808 and RK818 Power Management chips. This driver provides common support for accessing the device through I2C interface. The device supports multiple sub-devices @@ -1294,6 +1308,7 @@ config TPS6507X config MFD_TPS65086 tristate "TI TPS65086 Power Management Integrated Chips (PMICs)" + select MFD_CORE select REGMAP select REGMAP_IRQ select REGMAP_I2C @@ -1337,6 +1352,24 @@ config MFD_TPS65217 This driver can also be built as a module. If so, the module will be called tps65217. +config MFD_TPS68470 + bool "TI TPS68470 Power Management / LED chips" + depends on ACPI && I2C=y + select MFD_CORE + select REGMAP_I2C + select I2C_DESIGNWARE_PLATFORM + help + If you say yes here you get support for the TPS68470 series of + Power Management / LED chips. + + These include voltage regulators, LEDs and other features + that are often used in portable devices. + + This option is a bool as it provides an ACPI operation + region, which must be available before any of the devices + using this are probed. This option also configures the + designware-i2c driver to be built-in, for the same reason. + config MFD_TI_LP873X tristate "TI LP873X Power Management IC" depends on I2C @@ -1723,6 +1756,20 @@ config MFD_STW481X in various ST Microelectronics and ST-Ericsson embedded Nomadik series. +config MFD_STM32_LPTIMER + tristate "Support for STM32 Low-Power Timer" + depends on (ARCH_STM32 && OF) || COMPILE_TEST + select MFD_CORE + select REGMAP + select REGMAP_MMIO + help + Select this option to enable STM32 Low-Power Timer driver + used for PWM, IIO Trigger, IIO Encoder and Counter. Shared + resources are also dealt with here. + + To compile this driver as a module, choose M here: the + module will be called stm32-lptimer. + config MFD_STM32_TIMERS tristate "Support for STM32 Timers" depends on (ARCH_STM32 && OF) || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 080793b3fd0e..c3d0a1b39bb6 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_ACT8945A) += act8945a.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o +obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o cros_ec_core-objs := cros_ec.o cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o @@ -83,6 +84,7 @@ obj-$(CONFIG_MFD_TPS65910) += tps65910.o obj-$(CONFIG_MFD_TPS65912) += tps65912-core.o obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o +obj-$(CONFIG_MFD_TPS68470) += tps68470.o obj-$(CONFIG_MFD_TPS80031) += tps80031.o obj-$(CONFIG_MENELAUS) += menelaus.o @@ -221,5 +223,6 @@ obj-$(CONFIG_MFD_MT6397) += mt6397-core.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o +obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 8511c068a610..30d09d177171 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1059,15 +1059,15 @@ static struct attribute *ab9540_sysfs_entries[] = { NULL, }; -static struct attribute_group ab8500_attr_group = { +static const struct attribute_group ab8500_attr_group = { .attrs = ab8500_sysfs_entries, }; -static struct attribute_group ab8505_attr_group = { +static const struct attribute_group ab8505_attr_group = { .attrs = ab8505_sysfs_entries, }; -static struct attribute_group ab9540_attr_group = { +static const struct attribute_group ab9540_attr_group = { .attrs = ab9540_sysfs_entries, }; diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index 20cc0ea470fa..7d77948567d7 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -258,19 +258,21 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply); * atmel_hsmc_cs_conf_apply - apply an SMC CS conf * @regmap: the HSMC regmap * @cs: the CS id + * @layout: the layout of registers * @conf the SMC CS conf to apply * * Applies an SMC CS configuration. * Only valid on post-sama5 SoCs. */ -void atmel_hsmc_cs_conf_apply(struct regmap *regmap, int cs, - const struct atmel_smc_cs_conf *conf) +void atmel_hsmc_cs_conf_apply(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *layout, + int cs, const struct atmel_smc_cs_conf *conf) { - regmap_write(regmap, ATMEL_HSMC_SETUP(cs), conf->setup); - regmap_write(regmap, ATMEL_HSMC_PULSE(cs), conf->pulse); - regmap_write(regmap, ATMEL_HSMC_CYCLE(cs), conf->cycle); - regmap_write(regmap, ATMEL_HSMC_TIMINGS(cs), conf->timings); - regmap_write(regmap, ATMEL_HSMC_MODE(cs), conf->mode); + regmap_write(regmap, ATMEL_HSMC_SETUP(layout, cs), conf->setup); + regmap_write(regmap, ATMEL_HSMC_PULSE(layout, cs), conf->pulse); + regmap_write(regmap, ATMEL_HSMC_CYCLE(layout, cs), conf->cycle); + regmap_write(regmap, ATMEL_HSMC_TIMINGS(layout, cs), conf->timings); + regmap_write(regmap, ATMEL_HSMC_MODE(layout, cs), conf->mode); } EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply); @@ -297,18 +299,55 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get); * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf * @regmap: the HSMC regmap * @cs: the CS id + * @layout: the layout of registers * @conf: the SMC CS conf object to store the current conf * * Retrieve the SMC CS configuration. * Only valid on post-sama5 SoCs. */ -void atmel_hsmc_cs_conf_get(struct regmap *regmap, int cs, - struct atmel_smc_cs_conf *conf) +void atmel_hsmc_cs_conf_get(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *layout, + int cs, struct atmel_smc_cs_conf *conf) { - regmap_read(regmap, ATMEL_HSMC_SETUP(cs), &conf->setup); - regmap_read(regmap, ATMEL_HSMC_PULSE(cs), &conf->pulse); - regmap_read(regmap, ATMEL_HSMC_CYCLE(cs), &conf->cycle); - regmap_read(regmap, ATMEL_HSMC_TIMINGS(cs), &conf->timings); - regmap_read(regmap, ATMEL_HSMC_MODE(cs), &conf->mode); + regmap_read(regmap, ATMEL_HSMC_SETUP(layout, cs), &conf->setup); + regmap_read(regmap, ATMEL_HSMC_PULSE(layout, cs), &conf->pulse); + regmap_read(regmap, ATMEL_HSMC_CYCLE(layout, cs), &conf->cycle); + regmap_read(regmap, ATMEL_HSMC_TIMINGS(layout, cs), &conf->timings); + regmap_read(regmap, ATMEL_HSMC_MODE(layout, cs), &conf->mode); } EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get); + +static const struct atmel_hsmc_reg_layout sama5d3_reg_layout = { + .timing_regs_offset = 0x600, +}; + +static const struct atmel_hsmc_reg_layout sama5d2_reg_layout = { + .timing_regs_offset = 0x700, +}; + +static const struct of_device_id atmel_smc_ids[] = { + { .compatible = "atmel,at91sam9260-smc", .data = NULL }, + { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout }, + { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout }, + { /* sentinel */ }, +}; + +/** + * atmel_hsmc_get_reg_layout - retrieve the layout of HSMC registers + * @np: the HSMC regmap + * + * Retrieve the layout of HSMC registers. + * + * Returns NULL in case of SMC, a struct atmel_hsmc_reg_layout pointer + * in HSMC case, otherwise ERR_PTR(-EINVAL). + */ +const struct atmel_hsmc_reg_layout * +atmel_hsmc_get_reg_layout(struct device_node *np) +{ + const struct of_device_id *match; + + match = of_match_node(atmel_smc_ids, np); + + return match ? match->data : ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(atmel_hsmc_get_reg_layout); diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c index fd5c7267b136..7ddbd9e8dd03 100644 --- a/drivers/mfd/axp20x-rsb.c +++ b/drivers/mfd/axp20x-rsb.c @@ -64,6 +64,7 @@ static const struct of_device_id axp20x_rsb_of_match[] = { { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID }, { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, { .compatible = "x-powers,axp809", .data = (void *)AXP809_ID }, + { .compatible = "x-powers,axp813", .data = (void *)AXP813_ID }, { }, }; MODULE_DEVICE_TABLE(of, axp20x_rsb_of_match); diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 917b6ddc4f15..336de66ca408 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -44,6 +44,7 @@ static const char * const axp20x_model_names[] = { "AXP803", "AXP806", "AXP809", + "AXP813", }; static const struct regmap_range axp152_writeable_ranges[] = { @@ -676,7 +677,7 @@ static struct mfd_cell axp20x_cells[] = { static struct mfd_cell axp221_cells[] = { { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp22x_pek_resources), .resources = axp22x_pek_resources, }, { @@ -701,7 +702,7 @@ static struct mfd_cell axp221_cells[] = { static struct mfd_cell axp223_cells[] = { { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp22x_pek_resources), .resources = axp22x_pek_resources, }, { @@ -834,7 +835,7 @@ static struct mfd_cell axp288_cells[] = { .resources = axp288_fuel_gauge_resources, }, { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp288_power_button_resources), .resources = axp288_power_button_resources, }, @@ -845,7 +846,7 @@ static struct mfd_cell axp288_cells[] = { static struct mfd_cell axp803_cells[] = { { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp803_pek_resources), .resources = axp803_pek_resources, }, @@ -861,7 +862,7 @@ static struct mfd_cell axp806_cells[] = { static struct mfd_cell axp809_cells[] = { { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp809_pek_resources), .resources = axp809_pek_resources, }, { @@ -870,6 +871,14 @@ static struct mfd_cell axp809_cells[] = { }, }; +static struct mfd_cell axp813_cells[] = { + { + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp803_pek_resources), + .resources = axp803_pek_resources, + } +}; + static struct axp20x_dev *axp20x_pm_power_off; static void axp20x_power_off(void) { @@ -956,6 +965,19 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_cfg = &axp22x_regmap_config; axp20x->regmap_irq_chip = &axp809_regmap_irq_chip; break; + case AXP813_ID: + axp20x->nr_cells = ARRAY_SIZE(axp813_cells); + axp20x->cells = axp813_cells; + axp20x->regmap_cfg = &axp288_regmap_config; + /* + * The IRQ table given in the datasheet is incorrect. + * In IRQ enable/status registers 1, there are separate + * IRQs for ACIN and VBUS, instead of bits [7:5] being + * the same as bits [4:2]. So it shares the same IRQs + * as the AXP803, rather than the AXP288. + */ + axp20x->regmap_irq_chip = &axp803_regmap_irq_chip; + break; default: dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); return -EINVAL; diff --git a/drivers/mfd/bd9571mwv.c b/drivers/mfd/bd9571mwv.c new file mode 100644 index 000000000000..64e088dfe7b0 --- /dev/null +++ b/drivers/mfd/bd9571mwv.c @@ -0,0 +1,230 @@ +/* + * ROHM BD9571MWV-M MFD driver + * + * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether expressed or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + * + * Based on the TPS65086 driver + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mfd/core.h> +#include <linux/module.h> + +#include <linux/mfd/bd9571mwv.h> + +static const struct mfd_cell bd9571mwv_cells[] = { + { .name = "bd9571mwv-regulator", }, + { .name = "bd9571mwv-gpio", }, +}; + +static const struct regmap_range bd9571mwv_readable_yes_ranges[] = { + regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION), + regmap_reg_range(BD9571MWV_AVS_SET_MONI, BD9571MWV_AVS_DVFS_VID(3)), + regmap_reg_range(BD9571MWV_VD18_VID, BD9571MWV_VD33_VID), + regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_VINIT), + regmap_reg_range(BD9571MWV_DVFS_SETVMAX, BD9571MWV_DVFS_MONIVDAC), + regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN), + regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INTMASK), + regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK), +}; + +static const struct regmap_access_table bd9571mwv_readable_table = { + .yes_ranges = bd9571mwv_readable_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(bd9571mwv_readable_yes_ranges), +}; + +static const struct regmap_range bd9571mwv_writable_yes_ranges[] = { + regmap_reg_range(BD9571MWV_AVS_VD09_VID(0), BD9571MWV_AVS_VD09_VID(3)), + regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID), + regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT), + regmap_reg_range(BD9571MWV_GPIO_INT_SET, BD9571MWV_GPIO_INTMASK), + regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK), +}; + +static const struct regmap_access_table bd9571mwv_writable_table = { + .yes_ranges = bd9571mwv_writable_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(bd9571mwv_writable_yes_ranges), +}; + +static const struct regmap_range bd9571mwv_volatile_yes_ranges[] = { + regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN), + regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT), + regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ), +}; + +static const struct regmap_access_table bd9571mwv_volatile_table = { + .yes_ranges = bd9571mwv_volatile_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(bd9571mwv_volatile_yes_ranges), +}; + +static const struct regmap_config bd9571mwv_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .rd_table = &bd9571mwv_readable_table, + .wr_table = &bd9571mwv_writable_table, + .volatile_table = &bd9571mwv_volatile_table, + .max_register = 0xff, +}; + +static const struct regmap_irq bd9571mwv_irqs[] = { + REGMAP_IRQ_REG(BD9571MWV_IRQ_MD1, 0, + BD9571MWV_INT_INTREQ_MD1_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E1, 0, + BD9571MWV_INT_INTREQ_MD2_E1_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E2, 0, + BD9571MWV_INT_INTREQ_MD2_E2_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_PROT_ERR, 0, + BD9571MWV_INT_INTREQ_PROT_ERR_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_GP, 0, + BD9571MWV_INT_INTREQ_GP_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_128H_OF, 0, + BD9571MWV_INT_INTREQ_128H_OF_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_WDT_OF, 0, + BD9571MWV_INT_INTREQ_WDT_OF_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_BKUP_TRG, 0, + BD9571MWV_INT_INTREQ_BKUP_TRG_INT), +}; + +static struct regmap_irq_chip bd9571mwv_irq_chip = { + .name = "bd9571mwv", + .status_base = BD9571MWV_INT_INTREQ, + .mask_base = BD9571MWV_INT_INTMASK, + .ack_base = BD9571MWV_INT_INTREQ, + .init_ack_masked = true, + .num_regs = 1, + .irqs = bd9571mwv_irqs, + .num_irqs = ARRAY_SIZE(bd9571mwv_irqs), +}; + +static int bd9571mwv_identify(struct bd9571mwv *bd) +{ + struct device *dev = bd->dev; + unsigned int value; + int ret; + + ret = regmap_read(bd->regmap, BD9571MWV_VENDOR_CODE, &value); + if (ret) { + dev_err(dev, "Failed to read vendor code register (ret=%i)\n", + ret); + return ret; + } + + if (value != BD9571MWV_VENDOR_CODE_VAL) { + dev_err(dev, "Invalid vendor code ID %02x (expected %02x)\n", + value, BD9571MWV_VENDOR_CODE_VAL); + return -EINVAL; + } + + ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_CODE, &value); + if (ret) { + dev_err(dev, "Failed to read product code register (ret=%i)\n", + ret); + return ret; + } + + if (value != BD9571MWV_PRODUCT_CODE_VAL) { + dev_err(dev, "Invalid product code ID %02x (expected %02x)\n", + value, BD9571MWV_PRODUCT_CODE_VAL); + return -EINVAL; + } + + ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_REVISION, &value); + if (ret) { + dev_err(dev, "Failed to read revision register (ret=%i)\n", + ret); + return ret; + } + + dev_info(dev, "Device: BD9571MWV rev. %d\n", value & 0xff); + + return 0; +} + +static int bd9571mwv_probe(struct i2c_client *client, + const struct i2c_device_id *ids) +{ + struct bd9571mwv *bd; + int ret; + + bd = devm_kzalloc(&client->dev, sizeof(*bd), GFP_KERNEL); + if (!bd) + return -ENOMEM; + + i2c_set_clientdata(client, bd); + bd->dev = &client->dev; + bd->irq = client->irq; + + bd->regmap = devm_regmap_init_i2c(client, &bd9571mwv_regmap_config); + if (IS_ERR(bd->regmap)) { + dev_err(bd->dev, "Failed to initialize register map\n"); + return PTR_ERR(bd->regmap); + } + + ret = bd9571mwv_identify(bd); + if (ret) + return ret; + + ret = regmap_add_irq_chip(bd->regmap, bd->irq, IRQF_ONESHOT, 0, + &bd9571mwv_irq_chip, &bd->irq_data); + if (ret) { + dev_err(bd->dev, "Failed to register IRQ chip\n"); + return ret; + } + + ret = mfd_add_devices(bd->dev, PLATFORM_DEVID_AUTO, bd9571mwv_cells, + ARRAY_SIZE(bd9571mwv_cells), NULL, 0, + regmap_irq_get_domain(bd->irq_data)); + if (ret) { + regmap_del_irq_chip(bd->irq, bd->irq_data); + return ret; + } + + return 0; +} + +static int bd9571mwv_remove(struct i2c_client *client) +{ + struct bd9571mwv *bd = i2c_get_clientdata(client); + + regmap_del_irq_chip(bd->irq, bd->irq_data); + + return 0; +} + +static const struct of_device_id bd9571mwv_of_match_table[] = { + { .compatible = "rohm,bd9571mwv", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table); + +static const struct i2c_device_id bd9571mwv_id_table[] = { + { "bd9571mwv", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, bd9571mwv_id_table); + +static struct i2c_driver bd9571mwv_driver = { + .driver = { + .name = "bd9571mwv", + .of_match_table = bd9571mwv_of_match_table, + }, + .probe = bd9571mwv_probe, + .remove = bd9571mwv_remove, + .id_table = bd9571mwv_id_table, +}; +module_i2c_driver(bd9571mwv_driver); + +MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>"); +MODULE_DESCRIPTION("BD9571MWV PMIC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index a23a3a1c7061..433add43a0a9 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -387,6 +387,8 @@ int da9052_adc_manual_read(struct da9052 *da9052, unsigned char channel) mutex_lock(&da9052->auxadc_lock); + reinit_completion(&da9052->done); + /* Channel gets activated on enabling the Conversion bit */ mux_sel = chan_mux[channel] | DA9052_ADC_MAN_MAN_CONV; diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index b9ea1b27db64..abfb11818fdc 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -67,7 +67,7 @@ static int da9052_spi_remove(struct spi_device *spi) return 0; } -static struct spi_device_id da9052_spi_id[] = { +static const struct spi_device_id da9052_spi_id[] = { {"da9052", DA9052}, {"da9053-aa", DA9053_AA}, {"da9053-ba", DA9053_BA}, diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index b53e100f577c..8169a5c2fa20 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -62,7 +62,7 @@ static int da9055_i2c_remove(struct i2c_client *i2c) * purposes separate). As a result there are specific DA9055 ids for PMIC * and CODEC, which must be different to operate together. */ -static struct i2c_device_id da9055_i2c_id[] = { +static const struct i2c_device_id da9055_i2c_id[] = { {"da9055-pmic", 0}, { } }; diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 86eca614507b..2a2756709f22 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -18,7 +18,7 @@ #include <linux/gpio.h> #include <linux/leds.h> #include <linux/i2c.h> -#include <linux/i2c/dm355evm_msp.h> +#include <linux/mfd/dm355evm_msp.h> /* diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c index 3fd703fe3aba..6fb7ba272e09 100644 --- a/drivers/mfd/hi6421-pmic-core.c +++ b/drivers/mfd/hi6421-pmic-core.c @@ -1,40 +1,35 @@ /* - * Device driver for Hi6421 IC + * Device driver for Hi6421 PMIC * * Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd. * http://www.hisilicon.com - * Copyright (c) <2013-2014> Linaro Ltd. + * Copyright (c) <2013-2017> 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 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 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/>. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include <linux/device.h> #include <linux/err.h> #include <linux/mfd/core.h> +#include <linux/mfd/hi6421-pmic.h> #include <linux/module.h> -#include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> -#include <linux/mfd/hi6421-pmic.h> static const struct mfd_cell hi6421_devs[] = { { .name = "hi6421-regulator", }, }; +static const struct mfd_cell hi6421v530_devs[] = { + { .name = "hi6421v530-regulator", }, +}; + static const struct regmap_config hi6421_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -42,12 +37,33 @@ static const struct regmap_config hi6421_regmap_config = { .max_register = HI6421_REG_TO_BUS_ADDR(HI6421_REG_MAX), }; +static const struct of_device_id of_hi6421_pmic_match[] = { + { + .compatible = "hisilicon,hi6421-pmic", + .data = (void *)HI6421 + }, + { + .compatible = "hisilicon,hi6421v530-pmic", + .data = (void *)HI6421_V530 + }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_hi6421_pmic_match); + static int hi6421_pmic_probe(struct platform_device *pdev) { struct hi6421_pmic *pmic; struct resource *res; + const struct of_device_id *id; + const struct mfd_cell *subdevs; + enum hi6421_type type; void __iomem *base; - int ret; + int n_subdevs, ret; + + id = of_match_device(of_hi6421_pmic_match, &pdev->dev); + if (!id) + return -EINVAL; + type = (enum hi6421_type)id->data; pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) @@ -61,41 +77,50 @@ static int hi6421_pmic_probe(struct platform_device *pdev) pmic->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base, &hi6421_regmap_config); if (IS_ERR(pmic->regmap)) { - dev_err(&pdev->dev, - "regmap init failed: %ld\n", PTR_ERR(pmic->regmap)); + dev_err(&pdev->dev, "Failed to initialise Regmap: %ld\n", + PTR_ERR(pmic->regmap)); return PTR_ERR(pmic->regmap); } - /* set over-current protection debounce 8ms */ - regmap_update_bits(pmic->regmap, HI6421_OCP_DEB_CTRL_REG, + platform_set_drvdata(pdev, pmic); + + switch (type) { + case HI6421: + /* set over-current protection debounce 8ms */ + regmap_update_bits(pmic->regmap, HI6421_OCP_DEB_CTRL_REG, (HI6421_OCP_DEB_SEL_MASK | HI6421_OCP_EN_DEBOUNCE_MASK | HI6421_OCP_AUTO_STOP_MASK), (HI6421_OCP_DEB_SEL_8MS | HI6421_OCP_EN_DEBOUNCE_ENABLE)); - platform_set_drvdata(pdev, pmic); + subdevs = hi6421_devs; + n_subdevs = ARRAY_SIZE(hi6421_devs); + break; + case HI6421_V530: + subdevs = hi6421v530_devs; + n_subdevs = ARRAY_SIZE(hi6421v530_devs); + break; + default: + dev_err(&pdev->dev, "Unknown device type %d\n", + (unsigned int)type); + return -EINVAL; + } - ret = devm_mfd_add_devices(&pdev->dev, 0, hi6421_devs, - ARRAY_SIZE(hi6421_devs), NULL, 0, NULL); + ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, + subdevs, n_subdevs, NULL, 0, NULL); if (ret) { - dev_err(&pdev->dev, "add mfd devices failed: %d\n", ret); + dev_err(&pdev->dev, "Failed to add child devices: %d\n", ret); return ret; } return 0; } -static const struct of_device_id of_hi6421_pmic_match_tbl[] = { - { .compatible = "hisilicon,hi6421-pmic", }, - { }, -}; -MODULE_DEVICE_TABLE(of, of_hi6421_pmic_match_tbl); - static struct platform_driver hi6421_pmic_driver = { .driver = { - .name = "hi6421_pmic", - .of_match_table = of_hi6421_pmic_match_tbl, + .name = "hi6421_pmic", + .of_match_table = of_hi6421_pmic_match, }, .probe = hi6421_pmic_probe, }; diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index ad388bb056cd..d1c46de89eb4 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -221,6 +221,7 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa162), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info }, /* KBL-H */ { PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&spt_uart_info }, diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 70c646b0097d..0e0ab9bb1530 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -502,6 +502,14 @@ int intel_lpss_suspend(struct device *dev) for (i = 0; i < LPSS_PRIV_REG_COUNT; i++) lpss->priv_ctx[i] = readl(lpss->priv + i * 4); + /* + * If the device type is not UART, then put the controller into + * reset. UART cannot be put into reset since S3/S0ix fail when + * no_console_suspend flag is enabled. + */ + if (lpss->type != LPSS_DEV_UART) + writel(0, lpss->priv + LPSS_PRIV_RESETS); + return 0; } EXPORT_SYMBOL_GPL(intel_lpss_suspend); diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index 13737be6df35..36adf9e8153e 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -16,6 +16,7 @@ * Author: Zhu, Lejun <lejun.zhu@linux.intel.com> */ +#include <linux/acpi.h> #include <linux/module.h> #include <linux/mfd/core.h> #include <linux/i2c.h> @@ -28,6 +29,10 @@ #include <linux/pwm.h> #include "intel_soc_pmic_core.h" +/* Crystal Cove PMIC shares same ACPI ID between different platforms */ +#define BYT_CRC_HRV 2 +#define CHT_CRC_HRV 3 + /* Lookup table for the Panel Enable/Disable line as GPIO signals */ static struct gpiod_lookup_table panel_gpio_table = { /* Intel GFX is consumer */ @@ -48,16 +53,33 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id) { struct device *dev = &i2c->dev; - const struct acpi_device_id *id; struct intel_soc_pmic_config *config; struct intel_soc_pmic *pmic; + unsigned long long hrv; + acpi_status status; int ret; - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id || !id->driver_data) + /* + * There are 2 different Crystal Cove PMICs a Bay Trail and Cherry + * Trail version, use _HRV to differentiate between the 2. + */ + status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Failed to get PMIC hardware revision\n"); return -ENODEV; - - config = (struct intel_soc_pmic_config *)id->driver_data; + } + + switch (hrv) { + case BYT_CRC_HRV: + config = &intel_soc_pmic_config_byt_crc; + break; + case CHT_CRC_HRV: + config = &intel_soc_pmic_config_cht_crc; + break; + default: + dev_warn(dev, "Unknown hardware rev %llu, assuming BYT\n", hrv); + config = &intel_soc_pmic_config_byt_crc; + } pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) @@ -157,7 +179,7 @@ MODULE_DEVICE_TABLE(i2c, intel_soc_pmic_i2c_id); #if defined(CONFIG_ACPI) static const struct acpi_device_id intel_soc_pmic_acpi_match[] = { - {"INT33FD", (kernel_ulong_t)&intel_soc_pmic_config_crc}, + { "INT33FD" }, { }, }; MODULE_DEVICE_TABLE(acpi, intel_soc_pmic_acpi_match); diff --git a/drivers/mfd/intel_soc_pmic_core.h b/drivers/mfd/intel_soc_pmic_core.h index ff2464bc172f..90a1416d4dac 100644 --- a/drivers/mfd/intel_soc_pmic_core.h +++ b/drivers/mfd/intel_soc_pmic_core.h @@ -27,6 +27,7 @@ struct intel_soc_pmic_config { const struct regmap_irq_chip *irq_chip; }; -extern struct intel_soc_pmic_config intel_soc_pmic_config_crc; +extern struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc; +extern struct intel_soc_pmic_config intel_soc_pmic_config_cht_crc; #endif /* __INTEL_SOC_PMIC_CORE_H__ */ diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 4a7494872da2..6d19a6d0fb97 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -80,7 +80,7 @@ static struct resource bcu_resources[] = { }, }; -static struct mfd_cell crystal_cove_dev[] = { +static struct mfd_cell crystal_cove_byt_dev[] = { { .name = "crystal_cove_pwrsrc", .num_resources = ARRAY_SIZE(pwrsrc_resources), @@ -114,6 +114,17 @@ static struct mfd_cell crystal_cove_dev[] = { }, }; +static struct mfd_cell crystal_cove_cht_dev[] = { + { + .name = "crystal_cove_gpio", + .num_resources = ARRAY_SIZE(gpio_resources), + .resources = gpio_resources, + }, + { + .name = "crystal_cove_pwm", + }, +}; + static const struct regmap_config crystal_cove_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -155,10 +166,18 @@ static const struct regmap_irq_chip crystal_cove_irq_chip = { .mask_base = CRYSTAL_COVE_REG_MIRQLVL1, }; -struct intel_soc_pmic_config intel_soc_pmic_config_crc = { +struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc = { + .irq_flags = IRQF_TRIGGER_RISING, + .cell_dev = crystal_cove_byt_dev, + .n_cell_devs = ARRAY_SIZE(crystal_cove_byt_dev), + .regmap_config = &crystal_cove_regmap_config, + .irq_chip = &crystal_cove_irq_chip, +}; + +struct intel_soc_pmic_config intel_soc_pmic_config_cht_crc = { .irq_flags = IRQF_TRIGGER_RISING, - .cell_dev = crystal_cove_dev, - .n_cell_devs = ARRAY_SIZE(crystal_cove_dev), + .cell_dev = crystal_cove_cht_dev, + .n_cell_devs = ARRAY_SIZE(crystal_cove_cht_dev), .regmap_config = &crystal_cove_regmap_config, .irq_chip = &crystal_cove_irq_chip, }; diff --git a/drivers/mfd/lp87565.c b/drivers/mfd/lp87565.c index 340ad0c63744..32d2a07d4354 100644 --- a/drivers/mfd/lp87565.c +++ b/drivers/mfd/lp87565.c @@ -73,10 +73,9 @@ static int lp87565_probe(struct i2c_client *client, i2c_set_clientdata(client, lp87565); - ret = mfd_add_devices(lp87565->dev, PLATFORM_DEVID_AUTO, lp87565_cells, - ARRAY_SIZE(lp87565_cells), NULL, 0, NULL); - - return ret; + return devm_mfd_add_devices(lp87565->dev, PLATFORM_DEVID_AUTO, + lp87565_cells, ARRAY_SIZE(lp87565_cells), + NULL, 0, NULL); } static const struct i2c_device_id lp87565_id_table[] = { diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 773f1554d2f9..450ae36645aa 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -1119,17 +1119,7 @@ static int lpc_ich_init_spi(struct pci_dev *dev) res->start = spi_base + SPIBASE_LPT; res->end = res->start + SPIBASE_LPT_SZ - 1; - /* - * Try to make the flash chip writeable now by - * setting BCR_WPD. It it fails we tell the driver - * that it can only read the chip. - */ pci_read_config_dword(dev, BCR, &bcr); - if (!(bcr & BCR_WPD)) { - bcr |= BCR_WPD; - pci_write_config_dword(dev, BCR, bcr); - pci_read_config_dword(dev, BCR, &bcr); - } info->writeable = !!(bcr & BCR_WPD); } break; diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 5c80aea3211f..10063236132c 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -151,7 +151,7 @@ static int max8925_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max8925_platform_data *pdata = dev_get_platdata(&client->dev); - static struct max8925_chip *chip; + struct max8925_chip *chip; struct device_node *node = client->dev.of_node; if (node && !pdata) { diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 4c33b8063bc3..b1d3f70782d9 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -192,10 +192,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) { pdata = max8998_i2c_parse_dt_pdata(&i2c->dev); - if (IS_ERR(pdata)) { - ret = PTR_ERR(pdata); - goto err; - } + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } i2c_set_clientdata(i2c, max8998); diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 6f5300b0eb31..44a5d66314c6 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -131,12 +131,12 @@ static inline u32 usbtll_read(void __iomem *base, u32 reg) return readl_relaxed(base + reg); } -static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val) +static inline void usbtll_writeb(void __iomem *base, u32 reg, u8 val) { writeb_relaxed(val, base + reg); } -static inline u8 usbtll_readb(void __iomem *base, u8 reg) +static inline u8 usbtll_readb(void __iomem *base, u32 reg) { return readb_relaxed(base + reg); } diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c index d4c114abeb75..e7d27b7861c1 100644 --- a/drivers/mfd/retu-mfd.c +++ b/drivers/mfd/retu-mfd.c @@ -302,15 +302,23 @@ static int retu_remove(struct i2c_client *i2c) } static const struct i2c_device_id retu_id[] = { - { "retu-mfd", 0 }, - { "tahvo-mfd", 0 }, + { "retu", 0 }, + { "tahvo", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, retu_id); +static const struct of_device_id retu_of_match[] = { + { .compatible = "nokia,retu" }, + { .compatible = "nokia,tahvo" }, + { } +}; +MODULE_DEVICE_TABLE(of, retu_of_match); + static struct i2c_driver retu_driver = { .driver = { .name = "retu-mfd", + .of_match_table = retu_of_match, }, .probe = retu_probe, .remove = retu_remove, diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index fd087cbb0bde..216fbf6adec9 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -70,6 +70,14 @@ static const struct regmap_config rk818_regmap_config = { .volatile_reg = rk808_is_volatile_reg, }; +static const struct regmap_config rk805_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK805_OFF_SOURCE_REG, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = rk808_is_volatile_reg, +}; + static const struct regmap_config rk808_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -86,6 +94,34 @@ static struct resource rtc_resources[] = { } }; +static struct resource rk805_key_resources[] = { + { + .start = RK805_IRQ_PWRON_FALL, + .end = RK805_IRQ_PWRON_FALL, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK805_IRQ_PWRON_RISE, + .end = RK805_IRQ_PWRON_RISE, + .flags = IORESOURCE_IRQ, + } +}; + +static const struct mfd_cell rk805s[] = { + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { .name = "rk805-pinctrl", }, + { + .name = "rk808-rtc", + .num_resources = ARRAY_SIZE(rtc_resources), + .resources = &rtc_resources[0], + }, + { .name = "rk805-pwrkey", + .num_resources = ARRAY_SIZE(rk805_key_resources), + .resources = &rk805_key_resources[0], + }, +}; + static const struct mfd_cell rk808s[] = { { .name = "rk808-clkout", }, { .name = "rk808-regulator", }, @@ -106,6 +142,20 @@ static const struct mfd_cell rk818s[] = { }, }; +static const struct rk808_reg_data rk805_pre_init_reg[] = { + {RK805_BUCK1_CONFIG_REG, RK805_BUCK1_2_ILMAX_MASK, + RK805_BUCK1_2_ILMAX_4000MA}, + {RK805_BUCK2_CONFIG_REG, RK805_BUCK1_2_ILMAX_MASK, + RK805_BUCK1_2_ILMAX_4000MA}, + {RK805_BUCK3_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK, + RK805_BUCK3_ILMAX_3000MA}, + {RK805_BUCK4_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK, + RK805_BUCK4_ILMAX_3500MA}, + {RK805_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_400MA}, + {RK805_GPIO_IO_POL_REG, SLP_SD_MSK, SLEEP_FUN}, + {RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C}, +}; + static const struct rk808_reg_data rk808_pre_init_reg[] = { { RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA }, { RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA }, @@ -135,6 +185,41 @@ static const struct rk808_reg_data rk818_pre_init_reg[] = { VB_LO_SEL_3500MV }, }; +static const struct regmap_irq rk805_irqs[] = { + [RK805_IRQ_PWRON_RISE] = { + .mask = RK805_IRQ_PWRON_RISE_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_VB_LOW] = { + .mask = RK805_IRQ_VB_LOW_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_PWRON] = { + .mask = RK805_IRQ_PWRON_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_PWRON_LP] = { + .mask = RK805_IRQ_PWRON_LP_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_HOTDIE] = { + .mask = RK805_IRQ_HOTDIE_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_RTC_ALARM] = { + .mask = RK805_IRQ_RTC_ALARM_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_RTC_PERIOD] = { + .mask = RK805_IRQ_RTC_PERIOD_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_PWRON_FALL] = { + .mask = RK805_IRQ_PWRON_FALL_MSK, + .reg_offset = 0, + }, +}; + static const struct regmap_irq rk808_irqs[] = { /* INT_STS */ [RK808_IRQ_VOUT_LO] = { @@ -247,6 +332,17 @@ static const struct regmap_irq rk818_irqs[] = { }, }; +static struct regmap_irq_chip rk805_irq_chip = { + .name = "rk805", + .irqs = rk805_irqs, + .num_irqs = ARRAY_SIZE(rk805_irqs), + .num_regs = 1, + .status_base = RK805_INT_STS_REG, + .mask_base = RK805_INT_STS_MSK_REG, + .ack_base = RK805_INT_STS_REG, + .init_ack_masked = true, +}; + static const struct regmap_irq_chip rk808_irq_chip = { .name = "rk808", .irqs = rk808_irqs, @@ -272,6 +368,25 @@ static const struct regmap_irq_chip rk818_irq_chip = { }; static struct i2c_client *rk808_i2c_client; + +static void rk805_device_shutdown(void) +{ + int ret; + struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); + + if (!rk808) { + dev_warn(&rk808_i2c_client->dev, + "have no rk805, so do nothing here\n"); + return; + } + + ret = regmap_update_bits(rk808->regmap, + RK805_DEV_CTRL_REG, + DEV_OFF, DEV_OFF); + if (ret) + dev_err(&rk808_i2c_client->dev, "power off error!\n"); +} + static void rk808_device_shutdown(void) { int ret; @@ -309,6 +424,7 @@ static void rk818_device_shutdown(void) } static const struct of_device_id rk808_of_match[] = { + { .compatible = "rockchip,rk805" }, { .compatible = "rockchip,rk808" }, { .compatible = "rockchip,rk818" }, { }, @@ -325,7 +441,7 @@ static int rk808_probe(struct i2c_client *client, void (*pm_pwroff_fn)(void); int nr_pre_init_regs; int nr_cells; - int pm_off = 0; + int pm_off = 0, msb, lsb; int ret; int i; @@ -333,16 +449,34 @@ static int rk808_probe(struct i2c_client *client, if (!rk808) return -ENOMEM; - rk808->variant = i2c_smbus_read_word_data(client, RK808_ID_MSB); - if (rk808->variant < 0) { - dev_err(&client->dev, "Failed to read the chip id at 0x%02x\n", + /* Read chip variant */ + msb = i2c_smbus_read_byte_data(client, RK808_ID_MSB); + if (msb < 0) { + dev_err(&client->dev, "failed to read the chip id at 0x%x\n", RK808_ID_MSB); - return rk808->variant; + return msb; + } + + lsb = i2c_smbus_read_byte_data(client, RK808_ID_LSB); + if (lsb < 0) { + dev_err(&client->dev, "failed to read the chip id at 0x%x\n", + RK808_ID_LSB); + return lsb; } - dev_dbg(&client->dev, "Chip id: 0x%x\n", (unsigned int)rk808->variant); + rk808->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK; + dev_info(&client->dev, "chip id: 0x%x\n", (unsigned int)rk808->variant); switch (rk808->variant) { + case RK805_ID: + rk808->regmap_cfg = &rk805_regmap_config; + rk808->regmap_irq_chip = &rk805_irq_chip; + pre_init_reg = rk805_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk805_pre_init_reg); + cells = rk805s; + nr_cells = ARRAY_SIZE(rk805s); + pm_pwroff_fn = rk805_device_shutdown; + break; case RK808_ID: rk808->regmap_cfg = &rk808_regmap_config; rk808->regmap_irq_chip = &rk808_irq_chip; @@ -435,6 +569,7 @@ static int rk808_remove(struct i2c_client *client) } static const struct i2c_device_id rk808_ids[] = { + { "rk805" }, { "rk808" }, { "rk818" }, { }, diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index a0ac89dfdf0f..3cf69e5c5703 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -644,7 +644,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, { int err, clk; u8 n, clk_divider, mcu_cnt, div; - u8 depth[] = { + static const u8 depth[] = { [RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M, [RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M, [RTSX_SSC_DEPTH_1M] = SSC_DEPTH_1M, @@ -768,7 +768,7 @@ EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off); int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card) { - unsigned int cd_mask[] = { + static const unsigned int cd_mask[] = { [RTSX_SD_CARD] = SD_EXIST, [RTSX_MS_CARD] = MS_EXIST }; diff --git a/drivers/mfd/stm32-lptimer.c b/drivers/mfd/stm32-lptimer.c new file mode 100644 index 000000000000..075330a25f61 --- /dev/null +++ b/drivers/mfd/stm32-lptimer.c @@ -0,0 +1,107 @@ +/* + * STM32 Low-Power Timer parent driver. + * + * Copyright (C) STMicroelectronics 2017 + * + * Author: Fabrice Gasnier <fabrice.gasnier@st.com> + * + * Inspired by Benjamin Gaignard's stm32-timers driver + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/mfd/stm32-lptimer.h> +#include <linux/module.h> +#include <linux/of_platform.h> + +#define STM32_LPTIM_MAX_REGISTER 0x3fc + +static const struct regmap_config stm32_lptimer_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = sizeof(u32), + .max_register = STM32_LPTIM_MAX_REGISTER, +}; + +static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata) +{ + u32 val; + int ret; + + /* + * Quadrature encoder mode bit can only be written and read back when + * Low-Power Timer supports it. + */ + ret = regmap_update_bits(ddata->regmap, STM32_LPTIM_CFGR, + STM32_LPTIM_ENC, STM32_LPTIM_ENC); + if (ret) + return ret; + + ret = regmap_read(ddata->regmap, STM32_LPTIM_CFGR, &val); + if (ret) + return ret; + + ret = regmap_update_bits(ddata->regmap, STM32_LPTIM_CFGR, + STM32_LPTIM_ENC, 0); + if (ret) + return ret; + + ddata->has_encoder = !!(val & STM32_LPTIM_ENC); + + return 0; +} + +static int stm32_lptimer_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct stm32_lptimer *ddata; + struct resource *res; + void __iomem *mmio; + int ret; + + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(mmio)) + return PTR_ERR(mmio); + + ddata->regmap = devm_regmap_init_mmio_clk(dev, "mux", mmio, + &stm32_lptimer_regmap_cfg); + if (IS_ERR(ddata->regmap)) + return PTR_ERR(ddata->regmap); + + ddata->clk = devm_clk_get(dev, NULL); + if (IS_ERR(ddata->clk)) + return PTR_ERR(ddata->clk); + + ret = stm32_lptimer_detect_encoder(ddata); + if (ret) + return ret; + + platform_set_drvdata(pdev, ddata); + + return devm_of_platform_populate(&pdev->dev); +} + +static const struct of_device_id stm32_lptimer_of_match[] = { + { .compatible = "st,stm32-lptimer", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_lptimer_of_match); + +static struct platform_driver stm32_lptimer_driver = { + .probe = stm32_lptimer_probe, + .driver = { + .name = "stm32-lptimer", + .of_match_table = stm32_lptimer_of_match, + }, +}; +module_platform_driver(stm32_lptimer_driver); + +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics STM32 Low-Power Timer"); +MODULE_ALIAS("platform:stm32-lptimer"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 22c811396edc..43d8683266de 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -86,8 +86,11 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc) struct t7l66xb *t7l66xb = platform_get_drvdata(dev); unsigned long flags; u8 dev_ctl; + int ret; - clk_prepare_enable(t7l66xb->clk32k); + ret = clk_prepare_enable(t7l66xb->clk32k); + if (ret) + return ret; raw_spin_lock_irqsave(&t7l66xb->lock, flags); @@ -286,8 +289,12 @@ static int t7l66xb_resume(struct platform_device *dev) { struct t7l66xb *t7l66xb = platform_get_drvdata(dev); struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); + int ret; + + ret = clk_prepare_enable(t7l66xb->clk48m); + if (ret) + return ret; - clk_prepare_enable(t7l66xb->clk48m); if (pdata && pdata->resume) pdata->resume(dev); @@ -361,7 +368,9 @@ static int t7l66xb_probe(struct platform_device *dev) goto err_ioremap; } - clk_prepare_enable(t7l66xb->clk48m); + ret = clk_prepare_enable(t7l66xb->clk48m); + if (ret) + goto err_clk_enable; if (pdata->enable) pdata->enable(dev); @@ -386,6 +395,8 @@ static int t7l66xb_probe(struct platform_device *dev) return 0; t7l66xb_detach_irq(dev); + clk_disable_unprepare(t7l66xb->clk48m); +err_clk_enable: iounmap(t7l66xb->scr); err_ioremap: release_resource(&t7l66xb->rscr); diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index baa12ea666fb..187848c93779 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -173,9 +173,17 @@ static const struct i2c_device_id tps6105x_id[] = { }; MODULE_DEVICE_TABLE(i2c, tps6105x_id); +static const struct of_device_id tps6105x_of_match[] = { + { .compatible = "ti,tps61050" }, + { .compatible = "ti,tps61052" }, + { }, +}; +MODULE_DEVICE_TABLE(of, tps6105x_of_match); + static struct i2c_driver tps6105x_driver = { .driver = { .name = "tps6105x", + .of_match_table = tps6105x_of_match, }, .probe = tps6105x_probe, .remove = tps6105x_remove, diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index d829a6131f09..2ab67386b4ef 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -32,7 +32,7 @@ #include <linux/mutex.h> #include <linux/platform_device.h> -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #include <linux/gpio/driver.h> diff --git a/drivers/mfd/tps68470.c b/drivers/mfd/tps68470.c new file mode 100644 index 000000000000..189efaea054c --- /dev/null +++ b/drivers/mfd/tps68470.c @@ -0,0 +1,106 @@ +/* + * TPS68470 chip Parent driver + * + * Copyright (C) 2017 Intel Corporation + * + * Authors: + * Rajmohan Mani <rajmohan.mani@intel.com> + * Tianshu Qiu <tian.shu.qiu@intel.com> + * Jian Xu Zheng <jian.xu.zheng@intel.com> + * Yuning Pu <yuning.pu@intel.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/mfd/core.h> +#include <linux/mfd/tps68470.h> +#include <linux/regmap.h> + +static const struct mfd_cell tps68470s[] = { + { .name = "tps68470-gpio" }, + { .name = "tps68470_pmic_opregion" }, +}; + +static const struct regmap_config tps68470_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = TPS68470_REG_MAX, +}; + +static int tps68470_chip_init(struct device *dev, struct regmap *regmap) +{ + unsigned int version; + int ret; + + /* Force software reset */ + ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK); + if (ret) + return ret; + + ret = regmap_read(regmap, TPS68470_REG_REVID, &version); + if (ret) { + dev_err(dev, "Failed to read revision register: %d\n", ret); + return ret; + } + + dev_info(dev, "TPS68470 REVID: 0x%x\n", version); + + return 0; +} + +static int tps68470_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "devm_regmap_init_i2c Error %ld\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + i2c_set_clientdata(client, regmap); + + ret = tps68470_chip_init(dev, regmap); + if (ret < 0) { + dev_err(dev, "TPS68470 Init Error %d\n", ret); + return ret; + } + + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, tps68470s, + ARRAY_SIZE(tps68470s), NULL, 0, NULL); + if (ret < 0) { + dev_err(dev, "devm_mfd_add_devices failed: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct acpi_device_id tps68470_acpi_ids[] = { + {"INT3472"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, tps68470_acpi_ids); + +static struct i2c_driver tps68470_driver = { + .driver = { + .name = "tps68470", + .acpi_match_table = tps68470_acpi_ids, + }, + .probe_new = tps68470_probe, +}; +builtin_i2c_driver(tps68470_driver); diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index c64615dca2bd..d3133a371e27 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -44,7 +44,7 @@ #include <linux/regulator/machine.h> #include <linux/i2c.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> /* Register descriptions for audio */ #include <linux/mfd/twl4030-audio.h> @@ -173,7 +173,7 @@ static struct twl_private *twl_priv; static struct twl_mapping twl4030_map[] = { /* * NOTE: don't change this table without updating the - * <linux/i2c/twl.h> defines for TWL4030_MODULE_* + * <linux/mfd/twl.h> defines for TWL4030_MODULE_* * so they continue to match the order in this table. */ @@ -344,7 +344,7 @@ static const struct regmap_config twl4030_regmap_config[4] = { static struct twl_mapping twl6030_map[] = { /* * NOTE: don't change this table without updating the - * <linux/i2c/twl.h> defines for TWL4030_MODULE_* + * <linux/mfd/twl.h> defines for TWL4030_MODULE_* * so they continue to match the order in this table. */ @@ -448,7 +448,7 @@ static struct regmap *twl_get_regmap(u8 mod_no) * @reg: register address (just offset will do) * @num_bytes: number of bytes to transfer * - * Returns the result of operation - 0 is success + * Returns 0 on success or else a negative error code. */ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) { @@ -476,7 +476,7 @@ EXPORT_SYMBOL(twl_i2c_write); * @reg: register address (just offset will do) * @num_bytes: number of bytes to transfer * - * Returns result of operation - num_bytes is success else failure. + * Returns 0 on success or else a negative error code. */ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) { diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 0a1606480023..da16bf45fab4 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -30,7 +30,7 @@ #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_platform.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/mfd/core.h> #include <linux/mfd/twl4030-audio.h> diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 378c02d43bf7..b16c16f194fd 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -33,7 +33,7 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/irqdomain.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include "twl-core.h" diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index f4b2c29d77e3..6b36932263ba 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -25,7 +25,7 @@ #include <linux/module.h> #include <linux/pm.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_device.h> diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 53574508a613..e3ec8dfa9f1e 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -35,7 +35,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/kthread.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/platform_device.h> #include <linux/suspend.h> #include <linux/of.h> diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index ceec21bd30c4..1913ce18fb1c 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -247,6 +247,7 @@ struct atmel_hsmc_nand_controller { void __iomem *virt; dma_addr_t dma; } sram; + const struct atmel_hsmc_reg_layout *hsmc_layout; struct regmap *io; struct atmel_nfc_op op; struct completion complete; @@ -1442,12 +1443,12 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand, int csline, const struct nand_data_interface *conf) { - struct atmel_nand_controller *nc; + struct atmel_hsmc_nand_controller *nc; struct atmel_smc_cs_conf smcconf; struct atmel_nand_cs *cs; int ret; - nc = to_nand_controller(nand->base.controller); + nc = to_hsmc_nand_controller(nand->base.controller); ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf); if (ret) @@ -1462,7 +1463,8 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand, if (cs->rb.type == ATMEL_NAND_NATIVE_RB) cs->smcconf.timings |= ATMEL_HSMC_TIMINGS_RBNSEL(cs->rb.id); - atmel_hsmc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf); + atmel_hsmc_cs_conf_apply(nc->base.smc, nc->hsmc_layout, cs->id, + &cs->smcconf); return 0; } @@ -2177,6 +2179,8 @@ atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc) return -EINVAL; } + nc->hsmc_layout = atmel_hsmc_get_reg_layout(np); + nc->irq = of_irq_get(np, 0); of_node_put(np); if (nc->irq < 0) { diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index 0e9013868188..a44680d64f9b 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -36,7 +36,7 @@ #include <linux/pm_runtime.h> #include <linux/usb/musb.h> #include <linux/usb/ulpi.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/regulator/consumer.h> #include <linux/err.h> #include <linux/slab.h> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 34ad10873452..1778cf4f81c7 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -338,6 +338,15 @@ config PINCTRL_INGENIC select GENERIC_PINMUX_FUNCTIONS select REGMAP_MMIO +config PINCTRL_RK805 + tristate "Pinctrl and GPIO driver for RK805 PMIC" + depends on MFD_RK808 + select GPIOLIB + select PINMUX + select GENERIC_PINCONF + help + This selects the pinctrl driver for RK805. + source "drivers/pinctrl/aspeed/Kconfig" source "drivers/pinctrl/bcm/Kconfig" source "drivers/pinctrl/berlin/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 4c44703ac97f..c16e27900dbb 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o +obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-y += bcm/ diff --git a/drivers/pinctrl/pinctrl-rk805.c b/drivers/pinctrl/pinctrl-rk805.c new file mode 100644 index 000000000000..b0bfd3082a1b --- /dev/null +++ b/drivers/pinctrl/pinctrl-rk805.c @@ -0,0 +1,493 @@ +/* + * Pinctrl driver for Rockchip RK805 PMIC + * + * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd + * + * Author: Joseph Chen <chenjh@rock-chips.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. + * + * Based on the pinctrl-as3722 driver + */ + +#include <linux/gpio/driver.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/rk808.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pm.h> +#include <linux/slab.h> + +#include "core.h" +#include "pinconf.h" +#include "pinctrl-utils.h" + +struct rk805_pin_function { + const char *name; + const char *const *groups; + unsigned int ngroups; + int mux_option; +}; + +struct rk805_pin_group { + const char *name; + const unsigned int pins[1]; + unsigned int npins; +}; + +/* + * @reg: gpio setting register; + * @fun_mask: functions select mask value, when set is gpio; + * @dir_mask: input or output mask value, when set is output, otherwise input; + * @val_mask: gpio set value, when set is level high, otherwise low; + * + * Different PMIC has different pin features, belowing 3 mask members are not + * all necessary for every PMIC. For example, RK805 has 2 pins that can be used + * as output only GPIOs, so func_mask and dir_mask are not needed. RK816 has 1 + * pin that can be used as TS/GPIO, so fun_mask, dir_mask and val_mask are all + * necessary. + */ +struct rk805_pin_config { + u8 reg; + u8 fun_msk; + u8 dir_msk; + u8 val_msk; +}; + +struct rk805_pctrl_info { + struct rk808 *rk808; + struct device *dev; + struct pinctrl_dev *pctl; + struct gpio_chip gpio_chip; + struct pinctrl_desc pinctrl_desc; + const struct rk805_pin_function *functions; + unsigned int num_functions; + const struct rk805_pin_group *groups; + int num_pin_groups; + const struct pinctrl_pin_desc *pins; + unsigned int num_pins; + struct rk805_pin_config *pin_cfg; +}; + +enum rk805_pinmux_option { + RK805_PINMUX_GPIO, +}; + +enum { + RK805_GPIO0, + RK805_GPIO1, +}; + +static const char *const rk805_gpio_groups[] = { + "gpio0", + "gpio1", +}; + +/* RK805: 2 output only GPIOs */ +static const struct pinctrl_pin_desc rk805_pins_desc[] = { + PINCTRL_PIN(RK805_GPIO0, "gpio0"), + PINCTRL_PIN(RK805_GPIO1, "gpio1"), +}; + +static const struct rk805_pin_function rk805_pin_functions[] = { + { + .name = "gpio", + .groups = rk805_gpio_groups, + .ngroups = ARRAY_SIZE(rk805_gpio_groups), + .mux_option = RK805_PINMUX_GPIO, + }, +}; + +static const struct rk805_pin_group rk805_pin_groups[] = { + { + .name = "gpio0", + .pins = { RK805_GPIO0 }, + .npins = 1, + }, + { + .name = "gpio1", + .pins = { RK805_GPIO1 }, + .npins = 1, + }, +}; + +#define RK805_GPIO0_VAL_MSK BIT(0) +#define RK805_GPIO1_VAL_MSK BIT(1) + +static struct rk805_pin_config rk805_gpio_cfgs[] = { + { + .reg = RK805_OUT_REG, + .val_msk = RK805_GPIO0_VAL_MSK, + }, + { + .reg = RK805_OUT_REG, + .val_msk = RK805_GPIO1_VAL_MSK, + }, +}; + +/* generic gpio chip */ +static int rk805_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct rk805_pctrl_info *pci = gpiochip_get_data(chip); + int ret, val; + + ret = regmap_read(pci->rk808->regmap, pci->pin_cfg[offset].reg, &val); + if (ret) { + dev_err(pci->dev, "get gpio%d value failed\n", offset); + return ret; + } + + return !!(val & pci->pin_cfg[offset].val_msk); +} + +static void rk805_gpio_set(struct gpio_chip *chip, + unsigned int offset, + int value) +{ + struct rk805_pctrl_info *pci = gpiochip_get_data(chip); + int ret; + + ret = regmap_update_bits(pci->rk808->regmap, + pci->pin_cfg[offset].reg, + pci->pin_cfg[offset].val_msk, + value ? pci->pin_cfg[offset].val_msk : 0); + if (ret) + dev_err(pci->dev, "set gpio%d value %d failed\n", + offset, value); +} + +static int rk805_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + return pinctrl_gpio_direction_input(chip->base + offset); +} + +static int rk805_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + rk805_gpio_set(chip, offset, value); + return pinctrl_gpio_direction_output(chip->base + offset); +} + +static int rk805_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct rk805_pctrl_info *pci = gpiochip_get_data(chip); + unsigned int val; + int ret; + + /* default output*/ + if (!pci->pin_cfg[offset].dir_msk) + return 0; + + ret = regmap_read(pci->rk808->regmap, + pci->pin_cfg[offset].reg, + &val); + if (ret) { + dev_err(pci->dev, "get gpio%d direction failed\n", offset); + return ret; + } + + return !(val & pci->pin_cfg[offset].dir_msk); +} + +static struct gpio_chip rk805_gpio_chip = { + .label = "rk805-gpio", + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .get_direction = rk805_gpio_get_direction, + .get = rk805_gpio_get, + .set = rk805_gpio_set, + .direction_input = rk805_gpio_direction_input, + .direction_output = rk805_gpio_direction_output, + .can_sleep = true, + .base = -1, + .owner = THIS_MODULE, +}; + +/* generic pinctrl */ +static int rk805_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + + return pci->num_pin_groups; +} + +static const char *rk805_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + + return pci->groups[group].name; +} + +static int rk805_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + + *pins = pci->groups[group].pins; + *num_pins = pci->groups[group].npins; + + return 0; +} + +static const struct pinctrl_ops rk805_pinctrl_ops = { + .get_groups_count = rk805_pinctrl_get_groups_count, + .get_group_name = rk805_pinctrl_get_group_name, + .get_group_pins = rk805_pinctrl_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinctrl_utils_free_map, +}; + +static int rk805_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + + return pci->num_functions; +} + +static const char *rk805_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned int function) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + + return pci->functions[function].name; +} + +static int rk805_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, + unsigned int function, + const char *const **groups, + unsigned int *const num_groups) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + + *groups = pci->functions[function].groups; + *num_groups = pci->functions[function].ngroups; + + return 0; +} + +static int _rk805_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned int offset, + int mux) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + int ret; + + if (!pci->pin_cfg[offset].fun_msk) + return 0; + + if (mux == RK805_PINMUX_GPIO) { + ret = regmap_update_bits(pci->rk808->regmap, + pci->pin_cfg[offset].reg, + pci->pin_cfg[offset].fun_msk, + pci->pin_cfg[offset].fun_msk); + if (ret) { + dev_err(pci->dev, "set gpio%d GPIO failed\n", offset); + return ret; + } + } else { + dev_err(pci->dev, "Couldn't find function mux %d\n", mux); + return -EINVAL; + } + + return 0; +} + +static int rk805_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, + unsigned int group) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + int mux = pci->functions[function].mux_option; + int offset = group; + + return _rk805_pinctrl_set_mux(pctldev, offset, mux); +} + +static int rk805_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + int ret; + + /* switch to gpio function */ + ret = _rk805_pinctrl_set_mux(pctldev, offset, RK805_PINMUX_GPIO); + if (ret) { + dev_err(pci->dev, "set gpio%d mux failed\n", offset); + return ret; + } + + /* set direction */ + if (!pci->pin_cfg[offset].dir_msk) + return 0; + + ret = regmap_update_bits(pci->rk808->regmap, + pci->pin_cfg[offset].reg, + pci->pin_cfg[offset].dir_msk, + input ? 0 : pci->pin_cfg[offset].dir_msk); + if (ret) { + dev_err(pci->dev, "set gpio%d direction failed\n", offset); + return ret; + } + + return ret; +} + +static const struct pinmux_ops rk805_pinmux_ops = { + .get_functions_count = rk805_pinctrl_get_funcs_count, + .get_function_name = rk805_pinctrl_get_func_name, + .get_function_groups = rk805_pinctrl_get_func_groups, + .set_mux = rk805_pinctrl_set_mux, + .gpio_set_direction = rk805_pmx_gpio_set_direction, +}; + +static int rk805_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + u32 arg = 0; + + switch (param) { + case PIN_CONFIG_OUTPUT: + arg = rk805_gpio_get(&pci->gpio_chip, pin); + break; + default: + dev_err(pci->dev, "Properties not supported\n"); + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, (u16)arg); + + return 0; +} + +static int rk805_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *configs, + unsigned int num_configs) +{ + struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param; + u32 i, arg = 0; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_OUTPUT: + rk805_gpio_set(&pci->gpio_chip, pin, arg); + rk805_pmx_gpio_set_direction(pctldev, NULL, pin, false); + break; + default: + dev_err(pci->dev, "Properties not supported\n"); + return -ENOTSUPP; + } + } + + return 0; +} + +static const struct pinconf_ops rk805_pinconf_ops = { + .pin_config_get = rk805_pinconf_get, + .pin_config_set = rk805_pinconf_set, +}; + +static struct pinctrl_desc rk805_pinctrl_desc = { + .name = "rk805-pinctrl", + .pctlops = &rk805_pinctrl_ops, + .pmxops = &rk805_pinmux_ops, + .confops = &rk805_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int rk805_pinctrl_probe(struct platform_device *pdev) +{ + struct rk805_pctrl_info *pci; + int ret; + + pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL); + if (!pci) + return -ENOMEM; + + pci->dev = &pdev->dev; + pci->dev->of_node = pdev->dev.parent->of_node; + pci->rk808 = dev_get_drvdata(pdev->dev.parent); + + pci->pinctrl_desc = rk805_pinctrl_desc; + pci->gpio_chip = rk805_gpio_chip; + pci->gpio_chip.parent = &pdev->dev; + pci->gpio_chip.of_node = pdev->dev.parent->of_node; + + platform_set_drvdata(pdev, pci); + + switch (pci->rk808->variant) { + case RK805_ID: + pci->pins = rk805_pins_desc; + pci->num_pins = ARRAY_SIZE(rk805_pins_desc); + pci->functions = rk805_pin_functions; + pci->num_functions = ARRAY_SIZE(rk805_pin_functions); + pci->groups = rk805_pin_groups; + pci->num_pin_groups = ARRAY_SIZE(rk805_pin_groups); + pci->pinctrl_desc.pins = rk805_pins_desc; + pci->pinctrl_desc.npins = ARRAY_SIZE(rk805_pins_desc); + pci->pin_cfg = rk805_gpio_cfgs; + pci->gpio_chip.ngpio = ARRAY_SIZE(rk805_gpio_cfgs); + break; + default: + dev_err(&pdev->dev, "unsupported RK805 ID %lu\n", + pci->rk808->variant); + return -EINVAL; + } + + /* Add gpio chip */ + ret = devm_gpiochip_add_data(&pdev->dev, &pci->gpio_chip, pci); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't add gpiochip\n"); + return ret; + } + + /* Add pinctrl */ + pci->pctl = devm_pinctrl_register(&pdev->dev, &pci->pinctrl_desc, pci); + if (IS_ERR(pci->pctl)) { + dev_err(&pdev->dev, "Couldn't add pinctrl\n"); + return PTR_ERR(pci->pctl); + } + + /* Add pin range */ + ret = gpiochip_add_pin_range(&pci->gpio_chip, dev_name(&pdev->dev), + 0, 0, pci->gpio_chip.ngpio); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't add gpiochip pin range\n"); + return ret; + } + + return 0; +} + +static struct platform_driver rk805_pinctrl_driver = { + .probe = rk805_pinctrl_probe, + .driver = { + .name = "rk805-pinctrl", + }, +}; +module_platform_driver(rk805_pinctrl_driver); + +MODULE_DESCRIPTION("RK805 pin control and GPIO driver"); +MODULE_AUTHOR("Joseph Chen <chenjh@rock-chips.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index 9dff1b4b85fc..a5915f498eea 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -18,7 +18,7 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/interrupt.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/power_supply.h> #include <linux/notifier.h> #include <linux/usb/otg.h> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 313c10789ca2..7cb982b54c8c 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -417,6 +417,16 @@ config PWM_STM32 To compile this driver as a module, choose M here: the module will be called pwm-stm32. +config PWM_STM32_LP + tristate "STMicroelectronics STM32 PWM LP" + depends on MFD_STM32_LPTIMER || COMPILE_TEST + help + Generic PWM framework driver for STMicroelectronics STM32 SoCs + with Low-Power Timer (LPTIM). + + To compile this driver as a module, choose M here: the module + will be called pwm-stm32-lp. + config PWM_STMPE bool "STMPE expander PWM export" depends on MFD_STMPE diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 93da1f79a3b8..a3a4beef6daa 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o obj-$(CONFIG_PWM_STI) += pwm-sti.o obj-$(CONFIG_PWM_STM32) += pwm-stm32.o +obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c new file mode 100644 index 000000000000..9793b296108f --- /dev/null +++ b/drivers/pwm/pwm-stm32-lp.c @@ -0,0 +1,246 @@ +/* + * STM32 Low-Power Timer PWM driver + * + * Copyright (C) STMicroelectronics 2017 + * + * Author: Gerald Baeza <gerald.baeza@st.com> + * + * License terms: GNU General Public License (GPL), version 2 + * + * Inspired by Gerald Baeza's pwm-stm32 driver + */ + +#include <linux/bitfield.h> +#include <linux/mfd/stm32-lptimer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> + +struct stm32_pwm_lp { + struct pwm_chip chip; + struct clk *clk; + struct regmap *regmap; +}; + +static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip) +{ + return container_of(chip, struct stm32_pwm_lp, chip); +} + +/* STM32 Low-Power Timer is preceded by a configurable power-of-2 prescaler */ +#define STM32_LPTIM_MAX_PRESCALER 128 + +static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip); + unsigned long long prd, div, dty; + struct pwm_state cstate; + u32 val, mask, cfgr, presc = 0; + bool reenable; + int ret; + + pwm_get_state(pwm, &cstate); + reenable = !cstate.enabled; + + if (!state->enabled) { + if (cstate.enabled) { + /* Disable LP timer */ + ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0); + if (ret) + return ret; + /* disable clock to PWM counter */ + clk_disable(priv->clk); + } + return 0; + } + + /* Calculate the period and prescaler value */ + div = (unsigned long long)clk_get_rate(priv->clk) * state->period; + do_div(div, NSEC_PER_SEC); + prd = div; + while (div > STM32_LPTIM_MAX_ARR) { + presc++; + if ((1 << presc) > STM32_LPTIM_MAX_PRESCALER) { + dev_err(priv->chip.dev, "max prescaler exceeded\n"); + return -EINVAL; + } + div = prd >> presc; + } + prd = div; + + /* Calculate the duty cycle */ + dty = prd * state->duty_cycle; + do_div(dty, state->period); + + if (!cstate.enabled) { + /* enable clock to drive PWM counter */ + ret = clk_enable(priv->clk); + if (ret) + return ret; + } + + ret = regmap_read(priv->regmap, STM32_LPTIM_CFGR, &cfgr); + if (ret) + goto err; + + if ((FIELD_GET(STM32_LPTIM_PRESC, cfgr) != presc) || + (FIELD_GET(STM32_LPTIM_WAVPOL, cfgr) != state->polarity)) { + val = FIELD_PREP(STM32_LPTIM_PRESC, presc); + val |= FIELD_PREP(STM32_LPTIM_WAVPOL, state->polarity); + mask = STM32_LPTIM_PRESC | STM32_LPTIM_WAVPOL; + + /* Must disable LP timer to modify CFGR */ + reenable = true; + ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0); + if (ret) + goto err; + + ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, + val); + if (ret) + goto err; + } + + if (reenable) { + /* Must (re)enable LP timer to modify CMP & ARR */ + ret = regmap_write(priv->regmap, STM32_LPTIM_CR, + STM32_LPTIM_ENABLE); + if (ret) + goto err; + } + + ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, prd - 1); + if (ret) + goto err; + + ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, prd - (1 + dty)); + if (ret) + goto err; + + /* ensure CMP & ARR registers are properly written */ + ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, + (val & STM32_LPTIM_CMPOK_ARROK), + 100, 1000); + if (ret) { + dev_err(priv->chip.dev, "ARR/CMP registers write issue\n"); + goto err; + } + ret = regmap_write(priv->regmap, STM32_LPTIM_ICR, + STM32_LPTIM_CMPOKCF_ARROKCF); + if (ret) + goto err; + + if (reenable) { + /* Start LP timer in continuous mode */ + ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CR, + STM32_LPTIM_CNTSTRT, + STM32_LPTIM_CNTSTRT); + if (ret) { + regmap_write(priv->regmap, STM32_LPTIM_CR, 0); + goto err; + } + } + + return 0; +err: + if (!cstate.enabled) + clk_disable(priv->clk); + + return ret; +} + +static void stm32_pwm_lp_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip); + unsigned long rate = clk_get_rate(priv->clk); + u32 val, presc, prd; + u64 tmp; + + regmap_read(priv->regmap, STM32_LPTIM_CR, &val); + state->enabled = !!FIELD_GET(STM32_LPTIM_ENABLE, val); + /* Keep PWM counter clock refcount in sync with PWM initial state */ + if (state->enabled) + clk_enable(priv->clk); + + regmap_read(priv->regmap, STM32_LPTIM_CFGR, &val); + presc = FIELD_GET(STM32_LPTIM_PRESC, val); + state->polarity = FIELD_GET(STM32_LPTIM_WAVPOL, val); + + regmap_read(priv->regmap, STM32_LPTIM_ARR, &prd); + tmp = prd + 1; + tmp = (tmp << presc) * NSEC_PER_SEC; + state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); + + regmap_read(priv->regmap, STM32_LPTIM_CMP, &val); + tmp = prd - val; + tmp = (tmp << presc) * NSEC_PER_SEC; + state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); +} + +static const struct pwm_ops stm32_pwm_lp_ops = { + .owner = THIS_MODULE, + .apply = stm32_pwm_lp_apply, + .get_state = stm32_pwm_lp_get_state, +}; + +static int stm32_pwm_lp_probe(struct platform_device *pdev) +{ + struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); + struct stm32_pwm_lp *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = ddata->regmap; + priv->clk = ddata->clk; + priv->chip.base = -1; + priv->chip.dev = &pdev->dev; + priv->chip.ops = &stm32_pwm_lp_ops; + priv->chip.npwm = 1; + + ret = pwmchip_add(&priv->chip); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int stm32_pwm_lp_remove(struct platform_device *pdev) +{ + struct stm32_pwm_lp *priv = platform_get_drvdata(pdev); + unsigned int i; + + for (i = 0; i < priv->chip.npwm; i++) + if (pwm_is_enabled(&priv->chip.pwms[i])) + pwm_disable(&priv->chip.pwms[i]); + + return pwmchip_remove(&priv->chip); +} + +static const struct of_device_id stm32_pwm_lp_of_match[] = { + { .compatible = "st,stm32-pwm-lp", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_pwm_lp_of_match); + +static struct platform_driver stm32_pwm_lp_driver = { + .probe = stm32_pwm_lp_probe, + .remove = stm32_pwm_lp_remove, + .driver = { + .name = "stm32-pwm-lp", + .of_match_table = of_match_ptr(stm32_pwm_lp_of_match), + }, +}; +module_platform_driver(stm32_pwm_lp_driver); + +MODULE_ALIAS("platform:stm32-pwm-lp"); +MODULE_DESCRIPTION("STMicroelectronics STM32 PWM LP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c index 21eff991d0e3..01153622778b 100644 --- a/drivers/pwm/pwm-twl-led.c +++ b/drivers/pwm/pwm-twl-led.c @@ -24,7 +24,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pwm.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/slab.h> /* diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c index 9de617b76680..b7a45be99815 100644 --- a/drivers/pwm/pwm-twl.c +++ b/drivers/pwm/pwm-twl.c @@ -21,7 +21,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pwm.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/slab.h> /* diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e740a66cb1d6..0fd6195601ba 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -696,11 +696,11 @@ config REGULATOR_RC5T583 outputs which can be controlled by i2c communication. config REGULATOR_RK808 - tristate "Rockchip RK808/RK818 Power regulators" + tristate "Rockchip RK805/RK808/RK818 Power regulators" depends on MFD_RK808 help Select this option to enable the power regulator of ROCKCHIP - PMIC RK808 and RK818. + PMIC RK805,RK808 and RK818. 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. diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index a16d81420612..213b68743cc8 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -65,6 +65,27 @@ /* max steps for increase voltage of Buck1/2, equal 100mv*/ #define MAX_STEPS_ONE_TIME 8 +#define RK805_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _etime) \ + [_id] = { \ + .name = (_match), \ + .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .id = (_id), \ + .n_voltages = (((_max) - (_min)) / (_step) + 1), \ + .owner = THIS_MODULE, \ + .min_uV = (_min) * 1000, \ + .uV_step = (_step) * 1000, \ + .vsel_reg = (_vreg), \ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .enable_time = (_etime), \ + .ops = &rk805_reg_ops, \ + } + #define RK8XX_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \ _vmask, _ereg, _emask, _etime) \ [_id] = { \ @@ -298,6 +319,28 @@ static int rk808_set_suspend_voltage_range(struct regulator_dev *rdev, int uv) sel); } +static int rk805_set_suspend_enable(struct regulator_dev *rdev) +{ + unsigned int reg; + + reg = rdev->desc->enable_reg + RK808_SLP_SET_OFF_REG_OFFSET; + + return regmap_update_bits(rdev->regmap, reg, + rdev->desc->enable_mask, + rdev->desc->enable_mask); +} + +static int rk805_set_suspend_disable(struct regulator_dev *rdev) +{ + unsigned int reg; + + reg = rdev->desc->enable_reg + RK808_SLP_SET_OFF_REG_OFFSET; + + return regmap_update_bits(rdev->regmap, reg, + rdev->desc->enable_mask, + 0); +} + static int rk808_set_suspend_enable(struct regulator_dev *rdev) { unsigned int reg; @@ -320,6 +363,27 @@ static int rk808_set_suspend_disable(struct regulator_dev *rdev) rdev->desc->enable_mask); } +static struct regulator_ops rk805_reg_ops = { + .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, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_suspend_voltage = rk808_set_suspend_voltage, + .set_suspend_enable = rk805_set_suspend_enable, + .set_suspend_disable = rk805_set_suspend_disable, +}; + +static struct regulator_ops rk805_switch_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_suspend_enable = rk805_set_suspend_enable, + .set_suspend_disable = rk805_set_suspend_disable, +}; + static struct regulator_ops rk808_buck1_2_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -369,6 +433,68 @@ static struct regulator_ops rk808_switch_ops = { .set_suspend_disable = rk808_set_suspend_disable, }; +static const struct regulator_desc rk805_reg[] = { + { + .name = "DCDC_REG1", + .supply_name = "vcc1", + .of_match = of_match_ptr("DCDC_REG1"), + .regulators_node = of_match_ptr("regulators"), + .id = RK805_ID_DCDC1, + .ops = &rk805_reg_ops, + .type = REGULATOR_VOLTAGE, + .min_uV = 712500, + .uV_step = 12500, + .n_voltages = 64, + .vsel_reg = RK805_BUCK1_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .enable_reg = RK805_DCDC_EN_REG, + .enable_mask = BIT(0), + .owner = THIS_MODULE, + }, { + .name = "DCDC_REG2", + .supply_name = "vcc2", + .of_match = of_match_ptr("DCDC_REG2"), + .regulators_node = of_match_ptr("regulators"), + .id = RK805_ID_DCDC2, + .ops = &rk805_reg_ops, + .type = REGULATOR_VOLTAGE, + .min_uV = 712500, + .uV_step = 12500, + .n_voltages = 64, + .vsel_reg = RK805_BUCK2_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .enable_reg = RK805_DCDC_EN_REG, + .enable_mask = BIT(1), + .owner = THIS_MODULE, + }, { + .name = "DCDC_REG3", + .supply_name = "vcc3", + .of_match = of_match_ptr("DCDC_REG3"), + .regulators_node = of_match_ptr("regulators"), + .id = RK805_ID_DCDC3, + .ops = &rk805_switch_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .enable_reg = RK805_DCDC_EN_REG, + .enable_mask = BIT(2), + .owner = THIS_MODULE, + }, + + RK805_DESC(RK805_ID_DCDC4, "DCDC_REG4", "vcc4", 800, 3400, 100, + RK805_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK, + RK805_DCDC_EN_REG, BIT(3), 0), + + RK805_DESC(RK805_ID_LDO1, "LDO_REG1", "vcc5", 800, 3400, 100, + RK805_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK805_LDO_EN_REG, + BIT(0), 400), + RK805_DESC(RK805_ID_LDO2, "LDO_REG2", "vcc5", 800, 3400, 100, + RK805_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK805_LDO_EN_REG, + BIT(1), 400), + RK805_DESC(RK805_ID_LDO3, "LDO_REG3", "vcc6", 800, 3400, 100, + RK805_LDO3_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK805_LDO_EN_REG, + BIT(2), 400), +}; + static const struct regulator_desc rk808_reg[] = { { .name = "DCDC_REG1", @@ -625,6 +751,10 @@ static int rk808_regulator_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pdata); switch (rk808->variant) { + case RK805_ID: + regulators = rk805_reg; + nregulators = RK805_NUM_REGULATORS; + break; case RK808_ID: regulators = rk808_reg; nregulators = RK808_NUM_REGULATORS; diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 6c9ec84121bd..a4456db5849d 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -20,7 +20,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/delay.h> /* diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c index 56aada387887..219cbd910dbf 100644 --- a/drivers/regulator/twl6030-regulator.c +++ b/drivers/regulator/twl6030-regulator.c @@ -21,7 +21,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/delay.h> struct twlreg_info { diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c index f225cd873ff6..97d8259b9494 100644 --- a/drivers/rtc/rtc-dm355evm.c +++ b/drivers/rtc/rtc-dm355evm.c @@ -13,7 +13,7 @@ #include <linux/rtc.h> #include <linux/platform_device.h> -#include <linux/i2c/dm355evm_msp.h> +#include <linux/mfd/dm355evm_msp.h> #include <linux/module.h> diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index c18c39212ce6..3472e79f2b17 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -31,7 +31,7 @@ #include <linux/interrupt.h> #include <linux/of.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> enum twl_class { TWL_4030 = 0, diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index a4d814b7f380..91393ec7d850 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -53,7 +53,7 @@ #define DRIVER_DESC "OHCI OMAP driver" #ifdef CONFIG_TPS65010 -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #else #define LOW 0 diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index 042c5a8fd423..c6052c814bcc 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -96,7 +96,7 @@ struct isp1301 { #if IS_REACHABLE(CONFIG_TPS65010) -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #else diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 628b600b02b1..b5dc077ed7d3 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -28,7 +28,7 @@ #include <linux/usb/musb.h> #include <linux/usb/phy_companion.h> #include <linux/phy/omap_usb.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/regulator/consumer.h> #include <linux/err.h> #include <linux/slab.h> diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c index 5d8bb8b20183..a186bc677c7d 100644 --- a/drivers/video/backlight/pandora_bl.c +++ b/drivers/video/backlight/pandora_bl.c @@ -16,7 +16,7 @@ #include <linux/delay.h> #include <linux/fb.h> #include <linux/backlight.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/err.h> #define TWL_PWM0_ON 0x00 diff --git a/drivers/video/fbdev/omap/lcd_h3.c b/drivers/video/fbdev/omap/lcd_h3.c index 9d2da146813e..796f4634c4c6 100644 --- a/drivers/video/fbdev/omap/lcd_h3.c +++ b/drivers/video/fbdev/omap/lcd_h3.c @@ -21,7 +21,7 @@ #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/i2c/tps65010.h> +#include <linux/mfd/tps65010.h> #include <linux/gpio.h> #include "omapfb.h" diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index 9bf3cc0f3961..569fe85e52da 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c @@ -24,7 +24,7 @@ #include <linux/kernel.h> #include <linux/watchdog.h> #include <linux/platform_device.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3 diff --git a/include/linux/iio/timer/stm32-lptim-trigger.h b/include/linux/iio/timer/stm32-lptim-trigger.h new file mode 100644 index 000000000000..34d59bfdce2d --- /dev/null +++ b/include/linux/iio/timer/stm32-lptim-trigger.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) STMicroelectronics 2017 + * + * Author: Fabrice Gasnier <fabrice.gasnier@st.com> + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STM32_LPTIM_TRIGGER_H_ +#define _STM32_LPTIM_TRIGGER_H_ + +#include <linux/iio/iio.h> +#include <linux/iio/trigger.h> + +#define LPTIM1_OUT "lptim1_out" +#define LPTIM2_OUT "lptim2_out" +#define LPTIM3_OUT "lptim3_out" + +#if IS_ENABLED(CONFIG_IIO_STM32_LPTIMER_TRIGGER) +bool is_stm32_lptim_trigger(struct iio_trigger *trig); +#else +static inline bool is_stm32_lptim_trigger(struct iio_trigger *trig) +{ + return false; +} +#endif +#endif diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index 965b027e31b3..e9c908c4fba8 100644 --- a/include/linux/mfd/axp20x.h +++ b/include/linux/mfd/axp20x.h @@ -23,6 +23,7 @@ enum axp20x_variants { AXP803_ID, AXP806_ID, AXP809_ID, + AXP813_ID, NR_AXP20X_VARIANTS, }; @@ -387,6 +388,34 @@ enum { AXP803_REG_ID_MAX, }; +enum { + AXP813_DCDC1 = 0, + AXP813_DCDC2, + AXP813_DCDC3, + AXP813_DCDC4, + AXP813_DCDC5, + AXP813_DCDC6, + AXP813_DCDC7, + AXP813_ALDO1, + AXP813_ALDO2, + AXP813_ALDO3, + AXP813_DLDO1, + AXP813_DLDO2, + AXP813_DLDO3, + AXP813_DLDO4, + AXP813_ELDO1, + AXP813_ELDO2, + AXP813_ELDO3, + AXP813_FLDO1, + AXP813_FLDO2, + AXP813_FLDO3, + AXP813_RTC_LDO, + AXP813_LDO_IO0, + AXP813_LDO_IO1, + AXP813_SW, + AXP813_REG_ID_MAX, +}; + /* IRQs */ enum { AXP152_IRQ_LDO0IN_CONNECT = 1, diff --git a/include/linux/mfd/bd9571mwv.h b/include/linux/mfd/bd9571mwv.h new file mode 100644 index 000000000000..f0708ba4cbba --- /dev/null +++ b/include/linux/mfd/bd9571mwv.h @@ -0,0 +1,115 @@ +/* + * ROHM BD9571MWV-M driver + * + * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether expressed or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + * + * Based on the TPS65086 driver + */ + +#ifndef __LINUX_MFD_BD9571MWV_H +#define __LINUX_MFD_BD9571MWV_H + +#include <linux/device.h> +#include <linux/regmap.h> + +/* List of registers for BD9571MWV */ +#define BD9571MWV_VENDOR_CODE 0x00 +#define BD9571MWV_VENDOR_CODE_VAL 0xdb +#define BD9571MWV_PRODUCT_CODE 0x01 +#define BD9571MWV_PRODUCT_CODE_VAL 0x60 +#define BD9571MWV_PRODUCT_REVISION 0x02 + +#define BD9571MWV_I2C_FUSA_MODE 0x10 +#define BD9571MWV_I2C_MD2_E1_BIT_1 0x11 +#define BD9571MWV_I2C_MD2_E1_BIT_2 0x12 + +#define BD9571MWV_BKUP_MODE_CNT 0x20 +#define BD9571MWV_BKUP_MODE_STATUS 0x21 +#define BD9571MWV_BKUP_RECOVERY_CNT 0x22 +#define BD9571MWV_BKUP_CTRL_TIM_CNT 0x23 +#define BD9571MWV_WAITBKUP_WDT_CNT 0x24 +#define BD9571MWV_128H_TIM_CNT 0x26 +#define BD9571MWV_QLLM_CNT 0x27 + +#define BD9571MWV_AVS_SET_MONI 0x31 +#define BD9571MWV_AVS_SET_MONI_MASK 0x3 +#define BD9571MWV_AVS_VD09_VID(n) (0x32 + (n)) +#define BD9571MWV_AVS_DVFS_VID(n) (0x36 + (n)) + +#define BD9571MWV_VD18_VID 0x42 +#define BD9571MWV_VD25_VID 0x43 +#define BD9571MWV_VD33_VID 0x44 + +#define BD9571MWV_DVFS_VINIT 0x50 +#define BD9571MWV_DVFS_SETVMAX 0x52 +#define BD9571MWV_DVFS_BOOSTVID 0x53 +#define BD9571MWV_DVFS_SETVID 0x54 +#define BD9571MWV_DVFS_MONIVDAC 0x55 +#define BD9571MWV_DVFS_PGD_CNT 0x56 + +#define BD9571MWV_GPIO_DIR 0x60 +#define BD9571MWV_GPIO_OUT 0x61 +#define BD9571MWV_GPIO_IN 0x62 +#define BD9571MWV_GPIO_DEB 0x63 +#define BD9571MWV_GPIO_INT_SET 0x64 +#define BD9571MWV_GPIO_INT 0x65 +#define BD9571MWV_GPIO_INTMASK 0x66 + +#define BD9571MWV_REG_KEEP(n) (0x70 + (n)) + +#define BD9571MWV_PMIC_INTERNAL_STATUS 0x80 +#define BD9571MWV_PROT_ERROR_STATUS0 0x81 +#define BD9571MWV_PROT_ERROR_STATUS1 0x82 +#define BD9571MWV_PROT_ERROR_STATUS2 0x83 +#define BD9571MWV_PROT_ERROR_STATUS3 0x84 +#define BD9571MWV_PROT_ERROR_STATUS4 0x85 + +#define BD9571MWV_INT_INTREQ 0x90 +#define BD9571MWV_INT_INTREQ_MD1_INT BIT(0) +#define BD9571MWV_INT_INTREQ_MD2_E1_INT BIT(1) +#define BD9571MWV_INT_INTREQ_MD2_E2_INT BIT(2) +#define BD9571MWV_INT_INTREQ_PROT_ERR_INT BIT(3) +#define BD9571MWV_INT_INTREQ_GP_INT BIT(4) +#define BD9571MWV_INT_INTREQ_128H_OF_INT BIT(5) +#define BD9571MWV_INT_INTREQ_WDT_OF_INT BIT(6) +#define BD9571MWV_INT_INTREQ_BKUP_TRG_INT BIT(7) +#define BD9571MWV_INT_INTMASK 0x91 + +#define BD9571MWV_ACCESS_KEY 0xff + +/* Define the BD9571MWV IRQ numbers */ +enum bd9571mwv_irqs { + BD9571MWV_IRQ_MD1, + BD9571MWV_IRQ_MD2_E1, + BD9571MWV_IRQ_MD2_E2, + BD9571MWV_IRQ_PROT_ERR, + BD9571MWV_IRQ_GP, + BD9571MWV_IRQ_128H_OF, + BD9571MWV_IRQ_WDT_OF, + BD9571MWV_IRQ_BKUP_TRG, +}; + +/** + * struct bd9571mwv - state holder for the bd9571mwv driver + * + * Device data may be used to access the BD9571MWV chip + */ +struct bd9571mwv { + struct device *dev; + struct regmap *regmap; + + /* IRQ Data */ + int irq; + struct regmap_irq_chip_data *irq_data; +}; + +#endif /* __LINUX_MFD_BD9571MWV_H */ diff --git a/include/linux/i2c/dm355evm_msp.h b/include/linux/mfd/dm355evm_msp.h index 372470350fab..372470350fab 100644 --- a/include/linux/i2c/dm355evm_msp.h +++ b/include/linux/mfd/dm355evm_msp.h diff --git a/include/linux/mfd/hi6421-pmic.h b/include/linux/mfd/hi6421-pmic.h index 587273e35acf..2580c08db7b1 100644 --- a/include/linux/mfd/hi6421-pmic.h +++ b/include/linux/mfd/hi6421-pmic.h @@ -38,4 +38,9 @@ struct hi6421_pmic { struct regmap *regmap; }; +enum hi6421_type { + HI6421 = 0, + HI6421_V530, +}; + #endif /* __HI6421_PMIC_H */ diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h index 83701ef7d3c7..d3156594674c 100644 --- a/include/linux/mfd/rk808.h +++ b/include/linux/mfd/rk808.h @@ -206,6 +206,97 @@ enum rk818_reg { #define RK818_USB_ILMIN_2000MA 0x7 #define RK818_USB_CHG_SD_VSEL_MASK 0x70 +/* RK805 */ +enum rk805_reg { + RK805_ID_DCDC1, + RK805_ID_DCDC2, + RK805_ID_DCDC3, + RK805_ID_DCDC4, + RK805_ID_LDO1, + RK805_ID_LDO2, + RK805_ID_LDO3, +}; + +/* CONFIG REGISTER */ +#define RK805_VB_MON_REG 0x21 +#define RK805_THERMAL_REG 0x22 + +/* POWER CHANNELS ENABLE REGISTER */ +#define RK805_DCDC_EN_REG 0x23 +#define RK805_SLP_DCDC_EN_REG 0x25 +#define RK805_SLP_LDO_EN_REG 0x26 +#define RK805_LDO_EN_REG 0x27 + +/* BUCK AND LDO CONFIG REGISTER */ +#define RK805_BUCK_LDO_SLP_LP_EN_REG 0x2A +#define RK805_BUCK1_CONFIG_REG 0x2E +#define RK805_BUCK1_ON_VSEL_REG 0x2F +#define RK805_BUCK1_SLP_VSEL_REG 0x30 +#define RK805_BUCK2_CONFIG_REG 0x32 +#define RK805_BUCK2_ON_VSEL_REG 0x33 +#define RK805_BUCK2_SLP_VSEL_REG 0x34 +#define RK805_BUCK3_CONFIG_REG 0x36 +#define RK805_BUCK4_CONFIG_REG 0x37 +#define RK805_BUCK4_ON_VSEL_REG 0x38 +#define RK805_BUCK4_SLP_VSEL_REG 0x39 +#define RK805_LDO1_ON_VSEL_REG 0x3B +#define RK805_LDO1_SLP_VSEL_REG 0x3C +#define RK805_LDO2_ON_VSEL_REG 0x3D +#define RK805_LDO2_SLP_VSEL_REG 0x3E +#define RK805_LDO3_ON_VSEL_REG 0x3F +#define RK805_LDO3_SLP_VSEL_REG 0x40 + +/* INTERRUPT REGISTER */ +#define RK805_PWRON_LP_INT_TIME_REG 0x47 +#define RK805_PWRON_DB_REG 0x48 +#define RK805_DEV_CTRL_REG 0x4B +#define RK805_INT_STS_REG 0x4C +#define RK805_INT_STS_MSK_REG 0x4D +#define RK805_GPIO_IO_POL_REG 0x50 +#define RK805_OUT_REG 0x52 +#define RK805_ON_SOURCE_REG 0xAE +#define RK805_OFF_SOURCE_REG 0xAF + +#define RK805_NUM_REGULATORS 7 + +#define RK805_PWRON_FALL_RISE_INT_EN 0x0 +#define RK805_PWRON_FALL_RISE_INT_MSK 0x81 + +/* RK805 IRQ Definitions */ +#define RK805_IRQ_PWRON_RISE 0 +#define RK805_IRQ_VB_LOW 1 +#define RK805_IRQ_PWRON 2 +#define RK805_IRQ_PWRON_LP 3 +#define RK805_IRQ_HOTDIE 4 +#define RK805_IRQ_RTC_ALARM 5 +#define RK805_IRQ_RTC_PERIOD 6 +#define RK805_IRQ_PWRON_FALL 7 + +#define RK805_IRQ_PWRON_RISE_MSK BIT(0) +#define RK805_IRQ_VB_LOW_MSK BIT(1) +#define RK805_IRQ_PWRON_MSK BIT(2) +#define RK805_IRQ_PWRON_LP_MSK BIT(3) +#define RK805_IRQ_HOTDIE_MSK BIT(4) +#define RK805_IRQ_RTC_ALARM_MSK BIT(5) +#define RK805_IRQ_RTC_PERIOD_MSK BIT(6) +#define RK805_IRQ_PWRON_FALL_MSK BIT(7) + +#define RK805_PWR_RISE_INT_STATUS BIT(0) +#define RK805_VB_LOW_INT_STATUS BIT(1) +#define RK805_PWRON_INT_STATUS BIT(2) +#define RK805_PWRON_LP_INT_STATUS BIT(3) +#define RK805_HOTDIE_INT_STATUS BIT(4) +#define RK805_ALARM_INT_STATUS BIT(5) +#define RK805_PERIOD_INT_STATUS BIT(6) +#define RK805_PWR_FALL_INT_STATUS BIT(7) + +#define RK805_BUCK1_2_ILMAX_MASK (3 << 6) +#define RK805_BUCK3_4_ILMAX_MASK (3 << 3) +#define RK805_RTC_PERIOD_INT_MASK (1 << 6) +#define RK805_RTC_ALARM_INT_MASK (1 << 5) +#define RK805_INT_ALARM_EN (1 << 3) +#define RK805_INT_TIMER_EN (1 << 2) + /* RK808 IRQ Definitions */ #define RK808_IRQ_VOUT_LO 0 #define RK808_IRQ_VB_LO 1 @@ -298,6 +389,14 @@ enum rk818_reg { #define VOUT_LO_INT BIT(0) #define CLK32KOUT2_EN BIT(0) +#define TEMP115C 0x0c +#define TEMP_HOTDIE_MSK 0x0c +#define SLP_SD_MSK (0x3 << 2) +#define SHUTDOWN_FUN (0x2 << 2) +#define SLEEP_FUN (0x1 << 2) +#define RK8XX_ID_MSK 0xfff0 +#define FPWM_MODE BIT(7) + enum { BUCK_ILMIN_50MA, BUCK_ILMIN_100MA, @@ -321,6 +420,28 @@ enum { }; enum { + RK805_BUCK1_2_ILMAX_2500MA, + RK805_BUCK1_2_ILMAX_3000MA, + RK805_BUCK1_2_ILMAX_3500MA, + RK805_BUCK1_2_ILMAX_4000MA, +}; + +enum { + RK805_BUCK3_ILMAX_1500MA, + RK805_BUCK3_ILMAX_2000MA, + RK805_BUCK3_ILMAX_2500MA, + RK805_BUCK3_ILMAX_3000MA, +}; + +enum { + RK805_BUCK4_ILMAX_2000MA, + RK805_BUCK4_ILMAX_2500MA, + RK805_BUCK4_ILMAX_3000MA, + RK805_BUCK4_ILMAX_3500MA, +}; + +enum { + RK805_ID = 0x8050, RK808_ID = 0x0000, RK818_ID = 0x8181, }; diff --git a/include/linux/mfd/stm32-lptimer.h b/include/linux/mfd/stm32-lptimer.h new file mode 100644 index 000000000000..77c7cf40d9b4 --- /dev/null +++ b/include/linux/mfd/stm32-lptimer.h @@ -0,0 +1,62 @@ +/* + * STM32 Low-Power Timer parent driver. + * + * Copyright (C) STMicroelectronics 2017 + * + * Author: Fabrice Gasnier <fabrice.gasnier@st.com> + * + * Inspired by Benjamin Gaignard's stm32-timers driver + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _LINUX_STM32_LPTIMER_H_ +#define _LINUX_STM32_LPTIMER_H_ + +#include <linux/clk.h> +#include <linux/regmap.h> + +#define STM32_LPTIM_ISR 0x00 /* Interrupt and Status Reg */ +#define STM32_LPTIM_ICR 0x04 /* Interrupt Clear Reg */ +#define STM32_LPTIM_IER 0x08 /* Interrupt Enable Reg */ +#define STM32_LPTIM_CFGR 0x0C /* Configuration Reg */ +#define STM32_LPTIM_CR 0x10 /* Control Reg */ +#define STM32_LPTIM_CMP 0x14 /* Compare Reg */ +#define STM32_LPTIM_ARR 0x18 /* Autoreload Reg */ +#define STM32_LPTIM_CNT 0x1C /* Counter Reg */ + +/* STM32_LPTIM_ISR - bit fields */ +#define STM32_LPTIM_CMPOK_ARROK GENMASK(4, 3) +#define STM32_LPTIM_ARROK BIT(4) +#define STM32_LPTIM_CMPOK BIT(3) + +/* STM32_LPTIM_ICR - bit fields */ +#define STM32_LPTIM_CMPOKCF_ARROKCF GENMASK(4, 3) + +/* STM32_LPTIM_CR - bit fields */ +#define STM32_LPTIM_CNTSTRT BIT(2) +#define STM32_LPTIM_ENABLE BIT(0) + +/* STM32_LPTIM_CFGR - bit fields */ +#define STM32_LPTIM_ENC BIT(24) +#define STM32_LPTIM_COUNTMODE BIT(23) +#define STM32_LPTIM_WAVPOL BIT(21) +#define STM32_LPTIM_PRESC GENMASK(11, 9) +#define STM32_LPTIM_CKPOL GENMASK(2, 1) + +/* STM32_LPTIM_ARR */ +#define STM32_LPTIM_MAX_ARR 0xFFFF + +/** + * struct stm32_lptimer - STM32 Low-Power Timer data assigned by parent device + * @clk: clock reference for this instance + * @regmap: register map reference for this instance + * @has_encoder: indicates this Low-Power Timer supports encoder mode + */ +struct stm32_lptimer { + struct clk *clk; + struct regmap *regmap; + bool has_encoder; +}; + +#endif diff --git a/include/linux/mfd/syscon/atmel-smc.h b/include/linux/mfd/syscon/atmel-smc.h index afa266169800..7a367f34b66a 100644 --- a/include/linux/mfd/syscon/atmel-smc.h +++ b/include/linux/mfd/syscon/atmel-smc.h @@ -15,21 +15,26 @@ #define _LINUX_MFD_SYSCON_ATMEL_SMC_H_ #include <linux/kernel.h> +#include <linux/of.h> #include <linux/regmap.h> #define ATMEL_SMC_SETUP(cs) (((cs) * 0x10)) -#define ATMEL_HSMC_SETUP(cs) (0x600 + ((cs) * 0x14)) +#define ATMEL_HSMC_SETUP(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14)) #define ATMEL_SMC_PULSE(cs) (((cs) * 0x10) + 0x4) -#define ATMEL_HSMC_PULSE(cs) (0x600 + ((cs) * 0x14) + 0x4) +#define ATMEL_HSMC_PULSE(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14) + 0x4) #define ATMEL_SMC_CYCLE(cs) (((cs) * 0x10) + 0x8) -#define ATMEL_HSMC_CYCLE(cs) (0x600 + ((cs) * 0x14) + 0x8) +#define ATMEL_HSMC_CYCLE(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14) + 0x8) #define ATMEL_SMC_NWE_SHIFT 0 #define ATMEL_SMC_NCS_WR_SHIFT 8 #define ATMEL_SMC_NRD_SHIFT 16 #define ATMEL_SMC_NCS_RD_SHIFT 24 #define ATMEL_SMC_MODE(cs) (((cs) * 0x10) + 0xc) -#define ATMEL_HSMC_MODE(cs) (0x600 + ((cs) * 0x14) + 0x10) +#define ATMEL_HSMC_MODE(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14) + 0x10) #define ATMEL_SMC_MODE_READMODE_MASK BIT(0) #define ATMEL_SMC_MODE_READMODE_NCS (0 << 0) #define ATMEL_SMC_MODE_READMODE_NRD (1 << 0) @@ -59,7 +64,8 @@ #define ATMEL_SMC_MODE_PS_16 (2 << 28) #define ATMEL_SMC_MODE_PS_32 (3 << 28) -#define ATMEL_HSMC_TIMINGS(cs) (0x600 + ((cs) * 0x14) + 0xc) +#define ATMEL_HSMC_TIMINGS(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14) + 0xc) #define ATMEL_HSMC_TIMINGS_OCMS BIT(12) #define ATMEL_HSMC_TIMINGS_RBNSEL(x) ((x) << 28) #define ATMEL_HSMC_TIMINGS_NFSEL BIT(31) @@ -69,6 +75,10 @@ #define ATMEL_HSMC_TIMINGS_TRR_SHIFT 16 #define ATMEL_HSMC_TIMINGS_TWB_SHIFT 24 +struct atmel_hsmc_reg_layout { + unsigned int timing_regs_offset; +}; + /** * struct atmel_smc_cs_conf - SMC CS config as described in the datasheet. * @setup: NCS/NWE/NRD setup timings (not applicable to at91rm9200) @@ -98,11 +108,15 @@ int atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf *conf, unsigned int shift, unsigned int ncycles); void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs, const struct atmel_smc_cs_conf *conf); -void atmel_hsmc_cs_conf_apply(struct regmap *regmap, int cs, - const struct atmel_smc_cs_conf *conf); +void atmel_hsmc_cs_conf_apply(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *reglayout, + int cs, const struct atmel_smc_cs_conf *conf); void atmel_smc_cs_conf_get(struct regmap *regmap, int cs, struct atmel_smc_cs_conf *conf); -void atmel_hsmc_cs_conf_get(struct regmap *regmap, int cs, - struct atmel_smc_cs_conf *conf); +void atmel_hsmc_cs_conf_get(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *reglayout, + int cs, struct atmel_smc_cs_conf *conf); +const struct atmel_hsmc_reg_layout * +atmel_hsmc_get_reg_layout(struct device_node *np); #endif /* _LINUX_MFD_SYSCON_ATMEL_SMC_H_ */ diff --git a/include/linux/i2c/tps65010.h b/include/linux/mfd/tps65010.h index 08aa92278d71..a1fb9bc5311d 100644 --- a/include/linux/i2c/tps65010.h +++ b/include/linux/mfd/tps65010.h @@ -1,4 +1,4 @@ -/* linux/i2c/tps65010.h +/* linux/mfd/tps65010.h * * Functions to access TPS65010 power management device. * diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h new file mode 100644 index 000000000000..44f9d9f647ed --- /dev/null +++ b/include/linux/mfd/tps68470.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * Functions to access TPS68470 power management chip. + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_MFD_TPS68470_H +#define __LINUX_MFD_TPS68470_H + +/* Register addresses */ +#define TPS68470_REG_POSTDIV2 0x06 +#define TPS68470_REG_BOOSTDIV 0x07 +#define TPS68470_REG_BUCKDIV 0x08 +#define TPS68470_REG_PLLSWR 0x09 +#define TPS68470_REG_XTALDIV 0x0A +#define TPS68470_REG_PLLDIV 0x0B +#define TPS68470_REG_POSTDIV 0x0C +#define TPS68470_REG_PLLCTL 0x0D +#define TPS68470_REG_PLLCTL2 0x0E +#define TPS68470_REG_CLKCFG1 0x0F +#define TPS68470_REG_CLKCFG2 0x10 +#define TPS68470_REG_GPCTL0A 0x14 +#define TPS68470_REG_GPCTL0B 0x15 +#define TPS68470_REG_GPCTL1A 0x16 +#define TPS68470_REG_GPCTL1B 0x17 +#define TPS68470_REG_GPCTL2A 0x18 +#define TPS68470_REG_GPCTL2B 0x19 +#define TPS68470_REG_GPCTL3A 0x1A +#define TPS68470_REG_GPCTL3B 0x1B +#define TPS68470_REG_GPCTL4A 0x1C +#define TPS68470_REG_GPCTL4B 0x1D +#define TPS68470_REG_GPCTL5A 0x1E +#define TPS68470_REG_GPCTL5B 0x1F +#define TPS68470_REG_GPCTL6A 0x20 +#define TPS68470_REG_GPCTL6B 0x21 +#define TPS68470_REG_SGPO 0x22 +#define TPS68470_REG_GPDI 0x26 +#define TPS68470_REG_GPDO 0x27 +#define TPS68470_REG_VCMVAL 0x3C +#define TPS68470_REG_VAUX1VAL 0x3D +#define TPS68470_REG_VAUX2VAL 0x3E +#define TPS68470_REG_VIOVAL 0x3F +#define TPS68470_REG_VSIOVAL 0x40 +#define TPS68470_REG_VAVAL 0x41 +#define TPS68470_REG_VDVAL 0x42 +#define TPS68470_REG_S_I2C_CTL 0x43 +#define TPS68470_REG_VCMCTL 0x44 +#define TPS68470_REG_VAUX1CTL 0x45 +#define TPS68470_REG_VAUX2CTL 0x46 +#define TPS68470_REG_VACTL 0x47 +#define TPS68470_REG_VDCTL 0x48 +#define TPS68470_REG_RESET 0x50 +#define TPS68470_REG_REVID 0xFF + +#define TPS68470_REG_MAX TPS68470_REG_REVID + +/* Register field definitions */ + +#define TPS68470_REG_RESET_MASK GENMASK(7, 0) +#define TPS68470_VAVAL_AVOLT_MASK GENMASK(6, 0) + +#define TPS68470_VDVAL_DVOLT_MASK GENMASK(5, 0) +#define TPS68470_VCMVAL_VCVOLT_MASK GENMASK(6, 0) +#define TPS68470_VIOVAL_IOVOLT_MASK GENMASK(6, 0) +#define TPS68470_VSIOVAL_IOVOLT_MASK GENMASK(6, 0) +#define TPS68470_VAUX1VAL_AUX1VOLT_MASK GENMASK(6, 0) +#define TPS68470_VAUX2VAL_AUX2VOLT_MASK GENMASK(6, 0) + +#define TPS68470_VACTL_EN_MASK GENMASK(0, 0) +#define TPS68470_VDCTL_EN_MASK GENMASK(0, 0) +#define TPS68470_VCMCTL_EN_MASK GENMASK(0, 0) +#define TPS68470_S_I2C_CTL_EN_MASK GENMASK(1, 0) +#define TPS68470_VAUX1CTL_EN_MASK GENMASK(0, 0) +#define TPS68470_VAUX2CTL_EN_MASK GENMASK(0, 0) +#define TPS68470_PLL_EN_MASK GENMASK(0, 0) + +#define TPS68470_CLKCFG1_MODE_A_MASK GENMASK(1, 0) +#define TPS68470_CLKCFG1_MODE_B_MASK GENMASK(3, 2) + +#define TPS68470_GPIO_CTL_REG_A(x) (TPS68470_REG_GPCTL0A + (x) * 2) +#define TPS68470_GPIO_CTL_REG_B(x) (TPS68470_REG_GPCTL0B + (x) * 2) +#define TPS68470_GPIO_MODE_MASK GENMASK(1, 0) +#define TPS68470_GPIO_MODE_IN 0 +#define TPS68470_GPIO_MODE_IN_PULLUP 1 +#define TPS68470_GPIO_MODE_OUT_CMOS 2 +#define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + +#endif /* __LINUX_MFD_TPS68470_H */ diff --git a/include/linux/i2c/twl.h b/include/linux/mfd/twl.h index 9ad7828d9d34..9ad7828d9d34 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/mfd/twl.h diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index d439c4c6fe50..c482b2e7a7d2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -28,7 +28,7 @@ #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_gpio.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #include <linux/slab.h> #include <linux/gpio.h> #include <sound/core.h> |