diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-23 20:31:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-23 20:31:27 -0400 |
commit | 84e9c87e6ffc519fdf91949482a65672a7314c9a (patch) | |
tree | 29775d71f1f58c41365ce597192524cf5544b340 | |
parent | 7fe0bf908d4f8f7d134cab280cac64fe65997ac1 (diff) | |
parent | 1abf25a25b86dcfe28d243a5af71bd1c9d6de1ef (diff) |
Merge tag 'mfd-for-linus-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"Changes to existing drivers:
- Constify structures; throughout the subsystem
- Move support to DT in; cros_ec
- DT changes and documentation; cros-ec, max77693, max77686, arizona, da9063
- ACPI changes and documentation; mfd-core
- Use different platform specific API in; cros_ec_*, arizona-core
- Remove unused parent field from; cros_ec_i2c
- Add wake-up/reset delay in; cross_ec_spi, arizona-core
- Staticise structures/functions in; cros_ec
- Remove redundant code; arizona-core, max77686
- Bugfix; twl4030-power
- Allow compile test; aat2870, tps65910
- MAINTAINERS adaptions; samsung, syscon
- Resource Management (devm_*); arizona-core
- Refactor Reset code; arizona-core
- Insist on at least one full boot; arizona-core
- Trivial formatting; arizona-core
- Add low-power-sleep; arizona-core
- IRQ ONESHOT changes; twl4030-irq, mc13xxx-core, wm831x-auxadc, htc-i2cpld,
wm8350-core, ab8500-debugfs, ab8500-gpadc, si476x-i2c
(Re-)moved drivers:
- Move protocol helpers out to drivers/platform; cros_ec
New drivers/supported devices:
- Add support for AXP22x into axp20x
- Add support for OnKey into da9063-core
- Add support for Pinctrl into mt6397-core
- New STMicroelectronics LPC Watchdog driver
- New STMicroelectronics LPC Real-Time Clock driver"
* tag 'mfd-for-linus-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (59 commits)
mfd: lpc_ich: Assign subdevice ids automatically
mfd: si476x-i2c: Pass the IRQF_ONESHOT flag
mfd: ab8500-gpadc: Pass the IRQF_ONESHOT flag
mfd: ab8500-debugfs: Pass the IRQF_ONESHOT flag
mfd: wm8350-core: Pass the IRQF_ONESHOT flag
mfd: htc-i2cpld: Pass the IRQF_ONESHOT flag
mfd: wm831x-auxadc: Pass the IRQF_ONESHOT flag
mfd: mc13xxx-core: Pass the IRQF_ONESHOT flag
mfd: twl4030-irq: Pass the IRQF_ONESHOT flag
mfd: mt6397-core: Add GPIO sub-module support
mfd: arizona: Add convience defines for micd_rate/micd_bias_starttime
mfd: dt: Add bindings for DA9063 OnKey
mfd: da9063: Add support for OnKey driver
mfd: arizona: Fix incorrect Makefile conditionals
mfd: arizona: Add stub for wm5102_patch()
mfd: Check ACPI device companion before checking resources
Documentation: Add WM8998/WM1814 device tree bindings
mfd: arizona: Split INx_MODE into two fields
mfd: wm5110: Add delay before releasing reset line
mfd: arizona: Add better support for system suspend
...
79 files changed, 3621 insertions, 660 deletions
diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt index 7665aa95979f..64fa3b2de6cd 100644 --- a/Documentation/devicetree/bindings/mfd/arizona.txt +++ b/Documentation/devicetree/bindings/mfd/arizona.txt | |||
@@ -10,6 +10,9 @@ Required properties: | |||
10 | "wlf,wm5110" | 10 | "wlf,wm5110" |
11 | "wlf,wm8280" | 11 | "wlf,wm8280" |
12 | "wlf,wm8997" | 12 | "wlf,wm8997" |
13 | "wlf,wm8998" | ||
14 | "wlf,wm1814" | ||
15 | |||
13 | - reg : I2C slave address when connected using I2C, chip select number when | 16 | - reg : I2C slave address when connected using I2C, chip select number when |
14 | using SPI. | 17 | using SPI. |
15 | 18 | ||
@@ -31,10 +34,10 @@ Required properties: | |||
31 | as covered in Documentation/devicetree/bindings/regulator/regulator.txt | 34 | as covered in Documentation/devicetree/bindings/regulator/regulator.txt |
32 | 35 | ||
33 | - DBVDD2-supply, DBVDD3-supply : Additional databus power supplies (wm5102, | 36 | - DBVDD2-supply, DBVDD3-supply : Additional databus power supplies (wm5102, |
34 | wm5110, wm8280) | 37 | wm5110, wm8280, wm8998, wm1814) |
35 | 38 | ||
36 | - SPKVDDL-supply, SPKVDDR-supply : Speaker driver power supplies (wm5102, | 39 | - SPKVDDL-supply, SPKVDDR-supply : Speaker driver power supplies (wm5102, |
37 | wm5110, wm8280) | 40 | wm5110, wm8280, wm8998, wm1814) |
38 | 41 | ||
39 | - SPKVDD-supply : Speaker driver power supply (wm8997) | 42 | - SPKVDD-supply : Speaker driver power supply (wm8997) |
40 | 43 | ||
@@ -53,8 +56,10 @@ Optional properties: | |||
53 | of input signals. Valid values are 0 (Differential), 1 (Single-ended) and | 56 | of input signals. Valid values are 0 (Differential), 1 (Single-ended) and |
54 | 2 (Digital Microphone). If absent, INn_MODE registers set to 0 by default. | 57 | 2 (Digital Microphone). If absent, INn_MODE registers set to 0 by default. |
55 | If present, values must be specified less than or equal to the number of | 58 | If present, values must be specified less than or equal to the number of |
56 | input singals. If values less than the number of input signals, elements | 59 | input signals. If values less than the number of input signals, elements |
57 | that has not been specifed are set to 0 by default. | 60 | that have not been specified are set to 0 by default. Entries are: |
61 | <IN1, IN2, IN3, IN4> (wm5102, wm5110, wm8280, wm8997) | ||
62 | <IN1A, IN2A, IN1B, IN2B> (wm8998, wm1814) | ||
58 | 63 | ||
59 | - wlf,dmic-ref : DMIC reference voltage source for each input, can be | 64 | - wlf,dmic-ref : DMIC reference voltage source for each input, can be |
60 | selected from either MICVDD or one of the MICBIAS's, defines | 65 | selected from either MICVDD or one of the MICBIAS's, defines |
diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt index 98685f291a72..753f14f46e85 100644 --- a/Documentation/devicetree/bindings/mfd/axp20x.txt +++ b/Documentation/devicetree/bindings/mfd/axp20x.txt | |||
@@ -1,15 +1,16 @@ | |||
1 | AXP202/AXP209 device tree bindings | 1 | AXP family PMIC device tree bindings |
2 | 2 | ||
3 | The axp20x family current members : | 3 | The axp20x family current members : |
4 | axp202 (X-Powers) | 4 | axp202 (X-Powers) |
5 | axp209 (X-Powers) | 5 | axp209 (X-Powers) |
6 | axp221 (X-Powers) | ||
6 | 7 | ||
7 | Required properties: | 8 | Required properties: |
8 | - compatible: "x-powers,axp202" or "x-powers,axp209" | 9 | - compatible: "x-powers,axp202", "x-powers,axp209", "x-powers,axp221" |
9 | - reg: The I2C slave address for the AXP chip | 10 | - reg: The I2C slave address for the AXP chip |
10 | - interrupt-parent: The parent interrupt controller | 11 | - interrupt-parent: The parent interrupt controller |
11 | - interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin | 12 | - interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin |
12 | - interrupt-controller: axp20x has its own internal IRQs | 13 | - interrupt-controller: The PMIC has its own internal IRQs |
13 | - #interrupt-cells: Should be set to 1 | 14 | - #interrupt-cells: Should be set to 1 |
14 | 15 | ||
15 | Optional properties: | 16 | Optional properties: |
@@ -48,6 +49,31 @@ LDO3 : LDO : ldo3in-supply | |||
48 | LDO4 : LDO : ldo24in-supply : shared supply | 49 | LDO4 : LDO : ldo24in-supply : shared supply |
49 | LDO5 : LDO : ldo5in-supply | 50 | LDO5 : LDO : ldo5in-supply |
50 | 51 | ||
52 | AXP221 regulators, type, and corresponding input supply names: | ||
53 | |||
54 | Regulator Type Supply Name Notes | ||
55 | --------- ---- ----------- ----- | ||
56 | DCDC1 : DC-DC buck : vin1-supply | ||
57 | DCDC2 : DC-DC buck : vin2-supply | ||
58 | DCDC3 : DC-DC buck : vin3-supply | ||
59 | DCDC4 : DC-DC buck : vin4-supply | ||
60 | DCDC5 : DC-DC buck : vin5-supply | ||
61 | DC1SW : On/Off Switch : dcdc1-supply : DCDC1 secondary output | ||
62 | DC5LDO : LDO : dcdc5-supply : input from DCDC5 | ||
63 | ALDO1 : LDO : aldoin-supply : shared supply | ||
64 | ALDO2 : LDO : aldoin-supply : shared supply | ||
65 | ALDO3 : LDO : aldoin-supply : shared supply | ||
66 | DLDO1 : LDO : dldoin-supply : shared supply | ||
67 | DLDO2 : LDO : dldoin-supply : shared supply | ||
68 | DLDO3 : LDO : dldoin-supply : shared supply | ||
69 | DLDO4 : LDO : dldoin-supply : shared supply | ||
70 | ELDO1 : LDO : eldoin-supply : shared supply | ||
71 | ELDO2 : LDO : eldoin-supply : shared supply | ||
72 | ELDO3 : LDO : eldoin-supply : shared supply | ||
73 | LDO_IO0 : LDO : ips-supply : GPIO 0 | ||
74 | LDO_IO1 : LDO : ips-supply : GPIO 1 | ||
75 | RTC_LDO : LDO : ips-supply : always on | ||
76 | |||
51 | Example: | 77 | Example: |
52 | 78 | ||
53 | axp209: pmic@34 { | 79 | axp209: pmic@34 { |
diff --git a/Documentation/devicetree/bindings/mfd/cros-ec.txt b/Documentation/devicetree/bindings/mfd/cros-ec.txt index 8009c3d87f33..1777916e9e28 100644 --- a/Documentation/devicetree/bindings/mfd/cros-ec.txt +++ b/Documentation/devicetree/bindings/mfd/cros-ec.txt | |||
@@ -18,6 +18,10 @@ Required properties (SPI): | |||
18 | - reg: SPI chip select | 18 | - reg: SPI chip select |
19 | 19 | ||
20 | Optional properties (SPI): | 20 | Optional properties (SPI): |
21 | - google,cros-ec-spi-pre-delay: Some implementations of the EC need a little | ||
22 | time to wake up from sleep before they can receive SPI transfers at a high | ||
23 | clock rate. This property specifies the delay, in usecs, between the | ||
24 | assertion of the CS to the start of the first clock pulse. | ||
21 | - google,cros-ec-spi-msg-delay: Some implementations of the EC require some | 25 | - google,cros-ec-spi-msg-delay: Some implementations of the EC require some |
22 | additional processing time in order to accept new transactions. If the delay | 26 | additional processing time in order to accept new transactions. If the delay |
23 | between transactions is not long enough the EC may not be able to respond | 27 | between transactions is not long enough the EC may not be able to respond |
diff --git a/Documentation/devicetree/bindings/mfd/da9063.txt b/Documentation/devicetree/bindings/mfd/da9063.txt index 42c6fa6f1c9a..05b21bcb8543 100644 --- a/Documentation/devicetree/bindings/mfd/da9063.txt +++ b/Documentation/devicetree/bindings/mfd/da9063.txt | |||
@@ -5,6 +5,7 @@ DA9093 consists of a large and varied group of sub-devices (I2C Only): | |||
5 | Device Supply Names Description | 5 | Device Supply Names Description |
6 | ------ ------------ ----------- | 6 | ------ ------------ ----------- |
7 | da9063-regulator : : LDOs & BUCKs | 7 | da9063-regulator : : LDOs & BUCKs |
8 | da9063-onkey : : On Key | ||
8 | da9063-rtc : : Real-Time Clock | 9 | da9063-rtc : : Real-Time Clock |
9 | da9063-watchdog : : Watchdog | 10 | da9063-watchdog : : Watchdog |
10 | 11 | ||
@@ -51,6 +52,18 @@ Sub-nodes: | |||
51 | the DA9063. There are currently no entries in this binding, however | 52 | the DA9063. There are currently no entries in this binding, however |
52 | compatible = "dlg,da9063-rtc" should be added if a node is created. | 53 | compatible = "dlg,da9063-rtc" should be added if a node is created. |
53 | 54 | ||
55 | - onkey : This node defines the OnKey settings for controlling the key | ||
56 | functionality of the device. The node should contain the compatible property | ||
57 | with the value "dlg,da9063-onkey". | ||
58 | |||
59 | Optional onkey properties: | ||
60 | |||
61 | - dlg,disable-key-power : Disable power-down using a long key-press. If this | ||
62 | entry exists the OnKey driver will remove support for the KEY_POWER key | ||
63 | press. If this entry does not exist then by default the key-press | ||
64 | triggered power down is enabled and the OnKey will support both KEY_POWER | ||
65 | and KEY_SLEEP. | ||
66 | |||
54 | - watchdog : This node defines settings for the Watchdog timer associated | 67 | - watchdog : This node defines settings for the Watchdog timer associated |
55 | with the DA9063. There are currently no entries in this binding, however | 68 | with the DA9063. There are currently no entries in this binding, however |
56 | compatible = "dlg,da9063-watchdog" should be added if a node is created. | 69 | compatible = "dlg,da9063-watchdog" should be added if a node is created. |
@@ -73,6 +86,11 @@ Example: | |||
73 | compatible = "dlg,da9063-watchdog"; | 86 | compatible = "dlg,da9063-watchdog"; |
74 | }; | 87 | }; |
75 | 88 | ||
89 | onkey { | ||
90 | compatible = "dlg,da9063-onkey"; | ||
91 | dlg,disable-key-power; | ||
92 | }; | ||
93 | |||
76 | regulators { | 94 | regulators { |
77 | DA9063_BCORE1: bcore1 { | 95 | DA9063_BCORE1: bcore1 { |
78 | regulator-name = "BCORE1"; | 96 | regulator-name = "BCORE1"; |
diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt index e39f0bc1f55e..163bd81a4607 100644 --- a/Documentation/devicetree/bindings/mfd/max77686.txt +++ b/Documentation/devicetree/bindings/mfd/max77686.txt | |||
@@ -1,6 +1,6 @@ | |||
1 | Maxim MAX77686 multi-function device | 1 | Maxim MAX77686 multi-function device |
2 | 2 | ||
3 | MAX77686 is a Mulitifunction device with PMIC, RTC and Charger on chip. It is | 3 | MAX77686 is a Multifunction device with PMIC, RTC and Charger on chip. It is |
4 | interfaced to host controller using i2c interface. PMIC and Charger submodules | 4 | interfaced to host controller using i2c interface. PMIC and Charger submodules |
5 | are addressed using same i2c slave address whereas RTC submodule uses | 5 | are addressed using same i2c slave address whereas RTC submodule uses |
6 | different i2c slave address,presently for which we are statically creating i2c | 6 | different i2c slave address,presently for which we are statically creating i2c |
diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt index 38e64405e98d..d3425846aa5b 100644 --- a/Documentation/devicetree/bindings/mfd/max77693.txt +++ b/Documentation/devicetree/bindings/mfd/max77693.txt | |||
@@ -76,7 +76,60 @@ Optional properties: | |||
76 | Valid values: 4300000, 4700000, 4800000, 4900000 | 76 | Valid values: 4300000, 4700000, 4800000, 4900000 |
77 | Default: 4300000 | 77 | Default: 4300000 |
78 | 78 | ||
79 | - led : the LED submodule device node | ||
80 | |||
81 | There are two LED outputs available - FLED1 and FLED2. Each of them can | ||
82 | control a separate LED or they can be connected together to double | ||
83 | the maximum current for a single connected LED. One LED is represented | ||
84 | by one child node. | ||
85 | |||
86 | Required properties: | ||
87 | - compatible : Must be "maxim,max77693-led". | ||
88 | |||
89 | Optional properties: | ||
90 | - maxim,boost-mode : | ||
91 | In boost mode the device can produce up to 1.2A of total current | ||
92 | on both outputs. The maximum current on each output is reduced | ||
93 | to 625mA then. If not enabled explicitly, boost setting defaults to | ||
94 | LEDS_BOOST_FIXED in case both current sources are used. | ||
95 | Possible values: | ||
96 | LEDS_BOOST_OFF (0) - no boost, | ||
97 | LEDS_BOOST_ADAPTIVE (1) - adaptive mode, | ||
98 | LEDS_BOOST_FIXED (2) - fixed mode. | ||
99 | - maxim,boost-mvout : Output voltage of the boost module in millivolts. | ||
100 | Valid values: 3300 - 5500, step by 25 (rounded down) | ||
101 | Default: 3300 | ||
102 | - maxim,mvsys-min : Low input voltage level in millivolts. Flash is not fired | ||
103 | if chip estimates that system voltage could drop below this level due | ||
104 | to flash power consumption. | ||
105 | Valid values: 2400 - 3400, step by 33 (rounded down) | ||
106 | Default: 2400 | ||
107 | |||
108 | Required properties for the LED child node: | ||
109 | - led-sources : see Documentation/devicetree/bindings/leds/common.txt; | ||
110 | device current output identifiers: 0 - FLED1, 1 - FLED2 | ||
111 | - led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt | ||
112 | Valid values for a LED connected to one FLED output: | ||
113 | 15625 - 250000, step by 15625 (rounded down) | ||
114 | Valid values for a LED connected to both FLED outputs: | ||
115 | 15625 - 500000, step by 15625 (rounded down) | ||
116 | - flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt | ||
117 | Valid values for a single LED connected to one FLED output | ||
118 | (boost mode must be turned off): | ||
119 | 15625 - 1000000, step by 15625 (rounded down) | ||
120 | Valid values for a single LED connected to both FLED outputs: | ||
121 | 15625 - 1250000, step by 15625 (rounded down) | ||
122 | Valid values for two LEDs case: | ||
123 | 15625 - 625000, step by 15625 (rounded down) | ||
124 | - flash-max-timeout-us : see Documentation/devicetree/bindings/leds/common.txt | ||
125 | Valid values: 62500 - 1000000, step by 62500 (rounded down) | ||
126 | |||
127 | Optional properties for the LED child node: | ||
128 | - label : see Documentation/devicetree/bindings/leds/common.txt | ||
129 | |||
79 | Example: | 130 | Example: |
131 | #include <dt-bindings/leds/common.h> | ||
132 | |||
80 | max77693@66 { | 133 | max77693@66 { |
81 | compatible = "maxim,max77693"; | 134 | compatible = "maxim,max77693"; |
82 | reg = <0x66>; | 135 | reg = <0x66>; |
@@ -117,5 +170,19 @@ Example: | |||
117 | maxim,thermal-regulation-celsius = <75>; | 170 | maxim,thermal-regulation-celsius = <75>; |
118 | maxim,battery-overcurrent-microamp = <3000000>; | 171 | maxim,battery-overcurrent-microamp = <3000000>; |
119 | maxim,charge-input-threshold-microvolt = <4300000>; | 172 | maxim,charge-input-threshold-microvolt = <4300000>; |
173 | |||
174 | led { | ||
175 | compatible = "maxim,max77693-led"; | ||
176 | maxim,boost-mode = <LEDS_BOOST_FIXED>; | ||
177 | maxim,boost-mvout = <5000>; | ||
178 | maxim,mvsys-min = <2400>; | ||
179 | |||
180 | camera_flash: flash-led { | ||
181 | label = "max77693-flash"; | ||
182 | led-sources = <0>, <1>; | ||
183 | led-max-microamp = <500000>; | ||
184 | flash-max-microamp = <1250000>; | ||
185 | flash-max-timeout-us = <1000000>; | ||
186 | }; | ||
120 | }; | 187 | }; |
121 | }; | 188 | }; |
diff --git a/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt b/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt new file mode 100644 index 000000000000..73407f502e4e --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt | |||
@@ -0,0 +1,25 @@ | |||
1 | STMicroelectronics Low Power Controller (LPC) - RTC | ||
2 | =================================================== | ||
3 | |||
4 | LPC currently supports Watchdog OR Real Time Clock functionality. | ||
5 | |||
6 | [See: ../watchdog/st_lpc_wdt.txt for Watchdog options] | ||
7 | |||
8 | Required properties | ||
9 | |||
10 | - compatible : Must be one of: "st,stih407-lpc" "st,stih416-lpc" | ||
11 | "st,stih415-lpc" "st,stid127-lpc" | ||
12 | - reg : LPC registers base address + size | ||
13 | - interrupts : LPC interrupt line number and associated flags | ||
14 | - clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) | ||
15 | - st,lpc-mode : The LPC can run either one of two modes ST_LPC_MODE_RTC [0] or | ||
16 | ST_LPC_MODE_WDT [1]. One (and only one) mode must be | ||
17 | selected. | ||
18 | |||
19 | Example: | ||
20 | lpc@fde05000 { | ||
21 | compatible = "st,stih407-lpc"; | ||
22 | reg = <0xfde05000 0x1000>; | ||
23 | clocks = <&clk_s_d3_flexgen CLK_LPC_0>; | ||
24 | st,lpc-mode = <ST_LPC_MODE_RTC>; | ||
25 | }; | ||
diff --git a/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt new file mode 100644 index 000000000000..388c88a01222 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt | |||
@@ -0,0 +1,38 @@ | |||
1 | STMicroelectronics Low Power Controller (LPC) - Watchdog | ||
2 | ======================================================== | ||
3 | |||
4 | LPC currently supports Watchdog OR Real Time Clock functionality. | ||
5 | |||
6 | [See: ../rtc/rtc-st-lpc.txt for RTC options] | ||
7 | |||
8 | Required properties | ||
9 | |||
10 | - compatible : Must be one of: "st,stih407-lpc" "st,stih416-lpc" | ||
11 | "st,stih415-lpc" "st,stid127-lpc" | ||
12 | - reg : LPC registers base address + size | ||
13 | - interrupts : LPC interrupt line number and associated flags | ||
14 | - clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) | ||
15 | - st,lpc-mode : The LPC can run either one of two modes ST_LPC_MODE_RTC [0] or | ||
16 | ST_LPC_MODE_WDT [1]. One (and only one) mode must be | ||
17 | selected. | ||
18 | |||
19 | Required properties [watchdog mode] | ||
20 | |||
21 | - st,syscfg : Phandle to syscfg node used to enable watchdog and configure | ||
22 | CPU reset type. | ||
23 | - timeout-sec : Watchdog timeout in seconds | ||
24 | |||
25 | Optional properties [watchdog mode] | ||
26 | |||
27 | - st,warm-reset : If present reset type will be 'warm' - if not it will be cold | ||
28 | |||
29 | Example: | ||
30 | lpc@fde05000 { | ||
31 | compatible = "st,stih407-lpc"; | ||
32 | reg = <0xfde05000 0x1000>; | ||
33 | clocks = <&clk_s_d3_flexgen CLK_LPC_0>; | ||
34 | st,syscfg = <&syscfg_core>; | ||
35 | timeout-sec = <120>; | ||
36 | st,lpc-mode = <ST_LPC_MODE_WDT>; | ||
37 | st,warm-reset; | ||
38 | }; | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 5829384460e6..a0ee3ca890ed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1489,10 +1489,12 @@ F: drivers/phy/phy-stih407-usb.c | |||
1489 | F: drivers/phy/phy-stih41x-usb.c | 1489 | F: drivers/phy/phy-stih41x-usb.c |
1490 | F: drivers/pinctrl/pinctrl-st.c | 1490 | F: drivers/pinctrl/pinctrl-st.c |
1491 | F: drivers/reset/sti/ | 1491 | F: drivers/reset/sti/ |
1492 | F: drivers/rtc/rtc-st-lpc.c | ||
1492 | F: drivers/tty/serial/st-asc.c | 1493 | F: drivers/tty/serial/st-asc.c |
1493 | F: drivers/usb/dwc3/dwc3-st.c | 1494 | F: drivers/usb/dwc3/dwc3-st.c |
1494 | F: drivers/usb/host/ehci-st.c | 1495 | F: drivers/usb/host/ehci-st.c |
1495 | F: drivers/usb/host/ohci-st.c | 1496 | F: drivers/usb/host/ohci-st.c |
1497 | F: drivers/watchdog/st_lpc_wdt.c | ||
1496 | F: drivers/ata/ahci_st.c | 1498 | F: drivers/ata/ahci_st.c |
1497 | 1499 | ||
1498 | ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT | 1500 | ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT |
@@ -8581,14 +8583,20 @@ L: linux-fbdev@vger.kernel.org | |||
8581 | S: Maintained | 8583 | S: Maintained |
8582 | F: drivers/video/fbdev/s3c-fb.c | 8584 | F: drivers/video/fbdev/s3c-fb.c |
8583 | 8585 | ||
8584 | SAMSUNG MULTIFUNCTION DEVICE DRIVERS | 8586 | SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS |
8585 | M: Sangbeom Kim <sbkim73@samsung.com> | 8587 | M: Sangbeom Kim <sbkim73@samsung.com> |
8588 | M: Krzysztof Kozlowski <k.kozlowski@samsung.com> | ||
8586 | L: linux-kernel@vger.kernel.org | 8589 | L: linux-kernel@vger.kernel.org |
8590 | L: linux-samsung-soc@vger.kernel.org | ||
8587 | S: Supported | 8591 | S: Supported |
8588 | F: drivers/mfd/sec*.c | 8592 | F: drivers/mfd/sec*.c |
8589 | F: drivers/regulator/s2m*.c | 8593 | F: drivers/regulator/s2m*.c |
8590 | F: drivers/regulator/s5m*.c | 8594 | F: drivers/regulator/s5m*.c |
8595 | F: drivers/clk/clk-s2mps11.c | ||
8596 | F: drivers/rtc/rtc-s5m.c | ||
8591 | F: include/linux/mfd/samsung/ | 8597 | F: include/linux/mfd/samsung/ |
8598 | F: Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt | ||
8599 | F: Documentation/devicetree/bindings/mfd/s2mp*.txt | ||
8592 | 8600 | ||
8593 | SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS | 8601 | SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS |
8594 | M: Kyungmin Park <kyungmin.park@samsung.com> | 8602 | M: Kyungmin Park <kyungmin.park@samsung.com> |
@@ -9627,6 +9635,13 @@ F: arch/arc/ | |||
9627 | F: Documentation/devicetree/bindings/arc/ | 9635 | F: Documentation/devicetree/bindings/arc/ |
9628 | F: drivers/tty/serial/arc_uart.c | 9636 | F: drivers/tty/serial/arc_uart.c |
9629 | 9637 | ||
9638 | SYSTEM CONFIGURATION (SYSCON) | ||
9639 | M: Lee Jones <lee.jones@linaro.org> | ||
9640 | M: Arnd Bergmann <arnd@arndb.de> | ||
9641 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git | ||
9642 | S: Supported | ||
9643 | F: drivers/mfd/syscon.c | ||
9644 | |||
9630 | SYSV FILESYSTEM | 9645 | SYSV FILESYSTEM |
9631 | M: Christoph Hellwig <hch@infradead.org> | 9646 | M: Christoph Hellwig <hch@infradead.org> |
9632 | S: Maintained | 9647 | S: Maintained |
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 2255af23b9c7..5f1c1c4f5d87 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -1103,7 +1103,7 @@ config I2C_SIBYTE | |||
1103 | 1103 | ||
1104 | config I2C_CROS_EC_TUNNEL | 1104 | config I2C_CROS_EC_TUNNEL |
1105 | tristate "ChromeOS EC tunnel I2C bus" | 1105 | tristate "ChromeOS EC tunnel I2C bus" |
1106 | depends on MFD_CROS_EC | 1106 | depends on CROS_EC_PROTO |
1107 | help | 1107 | help |
1108 | If you say yes here you get an I2C bus that will tunnel i2c commands | 1108 | If you say yes here you get an I2C bus that will tunnel i2c commands |
1109 | through to the other side of the ChromeOS EC to the i2c bus | 1109 | through to the other side of the ChromeOS EC to the i2c bus |
diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index fa8dedd8c3a2..a0d95ff682ae 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c | |||
@@ -182,8 +182,9 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], | |||
182 | const u16 bus_num = bus->remote_bus; | 182 | const u16 bus_num = bus->remote_bus; |
183 | int request_len; | 183 | int request_len; |
184 | int response_len; | 184 | int response_len; |
185 | int alloc_size; | ||
185 | int result; | 186 | int result; |
186 | struct cros_ec_command msg = { }; | 187 | struct cros_ec_command *msg; |
187 | 188 | ||
188 | request_len = ec_i2c_count_message(i2c_msgs, num); | 189 | request_len = ec_i2c_count_message(i2c_msgs, num); |
189 | if (request_len < 0) { | 190 | if (request_len < 0) { |
@@ -198,25 +199,39 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], | |||
198 | return response_len; | 199 | return response_len; |
199 | } | 200 | } |
200 | 201 | ||
201 | result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num); | 202 | alloc_size = max(request_len, response_len); |
202 | if (result) | 203 | msg = kmalloc(sizeof(*msg) + alloc_size, GFP_KERNEL); |
203 | return result; | 204 | if (!msg) |
205 | return -ENOMEM; | ||
204 | 206 | ||
205 | msg.version = 0; | 207 | result = ec_i2c_construct_message(msg->data, i2c_msgs, num, bus_num); |
206 | msg.command = EC_CMD_I2C_PASSTHRU; | 208 | if (result) { |
207 | msg.outsize = request_len; | 209 | dev_err(dev, "Error constructing EC i2c message %d\n", result); |
208 | msg.insize = response_len; | 210 | goto exit; |
211 | } | ||
209 | 212 | ||
210 | result = cros_ec_cmd_xfer(bus->ec, &msg); | 213 | msg->version = 0; |
211 | if (result < 0) | 214 | msg->command = EC_CMD_I2C_PASSTHRU; |
212 | return result; | 215 | msg->outsize = request_len; |
216 | msg->insize = response_len; | ||
213 | 217 | ||
214 | result = ec_i2c_parse_response(msg.indata, i2c_msgs, &num); | 218 | result = cros_ec_cmd_xfer(bus->ec, msg); |
215 | if (result < 0) | 219 | if (result < 0) { |
216 | return result; | 220 | dev_err(dev, "Error transferring EC i2c message %d\n", result); |
221 | goto exit; | ||
222 | } | ||
223 | |||
224 | result = ec_i2c_parse_response(msg->data, i2c_msgs, &num); | ||
225 | if (result < 0) { | ||
226 | dev_err(dev, "Error parsing EC i2c message %d\n", result); | ||
227 | goto exit; | ||
228 | } | ||
217 | 229 | ||
218 | /* Indicate success by saying how many messages were sent */ | 230 | /* Indicate success by saying how many messages were sent */ |
219 | return num; | 231 | result = num; |
232 | exit: | ||
233 | kfree(msg); | ||
234 | return result; | ||
220 | } | 235 | } |
221 | 236 | ||
222 | static u32 ec_i2c_functionality(struct i2c_adapter *adap) | 237 | static u32 ec_i2c_functionality(struct i2c_adapter *adap) |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 106fbac7f8c5..e8eb60c6d83e 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -677,7 +677,7 @@ config KEYBOARD_W90P910 | |||
677 | config KEYBOARD_CROS_EC | 677 | config KEYBOARD_CROS_EC |
678 | tristate "ChromeOS EC keyboard" | 678 | tristate "ChromeOS EC keyboard" |
679 | select INPUT_MATRIXKMAP | 679 | select INPUT_MATRIXKMAP |
680 | depends on MFD_CROS_EC | 680 | depends on CROS_EC_PROTO |
681 | help | 681 | help |
682 | Say Y here to enable the matrix keyboard used by ChromeOS devices | 682 | Say Y here to enable the matrix keyboard used by ChromeOS devices |
683 | and implemented on the ChromeOS EC. You must enable one bus option | 683 | and implemented on the ChromeOS EC. You must enable one bus option |
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index b50c5b8b8a4d..b01966dc7eb3 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c | |||
@@ -148,19 +148,28 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, | |||
148 | 148 | ||
149 | static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) | 149 | static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) |
150 | { | 150 | { |
151 | int ret; | 151 | int ret = 0; |
152 | struct cros_ec_command msg = { | 152 | struct cros_ec_command *msg; |
153 | .command = EC_CMD_MKBP_STATE, | ||
154 | .insize = ckdev->cols, | ||
155 | }; | ||
156 | 153 | ||
157 | ret = cros_ec_cmd_xfer(ckdev->ec, &msg); | 154 | msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL); |
158 | if (ret < 0) | 155 | if (!msg) |
159 | return ret; | 156 | return -ENOMEM; |
160 | 157 | ||
161 | memcpy(kb_state, msg.indata, ckdev->cols); | 158 | msg->version = 0; |
159 | msg->command = EC_CMD_MKBP_STATE; | ||
160 | msg->insize = ckdev->cols; | ||
161 | msg->outsize = 0; | ||
162 | 162 | ||
163 | return 0; | 163 | ret = cros_ec_cmd_xfer(ckdev->ec, msg); |
164 | if (ret < 0) { | ||
165 | dev_err(ckdev->dev, "Error transferring EC message %d\n", ret); | ||
166 | goto exit; | ||
167 | } | ||
168 | |||
169 | memcpy(kb_state, msg->data, ckdev->cols); | ||
170 | exit: | ||
171 | kfree(msg); | ||
172 | return ret; | ||
164 | } | 173 | } |
165 | 174 | ||
166 | static irqreturn_t cros_ec_keyb_irq(int irq, void *data) | 175 | static irqreturn_t cros_ec_keyb_irq(int irq, void *data) |
@@ -266,7 +275,7 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) | |||
266 | ckdev->dev = dev; | 275 | ckdev->dev = dev; |
267 | dev_set_drvdata(&pdev->dev, ckdev); | 276 | dev_set_drvdata(&pdev->dev, ckdev); |
268 | 277 | ||
269 | idev->name = ec->ec_name; | 278 | idev->name = CROS_EC_DEV_NAME; |
270 | idev->phys = ec->phys_name; | 279 | idev->phys = ec->phys_name; |
271 | __set_bit(EV_REP, idev->evbit); | 280 | __set_bit(EV_REP, idev->evbit); |
272 | 281 | ||
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index d2a85cde68da..e03b7f45b8f7 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
@@ -566,7 +566,7 @@ static int pm860x_irq_domain_map(struct irq_domain *d, unsigned int virq, | |||
566 | return 0; | 566 | return 0; |
567 | } | 567 | } |
568 | 568 | ||
569 | static struct irq_domain_ops pm860x_irq_domain_ops = { | 569 | static const struct irq_domain_ops pm860x_irq_domain_ops = { |
570 | .map = pm860x_irq_domain_map, | 570 | .map = pm860x_irq_domain_map, |
571 | .xlate = irq_domain_xlate_onetwocell, | 571 | .xlate = irq_domain_xlate_onetwocell, |
572 | }; | 572 | }; |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d5ad04dad081..653815950aa2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -52,7 +52,8 @@ config PMIC_ADP5520 | |||
52 | config MFD_AAT2870_CORE | 52 | config MFD_AAT2870_CORE |
53 | bool "AnalogicTech AAT2870" | 53 | bool "AnalogicTech AAT2870" |
54 | select MFD_CORE | 54 | select MFD_CORE |
55 | depends on I2C=y && GPIOLIB | 55 | depends on I2C=y |
56 | depends on GPIOLIB || COMPILE_TEST | ||
56 | help | 57 | help |
57 | If you say yes here you get support for the AAT2870. | 58 | If you say yes here you get support for the AAT2870. |
58 | This driver provides common support for accessing the device, | 59 | This driver provides common support for accessing the device, |
@@ -94,6 +95,8 @@ config MFD_AXP20X | |||
94 | config MFD_CROS_EC | 95 | config MFD_CROS_EC |
95 | tristate "ChromeOS Embedded Controller" | 96 | tristate "ChromeOS Embedded Controller" |
96 | select MFD_CORE | 97 | select MFD_CORE |
98 | select CHROME_PLATFORMS | ||
99 | select CROS_EC_PROTO | ||
97 | help | 100 | help |
98 | If you say Y here you get support for the ChromeOS Embedded | 101 | If you say Y here you get support for the ChromeOS Embedded |
99 | Controller (EC) providing keyboard, battery and power services. | 102 | Controller (EC) providing keyboard, battery and power services. |
@@ -102,7 +105,7 @@ config MFD_CROS_EC | |||
102 | 105 | ||
103 | config MFD_CROS_EC_I2C | 106 | config MFD_CROS_EC_I2C |
104 | tristate "ChromeOS Embedded Controller (I2C)" | 107 | tristate "ChromeOS Embedded Controller (I2C)" |
105 | depends on MFD_CROS_EC && I2C | 108 | depends on MFD_CROS_EC && CROS_EC_PROTO && I2C |
106 | 109 | ||
107 | help | 110 | help |
108 | If you say Y here, you get support for talking to the ChromeOS | 111 | If you say Y here, you get support for talking to the ChromeOS |
@@ -112,7 +115,7 @@ config MFD_CROS_EC_I2C | |||
112 | 115 | ||
113 | config MFD_CROS_EC_SPI | 116 | config MFD_CROS_EC_SPI |
114 | tristate "ChromeOS Embedded Controller (SPI)" | 117 | tristate "ChromeOS Embedded Controller (SPI)" |
115 | depends on MFD_CROS_EC && SPI && OF | 118 | depends on MFD_CROS_EC && CROS_EC_PROTO && SPI && OF |
116 | 119 | ||
117 | ---help--- | 120 | ---help--- |
118 | If you say Y here, you get support for talking to the ChromeOS EC | 121 | If you say Y here, you get support for talking to the ChromeOS EC |
@@ -1115,7 +1118,8 @@ config MFD_TPS6586X | |||
1115 | 1118 | ||
1116 | config MFD_TPS65910 | 1119 | config MFD_TPS65910 |
1117 | bool "TI TPS65910 Power Management chip" | 1120 | bool "TI TPS65910 Power Management chip" |
1118 | depends on I2C=y && GPIOLIB | 1121 | depends on I2C=y |
1122 | depends on GPIOLIB || COMPILE_TEST | ||
1119 | select MFD_CORE | 1123 | select MFD_CORE |
1120 | select REGMAP_I2C | 1124 | select REGMAP_I2C |
1121 | select REGMAP_IRQ | 1125 | select REGMAP_IRQ |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0e5cfeba107c..ea40e076cb61 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -39,13 +39,13 @@ obj-$(CONFIG_MFD_ARIZONA) += arizona-core.o | |||
39 | obj-$(CONFIG_MFD_ARIZONA) += arizona-irq.o | 39 | obj-$(CONFIG_MFD_ARIZONA) += arizona-irq.o |
40 | obj-$(CONFIG_MFD_ARIZONA_I2C) += arizona-i2c.o | 40 | obj-$(CONFIG_MFD_ARIZONA_I2C) += arizona-i2c.o |
41 | obj-$(CONFIG_MFD_ARIZONA_SPI) += arizona-spi.o | 41 | obj-$(CONFIG_MFD_ARIZONA_SPI) += arizona-spi.o |
42 | ifneq ($(CONFIG_MFD_WM5102),n) | 42 | ifeq ($(CONFIG_MFD_WM5102),y) |
43 | obj-$(CONFIG_MFD_ARIZONA) += wm5102-tables.o | 43 | obj-$(CONFIG_MFD_ARIZONA) += wm5102-tables.o |
44 | endif | 44 | endif |
45 | ifneq ($(CONFIG_MFD_WM5110),n) | 45 | ifeq ($(CONFIG_MFD_WM5110),y) |
46 | obj-$(CONFIG_MFD_ARIZONA) += wm5110-tables.o | 46 | obj-$(CONFIG_MFD_ARIZONA) += wm5110-tables.o |
47 | endif | 47 | endif |
48 | ifneq ($(CONFIG_MFD_WM8997),n) | 48 | ifeq ($(CONFIG_MFD_WM8997),y) |
49 | obj-$(CONFIG_MFD_ARIZONA) += wm8997-tables.o | 49 | obj-$(CONFIG_MFD_ARIZONA) += wm8997-tables.o |
50 | endif | 50 | endif |
51 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o | 51 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index c80a2925f8e5..000da72a0ae9 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -574,7 +574,7 @@ static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, | |||
574 | return 0; | 574 | return 0; |
575 | } | 575 | } |
576 | 576 | ||
577 | static struct irq_domain_ops ab8500_irq_ops = { | 577 | static const struct irq_domain_ops ab8500_irq_ops = { |
578 | .map = ab8500_irq_map, | 578 | .map = ab8500_irq_map, |
579 | .xlate = irq_domain_xlate_twocell, | 579 | .xlate = irq_domain_xlate_twocell, |
580 | }; | 580 | }; |
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index cdd6f3d63314..0236cd7cdce4 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c | |||
@@ -2885,7 +2885,7 @@ static ssize_t ab8500_subscribe_write(struct file *file, | |||
2885 | } | 2885 | } |
2886 | 2886 | ||
2887 | err = request_threaded_irq(user_val, NULL, ab8500_debug_handler, | 2887 | err = request_threaded_irq(user_val, NULL, ab8500_debug_handler, |
2888 | IRQF_SHARED | IRQF_NO_SUSPEND, | 2888 | IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, |
2889 | "ab8500-debug", &dev->kobj); | 2889 | "ab8500-debug", &dev->kobj); |
2890 | if (err < 0) { | 2890 | if (err < 0) { |
2891 | pr_info("request_threaded_irq failed %d, %lu\n", | 2891 | pr_info("request_threaded_irq failed %d, %lu\n", |
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index dabbc93abdd7..c51c1b188d64 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c | |||
@@ -948,7 +948,8 @@ static int ab8500_gpadc_probe(struct platform_device *pdev) | |||
948 | if (gpadc->irq_sw >= 0) { | 948 | if (gpadc->irq_sw >= 0) { |
949 | ret = request_threaded_irq(gpadc->irq_sw, NULL, | 949 | ret = request_threaded_irq(gpadc->irq_sw, NULL, |
950 | ab8500_bm_gpadcconvend_handler, | 950 | ab8500_bm_gpadcconvend_handler, |
951 | IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-sw", | 951 | IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT, |
952 | "ab8500-gpadc-sw", | ||
952 | gpadc); | 953 | gpadc); |
953 | if (ret < 0) { | 954 | if (ret < 0) { |
954 | dev_err(gpadc->dev, | 955 | dev_err(gpadc->dev, |
@@ -961,7 +962,8 @@ static int ab8500_gpadc_probe(struct platform_device *pdev) | |||
961 | if (gpadc->irq_hw >= 0) { | 962 | if (gpadc->irq_hw >= 0) { |
962 | ret = request_threaded_irq(gpadc->irq_hw, NULL, | 963 | ret = request_threaded_irq(gpadc->irq_hw, NULL, |
963 | ab8500_bm_gpadcconvend_handler, | 964 | ab8500_bm_gpadcconvend_handler, |
964 | IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-hw", | 965 | IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT, |
966 | "ab8500-gpadc-hw", | ||
965 | gpadc); | 967 | gpadc); |
966 | if (ret < 0) { | 968 | if (ret < 0) { |
967 | dev_err(gpadc->dev, | 969 | dev_err(gpadc->dev, |
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 6ca6dfab50eb..bebf58a06a6b 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c | |||
@@ -250,20 +250,50 @@ static int arizona_wait_for_boot(struct arizona *arizona) | |||
250 | return ret; | 250 | return ret; |
251 | } | 251 | } |
252 | 252 | ||
253 | static int arizona_apply_hardware_patch(struct arizona* arizona) | 253 | static inline void arizona_enable_reset(struct arizona *arizona) |
254 | { | ||
255 | if (arizona->pdata.reset) | ||
256 | gpio_set_value_cansleep(arizona->pdata.reset, 0); | ||
257 | } | ||
258 | |||
259 | static void arizona_disable_reset(struct arizona *arizona) | ||
260 | { | ||
261 | if (arizona->pdata.reset) { | ||
262 | switch (arizona->type) { | ||
263 | case WM5110: | ||
264 | case WM8280: | ||
265 | /* Meet requirements for minimum reset duration */ | ||
266 | msleep(5); | ||
267 | break; | ||
268 | default: | ||
269 | break; | ||
270 | } | ||
271 | |||
272 | gpio_set_value_cansleep(arizona->pdata.reset, 1); | ||
273 | msleep(1); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | struct arizona_sysclk_state { | ||
278 | unsigned int fll; | ||
279 | unsigned int sysclk; | ||
280 | }; | ||
281 | |||
282 | static int arizona_enable_freerun_sysclk(struct arizona *arizona, | ||
283 | struct arizona_sysclk_state *state) | ||
254 | { | 284 | { |
255 | unsigned int fll, sysclk; | ||
256 | int ret, err; | 285 | int ret, err; |
257 | 286 | ||
258 | /* Cache existing FLL and SYSCLK settings */ | 287 | /* Cache existing FLL and SYSCLK settings */ |
259 | ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); | 288 | ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &state->fll); |
260 | if (ret != 0) { | 289 | if (ret) { |
261 | dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", | 290 | dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", |
262 | ret); | 291 | ret); |
263 | return ret; | 292 | return ret; |
264 | } | 293 | } |
265 | ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); | 294 | ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, |
266 | if (ret != 0) { | 295 | &state->sysclk); |
296 | if (ret) { | ||
267 | dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", | 297 | dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", |
268 | ret); | 298 | ret); |
269 | return ret; | 299 | return ret; |
@@ -272,7 +302,7 @@ static int arizona_apply_hardware_patch(struct arizona* arizona) | |||
272 | /* Start up SYSCLK using the FLL in free running mode */ | 302 | /* Start up SYSCLK using the FLL in free running mode */ |
273 | ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, | 303 | ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, |
274 | ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); | 304 | ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); |
275 | if (ret != 0) { | 305 | if (ret) { |
276 | dev_err(arizona->dev, | 306 | dev_err(arizona->dev, |
277 | "Failed to start FLL in freerunning mode: %d\n", | 307 | "Failed to start FLL in freerunning mode: %d\n", |
278 | ret); | 308 | ret); |
@@ -281,53 +311,137 @@ static int arizona_apply_hardware_patch(struct arizona* arizona) | |||
281 | ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, | 311 | ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, |
282 | ARIZONA_FLL1_CLOCK_OK_STS, | 312 | ARIZONA_FLL1_CLOCK_OK_STS, |
283 | ARIZONA_FLL1_CLOCK_OK_STS); | 313 | ARIZONA_FLL1_CLOCK_OK_STS); |
284 | if (ret != 0) { | 314 | if (ret) { |
285 | ret = -ETIMEDOUT; | 315 | ret = -ETIMEDOUT; |
286 | goto err_fll; | 316 | goto err_fll; |
287 | } | 317 | } |
288 | 318 | ||
289 | ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); | 319 | ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); |
290 | if (ret != 0) { | 320 | if (ret) { |
291 | dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); | 321 | dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); |
292 | goto err_fll; | 322 | goto err_fll; |
293 | } | 323 | } |
294 | 324 | ||
325 | return 0; | ||
326 | |||
327 | err_fll: | ||
328 | err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); | ||
329 | if (err) | ||
330 | dev_err(arizona->dev, | ||
331 | "Failed to re-apply old FLL settings: %d\n", err); | ||
332 | |||
333 | return ret; | ||
334 | } | ||
335 | |||
336 | static int arizona_disable_freerun_sysclk(struct arizona *arizona, | ||
337 | struct arizona_sysclk_state *state) | ||
338 | { | ||
339 | int ret; | ||
340 | |||
341 | ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, | ||
342 | state->sysclk); | ||
343 | if (ret) { | ||
344 | dev_err(arizona->dev, | ||
345 | "Failed to re-apply old SYSCLK settings: %d\n", ret); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); | ||
350 | if (ret) { | ||
351 | dev_err(arizona->dev, | ||
352 | "Failed to re-apply old FLL settings: %d\n", ret); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int wm5102_apply_hardware_patch(struct arizona *arizona) | ||
360 | { | ||
361 | struct arizona_sysclk_state state; | ||
362 | int err, ret; | ||
363 | |||
364 | ret = arizona_enable_freerun_sysclk(arizona, &state); | ||
365 | if (ret) | ||
366 | return ret; | ||
367 | |||
295 | /* Start the write sequencer and wait for it to finish */ | 368 | /* Start the write sequencer and wait for it to finish */ |
296 | ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | 369 | ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, |
297 | ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); | 370 | ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); |
298 | if (ret != 0) { | 371 | if (ret) { |
299 | dev_err(arizona->dev, "Failed to start write sequencer: %d\n", | 372 | dev_err(arizona->dev, "Failed to start write sequencer: %d\n", |
300 | ret); | 373 | ret); |
301 | goto err_sysclk; | 374 | goto err; |
302 | } | 375 | } |
376 | |||
303 | ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, | 377 | ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, |
304 | ARIZONA_WSEQ_BUSY, 0); | 378 | ARIZONA_WSEQ_BUSY, 0); |
305 | if (ret != 0) { | 379 | if (ret) { |
306 | regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | 380 | regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, |
307 | ARIZONA_WSEQ_ABORT); | 381 | ARIZONA_WSEQ_ABORT); |
308 | ret = -ETIMEDOUT; | 382 | ret = -ETIMEDOUT; |
309 | } | 383 | } |
310 | 384 | ||
311 | err_sysclk: | 385 | err: |
312 | err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); | 386 | err = arizona_disable_freerun_sysclk(arizona, &state); |
313 | if (err != 0) { | ||
314 | dev_err(arizona->dev, | ||
315 | "Failed to re-apply old SYSCLK settings: %d\n", | ||
316 | err); | ||
317 | } | ||
318 | 387 | ||
319 | err_fll: | 388 | return ret ?: err; |
320 | err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); | 389 | } |
321 | if (err != 0) { | 390 | |
391 | /* | ||
392 | * Register patch to some of the CODECs internal write sequences | ||
393 | * to ensure a clean exit from the low power sleep state. | ||
394 | */ | ||
395 | static const struct reg_default wm5110_sleep_patch[] = { | ||
396 | { 0x337A, 0xC100 }, | ||
397 | { 0x337B, 0x0041 }, | ||
398 | { 0x3300, 0xA210 }, | ||
399 | { 0x3301, 0x050C }, | ||
400 | }; | ||
401 | |||
402 | static int wm5110_apply_sleep_patch(struct arizona *arizona) | ||
403 | { | ||
404 | struct arizona_sysclk_state state; | ||
405 | int err, ret; | ||
406 | |||
407 | ret = arizona_enable_freerun_sysclk(arizona, &state); | ||
408 | if (ret) | ||
409 | return ret; | ||
410 | |||
411 | ret = regmap_multi_reg_write_bypassed(arizona->regmap, | ||
412 | wm5110_sleep_patch, | ||
413 | ARRAY_SIZE(wm5110_sleep_patch)); | ||
414 | |||
415 | err = arizona_disable_freerun_sysclk(arizona, &state); | ||
416 | |||
417 | return ret ?: err; | ||
418 | } | ||
419 | |||
420 | static int wm5102_clear_write_sequencer(struct arizona *arizona) | ||
421 | { | ||
422 | int ret; | ||
423 | |||
424 | ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_3, | ||
425 | 0x0); | ||
426 | if (ret) { | ||
322 | dev_err(arizona->dev, | 427 | dev_err(arizona->dev, |
323 | "Failed to re-apply old FLL settings: %d\n", | 428 | "Failed to clear write sequencer state: %d\n", ret); |
324 | err); | 429 | return ret; |
325 | } | 430 | } |
326 | 431 | ||
327 | if (ret != 0) | 432 | arizona_enable_reset(arizona); |
433 | regulator_disable(arizona->dcvdd); | ||
434 | |||
435 | msleep(20); | ||
436 | |||
437 | ret = regulator_enable(arizona->dcvdd); | ||
438 | if (ret) { | ||
439 | dev_err(arizona->dev, "Failed to re-enable DCVDD: %d\n", ret); | ||
328 | return ret; | 440 | return ret; |
329 | else | 441 | } |
330 | return err; | 442 | arizona_disable_reset(arizona); |
443 | |||
444 | return 0; | ||
331 | } | 445 | } |
332 | 446 | ||
333 | #ifdef CONFIG_PM | 447 | #ifdef CONFIG_PM |
@@ -338,12 +452,33 @@ static int arizona_runtime_resume(struct device *dev) | |||
338 | 452 | ||
339 | dev_dbg(arizona->dev, "Leaving AoD mode\n"); | 453 | dev_dbg(arizona->dev, "Leaving AoD mode\n"); |
340 | 454 | ||
455 | if (arizona->has_fully_powered_off) { | ||
456 | dev_dbg(arizona->dev, "Re-enabling core supplies\n"); | ||
457 | |||
458 | ret = regulator_bulk_enable(arizona->num_core_supplies, | ||
459 | arizona->core_supplies); | ||
460 | if (ret) { | ||
461 | dev_err(dev, "Failed to enable core supplies: %d\n", | ||
462 | ret); | ||
463 | return ret; | ||
464 | } | ||
465 | } | ||
466 | |||
341 | ret = regulator_enable(arizona->dcvdd); | 467 | ret = regulator_enable(arizona->dcvdd); |
342 | if (ret != 0) { | 468 | if (ret != 0) { |
343 | dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); | 469 | dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); |
470 | if (arizona->has_fully_powered_off) | ||
471 | regulator_bulk_disable(arizona->num_core_supplies, | ||
472 | arizona->core_supplies); | ||
344 | return ret; | 473 | return ret; |
345 | } | 474 | } |
346 | 475 | ||
476 | if (arizona->has_fully_powered_off) { | ||
477 | arizona_disable_reset(arizona); | ||
478 | enable_irq(arizona->irq); | ||
479 | arizona->has_fully_powered_off = false; | ||
480 | } | ||
481 | |||
347 | regcache_cache_only(arizona->regmap, false); | 482 | regcache_cache_only(arizona->regmap, false); |
348 | 483 | ||
349 | switch (arizona->type) { | 484 | switch (arizona->type) { |
@@ -366,14 +501,53 @@ static int arizona_runtime_resume(struct device *dev) | |||
366 | goto err; | 501 | goto err; |
367 | } | 502 | } |
368 | 503 | ||
369 | ret = arizona_apply_hardware_patch(arizona); | 504 | ret = wm5102_apply_hardware_patch(arizona); |
370 | if (ret != 0) { | 505 | if (ret) { |
371 | dev_err(arizona->dev, | 506 | dev_err(arizona->dev, |
372 | "Failed to apply hardware patch: %d\n", | 507 | "Failed to apply hardware patch: %d\n", |
373 | ret); | 508 | ret); |
374 | goto err; | 509 | goto err; |
375 | } | 510 | } |
376 | break; | 511 | break; |
512 | case WM5110: | ||
513 | case WM8280: | ||
514 | ret = arizona_wait_for_boot(arizona); | ||
515 | if (ret) | ||
516 | goto err; | ||
517 | |||
518 | if (arizona->external_dcvdd) { | ||
519 | ret = regmap_update_bits(arizona->regmap, | ||
520 | ARIZONA_ISOLATION_CONTROL, | ||
521 | ARIZONA_ISOLATE_DCVDD1, 0); | ||
522 | if (ret) { | ||
523 | dev_err(arizona->dev, | ||
524 | "Failed to connect DCVDD: %d\n", ret); | ||
525 | goto err; | ||
526 | } | ||
527 | } else { | ||
528 | /* | ||
529 | * As this is only called for the internal regulator | ||
530 | * (where we know voltage ranges available) it is ok | ||
531 | * to request an exact range. | ||
532 | */ | ||
533 | ret = regulator_set_voltage(arizona->dcvdd, | ||
534 | 1200000, 1200000); | ||
535 | if (ret < 0) { | ||
536 | dev_err(arizona->dev, | ||
537 | "Failed to set resume voltage: %d\n", | ||
538 | ret); | ||
539 | goto err; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | ret = wm5110_apply_sleep_patch(arizona); | ||
544 | if (ret) { | ||
545 | dev_err(arizona->dev, | ||
546 | "Failed to re-apply sleep patch: %d\n", | ||
547 | ret); | ||
548 | goto err; | ||
549 | } | ||
550 | break; | ||
377 | default: | 551 | default: |
378 | ret = arizona_wait_for_boot(arizona); | 552 | ret = arizona_wait_for_boot(arizona); |
379 | if (ret != 0) { | 553 | if (ret != 0) { |
@@ -410,10 +584,17 @@ err: | |||
410 | static int arizona_runtime_suspend(struct device *dev) | 584 | static int arizona_runtime_suspend(struct device *dev) |
411 | { | 585 | { |
412 | struct arizona *arizona = dev_get_drvdata(dev); | 586 | struct arizona *arizona = dev_get_drvdata(dev); |
587 | unsigned int val; | ||
413 | int ret; | 588 | int ret; |
414 | 589 | ||
415 | dev_dbg(arizona->dev, "Entering AoD mode\n"); | 590 | dev_dbg(arizona->dev, "Entering AoD mode\n"); |
416 | 591 | ||
592 | ret = regmap_read(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, &val); | ||
593 | if (ret) { | ||
594 | dev_err(dev, "Failed to check jack det status: %d\n", ret); | ||
595 | return ret; | ||
596 | } | ||
597 | |||
417 | if (arizona->external_dcvdd) { | 598 | if (arizona->external_dcvdd) { |
418 | ret = regmap_update_bits(arizona->regmap, | 599 | ret = regmap_update_bits(arizona->regmap, |
419 | ARIZONA_ISOLATION_CONTROL, | 600 | ARIZONA_ISOLATION_CONTROL, |
@@ -426,10 +607,56 @@ static int arizona_runtime_suspend(struct device *dev) | |||
426 | } | 607 | } |
427 | } | 608 | } |
428 | 609 | ||
610 | switch (arizona->type) { | ||
611 | case WM5110: | ||
612 | case WM8280: | ||
613 | if (arizona->external_dcvdd) | ||
614 | break; | ||
615 | |||
616 | /* | ||
617 | * As this is only called for the internal regulator | ||
618 | * (where we know voltage ranges available) it is ok | ||
619 | * to request an exact range. | ||
620 | */ | ||
621 | ret = regulator_set_voltage(arizona->dcvdd, 1175000, 1175000); | ||
622 | if (ret < 0) { | ||
623 | dev_err(arizona->dev, | ||
624 | "Failed to set suspend voltage: %d\n", ret); | ||
625 | return ret; | ||
626 | } | ||
627 | break; | ||
628 | case WM5102: | ||
629 | if (!(val & ARIZONA_JD1_ENA)) { | ||
630 | ret = regmap_write(arizona->regmap, | ||
631 | ARIZONA_WRITE_SEQUENCER_CTRL_3, 0x0); | ||
632 | if (ret) { | ||
633 | dev_err(arizona->dev, | ||
634 | "Failed to clear write sequencer: %d\n", | ||
635 | ret); | ||
636 | return ret; | ||
637 | } | ||
638 | } | ||
639 | break; | ||
640 | default: | ||
641 | break; | ||
642 | } | ||
643 | |||
429 | regcache_cache_only(arizona->regmap, true); | 644 | regcache_cache_only(arizona->regmap, true); |
430 | regcache_mark_dirty(arizona->regmap); | 645 | regcache_mark_dirty(arizona->regmap); |
431 | regulator_disable(arizona->dcvdd); | 646 | regulator_disable(arizona->dcvdd); |
432 | 647 | ||
648 | /* Allow us to completely power down if no jack detection */ | ||
649 | if (!(val & ARIZONA_JD1_ENA)) { | ||
650 | dev_dbg(arizona->dev, "Fully powering off\n"); | ||
651 | |||
652 | arizona->has_fully_powered_off = true; | ||
653 | |||
654 | disable_irq(arizona->irq); | ||
655 | arizona_enable_reset(arizona); | ||
656 | regulator_bulk_disable(arizona->num_core_supplies, | ||
657 | arizona->core_supplies); | ||
658 | } | ||
659 | |||
433 | return 0; | 660 | return 0; |
434 | } | 661 | } |
435 | #endif | 662 | #endif |
@@ -728,9 +955,9 @@ int arizona_dev_init(struct arizona *arizona) | |||
728 | 955 | ||
729 | if (arizona->pdata.reset) { | 956 | if (arizona->pdata.reset) { |
730 | /* Start out with /RESET low to put the chip into reset */ | 957 | /* Start out with /RESET low to put the chip into reset */ |
731 | ret = gpio_request_one(arizona->pdata.reset, | 958 | ret = devm_gpio_request_one(arizona->dev, arizona->pdata.reset, |
732 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, | 959 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, |
733 | "arizona /RESET"); | 960 | "arizona /RESET"); |
734 | if (ret != 0) { | 961 | if (ret != 0) { |
735 | dev_err(dev, "Failed to request /RESET: %d\n", ret); | 962 | dev_err(dev, "Failed to request /RESET: %d\n", ret); |
736 | goto err_dcvdd; | 963 | goto err_dcvdd; |
@@ -751,10 +978,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
751 | goto err_enable; | 978 | goto err_enable; |
752 | } | 979 | } |
753 | 980 | ||
754 | if (arizona->pdata.reset) { | 981 | arizona_disable_reset(arizona); |
755 | gpio_set_value_cansleep(arizona->pdata.reset, 1); | ||
756 | msleep(1); | ||
757 | } | ||
758 | 982 | ||
759 | regcache_cache_only(arizona->regmap, false); | 983 | regcache_cache_only(arizona->regmap, false); |
760 | 984 | ||
@@ -777,8 +1001,6 @@ int arizona_dev_init(struct arizona *arizona) | |||
777 | 1001 | ||
778 | /* If we have a /RESET GPIO we'll already be reset */ | 1002 | /* If we have a /RESET GPIO we'll already be reset */ |
779 | if (!arizona->pdata.reset) { | 1003 | if (!arizona->pdata.reset) { |
780 | regcache_mark_dirty(arizona->regmap); | ||
781 | |||
782 | ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); | 1004 | ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); |
783 | if (ret != 0) { | 1005 | if (ret != 0) { |
784 | dev_err(dev, "Failed to reset device: %d\n", ret); | 1006 | dev_err(dev, "Failed to reset device: %d\n", ret); |
@@ -786,12 +1008,6 @@ int arizona_dev_init(struct arizona *arizona) | |||
786 | } | 1008 | } |
787 | 1009 | ||
788 | msleep(1); | 1010 | msleep(1); |
789 | |||
790 | ret = regcache_sync(arizona->regmap); | ||
791 | if (ret != 0) { | ||
792 | dev_err(dev, "Failed to sync device: %d\n", ret); | ||
793 | goto err_reset; | ||
794 | } | ||
795 | } | 1011 | } |
796 | 1012 | ||
797 | /* Ensure device startup is complete */ | 1013 | /* Ensure device startup is complete */ |
@@ -799,21 +1015,24 @@ int arizona_dev_init(struct arizona *arizona) | |||
799 | case WM5102: | 1015 | case WM5102: |
800 | ret = regmap_read(arizona->regmap, | 1016 | ret = regmap_read(arizona->regmap, |
801 | ARIZONA_WRITE_SEQUENCER_CTRL_3, &val); | 1017 | ARIZONA_WRITE_SEQUENCER_CTRL_3, &val); |
802 | if (ret != 0) | 1018 | if (ret) { |
803 | dev_err(dev, | 1019 | dev_err(dev, |
804 | "Failed to check write sequencer state: %d\n", | 1020 | "Failed to check write sequencer state: %d\n", |
805 | ret); | 1021 | ret); |
806 | else if (val & 0x01) | 1022 | } else if (val & 0x01) { |
807 | break; | 1023 | ret = wm5102_clear_write_sequencer(arizona); |
808 | /* Fall through */ | 1024 | if (ret) |
809 | default: | 1025 | return ret; |
810 | ret = arizona_wait_for_boot(arizona); | ||
811 | if (ret != 0) { | ||
812 | dev_err(arizona->dev, | ||
813 | "Device failed initial boot: %d\n", ret); | ||
814 | goto err_reset; | ||
815 | } | 1026 | } |
816 | break; | 1027 | break; |
1028 | default: | ||
1029 | break; | ||
1030 | } | ||
1031 | |||
1032 | ret = arizona_wait_for_boot(arizona); | ||
1033 | if (ret) { | ||
1034 | dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); | ||
1035 | goto err_reset; | ||
817 | } | 1036 | } |
818 | 1037 | ||
819 | /* Read the device ID information & do device specific stuff */ | 1038 | /* Read the device ID information & do device specific stuff */ |
@@ -891,14 +1110,24 @@ int arizona_dev_init(struct arizona *arizona) | |||
891 | 1110 | ||
892 | switch (arizona->type) { | 1111 | switch (arizona->type) { |
893 | case WM5102: | 1112 | case WM5102: |
894 | ret = arizona_apply_hardware_patch(arizona); | 1113 | ret = wm5102_apply_hardware_patch(arizona); |
895 | if (ret != 0) { | 1114 | if (ret) { |
896 | dev_err(arizona->dev, | 1115 | dev_err(arizona->dev, |
897 | "Failed to apply hardware patch: %d\n", | 1116 | "Failed to apply hardware patch: %d\n", |
898 | ret); | 1117 | ret); |
899 | goto err_reset; | 1118 | goto err_reset; |
900 | } | 1119 | } |
901 | break; | 1120 | break; |
1121 | case WM5110: | ||
1122 | case WM8280: | ||
1123 | ret = wm5110_apply_sleep_patch(arizona); | ||
1124 | if (ret) { | ||
1125 | dev_err(arizona->dev, | ||
1126 | "Failed to apply sleep patch: %d\n", | ||
1127 | ret); | ||
1128 | goto err_reset; | ||
1129 | } | ||
1130 | break; | ||
902 | default: | 1131 | default: |
903 | break; | 1132 | break; |
904 | } | 1133 | } |
@@ -977,12 +1206,16 @@ int arizona_dev_init(struct arizona *arizona) | |||
977 | /* Default for both is 0 so noop with defaults */ | 1206 | /* Default for both is 0 so noop with defaults */ |
978 | val = arizona->pdata.dmic_ref[i] | 1207 | val = arizona->pdata.dmic_ref[i] |
979 | << ARIZONA_IN1_DMIC_SUP_SHIFT; | 1208 | << ARIZONA_IN1_DMIC_SUP_SHIFT; |
980 | val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT; | 1209 | if (arizona->pdata.inmode[i] & ARIZONA_INMODE_DMIC) |
1210 | val |= 1 << ARIZONA_IN1_MODE_SHIFT; | ||
1211 | if (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) | ||
1212 | val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT; | ||
981 | 1213 | ||
982 | regmap_update_bits(arizona->regmap, | 1214 | regmap_update_bits(arizona->regmap, |
983 | ARIZONA_IN1L_CONTROL + (i * 8), | 1215 | ARIZONA_IN1L_CONTROL + (i * 8), |
984 | ARIZONA_IN1_DMIC_SUP_MASK | | 1216 | ARIZONA_IN1_DMIC_SUP_MASK | |
985 | ARIZONA_IN1_MODE_MASK, val); | 1217 | ARIZONA_IN1_MODE_MASK | |
1218 | ARIZONA_IN1_SINGLE_ENDED_MASK, val); | ||
986 | } | 1219 | } |
987 | 1220 | ||
988 | for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { | 1221 | for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { |
@@ -1054,10 +1287,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
1054 | err_irq: | 1287 | err_irq: |
1055 | arizona_irq_exit(arizona); | 1288 | arizona_irq_exit(arizona); |
1056 | err_reset: | 1289 | err_reset: |
1057 | if (arizona->pdata.reset) { | 1290 | arizona_enable_reset(arizona); |
1058 | gpio_set_value_cansleep(arizona->pdata.reset, 0); | ||
1059 | gpio_free(arizona->pdata.reset); | ||
1060 | } | ||
1061 | regulator_disable(arizona->dcvdd); | 1291 | regulator_disable(arizona->dcvdd); |
1062 | err_enable: | 1292 | err_enable: |
1063 | regulator_bulk_disable(arizona->num_core_supplies, | 1293 | regulator_bulk_disable(arizona->num_core_supplies, |
@@ -1082,8 +1312,7 @@ int arizona_dev_exit(struct arizona *arizona) | |||
1082 | arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); | 1312 | arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); |
1083 | arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); | 1313 | arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); |
1084 | arizona_irq_exit(arizona); | 1314 | arizona_irq_exit(arizona); |
1085 | if (arizona->pdata.reset) | 1315 | arizona_enable_reset(arizona); |
1086 | gpio_set_value_cansleep(arizona->pdata.reset, 0); | ||
1087 | 1316 | ||
1088 | regulator_bulk_disable(arizona->num_core_supplies, | 1317 | regulator_bulk_disable(arizona->num_core_supplies, |
1089 | arizona->core_supplies); | 1318 | arizona->core_supplies); |
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index d063b94b94b5..2b9965d53e4e 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c | |||
@@ -186,7 +186,7 @@ static int arizona_irq_map(struct irq_domain *h, unsigned int virq, | |||
186 | return 0; | 186 | return 0; |
187 | } | 187 | } |
188 | 188 | ||
189 | static struct irq_domain_ops arizona_domain_ops = { | 189 | static const struct irq_domain_ops arizona_domain_ops = { |
190 | .map = arizona_irq_map, | 190 | .map = arizona_irq_map, |
191 | .xlate = irq_domain_xlate_twocell, | 191 | .xlate = irq_domain_xlate_twocell, |
192 | }; | 192 | }; |
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index d18029be6a78..6df91556faf3 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c | |||
@@ -32,6 +32,7 @@ | |||
32 | static const char * const axp20x_model_names[] = { | 32 | static const char * const axp20x_model_names[] = { |
33 | "AXP202", | 33 | "AXP202", |
34 | "AXP209", | 34 | "AXP209", |
35 | "AXP221", | ||
35 | "AXP288", | 36 | "AXP288", |
36 | }; | 37 | }; |
37 | 38 | ||
@@ -54,6 +55,25 @@ static const struct regmap_access_table axp20x_volatile_table = { | |||
54 | .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), | 55 | .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), |
55 | }; | 56 | }; |
56 | 57 | ||
58 | static const struct regmap_range axp22x_writeable_ranges[] = { | ||
59 | regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), | ||
60 | regmap_reg_range(AXP20X_DCDC_MODE, AXP22X_BATLOW_THRES1), | ||
61 | }; | ||
62 | |||
63 | static const struct regmap_range axp22x_volatile_ranges[] = { | ||
64 | regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE), | ||
65 | }; | ||
66 | |||
67 | static const struct regmap_access_table axp22x_writeable_table = { | ||
68 | .yes_ranges = axp22x_writeable_ranges, | ||
69 | .n_yes_ranges = ARRAY_SIZE(axp22x_writeable_ranges), | ||
70 | }; | ||
71 | |||
72 | static const struct regmap_access_table axp22x_volatile_table = { | ||
73 | .yes_ranges = axp22x_volatile_ranges, | ||
74 | .n_yes_ranges = ARRAY_SIZE(axp22x_volatile_ranges), | ||
75 | }; | ||
76 | |||
57 | static const struct regmap_range axp288_writeable_ranges[] = { | 77 | static const struct regmap_range axp288_writeable_ranges[] = { |
58 | regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE), | 78 | regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE), |
59 | regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5), | 79 | regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5), |
@@ -87,6 +107,20 @@ static struct resource axp20x_pek_resources[] = { | |||
87 | }, | 107 | }, |
88 | }; | 108 | }; |
89 | 109 | ||
110 | static struct resource axp22x_pek_resources[] = { | ||
111 | { | ||
112 | .name = "PEK_DBR", | ||
113 | .start = AXP22X_IRQ_PEK_RIS_EDGE, | ||
114 | .end = AXP22X_IRQ_PEK_RIS_EDGE, | ||
115 | .flags = IORESOURCE_IRQ, | ||
116 | }, { | ||
117 | .name = "PEK_DBF", | ||
118 | .start = AXP22X_IRQ_PEK_FAL_EDGE, | ||
119 | .end = AXP22X_IRQ_PEK_FAL_EDGE, | ||
120 | .flags = IORESOURCE_IRQ, | ||
121 | }, | ||
122 | }; | ||
123 | |||
90 | static struct resource axp288_fuel_gauge_resources[] = { | 124 | static struct resource axp288_fuel_gauge_resources[] = { |
91 | { | 125 | { |
92 | .start = AXP288_IRQ_QWBTU, | 126 | .start = AXP288_IRQ_QWBTU, |
@@ -129,6 +163,15 @@ static const struct regmap_config axp20x_regmap_config = { | |||
129 | .cache_type = REGCACHE_RBTREE, | 163 | .cache_type = REGCACHE_RBTREE, |
130 | }; | 164 | }; |
131 | 165 | ||
166 | static const struct regmap_config axp22x_regmap_config = { | ||
167 | .reg_bits = 8, | ||
168 | .val_bits = 8, | ||
169 | .wr_table = &axp22x_writeable_table, | ||
170 | .volatile_table = &axp22x_volatile_table, | ||
171 | .max_register = AXP22X_BATLOW_THRES1, | ||
172 | .cache_type = REGCACHE_RBTREE, | ||
173 | }; | ||
174 | |||
132 | static const struct regmap_config axp288_regmap_config = { | 175 | static const struct regmap_config axp288_regmap_config = { |
133 | .reg_bits = 8, | 176 | .reg_bits = 8, |
134 | .val_bits = 8, | 177 | .val_bits = 8, |
@@ -181,6 +224,34 @@ static const struct regmap_irq axp20x_regmap_irqs[] = { | |||
181 | INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0), | 224 | INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0), |
182 | }; | 225 | }; |
183 | 226 | ||
227 | static const struct regmap_irq axp22x_regmap_irqs[] = { | ||
228 | INIT_REGMAP_IRQ(AXP22X, ACIN_OVER_V, 0, 7), | ||
229 | INIT_REGMAP_IRQ(AXP22X, ACIN_PLUGIN, 0, 6), | ||
230 | INIT_REGMAP_IRQ(AXP22X, ACIN_REMOVAL, 0, 5), | ||
231 | INIT_REGMAP_IRQ(AXP22X, VBUS_OVER_V, 0, 4), | ||
232 | INIT_REGMAP_IRQ(AXP22X, VBUS_PLUGIN, 0, 3), | ||
233 | INIT_REGMAP_IRQ(AXP22X, VBUS_REMOVAL, 0, 2), | ||
234 | INIT_REGMAP_IRQ(AXP22X, VBUS_V_LOW, 0, 1), | ||
235 | INIT_REGMAP_IRQ(AXP22X, BATT_PLUGIN, 1, 7), | ||
236 | INIT_REGMAP_IRQ(AXP22X, BATT_REMOVAL, 1, 6), | ||
237 | INIT_REGMAP_IRQ(AXP22X, BATT_ENT_ACT_MODE, 1, 5), | ||
238 | INIT_REGMAP_IRQ(AXP22X, BATT_EXIT_ACT_MODE, 1, 4), | ||
239 | INIT_REGMAP_IRQ(AXP22X, CHARG, 1, 3), | ||
240 | INIT_REGMAP_IRQ(AXP22X, CHARG_DONE, 1, 2), | ||
241 | INIT_REGMAP_IRQ(AXP22X, BATT_TEMP_HIGH, 1, 1), | ||
242 | INIT_REGMAP_IRQ(AXP22X, BATT_TEMP_LOW, 1, 0), | ||
243 | INIT_REGMAP_IRQ(AXP22X, DIE_TEMP_HIGH, 2, 7), | ||
244 | INIT_REGMAP_IRQ(AXP22X, PEK_SHORT, 2, 1), | ||
245 | INIT_REGMAP_IRQ(AXP22X, PEK_LONG, 2, 0), | ||
246 | INIT_REGMAP_IRQ(AXP22X, LOW_PWR_LVL1, 3, 1), | ||
247 | INIT_REGMAP_IRQ(AXP22X, LOW_PWR_LVL2, 3, 0), | ||
248 | INIT_REGMAP_IRQ(AXP22X, TIMER, 4, 7), | ||
249 | INIT_REGMAP_IRQ(AXP22X, PEK_RIS_EDGE, 4, 6), | ||
250 | INIT_REGMAP_IRQ(AXP22X, PEK_FAL_EDGE, 4, 5), | ||
251 | INIT_REGMAP_IRQ(AXP22X, GPIO1_INPUT, 4, 1), | ||
252 | INIT_REGMAP_IRQ(AXP22X, GPIO0_INPUT, 4, 0), | ||
253 | }; | ||
254 | |||
184 | /* some IRQs are compatible with axp20x models */ | 255 | /* some IRQs are compatible with axp20x models */ |
185 | static const struct regmap_irq axp288_regmap_irqs[] = { | 256 | static const struct regmap_irq axp288_regmap_irqs[] = { |
186 | INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2), | 257 | INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2), |
@@ -224,6 +295,7 @@ static const struct regmap_irq axp288_regmap_irqs[] = { | |||
224 | static const struct of_device_id axp20x_of_match[] = { | 295 | static const struct of_device_id axp20x_of_match[] = { |
225 | { .compatible = "x-powers,axp202", .data = (void *) AXP202_ID }, | 296 | { .compatible = "x-powers,axp202", .data = (void *) AXP202_ID }, |
226 | { .compatible = "x-powers,axp209", .data = (void *) AXP209_ID }, | 297 | { .compatible = "x-powers,axp209", .data = (void *) AXP209_ID }, |
298 | { .compatible = "x-powers,axp221", .data = (void *) AXP221_ID }, | ||
227 | { }, | 299 | { }, |
228 | }; | 300 | }; |
229 | MODULE_DEVICE_TABLE(of, axp20x_of_match); | 301 | MODULE_DEVICE_TABLE(of, axp20x_of_match); |
@@ -258,6 +330,18 @@ static const struct regmap_irq_chip axp20x_regmap_irq_chip = { | |||
258 | 330 | ||
259 | }; | 331 | }; |
260 | 332 | ||
333 | static const struct regmap_irq_chip axp22x_regmap_irq_chip = { | ||
334 | .name = "axp22x_irq_chip", | ||
335 | .status_base = AXP20X_IRQ1_STATE, | ||
336 | .ack_base = AXP20X_IRQ1_STATE, | ||
337 | .mask_base = AXP20X_IRQ1_EN, | ||
338 | .mask_invert = true, | ||
339 | .init_ack_masked = true, | ||
340 | .irqs = axp22x_regmap_irqs, | ||
341 | .num_irqs = ARRAY_SIZE(axp22x_regmap_irqs), | ||
342 | .num_regs = 5, | ||
343 | }; | ||
344 | |||
261 | static const struct regmap_irq_chip axp288_regmap_irq_chip = { | 345 | static const struct regmap_irq_chip axp288_regmap_irq_chip = { |
262 | .name = "axp288_irq_chip", | 346 | .name = "axp288_irq_chip", |
263 | .status_base = AXP20X_IRQ1_STATE, | 347 | .status_base = AXP20X_IRQ1_STATE, |
@@ -281,6 +365,16 @@ static struct mfd_cell axp20x_cells[] = { | |||
281 | }, | 365 | }, |
282 | }; | 366 | }; |
283 | 367 | ||
368 | static struct mfd_cell axp22x_cells[] = { | ||
369 | { | ||
370 | .name = "axp20x-pek", | ||
371 | .num_resources = ARRAY_SIZE(axp22x_pek_resources), | ||
372 | .resources = axp22x_pek_resources, | ||
373 | }, { | ||
374 | .name = "axp20x-regulator", | ||
375 | }, | ||
376 | }; | ||
377 | |||
284 | static struct resource axp288_adc_resources[] = { | 378 | static struct resource axp288_adc_resources[] = { |
285 | { | 379 | { |
286 | .name = "GPADC", | 380 | .name = "GPADC", |
@@ -426,6 +520,12 @@ static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev) | |||
426 | axp20x->regmap_cfg = &axp20x_regmap_config; | 520 | axp20x->regmap_cfg = &axp20x_regmap_config; |
427 | axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip; | 521 | axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip; |
428 | break; | 522 | break; |
523 | case AXP221_ID: | ||
524 | axp20x->nr_cells = ARRAY_SIZE(axp22x_cells); | ||
525 | axp20x->cells = axp22x_cells; | ||
526 | axp20x->regmap_cfg = &axp22x_regmap_config; | ||
527 | axp20x->regmap_irq_chip = &axp22x_regmap_irq_chip; | ||
528 | break; | ||
429 | case AXP288_ID: | 529 | case AXP288_ID: |
430 | axp20x->cells = axp288_cells; | 530 | axp20x->cells = axp288_cells; |
431 | axp20x->nr_cells = ARRAY_SIZE(axp288_cells); | 531 | axp20x->nr_cells = ARRAY_SIZE(axp288_cells); |
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index c4aecc6f8373..0eee63542038 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c | |||
@@ -17,111 +17,36 @@ | |||
17 | * battery charging and regulator control, firmware update. | 17 | * battery charging and regulator control, firmware update. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/of_platform.h> | ||
20 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
23 | #include <linux/mfd/core.h> | 24 | #include <linux/mfd/core.h> |
24 | #include <linux/mfd/cros_ec.h> | 25 | #include <linux/mfd/cros_ec.h> |
25 | #include <linux/mfd/cros_ec_commands.h> | ||
26 | #include <linux/delay.h> | ||
27 | 26 | ||
28 | #define EC_COMMAND_RETRIES 50 | 27 | #define CROS_EC_DEV_EC_INDEX 0 |
28 | #define CROS_EC_DEV_PD_INDEX 1 | ||
29 | 29 | ||
30 | int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, | 30 | static struct cros_ec_platform ec_p = { |
31 | struct cros_ec_command *msg) | 31 | .ec_name = CROS_EC_DEV_NAME, |
32 | { | 32 | .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX), |
33 | uint8_t *out; | 33 | }; |
34 | int csum, i; | ||
35 | |||
36 | BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE); | ||
37 | out = ec_dev->dout; | ||
38 | out[0] = EC_CMD_VERSION0 + msg->version; | ||
39 | out[1] = msg->command; | ||
40 | out[2] = msg->outsize; | ||
41 | csum = out[0] + out[1] + out[2]; | ||
42 | for (i = 0; i < msg->outsize; i++) | ||
43 | csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->outdata[i]; | ||
44 | out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = (uint8_t)(csum & 0xff); | ||
45 | |||
46 | return EC_MSG_TX_PROTO_BYTES + msg->outsize; | ||
47 | } | ||
48 | EXPORT_SYMBOL(cros_ec_prepare_tx); | ||
49 | |||
50 | int cros_ec_check_result(struct cros_ec_device *ec_dev, | ||
51 | struct cros_ec_command *msg) | ||
52 | { | ||
53 | switch (msg->result) { | ||
54 | case EC_RES_SUCCESS: | ||
55 | return 0; | ||
56 | case EC_RES_IN_PROGRESS: | ||
57 | dev_dbg(ec_dev->dev, "command 0x%02x in progress\n", | ||
58 | msg->command); | ||
59 | return -EAGAIN; | ||
60 | default: | ||
61 | dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n", | ||
62 | msg->command, msg->result); | ||
63 | return 0; | ||
64 | } | ||
65 | } | ||
66 | EXPORT_SYMBOL(cros_ec_check_result); | ||
67 | |||
68 | int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, | ||
69 | struct cros_ec_command *msg) | ||
70 | { | ||
71 | int ret; | ||
72 | |||
73 | mutex_lock(&ec_dev->lock); | ||
74 | ret = ec_dev->cmd_xfer(ec_dev, msg); | ||
75 | if (msg->result == EC_RES_IN_PROGRESS) { | ||
76 | int i; | ||
77 | struct cros_ec_command status_msg = { }; | ||
78 | struct ec_response_get_comms_status *status; | ||
79 | |||
80 | status_msg.command = EC_CMD_GET_COMMS_STATUS; | ||
81 | status_msg.insize = sizeof(*status); | ||
82 | |||
83 | /* | ||
84 | * Query the EC's status until it's no longer busy or | ||
85 | * we encounter an error. | ||
86 | */ | ||
87 | for (i = 0; i < EC_COMMAND_RETRIES; i++) { | ||
88 | usleep_range(10000, 11000); | ||
89 | |||
90 | ret = ec_dev->cmd_xfer(ec_dev, &status_msg); | ||
91 | if (ret < 0) | ||
92 | break; | ||
93 | 34 | ||
94 | msg->result = status_msg.result; | 35 | static struct cros_ec_platform pd_p = { |
95 | if (status_msg.result != EC_RES_SUCCESS) | 36 | .ec_name = CROS_EC_DEV_PD_NAME, |
96 | break; | 37 | .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX), |
38 | }; | ||
97 | 39 | ||
98 | status = (struct ec_response_get_comms_status *) | 40 | static const struct mfd_cell ec_cell = { |
99 | status_msg.indata; | 41 | .name = "cros-ec-ctl", |
100 | if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) | 42 | .platform_data = &ec_p, |
101 | break; | 43 | .pdata_size = sizeof(ec_p), |
102 | } | 44 | }; |
103 | } | ||
104 | mutex_unlock(&ec_dev->lock); | ||
105 | 45 | ||
106 | return ret; | 46 | static const struct mfd_cell ec_pd_cell = { |
107 | } | 47 | .name = "cros-ec-ctl", |
108 | EXPORT_SYMBOL(cros_ec_cmd_xfer); | 48 | .platform_data = &pd_p, |
109 | 49 | .pdata_size = sizeof(pd_p), | |
110 | static const struct mfd_cell cros_devs[] = { | ||
111 | { | ||
112 | .name = "cros-ec-keyb", | ||
113 | .id = 1, | ||
114 | .of_compatible = "google,cros-ec-keyb", | ||
115 | }, | ||
116 | { | ||
117 | .name = "cros-ec-i2c-tunnel", | ||
118 | .id = 2, | ||
119 | .of_compatible = "google,cros-ec-i2c-tunnel", | ||
120 | }, | ||
121 | { | ||
122 | .name = "cros-ec-ctl", | ||
123 | .id = 3, | ||
124 | }, | ||
125 | }; | 50 | }; |
126 | 51 | ||
127 | int cros_ec_register(struct cros_ec_device *ec_dev) | 52 | int cros_ec_register(struct cros_ec_device *ec_dev) |
@@ -129,27 +54,59 @@ int cros_ec_register(struct cros_ec_device *ec_dev) | |||
129 | struct device *dev = ec_dev->dev; | 54 | struct device *dev = ec_dev->dev; |
130 | int err = 0; | 55 | int err = 0; |
131 | 56 | ||
132 | if (ec_dev->din_size) { | 57 | ec_dev->max_request = sizeof(struct ec_params_hello); |
133 | ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL); | 58 | ec_dev->max_response = sizeof(struct ec_response_get_protocol_info); |
134 | if (!ec_dev->din) | 59 | ec_dev->max_passthru = 0; |
135 | return -ENOMEM; | 60 | |
136 | } | 61 | ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL); |
137 | if (ec_dev->dout_size) { | 62 | if (!ec_dev->din) |
138 | ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL); | 63 | return -ENOMEM; |
139 | if (!ec_dev->dout) | 64 | |
140 | return -ENOMEM; | 65 | ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL); |
141 | } | 66 | if (!ec_dev->dout) |
67 | return -ENOMEM; | ||
142 | 68 | ||
143 | mutex_init(&ec_dev->lock); | 69 | mutex_init(&ec_dev->lock); |
144 | 70 | ||
145 | err = mfd_add_devices(dev, 0, cros_devs, | 71 | cros_ec_query_all(ec_dev); |
146 | ARRAY_SIZE(cros_devs), | 72 | |
73 | err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell, 1, | ||
147 | NULL, ec_dev->irq, NULL); | 74 | NULL, ec_dev->irq, NULL); |
148 | if (err) { | 75 | if (err) { |
149 | dev_err(dev, "failed to add mfd devices\n"); | 76 | dev_err(dev, |
77 | "Failed to register Embedded Controller subdevice %d\n", | ||
78 | err); | ||
150 | return err; | 79 | return err; |
151 | } | 80 | } |
152 | 81 | ||
82 | if (ec_dev->max_passthru) { | ||
83 | /* | ||
84 | * Register a PD device as well on top of this device. | ||
85 | * We make the following assumptions: | ||
86 | * - behind an EC, we have a pd | ||
87 | * - only one device added. | ||
88 | * - the EC is responsive at init time (it is not true for a | ||
89 | * sensor hub. | ||
90 | */ | ||
91 | err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, | ||
92 | &ec_pd_cell, 1, NULL, ec_dev->irq, NULL); | ||
93 | if (err) { | ||
94 | dev_err(dev, | ||
95 | "Failed to register Power Delivery subdevice %d\n", | ||
96 | err); | ||
97 | return err; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | if (IS_ENABLED(CONFIG_OF) && dev->of_node) { | ||
102 | err = of_platform_populate(dev->of_node, NULL, NULL, dev); | ||
103 | if (err) { | ||
104 | mfd_remove_devices(dev); | ||
105 | dev_err(dev, "Failed to register sub-devices\n"); | ||
106 | return err; | ||
107 | } | ||
108 | } | ||
109 | |||
153 | dev_info(dev, "Chrome EC device registered\n"); | 110 | dev_info(dev, "Chrome EC device registered\n"); |
154 | 111 | ||
155 | return 0; | 112 | return 0; |
diff --git a/drivers/mfd/cros_ec_i2c.c b/drivers/mfd/cros_ec_i2c.c index c0c30f4f946f..b9a0963ca5c3 100644 --- a/drivers/mfd/cros_ec_i2c.c +++ b/drivers/mfd/cros_ec_i2c.c | |||
@@ -13,6 +13,7 @@ | |||
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/delay.h> | ||
16 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
18 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
@@ -22,6 +23,32 @@ | |||
22 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
23 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
24 | 25 | ||
26 | /** | ||
27 | * Request format for protocol v3 | ||
28 | * byte 0 0xda (EC_COMMAND_PROTOCOL_3) | ||
29 | * byte 1-8 struct ec_host_request | ||
30 | * byte 10- response data | ||
31 | */ | ||
32 | struct ec_host_request_i2c { | ||
33 | /* Always 0xda to backward compatible with v2 struct */ | ||
34 | uint8_t command_protocol; | ||
35 | struct ec_host_request ec_request; | ||
36 | } __packed; | ||
37 | |||
38 | |||
39 | /* | ||
40 | * Response format for protocol v3 | ||
41 | * byte 0 result code | ||
42 | * byte 1 packet_length | ||
43 | * byte 2-9 struct ec_host_response | ||
44 | * byte 10- response data | ||
45 | */ | ||
46 | struct ec_host_response_i2c { | ||
47 | uint8_t result; | ||
48 | uint8_t packet_length; | ||
49 | struct ec_host_response ec_response; | ||
50 | } __packed; | ||
51 | |||
25 | static inline struct cros_ec_device *to_ec_dev(struct device *dev) | 52 | static inline struct cros_ec_device *to_ec_dev(struct device *dev) |
26 | { | 53 | { |
27 | struct i2c_client *client = to_i2c_client(dev); | 54 | struct i2c_client *client = to_i2c_client(dev); |
@@ -29,6 +56,134 @@ static inline struct cros_ec_device *to_ec_dev(struct device *dev) | |||
29 | return i2c_get_clientdata(client); | 56 | return i2c_get_clientdata(client); |
30 | } | 57 | } |
31 | 58 | ||
59 | static int cros_ec_pkt_xfer_i2c(struct cros_ec_device *ec_dev, | ||
60 | struct cros_ec_command *msg) | ||
61 | { | ||
62 | struct i2c_client *client = ec_dev->priv; | ||
63 | int ret = -ENOMEM; | ||
64 | int i; | ||
65 | int packet_len; | ||
66 | u8 *out_buf = NULL; | ||
67 | u8 *in_buf = NULL; | ||
68 | u8 sum; | ||
69 | struct i2c_msg i2c_msg[2]; | ||
70 | struct ec_host_response *ec_response; | ||
71 | struct ec_host_request_i2c *ec_request_i2c; | ||
72 | struct ec_host_response_i2c *ec_response_i2c; | ||
73 | int request_header_size = sizeof(struct ec_host_request_i2c); | ||
74 | int response_header_size = sizeof(struct ec_host_response_i2c); | ||
75 | |||
76 | i2c_msg[0].addr = client->addr; | ||
77 | i2c_msg[0].flags = 0; | ||
78 | i2c_msg[1].addr = client->addr; | ||
79 | i2c_msg[1].flags = I2C_M_RD; | ||
80 | |||
81 | packet_len = msg->insize + response_header_size; | ||
82 | BUG_ON(packet_len > ec_dev->din_size); | ||
83 | in_buf = ec_dev->din; | ||
84 | i2c_msg[1].len = packet_len; | ||
85 | i2c_msg[1].buf = (char *) in_buf; | ||
86 | |||
87 | packet_len = msg->outsize + request_header_size; | ||
88 | BUG_ON(packet_len > ec_dev->dout_size); | ||
89 | out_buf = ec_dev->dout; | ||
90 | i2c_msg[0].len = packet_len; | ||
91 | i2c_msg[0].buf = (char *) out_buf; | ||
92 | |||
93 | /* create request data */ | ||
94 | ec_request_i2c = (struct ec_host_request_i2c *) out_buf; | ||
95 | ec_request_i2c->command_protocol = EC_COMMAND_PROTOCOL_3; | ||
96 | |||
97 | ec_dev->dout++; | ||
98 | ret = cros_ec_prepare_tx(ec_dev, msg); | ||
99 | ec_dev->dout--; | ||
100 | |||
101 | /* send command to EC and read answer */ | ||
102 | ret = i2c_transfer(client->adapter, i2c_msg, 2); | ||
103 | if (ret < 0) { | ||
104 | dev_dbg(ec_dev->dev, "i2c transfer failed: %d\n", ret); | ||
105 | goto done; | ||
106 | } else if (ret != 2) { | ||
107 | dev_err(ec_dev->dev, "failed to get response: %d\n", ret); | ||
108 | ret = -EIO; | ||
109 | goto done; | ||
110 | } | ||
111 | |||
112 | ec_response_i2c = (struct ec_host_response_i2c *) in_buf; | ||
113 | msg->result = ec_response_i2c->result; | ||
114 | ec_response = &ec_response_i2c->ec_response; | ||
115 | |||
116 | switch (msg->result) { | ||
117 | case EC_RES_SUCCESS: | ||
118 | break; | ||
119 | case EC_RES_IN_PROGRESS: | ||
120 | ret = -EAGAIN; | ||
121 | dev_dbg(ec_dev->dev, "command 0x%02x in progress\n", | ||
122 | msg->command); | ||
123 | goto done; | ||
124 | |||
125 | default: | ||
126 | dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n", | ||
127 | msg->command, msg->result); | ||
128 | /* | ||
129 | * When we send v3 request to v2 ec, ec won't recognize the | ||
130 | * 0xda (EC_COMMAND_PROTOCOL_3) and will return with status | ||
131 | * EC_RES_INVALID_COMMAND with zero data length. | ||
132 | * | ||
133 | * In case of invalid command for v3 protocol the data length | ||
134 | * will be at least sizeof(struct ec_host_response) | ||
135 | */ | ||
136 | if (ec_response_i2c->result == EC_RES_INVALID_COMMAND && | ||
137 | ec_response_i2c->packet_length == 0) { | ||
138 | ret = -EPROTONOSUPPORT; | ||
139 | goto done; | ||
140 | } | ||
141 | } | ||
142 | |||
143 | if (ec_response_i2c->packet_length < sizeof(struct ec_host_response)) { | ||
144 | dev_err(ec_dev->dev, | ||
145 | "response of %u bytes too short; not a full header\n", | ||
146 | ec_response_i2c->packet_length); | ||
147 | ret = -EBADMSG; | ||
148 | goto done; | ||
149 | } | ||
150 | |||
151 | if (msg->insize < ec_response->data_len) { | ||
152 | dev_err(ec_dev->dev, | ||
153 | "response data size is too large: expected %u, got %u\n", | ||
154 | msg->insize, | ||
155 | ec_response->data_len); | ||
156 | ret = -EMSGSIZE; | ||
157 | goto done; | ||
158 | } | ||
159 | |||
160 | /* copy response packet payload and compute checksum */ | ||
161 | sum = 0; | ||
162 | for (i = 0; i < sizeof(struct ec_host_response); i++) | ||
163 | sum += ((u8 *)ec_response)[i]; | ||
164 | |||
165 | memcpy(msg->data, | ||
166 | in_buf + response_header_size, | ||
167 | ec_response->data_len); | ||
168 | for (i = 0; i < ec_response->data_len; i++) | ||
169 | sum += msg->data[i]; | ||
170 | |||
171 | /* All bytes should sum to zero */ | ||
172 | if (sum) { | ||
173 | dev_err(ec_dev->dev, "bad packet checksum\n"); | ||
174 | ret = -EBADMSG; | ||
175 | goto done; | ||
176 | } | ||
177 | |||
178 | ret = ec_response->data_len; | ||
179 | |||
180 | done: | ||
181 | if (msg->command == EC_CMD_REBOOT_EC) | ||
182 | msleep(EC_REBOOT_DELAY_MS); | ||
183 | |||
184 | return ret; | ||
185 | } | ||
186 | |||
32 | static int cros_ec_cmd_xfer_i2c(struct cros_ec_device *ec_dev, | 187 | static int cros_ec_cmd_xfer_i2c(struct cros_ec_device *ec_dev, |
33 | struct cros_ec_command *msg) | 188 | struct cros_ec_command *msg) |
34 | { | 189 | { |
@@ -76,7 +231,7 @@ static int cros_ec_cmd_xfer_i2c(struct cros_ec_device *ec_dev, | |||
76 | /* copy message payload and compute checksum */ | 231 | /* copy message payload and compute checksum */ |
77 | sum = out_buf[0] + out_buf[1] + out_buf[2]; | 232 | sum = out_buf[0] + out_buf[1] + out_buf[2]; |
78 | for (i = 0; i < msg->outsize; i++) { | 233 | for (i = 0; i < msg->outsize; i++) { |
79 | out_buf[3 + i] = msg->outdata[i]; | 234 | out_buf[3 + i] = msg->data[i]; |
80 | sum += out_buf[3 + i]; | 235 | sum += out_buf[3 + i]; |
81 | } | 236 | } |
82 | out_buf[3 + msg->outsize] = sum; | 237 | out_buf[3 + msg->outsize] = sum; |
@@ -109,7 +264,7 @@ static int cros_ec_cmd_xfer_i2c(struct cros_ec_device *ec_dev, | |||
109 | /* copy response packet payload and compute checksum */ | 264 | /* copy response packet payload and compute checksum */ |
110 | sum = in_buf[0] + in_buf[1]; | 265 | sum = in_buf[0] + in_buf[1]; |
111 | for (i = 0; i < len; i++) { | 266 | for (i = 0; i < len; i++) { |
112 | msg->indata[i] = in_buf[2 + i]; | 267 | msg->data[i] = in_buf[2 + i]; |
113 | sum += in_buf[2 + i]; | 268 | sum += in_buf[2 + i]; |
114 | } | 269 | } |
115 | dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n", | 270 | dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n", |
@@ -121,9 +276,12 @@ static int cros_ec_cmd_xfer_i2c(struct cros_ec_device *ec_dev, | |||
121 | } | 276 | } |
122 | 277 | ||
123 | ret = len; | 278 | ret = len; |
124 | done: | 279 | done: |
125 | kfree(in_buf); | 280 | kfree(in_buf); |
126 | kfree(out_buf); | 281 | kfree(out_buf); |
282 | if (msg->command == EC_CMD_REBOOT_EC) | ||
283 | msleep(EC_REBOOT_DELAY_MS); | ||
284 | |||
127 | return ret; | 285 | return ret; |
128 | } | 286 | } |
129 | 287 | ||
@@ -143,9 +301,11 @@ static int cros_ec_i2c_probe(struct i2c_client *client, | |||
143 | ec_dev->priv = client; | 301 | ec_dev->priv = client; |
144 | ec_dev->irq = client->irq; | 302 | ec_dev->irq = client->irq; |
145 | ec_dev->cmd_xfer = cros_ec_cmd_xfer_i2c; | 303 | ec_dev->cmd_xfer = cros_ec_cmd_xfer_i2c; |
146 | ec_dev->ec_name = client->name; | 304 | ec_dev->pkt_xfer = cros_ec_pkt_xfer_i2c; |
147 | ec_dev->phys_name = client->adapter->name; | 305 | ec_dev->phys_name = client->adapter->name; |
148 | ec_dev->parent = &client->dev; | 306 | ec_dev->din_size = sizeof(struct ec_host_response_i2c) + |
307 | sizeof(struct ec_response_get_protocol_info); | ||
308 | ec_dev->dout_size = sizeof(struct ec_host_request_i2c); | ||
149 | 309 | ||
150 | err = cros_ec_register(ec_dev); | 310 | err = cros_ec_register(ec_dev); |
151 | if (err) { | 311 | if (err) { |
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index bf6e08e8013e..16f228dc243f 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c | |||
@@ -65,29 +65,26 @@ | |||
65 | */ | 65 | */ |
66 | #define EC_SPI_RECOVERY_TIME_NS (200 * 1000) | 66 | #define EC_SPI_RECOVERY_TIME_NS (200 * 1000) |
67 | 67 | ||
68 | /* | ||
69 | * The EC is unresponsive for a time after a reboot command. Add a | ||
70 | * simple delay to make sure that the bus stays locked. | ||
71 | */ | ||
72 | #define EC_REBOOT_DELAY_MS 50 | ||
73 | |||
74 | /** | 68 | /** |
75 | * struct cros_ec_spi - information about a SPI-connected EC | 69 | * struct cros_ec_spi - information about a SPI-connected EC |
76 | * | 70 | * |
77 | * @spi: SPI device we are connected to | 71 | * @spi: SPI device we are connected to |
78 | * @last_transfer_ns: time that we last finished a transfer, or 0 if there | 72 | * @last_transfer_ns: time that we last finished a transfer, or 0 if there |
79 | * if no record | 73 | * if no record |
74 | * @start_of_msg_delay: used to set the delay_usecs on the spi_transfer that | ||
75 | * is sent when we want to turn on CS at the start of a transaction. | ||
80 | * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that | 76 | * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that |
81 | * is sent when we want to turn off CS at the end of a transaction. | 77 | * is sent when we want to turn off CS at the end of a transaction. |
82 | */ | 78 | */ |
83 | struct cros_ec_spi { | 79 | struct cros_ec_spi { |
84 | struct spi_device *spi; | 80 | struct spi_device *spi; |
85 | s64 last_transfer_ns; | 81 | s64 last_transfer_ns; |
82 | unsigned int start_of_msg_delay; | ||
86 | unsigned int end_of_msg_delay; | 83 | unsigned int end_of_msg_delay; |
87 | }; | 84 | }; |
88 | 85 | ||
89 | static void debug_packet(struct device *dev, const char *name, u8 *ptr, | 86 | static void debug_packet(struct device *dev, const char *name, u8 *ptr, |
90 | int len) | 87 | int len) |
91 | { | 88 | { |
92 | #ifdef DEBUG | 89 | #ifdef DEBUG |
93 | int i; | 90 | int i; |
@@ -100,6 +97,172 @@ static void debug_packet(struct device *dev, const char *name, u8 *ptr, | |||
100 | #endif | 97 | #endif |
101 | } | 98 | } |
102 | 99 | ||
100 | static int terminate_request(struct cros_ec_device *ec_dev) | ||
101 | { | ||
102 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
103 | struct spi_message msg; | ||
104 | struct spi_transfer trans; | ||
105 | int ret; | ||
106 | |||
107 | /* | ||
108 | * Turn off CS, possibly adding a delay to ensure the rising edge | ||
109 | * doesn't come too soon after the end of the data. | ||
110 | */ | ||
111 | spi_message_init(&msg); | ||
112 | memset(&trans, 0, sizeof(trans)); | ||
113 | trans.delay_usecs = ec_spi->end_of_msg_delay; | ||
114 | spi_message_add_tail(&trans, &msg); | ||
115 | |||
116 | ret = spi_sync(ec_spi->spi, &msg); | ||
117 | |||
118 | /* Reset end-of-response timer */ | ||
119 | ec_spi->last_transfer_ns = ktime_get_ns(); | ||
120 | if (ret < 0) { | ||
121 | dev_err(ec_dev->dev, | ||
122 | "cs-deassert spi transfer failed: %d\n", | ||
123 | ret); | ||
124 | } | ||
125 | |||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * receive_n_bytes - receive n bytes from the EC. | ||
131 | * | ||
132 | * Assumes buf is a pointer into the ec_dev->din buffer | ||
133 | */ | ||
134 | static int receive_n_bytes(struct cros_ec_device *ec_dev, u8 *buf, int n) | ||
135 | { | ||
136 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
137 | struct spi_transfer trans; | ||
138 | struct spi_message msg; | ||
139 | int ret; | ||
140 | |||
141 | BUG_ON(buf - ec_dev->din + n > ec_dev->din_size); | ||
142 | |||
143 | memset(&trans, 0, sizeof(trans)); | ||
144 | trans.cs_change = 1; | ||
145 | trans.rx_buf = buf; | ||
146 | trans.len = n; | ||
147 | |||
148 | spi_message_init(&msg); | ||
149 | spi_message_add_tail(&trans, &msg); | ||
150 | ret = spi_sync(ec_spi->spi, &msg); | ||
151 | if (ret < 0) | ||
152 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
153 | |||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | /** | ||
158 | * cros_ec_spi_receive_packet - Receive a packet from the EC. | ||
159 | * | ||
160 | * This function has two phases: reading the preamble bytes (since if we read | ||
161 | * data from the EC before it is ready to send, we just get preamble) and | ||
162 | * reading the actual message. | ||
163 | * | ||
164 | * The received data is placed into ec_dev->din. | ||
165 | * | ||
166 | * @ec_dev: ChromeOS EC device | ||
167 | * @need_len: Number of message bytes we need to read | ||
168 | */ | ||
169 | static int cros_ec_spi_receive_packet(struct cros_ec_device *ec_dev, | ||
170 | int need_len) | ||
171 | { | ||
172 | struct ec_host_response *response; | ||
173 | u8 *ptr, *end; | ||
174 | int ret; | ||
175 | unsigned long deadline; | ||
176 | int todo; | ||
177 | |||
178 | BUG_ON(EC_MSG_PREAMBLE_COUNT > ec_dev->din_size); | ||
179 | |||
180 | /* Receive data until we see the header byte */ | ||
181 | deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); | ||
182 | while (true) { | ||
183 | unsigned long start_jiffies = jiffies; | ||
184 | |||
185 | ret = receive_n_bytes(ec_dev, | ||
186 | ec_dev->din, | ||
187 | EC_MSG_PREAMBLE_COUNT); | ||
188 | if (ret < 0) | ||
189 | return ret; | ||
190 | |||
191 | ptr = ec_dev->din; | ||
192 | for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { | ||
193 | if (*ptr == EC_SPI_FRAME_START) { | ||
194 | dev_dbg(ec_dev->dev, "msg found at %zd\n", | ||
195 | ptr - ec_dev->din); | ||
196 | break; | ||
197 | } | ||
198 | } | ||
199 | if (ptr != end) | ||
200 | break; | ||
201 | |||
202 | /* | ||
203 | * Use the time at the start of the loop as a timeout. This | ||
204 | * gives us one last shot at getting the transfer and is useful | ||
205 | * in case we got context switched out for a while. | ||
206 | */ | ||
207 | if (time_after(start_jiffies, deadline)) { | ||
208 | dev_warn(ec_dev->dev, "EC failed to respond in time\n"); | ||
209 | return -ETIMEDOUT; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * ptr now points to the header byte. Copy any valid data to the | ||
215 | * start of our buffer | ||
216 | */ | ||
217 | todo = end - ++ptr; | ||
218 | BUG_ON(todo < 0 || todo > ec_dev->din_size); | ||
219 | todo = min(todo, need_len); | ||
220 | memmove(ec_dev->din, ptr, todo); | ||
221 | ptr = ec_dev->din + todo; | ||
222 | dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n", | ||
223 | need_len, todo); | ||
224 | need_len -= todo; | ||
225 | |||
226 | /* If the entire response struct wasn't read, get the rest of it. */ | ||
227 | if (todo < sizeof(*response)) { | ||
228 | ret = receive_n_bytes(ec_dev, ptr, sizeof(*response) - todo); | ||
229 | if (ret < 0) | ||
230 | return -EBADMSG; | ||
231 | ptr += (sizeof(*response) - todo); | ||
232 | todo = sizeof(*response); | ||
233 | } | ||
234 | |||
235 | response = (struct ec_host_response *)ec_dev->din; | ||
236 | |||
237 | /* Abort if data_len is too large. */ | ||
238 | if (response->data_len > ec_dev->din_size) | ||
239 | return -EMSGSIZE; | ||
240 | |||
241 | /* Receive data until we have it all */ | ||
242 | while (need_len > 0) { | ||
243 | /* | ||
244 | * We can't support transfers larger than the SPI FIFO size | ||
245 | * unless we have DMA. We don't have DMA on the ISP SPI ports | ||
246 | * for Exynos. We need a way of asking SPI driver for | ||
247 | * maximum-supported transfer size. | ||
248 | */ | ||
249 | todo = min(need_len, 256); | ||
250 | dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n", | ||
251 | todo, need_len, ptr - ec_dev->din); | ||
252 | |||
253 | ret = receive_n_bytes(ec_dev, ptr, todo); | ||
254 | if (ret < 0) | ||
255 | return ret; | ||
256 | |||
257 | ptr += todo; | ||
258 | need_len -= todo; | ||
259 | } | ||
260 | |||
261 | dev_dbg(ec_dev->dev, "loop done, ptr=%zd\n", ptr - ec_dev->din); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
103 | /** | 266 | /** |
104 | * cros_ec_spi_receive_response - Receive a response from the EC. | 267 | * cros_ec_spi_receive_response - Receive a response from the EC. |
105 | * | 268 | * |
@@ -115,34 +278,27 @@ static void debug_packet(struct device *dev, const char *name, u8 *ptr, | |||
115 | static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, | 278 | static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, |
116 | int need_len) | 279 | int need_len) |
117 | { | 280 | { |
118 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
119 | struct spi_transfer trans; | ||
120 | struct spi_message msg; | ||
121 | u8 *ptr, *end; | 281 | u8 *ptr, *end; |
122 | int ret; | 282 | int ret; |
123 | unsigned long deadline; | 283 | unsigned long deadline; |
124 | int todo; | 284 | int todo; |
125 | 285 | ||
286 | BUG_ON(EC_MSG_PREAMBLE_COUNT > ec_dev->din_size); | ||
287 | |||
126 | /* Receive data until we see the header byte */ | 288 | /* Receive data until we see the header byte */ |
127 | deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); | 289 | deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); |
128 | while (true) { | 290 | while (true) { |
129 | unsigned long start_jiffies = jiffies; | 291 | unsigned long start_jiffies = jiffies; |
130 | 292 | ||
131 | memset(&trans, 0, sizeof(trans)); | 293 | ret = receive_n_bytes(ec_dev, |
132 | trans.cs_change = 1; | 294 | ec_dev->din, |
133 | trans.rx_buf = ptr = ec_dev->din; | 295 | EC_MSG_PREAMBLE_COUNT); |
134 | trans.len = EC_MSG_PREAMBLE_COUNT; | 296 | if (ret < 0) |
135 | |||
136 | spi_message_init(&msg); | ||
137 | spi_message_add_tail(&trans, &msg); | ||
138 | ret = spi_sync(ec_spi->spi, &msg); | ||
139 | if (ret < 0) { | ||
140 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
141 | return ret; | 297 | return ret; |
142 | } | ||
143 | 298 | ||
299 | ptr = ec_dev->din; | ||
144 | for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { | 300 | for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { |
145 | if (*ptr == EC_MSG_HEADER) { | 301 | if (*ptr == EC_SPI_FRAME_START) { |
146 | dev_dbg(ec_dev->dev, "msg found at %zd\n", | 302 | dev_dbg(ec_dev->dev, "msg found at %zd\n", |
147 | ptr - ec_dev->din); | 303 | ptr - ec_dev->din); |
148 | break; | 304 | break; |
@@ -187,21 +343,9 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, | |||
187 | dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n", | 343 | dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n", |
188 | todo, need_len, ptr - ec_dev->din); | 344 | todo, need_len, ptr - ec_dev->din); |
189 | 345 | ||
190 | memset(&trans, 0, sizeof(trans)); | 346 | ret = receive_n_bytes(ec_dev, ptr, todo); |
191 | trans.cs_change = 1; | 347 | if (ret < 0) |
192 | trans.rx_buf = ptr; | ||
193 | trans.len = todo; | ||
194 | spi_message_init(&msg); | ||
195 | spi_message_add_tail(&trans, &msg); | ||
196 | |||
197 | /* send command to EC and read answer */ | ||
198 | BUG_ON((u8 *)trans.rx_buf - ec_dev->din + todo > | ||
199 | ec_dev->din_size); | ||
200 | ret = spi_sync(ec_spi->spi, &msg); | ||
201 | if (ret < 0) { | ||
202 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
203 | return ret; | 348 | return ret; |
204 | } | ||
205 | 349 | ||
206 | debug_packet(ec_dev->dev, "interim", ptr, todo); | 350 | debug_packet(ec_dev->dev, "interim", ptr, todo); |
207 | ptr += todo; | 351 | ptr += todo; |
@@ -214,6 +358,138 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, | |||
214 | } | 358 | } |
215 | 359 | ||
216 | /** | 360 | /** |
361 | * cros_ec_pkt_xfer_spi - Transfer a packet over SPI and receive the reply | ||
362 | * | ||
363 | * @ec_dev: ChromeOS EC device | ||
364 | * @ec_msg: Message to transfer | ||
365 | */ | ||
366 | static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev, | ||
367 | struct cros_ec_command *ec_msg) | ||
368 | { | ||
369 | struct ec_host_request *request; | ||
370 | struct ec_host_response *response; | ||
371 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
372 | struct spi_transfer trans, trans_delay; | ||
373 | struct spi_message msg; | ||
374 | int i, len; | ||
375 | u8 *ptr; | ||
376 | u8 *rx_buf; | ||
377 | u8 sum; | ||
378 | int ret = 0, final_ret; | ||
379 | |||
380 | len = cros_ec_prepare_tx(ec_dev, ec_msg); | ||
381 | request = (struct ec_host_request *)ec_dev->dout; | ||
382 | dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); | ||
383 | |||
384 | /* If it's too soon to do another transaction, wait */ | ||
385 | if (ec_spi->last_transfer_ns) { | ||
386 | unsigned long delay; /* The delay completed so far */ | ||
387 | |||
388 | delay = ktime_get_ns() - ec_spi->last_transfer_ns; | ||
389 | if (delay < EC_SPI_RECOVERY_TIME_NS) | ||
390 | ndelay(EC_SPI_RECOVERY_TIME_NS - delay); | ||
391 | } | ||
392 | |||
393 | rx_buf = kzalloc(len, GFP_KERNEL); | ||
394 | if (!rx_buf) { | ||
395 | ret = -ENOMEM; | ||
396 | goto exit; | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * Leave a gap between CS assertion and clocking of data to allow the | ||
401 | * EC time to wakeup. | ||
402 | */ | ||
403 | spi_message_init(&msg); | ||
404 | if (ec_spi->start_of_msg_delay) { | ||
405 | memset(&trans_delay, 0, sizeof(trans_delay)); | ||
406 | trans_delay.delay_usecs = ec_spi->start_of_msg_delay; | ||
407 | spi_message_add_tail(&trans_delay, &msg); | ||
408 | } | ||
409 | |||
410 | /* Transmit phase - send our message */ | ||
411 | memset(&trans, 0, sizeof(trans)); | ||
412 | trans.tx_buf = ec_dev->dout; | ||
413 | trans.rx_buf = rx_buf; | ||
414 | trans.len = len; | ||
415 | trans.cs_change = 1; | ||
416 | spi_message_add_tail(&trans, &msg); | ||
417 | ret = spi_sync(ec_spi->spi, &msg); | ||
418 | |||
419 | /* Get the response */ | ||
420 | if (!ret) { | ||
421 | /* Verify that EC can process command */ | ||
422 | for (i = 0; i < len; i++) { | ||
423 | switch (rx_buf[i]) { | ||
424 | case EC_SPI_PAST_END: | ||
425 | case EC_SPI_RX_BAD_DATA: | ||
426 | case EC_SPI_NOT_READY: | ||
427 | ret = -EAGAIN; | ||
428 | ec_msg->result = EC_RES_IN_PROGRESS; | ||
429 | default: | ||
430 | break; | ||
431 | } | ||
432 | if (ret) | ||
433 | break; | ||
434 | } | ||
435 | if (!ret) | ||
436 | ret = cros_ec_spi_receive_packet(ec_dev, | ||
437 | ec_msg->insize + sizeof(*response)); | ||
438 | } else { | ||
439 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
440 | } | ||
441 | |||
442 | final_ret = terminate_request(ec_dev); | ||
443 | if (!ret) | ||
444 | ret = final_ret; | ||
445 | if (ret < 0) | ||
446 | goto exit; | ||
447 | |||
448 | ptr = ec_dev->din; | ||
449 | |||
450 | /* check response error code */ | ||
451 | response = (struct ec_host_response *)ptr; | ||
452 | ec_msg->result = response->result; | ||
453 | |||
454 | ret = cros_ec_check_result(ec_dev, ec_msg); | ||
455 | if (ret) | ||
456 | goto exit; | ||
457 | |||
458 | len = response->data_len; | ||
459 | sum = 0; | ||
460 | if (len > ec_msg->insize) { | ||
461 | dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", | ||
462 | len, ec_msg->insize); | ||
463 | ret = -EMSGSIZE; | ||
464 | goto exit; | ||
465 | } | ||
466 | |||
467 | for (i = 0; i < sizeof(*response); i++) | ||
468 | sum += ptr[i]; | ||
469 | |||
470 | /* copy response packet payload and compute checksum */ | ||
471 | memcpy(ec_msg->data, ptr + sizeof(*response), len); | ||
472 | for (i = 0; i < len; i++) | ||
473 | sum += ec_msg->data[i]; | ||
474 | |||
475 | if (sum) { | ||
476 | dev_err(ec_dev->dev, | ||
477 | "bad packet checksum, calculated %x\n", | ||
478 | sum); | ||
479 | ret = -EBADMSG; | ||
480 | goto exit; | ||
481 | } | ||
482 | |||
483 | ret = len; | ||
484 | exit: | ||
485 | kfree(rx_buf); | ||
486 | if (ec_msg->command == EC_CMD_REBOOT_EC) | ||
487 | msleep(EC_REBOOT_DELAY_MS); | ||
488 | |||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | /** | ||
217 | * cros_ec_cmd_xfer_spi - Transfer a message over SPI and receive the reply | 493 | * cros_ec_cmd_xfer_spi - Transfer a message over SPI and receive the reply |
218 | * | 494 | * |
219 | * @ec_dev: ChromeOS EC device | 495 | * @ec_dev: ChromeOS EC device |
@@ -227,6 +503,7 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, | |||
227 | struct spi_message msg; | 503 | struct spi_message msg; |
228 | int i, len; | 504 | int i, len; |
229 | u8 *ptr; | 505 | u8 *ptr; |
506 | u8 *rx_buf; | ||
230 | int sum; | 507 | int sum; |
231 | int ret = 0, final_ret; | 508 | int ret = 0, final_ret; |
232 | 509 | ||
@@ -242,10 +519,17 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, | |||
242 | ndelay(EC_SPI_RECOVERY_TIME_NS - delay); | 519 | ndelay(EC_SPI_RECOVERY_TIME_NS - delay); |
243 | } | 520 | } |
244 | 521 | ||
522 | rx_buf = kzalloc(len, GFP_KERNEL); | ||
523 | if (!rx_buf) { | ||
524 | ret = -ENOMEM; | ||
525 | goto exit; | ||
526 | } | ||
527 | |||
245 | /* Transmit phase - send our message */ | 528 | /* Transmit phase - send our message */ |
246 | debug_packet(ec_dev->dev, "out", ec_dev->dout, len); | 529 | debug_packet(ec_dev->dev, "out", ec_dev->dout, len); |
247 | memset(&trans, 0, sizeof(trans)); | 530 | memset(&trans, 0, sizeof(trans)); |
248 | trans.tx_buf = ec_dev->dout; | 531 | trans.tx_buf = ec_dev->dout; |
532 | trans.rx_buf = rx_buf; | ||
249 | trans.len = len; | 533 | trans.len = len; |
250 | trans.cs_change = 1; | 534 | trans.cs_change = 1; |
251 | spi_message_init(&msg); | 535 | spi_message_init(&msg); |
@@ -254,29 +538,32 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, | |||
254 | 538 | ||
255 | /* Get the response */ | 539 | /* Get the response */ |
256 | if (!ret) { | 540 | if (!ret) { |
257 | ret = cros_ec_spi_receive_response(ec_dev, | 541 | /* Verify that EC can process command */ |
258 | ec_msg->insize + EC_MSG_TX_PROTO_BYTES); | 542 | for (i = 0; i < len; i++) { |
543 | switch (rx_buf[i]) { | ||
544 | case EC_SPI_PAST_END: | ||
545 | case EC_SPI_RX_BAD_DATA: | ||
546 | case EC_SPI_NOT_READY: | ||
547 | ret = -EAGAIN; | ||
548 | ec_msg->result = EC_RES_IN_PROGRESS; | ||
549 | default: | ||
550 | break; | ||
551 | } | ||
552 | if (ret) | ||
553 | break; | ||
554 | } | ||
555 | if (!ret) | ||
556 | ret = cros_ec_spi_receive_response(ec_dev, | ||
557 | ec_msg->insize + EC_MSG_TX_PROTO_BYTES); | ||
259 | } else { | 558 | } else { |
260 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | 559 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); |
261 | } | 560 | } |
262 | 561 | ||
263 | /* | 562 | final_ret = terminate_request(ec_dev); |
264 | * Turn off CS, possibly adding a delay to ensure the rising edge | ||
265 | * doesn't come too soon after the end of the data. | ||
266 | */ | ||
267 | spi_message_init(&msg); | ||
268 | memset(&trans, 0, sizeof(trans)); | ||
269 | trans.delay_usecs = ec_spi->end_of_msg_delay; | ||
270 | spi_message_add_tail(&trans, &msg); | ||
271 | |||
272 | final_ret = spi_sync(ec_spi->spi, &msg); | ||
273 | ec_spi->last_transfer_ns = ktime_get_ns(); | ||
274 | if (!ret) | 563 | if (!ret) |
275 | ret = final_ret; | 564 | ret = final_ret; |
276 | if (ret < 0) { | 565 | if (ret < 0) |
277 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
278 | goto exit; | 566 | goto exit; |
279 | } | ||
280 | 567 | ||
281 | ptr = ec_dev->din; | 568 | ptr = ec_dev->din; |
282 | 569 | ||
@@ -299,7 +586,7 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, | |||
299 | for (i = 0; i < len; i++) { | 586 | for (i = 0; i < len; i++) { |
300 | sum += ptr[i + 2]; | 587 | sum += ptr[i + 2]; |
301 | if (ec_msg->insize) | 588 | if (ec_msg->insize) |
302 | ec_msg->indata[i] = ptr[i + 2]; | 589 | ec_msg->data[i] = ptr[i + 2]; |
303 | } | 590 | } |
304 | sum &= 0xff; | 591 | sum &= 0xff; |
305 | 592 | ||
@@ -315,6 +602,7 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, | |||
315 | 602 | ||
316 | ret = len; | 603 | ret = len; |
317 | exit: | 604 | exit: |
605 | kfree(rx_buf); | ||
318 | if (ec_msg->command == EC_CMD_REBOOT_EC) | 606 | if (ec_msg->command == EC_CMD_REBOOT_EC) |
319 | msleep(EC_REBOOT_DELAY_MS); | 607 | msleep(EC_REBOOT_DELAY_MS); |
320 | 608 | ||
@@ -327,6 +615,10 @@ static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev) | |||
327 | u32 val; | 615 | u32 val; |
328 | int ret; | 616 | int ret; |
329 | 617 | ||
618 | ret = of_property_read_u32(np, "google,cros-ec-spi-pre-delay", &val); | ||
619 | if (!ret) | ||
620 | ec_spi->start_of_msg_delay = val; | ||
621 | |||
330 | ret = of_property_read_u32(np, "google,cros-ec-spi-msg-delay", &val); | 622 | ret = of_property_read_u32(np, "google,cros-ec-spi-msg-delay", &val); |
331 | if (!ret) | 623 | if (!ret) |
332 | ec_spi->end_of_msg_delay = val; | 624 | ec_spi->end_of_msg_delay = val; |
@@ -361,11 +653,13 @@ static int cros_ec_spi_probe(struct spi_device *spi) | |||
361 | ec_dev->priv = ec_spi; | 653 | ec_dev->priv = ec_spi; |
362 | ec_dev->irq = spi->irq; | 654 | ec_dev->irq = spi->irq; |
363 | ec_dev->cmd_xfer = cros_ec_cmd_xfer_spi; | 655 | ec_dev->cmd_xfer = cros_ec_cmd_xfer_spi; |
364 | ec_dev->ec_name = ec_spi->spi->modalias; | 656 | ec_dev->pkt_xfer = cros_ec_pkt_xfer_spi; |
365 | ec_dev->phys_name = dev_name(&ec_spi->spi->dev); | 657 | ec_dev->phys_name = dev_name(&ec_spi->spi->dev); |
366 | ec_dev->parent = &ec_spi->spi->dev; | 658 | ec_dev->din_size = EC_MSG_PREAMBLE_COUNT + |
367 | ec_dev->din_size = EC_MSG_BYTES + EC_MSG_PREAMBLE_COUNT; | 659 | sizeof(struct ec_host_response) + |
368 | ec_dev->dout_size = EC_MSG_BYTES; | 660 | sizeof(struct ec_response_get_protocol_info); |
661 | ec_dev->dout_size = sizeof(struct ec_host_request); | ||
662 | |||
369 | 663 | ||
370 | err = cros_ec_register(ec_dev); | 664 | err = cros_ec_register(ec_dev); |
371 | if (err) { | 665 | if (err) { |
diff --git a/drivers/mfd/da9052-irq.c b/drivers/mfd/da9052-irq.c index e65ca194fa98..f4cb4613140b 100644 --- a/drivers/mfd/da9052-irq.c +++ b/drivers/mfd/da9052-irq.c | |||
@@ -35,7 +35,7 @@ | |||
35 | #define DA9052_IRQ_MASK_POS_7 0x40 | 35 | #define DA9052_IRQ_MASK_POS_7 0x40 |
36 | #define DA9052_IRQ_MASK_POS_8 0x80 | 36 | #define DA9052_IRQ_MASK_POS_8 0x80 |
37 | 37 | ||
38 | static struct regmap_irq da9052_irqs[] = { | 38 | static const struct regmap_irq da9052_irqs[] = { |
39 | [DA9052_IRQ_DCIN] = { | 39 | [DA9052_IRQ_DCIN] = { |
40 | .reg_offset = 0, | 40 | .reg_offset = 0, |
41 | .mask = DA9052_IRQ_MASK_POS_1, | 41 | .mask = DA9052_IRQ_MASK_POS_1, |
@@ -166,7 +166,7 @@ static struct regmap_irq da9052_irqs[] = { | |||
166 | }, | 166 | }, |
167 | }; | 167 | }; |
168 | 168 | ||
169 | static struct regmap_irq_chip da9052_regmap_irq_chip = { | 169 | static const struct regmap_irq_chip da9052_regmap_irq_chip = { |
170 | .name = "da9052_irq", | 170 | .name = "da9052_irq", |
171 | .status_base = DA9052_EVENT_A_REG, | 171 | .status_base = DA9052_EVENT_A_REG, |
172 | .mask_base = DA9052_IRQ_MASK_A_REG, | 172 | .mask_base = DA9052_IRQ_MASK_A_REG, |
diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index b4d920c1ead1..177e65a12c12 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c | |||
@@ -222,7 +222,7 @@ static bool da9055_register_volatile(struct device *dev, unsigned int reg) | |||
222 | } | 222 | } |
223 | } | 223 | } |
224 | 224 | ||
225 | static struct regmap_irq da9055_irqs[] = { | 225 | static const struct regmap_irq da9055_irqs[] = { |
226 | [DA9055_IRQ_NONKEY] = { | 226 | [DA9055_IRQ_NONKEY] = { |
227 | .reg_offset = 0, | 227 | .reg_offset = 0, |
228 | .mask = DA9055_IRQ_NONKEY_MASK, | 228 | .mask = DA9055_IRQ_NONKEY_MASK, |
@@ -245,7 +245,7 @@ static struct regmap_irq da9055_irqs[] = { | |||
245 | }, | 245 | }, |
246 | }; | 246 | }; |
247 | 247 | ||
248 | struct regmap_config da9055_regmap_config = { | 248 | const struct regmap_config da9055_regmap_config = { |
249 | .reg_bits = 8, | 249 | .reg_bits = 8, |
250 | .val_bits = 8, | 250 | .val_bits = 8, |
251 | 251 | ||
@@ -367,7 +367,7 @@ static const struct mfd_cell da9055_devs[] = { | |||
367 | }, | 367 | }, |
368 | }; | 368 | }; |
369 | 369 | ||
370 | static struct regmap_irq_chip da9055_regmap_irq_chip = { | 370 | static const struct regmap_irq_chip da9055_regmap_irq_chip = { |
371 | .name = "da9055_irq", | 371 | .name = "da9055_irq", |
372 | .status_base = DA9055_REG_EVENT_A, | 372 | .status_base = DA9055_REG_EVENT_A, |
373 | .mask_base = DA9055_REG_IRQ_MASK_A, | 373 | .mask_base = DA9055_REG_IRQ_MASK_A, |
diff --git a/drivers/mfd/da9063-core.c b/drivers/mfd/da9063-core.c index facd3610ac77..af841c165787 100644 --- a/drivers/mfd/da9063-core.c +++ b/drivers/mfd/da9063-core.c | |||
@@ -60,6 +60,7 @@ static struct resource da9063_rtc_resources[] = { | |||
60 | 60 | ||
61 | static struct resource da9063_onkey_resources[] = { | 61 | static struct resource da9063_onkey_resources[] = { |
62 | { | 62 | { |
63 | .name = "ONKEY", | ||
63 | .start = DA9063_IRQ_ONKEY, | 64 | .start = DA9063_IRQ_ONKEY, |
64 | .end = DA9063_IRQ_ONKEY, | 65 | .end = DA9063_IRQ_ONKEY, |
65 | .flags = IORESOURCE_IRQ, | 66 | .flags = IORESOURCE_IRQ, |
@@ -97,6 +98,7 @@ static const struct mfd_cell da9063_devs[] = { | |||
97 | .name = DA9063_DRVNAME_ONKEY, | 98 | .name = DA9063_DRVNAME_ONKEY, |
98 | .num_resources = ARRAY_SIZE(da9063_onkey_resources), | 99 | .num_resources = ARRAY_SIZE(da9063_onkey_resources), |
99 | .resources = da9063_onkey_resources, | 100 | .resources = da9063_onkey_resources, |
101 | .of_compatible = "dlg,da9063-onkey", | ||
100 | }, | 102 | }, |
101 | { | 103 | { |
102 | .name = DA9063_DRVNAME_RTC, | 104 | .name = DA9063_DRVNAME_RTC, |
@@ -109,12 +111,64 @@ static const struct mfd_cell da9063_devs[] = { | |||
109 | }, | 111 | }, |
110 | }; | 112 | }; |
111 | 113 | ||
114 | static int da9063_clear_fault_log(struct da9063 *da9063) | ||
115 | { | ||
116 | int ret = 0; | ||
117 | int fault_log = 0; | ||
118 | |||
119 | ret = regmap_read(da9063->regmap, DA9063_REG_FAULT_LOG, &fault_log); | ||
120 | if (ret < 0) { | ||
121 | dev_err(da9063->dev, "Cannot read FAULT_LOG.\n"); | ||
122 | return -EIO; | ||
123 | } | ||
124 | |||
125 | if (fault_log) { | ||
126 | if (fault_log & DA9063_TWD_ERROR) | ||
127 | dev_dbg(da9063->dev, | ||
128 | "Fault log entry detected: DA9063_TWD_ERROR\n"); | ||
129 | if (fault_log & DA9063_POR) | ||
130 | dev_dbg(da9063->dev, | ||
131 | "Fault log entry detected: DA9063_POR\n"); | ||
132 | if (fault_log & DA9063_VDD_FAULT) | ||
133 | dev_dbg(da9063->dev, | ||
134 | "Fault log entry detected: DA9063_VDD_FAULT\n"); | ||
135 | if (fault_log & DA9063_VDD_START) | ||
136 | dev_dbg(da9063->dev, | ||
137 | "Fault log entry detected: DA9063_VDD_START\n"); | ||
138 | if (fault_log & DA9063_TEMP_CRIT) | ||
139 | dev_dbg(da9063->dev, | ||
140 | "Fault log entry detected: DA9063_TEMP_CRIT\n"); | ||
141 | if (fault_log & DA9063_KEY_RESET) | ||
142 | dev_dbg(da9063->dev, | ||
143 | "Fault log entry detected: DA9063_KEY_RESET\n"); | ||
144 | if (fault_log & DA9063_NSHUTDOWN) | ||
145 | dev_dbg(da9063->dev, | ||
146 | "Fault log entry detected: DA9063_NSHUTDOWN\n"); | ||
147 | if (fault_log & DA9063_WAIT_SHUT) | ||
148 | dev_dbg(da9063->dev, | ||
149 | "Fault log entry detected: DA9063_WAIT_SHUT\n"); | ||
150 | } | ||
151 | |||
152 | ret = regmap_write(da9063->regmap, | ||
153 | DA9063_REG_FAULT_LOG, | ||
154 | fault_log); | ||
155 | if (ret < 0) | ||
156 | dev_err(da9063->dev, | ||
157 | "Cannot reset FAULT_LOG values %d\n", ret); | ||
158 | |||
159 | return ret; | ||
160 | } | ||
161 | |||
112 | int da9063_device_init(struct da9063 *da9063, unsigned int irq) | 162 | int da9063_device_init(struct da9063 *da9063, unsigned int irq) |
113 | { | 163 | { |
114 | struct da9063_pdata *pdata = da9063->dev->platform_data; | 164 | struct da9063_pdata *pdata = da9063->dev->platform_data; |
115 | int model, variant_id, variant_code; | 165 | int model, variant_id, variant_code; |
116 | int ret; | 166 | int ret; |
117 | 167 | ||
168 | ret = da9063_clear_fault_log(da9063); | ||
169 | if (ret < 0) | ||
170 | dev_err(da9063->dev, "Cannot clear fault log\n"); | ||
171 | |||
118 | if (pdata) { | 172 | if (pdata) { |
119 | da9063->flags = pdata->flags; | 173 | da9063->flags = pdata->flags; |
120 | da9063->irq_base = pdata->irq_base; | 174 | da9063->irq_base = pdata->irq_base; |
diff --git a/drivers/mfd/da9063-irq.c b/drivers/mfd/da9063-irq.c index 822922602ce9..eaf1ec9208b2 100644 --- a/drivers/mfd/da9063-irq.c +++ b/drivers/mfd/da9063-irq.c | |||
@@ -34,7 +34,7 @@ struct da9063_irq_data { | |||
34 | u8 mask; | 34 | u8 mask; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | static struct regmap_irq da9063_irqs[] = { | 37 | static const struct regmap_irq da9063_irqs[] = { |
38 | /* DA9063 event A register */ | 38 | /* DA9063 event A register */ |
39 | [DA9063_IRQ_ONKEY] = { | 39 | [DA9063_IRQ_ONKEY] = { |
40 | .reg_offset = DA9063_REG_EVENT_A_OFFSET, | 40 | .reg_offset = DA9063_REG_EVENT_A_OFFSET, |
@@ -153,7 +153,7 @@ static struct regmap_irq da9063_irqs[] = { | |||
153 | }, | 153 | }, |
154 | }; | 154 | }; |
155 | 155 | ||
156 | static struct regmap_irq_chip da9063_irq_chip = { | 156 | static const struct regmap_irq_chip da9063_irq_chip = { |
157 | .name = "da9063-irq", | 157 | .name = "da9063-irq", |
158 | .irqs = da9063_irqs, | 158 | .irqs = da9063_irqs, |
159 | .num_irqs = DA9063_NUM_IRQ, | 159 | .num_irqs = DA9063_NUM_IRQ, |
diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c index 5549817df32e..94b9bbd1a69b 100644 --- a/drivers/mfd/da9150-core.c +++ b/drivers/mfd/da9150-core.c | |||
@@ -164,7 +164,7 @@ void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf) | |||
164 | } | 164 | } |
165 | EXPORT_SYMBOL_GPL(da9150_bulk_write); | 165 | EXPORT_SYMBOL_GPL(da9150_bulk_write); |
166 | 166 | ||
167 | static struct regmap_irq da9150_irqs[] = { | 167 | static const struct regmap_irq da9150_irqs[] = { |
168 | [DA9150_IRQ_VBUS] = { | 168 | [DA9150_IRQ_VBUS] = { |
169 | .reg_offset = 0, | 169 | .reg_offset = 0, |
170 | .mask = DA9150_E_VBUS_MASK, | 170 | .mask = DA9150_E_VBUS_MASK, |
@@ -251,7 +251,7 @@ static struct regmap_irq da9150_irqs[] = { | |||
251 | }, | 251 | }, |
252 | }; | 252 | }; |
253 | 253 | ||
254 | static struct regmap_irq_chip da9150_regmap_irq_chip = { | 254 | static const struct regmap_irq_chip da9150_regmap_irq_chip = { |
255 | .name = "da9150_irq", | 255 | .name = "da9150_irq", |
256 | .status_base = DA9150_EVENT_E, | 256 | .status_base = DA9150_EVENT_E, |
257 | .mask_base = DA9150_IRQ_MASK_E, | 257 | .mask_base = DA9150_IRQ_MASK_E, |
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index cc1a404328c2..8b14740f9fca 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c | |||
@@ -2659,7 +2659,7 @@ static int db8500_irq_map(struct irq_domain *d, unsigned int virq, | |||
2659 | return 0; | 2659 | return 0; |
2660 | } | 2660 | } |
2661 | 2661 | ||
2662 | static struct irq_domain_ops db8500_irq_ops = { | 2662 | static const struct irq_domain_ops db8500_irq_ops = { |
2663 | .map = db8500_irq_map, | 2663 | .map = db8500_irq_map, |
2664 | .xlate = irq_domain_xlate_twocell, | 2664 | .xlate = irq_domain_xlate_twocell, |
2665 | }; | 2665 | }; |
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index ebb9cf19e347..b54baad30164 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c | |||
@@ -564,7 +564,8 @@ static int htcpld_core_probe(struct platform_device *pdev) | |||
564 | htcpld->chained_irq = res->start; | 564 | htcpld->chained_irq = res->start; |
565 | 565 | ||
566 | /* Setup the chained interrupt handler */ | 566 | /* Setup the chained interrupt handler */ |
567 | flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING; | 567 | flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | |
568 | IRQF_ONESHOT; | ||
568 | ret = request_threaded_irq(htcpld->chained_irq, | 569 | ret = request_threaded_irq(htcpld->chained_irq, |
569 | NULL, htcpld_handler, | 570 | NULL, htcpld_handler, |
570 | flags, pdev->name, htcpld); | 571 | flags, pdev->name, htcpld); |
diff --git a/drivers/mfd/intel_soc_pmic_core.h b/drivers/mfd/intel_soc_pmic_core.h index 9498d6719847..ff2464bc172f 100644 --- a/drivers/mfd/intel_soc_pmic_core.h +++ b/drivers/mfd/intel_soc_pmic_core.h | |||
@@ -24,7 +24,7 @@ struct intel_soc_pmic_config { | |||
24 | struct mfd_cell *cell_dev; | 24 | struct mfd_cell *cell_dev; |
25 | int n_cell_devs; | 25 | int n_cell_devs; |
26 | const struct regmap_config *regmap_config; | 26 | const struct regmap_config *regmap_config; |
27 | struct regmap_irq_chip *irq_chip; | 27 | const struct regmap_irq_chip *irq_chip; |
28 | }; | 28 | }; |
29 | 29 | ||
30 | extern struct intel_soc_pmic_config intel_soc_pmic_config_crc; | 30 | extern struct intel_soc_pmic_config intel_soc_pmic_config_crc; |
diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 4cc1b324e971..7436075e8983 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c | |||
@@ -143,7 +143,7 @@ static const struct regmap_irq crystal_cove_irqs[] = { | |||
143 | }, | 143 | }, |
144 | }; | 144 | }; |
145 | 145 | ||
146 | static struct regmap_irq_chip crystal_cove_irq_chip = { | 146 | static const struct regmap_irq_chip crystal_cove_irq_chip = { |
147 | .name = "Crystal Cove", | 147 | .name = "Crystal Cove", |
148 | .irqs = crystal_cove_irqs, | 148 | .irqs = crystal_cove_irqs, |
149 | .num_irqs = ARRAY_SIZE(crystal_cove_irqs), | 149 | .num_irqs = ARRAY_SIZE(crystal_cove_irqs), |
diff --git a/drivers/mfd/lp8788-irq.c b/drivers/mfd/lp8788-irq.c index 23982dbf014d..a87f2b548f71 100644 --- a/drivers/mfd/lp8788-irq.c +++ b/drivers/mfd/lp8788-irq.c | |||
@@ -151,7 +151,7 @@ static int lp8788_irq_map(struct irq_domain *d, unsigned int virq, | |||
151 | return 0; | 151 | return 0; |
152 | } | 152 | } |
153 | 153 | ||
154 | static struct irq_domain_ops lp8788_domain_ops = { | 154 | static const struct irq_domain_ops lp8788_domain_ops = { |
155 | .map = lp8788_irq_map, | 155 | .map = lp8788_irq_map, |
156 | }; | 156 | }; |
157 | 157 | ||
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 12d960a60ec4..8de34398abc0 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c | |||
@@ -934,8 +934,8 @@ gpe0_done: | |||
934 | lpc_ich_enable_gpio_space(dev); | 934 | lpc_ich_enable_gpio_space(dev); |
935 | 935 | ||
936 | lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_GPIO]); | 936 | lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_GPIO]); |
937 | ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO], | 937 | ret = mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO, |
938 | 1, NULL, 0, NULL); | 938 | &lpc_ich_cells[LPC_GPIO], 1, NULL, 0, NULL); |
939 | 939 | ||
940 | gpio_done: | 940 | gpio_done: |
941 | if (acpi_conflict) | 941 | if (acpi_conflict) |
@@ -1008,8 +1008,8 @@ static int lpc_ich_init_wdt(struct pci_dev *dev) | |||
1008 | } | 1008 | } |
1009 | 1009 | ||
1010 | lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]); | 1010 | lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]); |
1011 | ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT], | 1011 | ret = mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO, |
1012 | 1, NULL, 0, NULL); | 1012 | &lpc_ich_cells[LPC_WDT], 1, NULL, 0, NULL); |
1013 | 1013 | ||
1014 | wdt_done: | 1014 | wdt_done: |
1015 | return ret; | 1015 | return ret; |
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 97a787ab3d51..8520bd68c1ff 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c | |||
@@ -658,7 +658,7 @@ static int max8925_irq_domain_map(struct irq_domain *d, unsigned int virq, | |||
658 | return 0; | 658 | return 0; |
659 | } | 659 | } |
660 | 660 | ||
661 | static struct irq_domain_ops max8925_irq_domain_ops = { | 661 | static const struct irq_domain_ops max8925_irq_domain_ops = { |
662 | .map = max8925_irq_domain_map, | 662 | .map = max8925_irq_domain_map, |
663 | .xlate = irq_domain_xlate_onetwocell, | 663 | .xlate = irq_domain_xlate_onetwocell, |
664 | }; | 664 | }; |
diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c index 43fa61413e93..d3025be57f39 100644 --- a/drivers/mfd/max8997-irq.c +++ b/drivers/mfd/max8997-irq.c | |||
@@ -303,7 +303,7 @@ static int max8997_irq_domain_map(struct irq_domain *d, unsigned int irq, | |||
303 | return 0; | 303 | return 0; |
304 | } | 304 | } |
305 | 305 | ||
306 | static struct irq_domain_ops max8997_irq_domain_ops = { | 306 | static const struct irq_domain_ops max8997_irq_domain_ops = { |
307 | .map = max8997_irq_domain_map, | 307 | .map = max8997_irq_domain_map, |
308 | }; | 308 | }; |
309 | 309 | ||
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c index c469477eb778..3702056628a8 100644 --- a/drivers/mfd/max8998-irq.c +++ b/drivers/mfd/max8998-irq.c | |||
@@ -214,7 +214,7 @@ static int max8998_irq_domain_map(struct irq_domain *d, unsigned int irq, | |||
214 | return 0; | 214 | return 0; |
215 | } | 215 | } |
216 | 216 | ||
217 | static struct irq_domain_ops max8998_irq_domain_ops = { | 217 | static const struct irq_domain_ops max8998_irq_domain_ops = { |
218 | .map = max8998_irq_domain_map, | 218 | .map = max8998_irq_domain_map, |
219 | }; | 219 | }; |
220 | 220 | ||
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 25fd7116493a..3f9f4c874d2a 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c | |||
@@ -163,7 +163,7 @@ int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq, | |||
163 | int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq); | 163 | int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq); |
164 | 164 | ||
165 | return devm_request_threaded_irq(mc13xxx->dev, virq, NULL, handler, | 165 | return devm_request_threaded_irq(mc13xxx->dev, virq, NULL, handler, |
166 | 0, name, dev); | 166 | IRQF_ONESHOT, name, dev); |
167 | } | 167 | } |
168 | EXPORT_SYMBOL(mc13xxx_irq_request); | 168 | EXPORT_SYMBOL(mc13xxx_irq_request); |
169 | 169 | ||
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 1aed3b7b8d9b..14fd5cbcf0f2 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -207,9 +207,11 @@ static int mfd_add_device(struct device *parent, int id, | |||
207 | } | 207 | } |
208 | 208 | ||
209 | if (!cell->ignore_resource_conflicts) { | 209 | if (!cell->ignore_resource_conflicts) { |
210 | ret = acpi_check_resource_conflict(&res[r]); | 210 | if (has_acpi_companion(&pdev->dev)) { |
211 | if (ret) | 211 | ret = acpi_check_resource_conflict(&res[r]); |
212 | goto fail_alias; | 212 | if (ret) |
213 | goto fail_alias; | ||
214 | } | ||
213 | } | 215 | } |
214 | } | 216 | } |
215 | 217 | ||
diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index 09bc7804952a..38a0458f7834 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c | |||
@@ -34,6 +34,9 @@ static const struct mfd_cell mt6397_devs[] = { | |||
34 | }, { | 34 | }, { |
35 | .name = "mt6397-clk", | 35 | .name = "mt6397-clk", |
36 | .of_compatible = "mediatek,mt6397-clk", | 36 | .of_compatible = "mediatek,mt6397-clk", |
37 | }, { | ||
38 | .name = "mt6397-pinctrl", | ||
39 | .of_compatible = "mediatek,mt6397-pinctrl", | ||
37 | }, | 40 | }, |
38 | }; | 41 | }; |
39 | 42 | ||
@@ -130,7 +133,7 @@ static int mt6397_irq_domain_map(struct irq_domain *d, unsigned int irq, | |||
130 | return 0; | 133 | return 0; |
131 | } | 134 | } |
132 | 135 | ||
133 | static struct irq_domain_ops mt6397_irq_domain_ops = { | 136 | static const struct irq_domain_ops mt6397_irq_domain_ops = { |
134 | .map = mt6397_irq_domain_map, | 137 | .map = mt6397_irq_domain_map, |
135 | }; | 138 | }; |
136 | 139 | ||
diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c index 7f87c62d91b3..e3deb466628b 100644 --- a/drivers/mfd/si476x-i2c.c +++ b/drivers/mfd/si476x-i2c.c | |||
@@ -777,7 +777,8 @@ static int si476x_core_probe(struct i2c_client *client, | |||
777 | rval = devm_request_threaded_irq(&client->dev, | 777 | rval = devm_request_threaded_irq(&client->dev, |
778 | client->irq, NULL, | 778 | client->irq, NULL, |
779 | si476x_core_interrupt, | 779 | si476x_core_interrupt, |
780 | IRQF_TRIGGER_FALLING, | 780 | IRQF_TRIGGER_FALLING | |
781 | IRQF_ONESHOT, | ||
781 | client->name, core); | 782 | client->name, core); |
782 | if (rval < 0) { | 783 | if (rval < 0) { |
783 | dev_err(&client->dev, "Could not request IRQ %d\n", | 784 | dev_err(&client->dev, "Could not request IRQ %d\n", |
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 2d7fae94c861..18c4d72d1d2a 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c | |||
@@ -989,7 +989,7 @@ static void stmpe_irq_unmap(struct irq_domain *d, unsigned int virq) | |||
989 | irq_set_chip_data(virq, NULL); | 989 | irq_set_chip_data(virq, NULL); |
990 | } | 990 | } |
991 | 991 | ||
992 | static struct irq_domain_ops stmpe_irq_ops = { | 992 | static const struct irq_domain_ops stmpe_irq_ops = { |
993 | .map = stmpe_irq_map, | 993 | .map = stmpe_irq_map, |
994 | .unmap = stmpe_irq_unmap, | 994 | .unmap = stmpe_irq_unmap, |
995 | .xlate = irq_domain_xlate_twocell, | 995 | .xlate = irq_domain_xlate_twocell, |
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index cf356395c9e9..96d420dfc15d 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c | |||
@@ -233,7 +233,7 @@ static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq) | |||
233 | irq_set_chip_data(virq, NULL); | 233 | irq_set_chip_data(virq, NULL); |
234 | } | 234 | } |
235 | 235 | ||
236 | static struct irq_domain_ops tc3589x_irq_ops = { | 236 | static const struct irq_domain_ops tc3589x_irq_ops = { |
237 | .map = tc3589x_irq_map, | 237 | .map = tc3589x_irq_map, |
238 | .unmap = tc3589x_irq_unmap, | 238 | .unmap = tc3589x_irq_unmap, |
239 | .xlate = irq_domain_xlate_onecell, | 239 | .xlate = irq_domain_xlate_onecell, |
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 8e1dbc469580..e0a2583916ce 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c | |||
@@ -311,7 +311,7 @@ static int tps6586x_irq_map(struct irq_domain *h, unsigned int virq, | |||
311 | return 0; | 311 | return 0; |
312 | } | 312 | } |
313 | 313 | ||
314 | static struct irq_domain_ops tps6586x_domain_ops = { | 314 | static const struct irq_domain_ops tps6586x_domain_ops = { |
315 | .map = tps6586x_irq_map, | 315 | .map = tps6586x_irq_map, |
316 | .xlate = irq_domain_xlate_twocell, | 316 | .xlate = irq_domain_xlate_twocell, |
317 | }; | 317 | }; |
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 1b772ef761cb..a3fa7f4f1fb4 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c | |||
@@ -674,7 +674,7 @@ int twl4030_sih_setup(struct device *dev, int module, int irq_base) | |||
674 | irq_set_handler_data(irq, agent); | 674 | irq_set_handler_data(irq, agent); |
675 | agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name); | 675 | agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name); |
676 | status = request_threaded_irq(irq, NULL, handle_twl4030_sih, | 676 | status = request_threaded_irq(irq, NULL, handle_twl4030_sih, |
677 | IRQF_EARLY_RESUME, | 677 | IRQF_EARLY_RESUME | IRQF_ONESHOT, |
678 | agent->irq_name ?: sih->name, NULL); | 678 | agent->irq_name ?: sih->name, NULL); |
679 | 679 | ||
680 | dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name, | 680 | dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name, |
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index f440aed61305..04b539850e72 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c | |||
@@ -264,7 +264,9 @@ out: | |||
264 | return err; | 264 | return err; |
265 | } | 265 | } |
266 | 266 | ||
267 | static int twl4030_config_wakeup12_sequence(u8 address) | 267 | static int |
268 | twl4030_config_wakeup12_sequence(const struct twl4030_power_data *pdata, | ||
269 | u8 address) | ||
268 | { | 270 | { |
269 | int err = 0; | 271 | int err = 0; |
270 | u8 data; | 272 | u8 data; |
@@ -293,13 +295,14 @@ static int twl4030_config_wakeup12_sequence(u8 address) | |||
293 | if (err) | 295 | if (err) |
294 | goto out; | 296 | goto out; |
295 | 297 | ||
296 | if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) { | 298 | if (pdata->ac_charger_quirk || machine_is_omap_3430sdp() || |
299 | machine_is_omap_ldp()) { | ||
297 | /* Disabling AC charger effect on sleep-active transitions */ | 300 | /* Disabling AC charger effect on sleep-active transitions */ |
298 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, | 301 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, |
299 | R_CFG_P1_TRANSITION); | 302 | R_CFG_P1_TRANSITION); |
300 | if (err) | 303 | if (err) |
301 | goto out; | 304 | goto out; |
302 | data &= ~(1<<1); | 305 | data &= ~STARTON_CHG; |
303 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, | 306 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, |
304 | R_CFG_P1_TRANSITION); | 307 | R_CFG_P1_TRANSITION); |
305 | if (err) | 308 | if (err) |
@@ -459,8 +462,9 @@ static int twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
459 | return 0; | 462 | return 0; |
460 | } | 463 | } |
461 | 464 | ||
462 | static int load_twl4030_script(struct twl4030_script *tscript, | 465 | static int load_twl4030_script(const struct twl4030_power_data *pdata, |
463 | u8 address) | 466 | struct twl4030_script *tscript, |
467 | u8 address) | ||
464 | { | 468 | { |
465 | int err; | 469 | int err; |
466 | static int order; | 470 | static int order; |
@@ -487,7 +491,7 @@ static int load_twl4030_script(struct twl4030_script *tscript, | |||
487 | if (err) | 491 | if (err) |
488 | goto out; | 492 | goto out; |
489 | 493 | ||
490 | err = twl4030_config_wakeup12_sequence(address); | 494 | err = twl4030_config_wakeup12_sequence(pdata, address); |
491 | if (err) | 495 | if (err) |
492 | goto out; | 496 | goto out; |
493 | order = 1; | 497 | order = 1; |
@@ -567,7 +571,7 @@ twl4030_power_configure_scripts(const struct twl4030_power_data *pdata) | |||
567 | u8 address = twl4030_start_script_address; | 571 | u8 address = twl4030_start_script_address; |
568 | 572 | ||
569 | for (i = 0; i < pdata->num; i++) { | 573 | for (i = 0; i < pdata->num; i++) { |
570 | err = load_twl4030_script(pdata->scripts[i], address); | 574 | err = load_twl4030_script(pdata, pdata->scripts[i], address); |
571 | if (err) | 575 | if (err) |
572 | return err; | 576 | return err; |
573 | address += pdata->scripts[i]->size; | 577 | address += pdata->scripts[i]->size; |
@@ -829,6 +833,21 @@ static struct twl4030_power_data osc_off_idle = { | |||
829 | .board_config = osc_off_rconfig, | 833 | .board_config = osc_off_rconfig, |
830 | }; | 834 | }; |
831 | 835 | ||
836 | static struct twl4030_power_data omap3_idle_ac_quirk = { | ||
837 | .scripts = omap3_idle_scripts, | ||
838 | .num = ARRAY_SIZE(omap3_idle_scripts), | ||
839 | .resource_config = omap3_idle_rconfig, | ||
840 | .ac_charger_quirk = true, | ||
841 | }; | ||
842 | |||
843 | static struct twl4030_power_data omap3_idle_ac_quirk_osc_off = { | ||
844 | .scripts = omap3_idle_scripts, | ||
845 | .num = ARRAY_SIZE(omap3_idle_scripts), | ||
846 | .resource_config = omap3_idle_rconfig, | ||
847 | .board_config = osc_off_rconfig, | ||
848 | .ac_charger_quirk = true, | ||
849 | }; | ||
850 | |||
832 | static const struct of_device_id twl4030_power_of_match[] = { | 851 | static const struct of_device_id twl4030_power_of_match[] = { |
833 | { | 852 | { |
834 | .compatible = "ti,twl4030-power", | 853 | .compatible = "ti,twl4030-power", |
@@ -845,6 +864,18 @@ static const struct of_device_id twl4030_power_of_match[] = { | |||
845 | .compatible = "ti,twl4030-power-idle-osc-off", | 864 | .compatible = "ti,twl4030-power-idle-osc-off", |
846 | .data = &osc_off_idle, | 865 | .data = &osc_off_idle, |
847 | }, | 866 | }, |
867 | { | ||
868 | .compatible = "ti,twl4030-power-omap3-sdp", | ||
869 | .data = &omap3_idle_ac_quirk, | ||
870 | }, | ||
871 | { | ||
872 | .compatible = "ti,twl4030-power-omap3-ldp", | ||
873 | .data = &omap3_idle_ac_quirk_osc_off, | ||
874 | }, | ||
875 | { | ||
876 | .compatible = "ti,twl4030-power-omap3-evm", | ||
877 | .data = &omap3_idle_ac_quirk, | ||
878 | }, | ||
848 | { }, | 879 | { }, |
849 | }; | 880 | }; |
850 | MODULE_DEVICE_TABLE(of, twl4030_power_of_match); | 881 | MODULE_DEVICE_TABLE(of, twl4030_power_of_match); |
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 2807e1a95663..20fb58179ada 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c | |||
@@ -376,7 +376,7 @@ static void twl6030_irq_unmap(struct irq_domain *d, unsigned int virq) | |||
376 | irq_set_chip_data(virq, NULL); | 376 | irq_set_chip_data(virq, NULL); |
377 | } | 377 | } |
378 | 378 | ||
379 | static struct irq_domain_ops twl6030_irq_domain_ops = { | 379 | static const struct irq_domain_ops twl6030_irq_domain_ops = { |
380 | .map = twl6030_irq_map, | 380 | .map = twl6030_irq_map, |
381 | .unmap = twl6030_irq_unmap, | 381 | .unmap = twl6030_irq_unmap, |
382 | .xlate = irq_domain_xlate_onetwocell, | 382 | .xlate = irq_domain_xlate_onetwocell, |
diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c index 6ee3018d8653..fd789d2eb0f5 100644 --- a/drivers/mfd/wm831x-auxadc.c +++ b/drivers/mfd/wm831x-auxadc.c | |||
@@ -285,7 +285,8 @@ void wm831x_auxadc_init(struct wm831x *wm831x) | |||
285 | 285 | ||
286 | ret = request_threaded_irq(wm831x_irq(wm831x, | 286 | ret = request_threaded_irq(wm831x_irq(wm831x, |
287 | WM831X_IRQ_AUXADC_DATA), | 287 | WM831X_IRQ_AUXADC_DATA), |
288 | NULL, wm831x_auxadc_irq, 0, | 288 | NULL, wm831x_auxadc_irq, |
289 | IRQF_ONESHOT, | ||
289 | "auxadc", wm831x); | 290 | "auxadc", wm831x); |
290 | if (ret < 0) { | 291 | if (ret < 0) { |
291 | dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", | 292 | dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", |
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 64e512eadf17..3da81263c764 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c | |||
@@ -564,7 +564,7 @@ static int wm831x_irq_map(struct irq_domain *h, unsigned int virq, | |||
564 | return 0; | 564 | return 0; |
565 | } | 565 | } |
566 | 566 | ||
567 | static struct irq_domain_ops wm831x_irq_domain_ops = { | 567 | static const struct irq_domain_ops wm831x_irq_domain_ops = { |
568 | .map = wm831x_irq_map, | 568 | .map = wm831x_irq_map, |
569 | .xlate = irq_domain_xlate_twocell, | 569 | .xlate = irq_domain_xlate_twocell, |
570 | }; | 570 | }; |
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index f5124a8acad8..8a07c5634aee 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c | |||
@@ -404,7 +404,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, | |||
404 | if (wm8350->irq_base) { | 404 | if (wm8350->irq_base) { |
405 | ret = request_threaded_irq(wm8350->irq_base + | 405 | ret = request_threaded_irq(wm8350->irq_base + |
406 | WM8350_IRQ_AUXADC_DATARDY, | 406 | WM8350_IRQ_AUXADC_DATARDY, |
407 | NULL, wm8350_auxadc_irq, 0, | 407 | NULL, wm8350_auxadc_irq, |
408 | IRQF_ONESHOT, | ||
408 | "auxadc", wm8350); | 409 | "auxadc", wm8350); |
409 | if (ret < 0) | 410 | if (ret < 0) |
410 | dev_warn(wm8350->dev, | 411 | dev_warn(wm8350->dev, |
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index a14407edbd89..55c380a67686 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | 30 | ||
31 | static struct regmap_irq wm8994_irqs[] = { | 31 | static const struct regmap_irq wm8994_irqs[] = { |
32 | [WM8994_IRQ_TEMP_SHUT] = { | 32 | [WM8994_IRQ_TEMP_SHUT] = { |
33 | .reg_offset = 1, | 33 | .reg_offset = 1, |
34 | .mask = WM8994_TEMP_SHUT_EINT, | 34 | .mask = WM8994_TEMP_SHUT_EINT, |
@@ -128,7 +128,7 @@ static struct regmap_irq wm8994_irqs[] = { | |||
128 | }, | 128 | }, |
129 | }; | 129 | }; |
130 | 130 | ||
131 | static struct regmap_irq_chip wm8994_irq_chip = { | 131 | static const struct regmap_irq_chip wm8994_irq_chip = { |
132 | .name = "wm8994", | 132 | .name = "wm8994", |
133 | .irqs = wm8994_irqs, | 133 | .irqs = wm8994_irqs, |
134 | .num_irqs = ARRAY_SIZE(wm8994_irqs), | 134 | .num_irqs = ARRAY_SIZE(wm8994_irqs), |
@@ -184,7 +184,7 @@ static int wm8994_edge_irq_map(struct irq_domain *h, unsigned int virq, | |||
184 | return 0; | 184 | return 0; |
185 | } | 185 | } |
186 | 186 | ||
187 | static struct irq_domain_ops wm8994_edge_irq_ops = { | 187 | static const struct irq_domain_ops wm8994_edge_irq_ops = { |
188 | .map = wm8994_edge_irq_map, | 188 | .map = wm8994_edge_irq_map, |
189 | .xlate = irq_domain_xlate_twocell, | 189 | .xlate = irq_domain_xlate_twocell, |
190 | }; | 190 | }; |
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 2a6531a5fde8..cb1329919527 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig | |||
@@ -40,7 +40,7 @@ config CHROMEOS_PSTORE | |||
40 | 40 | ||
41 | config CROS_EC_CHARDEV | 41 | config CROS_EC_CHARDEV |
42 | tristate "Chrome OS Embedded Controller userspace device interface" | 42 | tristate "Chrome OS Embedded Controller userspace device interface" |
43 | depends on MFD_CROS_EC | 43 | depends on CROS_EC_PROTO |
44 | ---help--- | 44 | ---help--- |
45 | This driver adds support to talk with the ChromeOS EC from userspace. | 45 | This driver adds support to talk with the ChromeOS EC from userspace. |
46 | 46 | ||
@@ -49,7 +49,7 @@ config CROS_EC_CHARDEV | |||
49 | 49 | ||
50 | config CROS_EC_LPC | 50 | config CROS_EC_LPC |
51 | tristate "ChromeOS Embedded Controller (LPC)" | 51 | tristate "ChromeOS Embedded Controller (LPC)" |
52 | depends on MFD_CROS_EC && (X86 || COMPILE_TEST) | 52 | depends on MFD_CROS_EC && CROS_EC_PROTO && (X86 || COMPILE_TEST) |
53 | help | 53 | help |
54 | If you say Y here, you get support for talking to the ChromeOS EC | 54 | If you say Y here, you get support for talking to the ChromeOS EC |
55 | over an LPC bus. This uses a simple byte-level protocol with a | 55 | over an LPC bus. This uses a simple byte-level protocol with a |
@@ -59,4 +59,9 @@ config CROS_EC_LPC | |||
59 | To compile this driver as a module, choose M here: the | 59 | To compile this driver as a module, choose M here: the |
60 | module will be called cros_ec_lpc. | 60 | module will be called cros_ec_lpc. |
61 | 61 | ||
62 | config CROS_EC_PROTO | ||
63 | bool | ||
64 | help | ||
65 | ChromeOS EC communication protocol helpers. | ||
66 | |||
62 | endif # CHROMEOS_PLATFORMS | 67 | endif # CHROMEOS_PLATFORMS |
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index bd8d8601e875..4a11b010f5d8 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile | |||
@@ -4,3 +4,4 @@ obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o | |||
4 | cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o cros_ec_lightbar.o | 4 | cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o cros_ec_lightbar.o |
5 | obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o | 5 | obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o |
6 | obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o | 6 | obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o |
7 | obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o | ||
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c index 6090d0b2826f..e8fcdc237029 100644 --- a/drivers/platform/chrome/cros_ec_dev.c +++ b/drivers/platform/chrome/cros_ec_dev.c | |||
@@ -20,44 +20,59 @@ | |||
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/slab.h> | ||
23 | #include <linux/uaccess.h> | 24 | #include <linux/uaccess.h> |
24 | 25 | ||
25 | #include "cros_ec_dev.h" | 26 | #include "cros_ec_dev.h" |
26 | 27 | ||
27 | /* Device variables */ | 28 | /* Device variables */ |
28 | #define CROS_MAX_DEV 128 | 29 | #define CROS_MAX_DEV 128 |
29 | static struct class *cros_class; | ||
30 | static int ec_major; | 30 | static int ec_major; |
31 | 31 | ||
32 | static const struct attribute_group *cros_ec_groups[] = { | ||
33 | &cros_ec_attr_group, | ||
34 | &cros_ec_lightbar_attr_group, | ||
35 | NULL, | ||
36 | }; | ||
37 | |||
38 | static struct class cros_class = { | ||
39 | .owner = THIS_MODULE, | ||
40 | .name = "chromeos", | ||
41 | .dev_groups = cros_ec_groups, | ||
42 | }; | ||
43 | |||
32 | /* Basic communication */ | 44 | /* Basic communication */ |
33 | static int ec_get_version(struct cros_ec_device *ec, char *str, int maxlen) | 45 | static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen) |
34 | { | 46 | { |
35 | struct ec_response_get_version *resp; | 47 | struct ec_response_get_version *resp; |
36 | static const char * const current_image_name[] = { | 48 | static const char * const current_image_name[] = { |
37 | "unknown", "read-only", "read-write", "invalid", | 49 | "unknown", "read-only", "read-write", "invalid", |
38 | }; | 50 | }; |
39 | struct cros_ec_command msg = { | 51 | struct cros_ec_command *msg; |
40 | .version = 0, | ||
41 | .command = EC_CMD_GET_VERSION, | ||
42 | .outdata = { 0 }, | ||
43 | .outsize = 0, | ||
44 | .indata = { 0 }, | ||
45 | .insize = sizeof(*resp), | ||
46 | }; | ||
47 | int ret; | 52 | int ret; |
48 | 53 | ||
49 | ret = cros_ec_cmd_xfer(ec, &msg); | 54 | msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); |
55 | if (!msg) | ||
56 | return -ENOMEM; | ||
57 | |||
58 | msg->version = 0; | ||
59 | msg->command = EC_CMD_GET_VERSION + ec->cmd_offset; | ||
60 | msg->insize = sizeof(*resp); | ||
61 | msg->outsize = 0; | ||
62 | |||
63 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); | ||
50 | if (ret < 0) | 64 | if (ret < 0) |
51 | return ret; | 65 | goto exit; |
52 | 66 | ||
53 | if (msg.result != EC_RES_SUCCESS) { | 67 | if (msg->result != EC_RES_SUCCESS) { |
54 | snprintf(str, maxlen, | 68 | snprintf(str, maxlen, |
55 | "%s\nUnknown EC version: EC returned %d\n", | 69 | "%s\nUnknown EC version: EC returned %d\n", |
56 | CROS_EC_DEV_VERSION, msg.result); | 70 | CROS_EC_DEV_VERSION, msg->result); |
57 | return 0; | 71 | ret = -EINVAL; |
72 | goto exit; | ||
58 | } | 73 | } |
59 | 74 | ||
60 | resp = (struct ec_response_get_version *)msg.indata; | 75 | resp = (struct ec_response_get_version *)msg->data; |
61 | if (resp->current_image >= ARRAY_SIZE(current_image_name)) | 76 | if (resp->current_image >= ARRAY_SIZE(current_image_name)) |
62 | resp->current_image = 3; /* invalid */ | 77 | resp->current_image = 3; /* invalid */ |
63 | 78 | ||
@@ -65,14 +80,19 @@ static int ec_get_version(struct cros_ec_device *ec, char *str, int maxlen) | |||
65 | resp->version_string_ro, resp->version_string_rw, | 80 | resp->version_string_ro, resp->version_string_rw, |
66 | current_image_name[resp->current_image]); | 81 | current_image_name[resp->current_image]); |
67 | 82 | ||
68 | return 0; | 83 | ret = 0; |
84 | exit: | ||
85 | kfree(msg); | ||
86 | return ret; | ||
69 | } | 87 | } |
70 | 88 | ||
71 | /* Device file ops */ | 89 | /* Device file ops */ |
72 | static int ec_device_open(struct inode *inode, struct file *filp) | 90 | static int ec_device_open(struct inode *inode, struct file *filp) |
73 | { | 91 | { |
74 | filp->private_data = container_of(inode->i_cdev, | 92 | struct cros_ec_dev *ec = container_of(inode->i_cdev, |
75 | struct cros_ec_device, cdev); | 93 | struct cros_ec_dev, cdev); |
94 | filp->private_data = ec; | ||
95 | nonseekable_open(inode, filp); | ||
76 | return 0; | 96 | return 0; |
77 | } | 97 | } |
78 | 98 | ||
@@ -84,7 +104,7 @@ static int ec_device_release(struct inode *inode, struct file *filp) | |||
84 | static ssize_t ec_device_read(struct file *filp, char __user *buffer, | 104 | static ssize_t ec_device_read(struct file *filp, char __user *buffer, |
85 | size_t length, loff_t *offset) | 105 | size_t length, loff_t *offset) |
86 | { | 106 | { |
87 | struct cros_ec_device *ec = filp->private_data; | 107 | struct cros_ec_dev *ec = filp->private_data; |
88 | char msg[sizeof(struct ec_response_get_version) + | 108 | char msg[sizeof(struct ec_response_get_version) + |
89 | sizeof(CROS_EC_DEV_VERSION)]; | 109 | sizeof(CROS_EC_DEV_VERSION)]; |
90 | size_t count; | 110 | size_t count; |
@@ -107,38 +127,53 @@ static ssize_t ec_device_read(struct file *filp, char __user *buffer, | |||
107 | } | 127 | } |
108 | 128 | ||
109 | /* Ioctls */ | 129 | /* Ioctls */ |
110 | static long ec_device_ioctl_xcmd(struct cros_ec_device *ec, void __user *arg) | 130 | static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) |
111 | { | 131 | { |
112 | long ret; | 132 | long ret; |
113 | struct cros_ec_command s_cmd = { }; | 133 | struct cros_ec_command u_cmd; |
134 | struct cros_ec_command *s_cmd; | ||
114 | 135 | ||
115 | if (copy_from_user(&s_cmd, arg, sizeof(s_cmd))) | 136 | if (copy_from_user(&u_cmd, arg, sizeof(u_cmd))) |
116 | return -EFAULT; | 137 | return -EFAULT; |
117 | 138 | ||
118 | ret = cros_ec_cmd_xfer(ec, &s_cmd); | 139 | s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize), |
140 | GFP_KERNEL); | ||
141 | if (!s_cmd) | ||
142 | return -ENOMEM; | ||
143 | |||
144 | if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) { | ||
145 | ret = -EFAULT; | ||
146 | goto exit; | ||
147 | } | ||
148 | |||
149 | s_cmd->command += ec->cmd_offset; | ||
150 | ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd); | ||
119 | /* Only copy data to userland if data was received. */ | 151 | /* Only copy data to userland if data was received. */ |
120 | if (ret < 0) | 152 | if (ret < 0) |
121 | return ret; | 153 | goto exit; |
122 | |||
123 | if (copy_to_user(arg, &s_cmd, sizeof(s_cmd))) | ||
124 | return -EFAULT; | ||
125 | 154 | ||
126 | return 0; | 155 | if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + u_cmd.insize)) |
156 | ret = -EFAULT; | ||
157 | exit: | ||
158 | kfree(s_cmd); | ||
159 | return ret; | ||
127 | } | 160 | } |
128 | 161 | ||
129 | static long ec_device_ioctl_readmem(struct cros_ec_device *ec, void __user *arg) | 162 | static long ec_device_ioctl_readmem(struct cros_ec_dev *ec, void __user *arg) |
130 | { | 163 | { |
164 | struct cros_ec_device *ec_dev = ec->ec_dev; | ||
131 | struct cros_ec_readmem s_mem = { }; | 165 | struct cros_ec_readmem s_mem = { }; |
132 | long num; | 166 | long num; |
133 | 167 | ||
134 | /* Not every platform supports direct reads */ | 168 | /* Not every platform supports direct reads */ |
135 | if (!ec->cmd_readmem) | 169 | if (!ec_dev->cmd_readmem) |
136 | return -ENOTTY; | 170 | return -ENOTTY; |
137 | 171 | ||
138 | if (copy_from_user(&s_mem, arg, sizeof(s_mem))) | 172 | if (copy_from_user(&s_mem, arg, sizeof(s_mem))) |
139 | return -EFAULT; | 173 | return -EFAULT; |
140 | 174 | ||
141 | num = ec->cmd_readmem(ec, s_mem.offset, s_mem.bytes, s_mem.buffer); | 175 | num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes, |
176 | s_mem.buffer); | ||
142 | if (num <= 0) | 177 | if (num <= 0) |
143 | return num; | 178 | return num; |
144 | 179 | ||
@@ -151,7 +186,7 @@ static long ec_device_ioctl_readmem(struct cros_ec_device *ec, void __user *arg) | |||
151 | static long ec_device_ioctl(struct file *filp, unsigned int cmd, | 186 | static long ec_device_ioctl(struct file *filp, unsigned int cmd, |
152 | unsigned long arg) | 187 | unsigned long arg) |
153 | { | 188 | { |
154 | struct cros_ec_device *ec = filp->private_data; | 189 | struct cros_ec_dev *ec = filp->private_data; |
155 | 190 | ||
156 | if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC) | 191 | if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC) |
157 | return -ENOTTY; | 192 | return -ENOTTY; |
@@ -174,45 +209,81 @@ static const struct file_operations fops = { | |||
174 | .unlocked_ioctl = ec_device_ioctl, | 209 | .unlocked_ioctl = ec_device_ioctl, |
175 | }; | 210 | }; |
176 | 211 | ||
212 | static void __remove(struct device *dev) | ||
213 | { | ||
214 | struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, | ||
215 | class_dev); | ||
216 | kfree(ec); | ||
217 | } | ||
218 | |||
177 | static int ec_device_probe(struct platform_device *pdev) | 219 | static int ec_device_probe(struct platform_device *pdev) |
178 | { | 220 | { |
179 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | 221 | int retval = -ENOMEM; |
180 | int retval = -ENOTTY; | 222 | struct device *dev = &pdev->dev; |
181 | dev_t devno = MKDEV(ec_major, 0); | 223 | struct cros_ec_platform *ec_platform = dev_get_platdata(dev); |
224 | dev_t devno = MKDEV(ec_major, pdev->id); | ||
225 | struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL); | ||
226 | |||
227 | if (!ec) | ||
228 | return retval; | ||
182 | 229 | ||
183 | /* Instantiate it (and remember the EC) */ | 230 | dev_set_drvdata(dev, ec); |
231 | ec->ec_dev = dev_get_drvdata(dev->parent); | ||
232 | ec->dev = dev; | ||
233 | ec->cmd_offset = ec_platform->cmd_offset; | ||
234 | device_initialize(&ec->class_dev); | ||
184 | cdev_init(&ec->cdev, &fops); | 235 | cdev_init(&ec->cdev, &fops); |
185 | 236 | ||
237 | /* | ||
238 | * Add the character device | ||
239 | * Link cdev to the class device to be sure device is not used | ||
240 | * before unbinding it. | ||
241 | */ | ||
242 | ec->cdev.kobj.parent = &ec->class_dev.kobj; | ||
186 | retval = cdev_add(&ec->cdev, devno, 1); | 243 | retval = cdev_add(&ec->cdev, devno, 1); |
187 | if (retval) { | 244 | if (retval) { |
188 | dev_err(&pdev->dev, ": failed to add character device\n"); | 245 | dev_err(dev, ": failed to add character device\n"); |
189 | return retval; | 246 | goto cdev_add_failed; |
190 | } | 247 | } |
191 | 248 | ||
192 | ec->vdev = device_create(cros_class, NULL, devno, ec, | 249 | /* |
193 | CROS_EC_DEV_NAME); | 250 | * Add the class device |
194 | if (IS_ERR(ec->vdev)) { | 251 | * Link to the character device for creating the /dev entry |
195 | retval = PTR_ERR(ec->vdev); | 252 | * in devtmpfs. |
196 | dev_err(&pdev->dev, ": failed to create device\n"); | 253 | */ |
197 | cdev_del(&ec->cdev); | 254 | ec->class_dev.devt = ec->cdev.dev; |
198 | return retval; | 255 | ec->class_dev.class = &cros_class; |
256 | ec->class_dev.parent = dev; | ||
257 | ec->class_dev.release = __remove; | ||
258 | |||
259 | retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name); | ||
260 | if (retval) { | ||
261 | dev_err(dev, "dev_set_name failed => %d\n", retval); | ||
262 | goto set_named_failed; | ||
199 | } | 263 | } |
200 | 264 | ||
201 | /* Initialize extra interfaces */ | 265 | retval = device_add(&ec->class_dev); |
202 | ec_dev_sysfs_init(ec); | 266 | if (retval) { |
203 | ec_dev_lightbar_init(ec); | 267 | dev_err(dev, "device_register failed => %d\n", retval); |
268 | goto dev_reg_failed; | ||
269 | } | ||
204 | 270 | ||
205 | return 0; | 271 | return 0; |
272 | |||
273 | dev_reg_failed: | ||
274 | set_named_failed: | ||
275 | dev_set_drvdata(dev, NULL); | ||
276 | cdev_del(&ec->cdev); | ||
277 | cdev_add_failed: | ||
278 | kfree(ec); | ||
279 | return retval; | ||
206 | } | 280 | } |
207 | 281 | ||
208 | static int ec_device_remove(struct platform_device *pdev) | 282 | static int ec_device_remove(struct platform_device *pdev) |
209 | { | 283 | { |
210 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | 284 | struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); |
211 | |||
212 | ec_dev_lightbar_remove(ec); | ||
213 | ec_dev_sysfs_remove(ec); | ||
214 | device_destroy(cros_class, MKDEV(ec_major, 0)); | ||
215 | cdev_del(&ec->cdev); | 285 | cdev_del(&ec->cdev); |
286 | device_unregister(&ec->class_dev); | ||
216 | return 0; | 287 | return 0; |
217 | } | 288 | } |
218 | 289 | ||
@@ -229,10 +300,10 @@ static int __init cros_ec_dev_init(void) | |||
229 | int ret; | 300 | int ret; |
230 | dev_t dev = 0; | 301 | dev_t dev = 0; |
231 | 302 | ||
232 | cros_class = class_create(THIS_MODULE, "chromeos"); | 303 | ret = class_register(&cros_class); |
233 | if (IS_ERR(cros_class)) { | 304 | if (ret) { |
234 | pr_err(CROS_EC_DEV_NAME ": failed to register device class\n"); | 305 | pr_err(CROS_EC_DEV_NAME ": failed to register device class\n"); |
235 | return PTR_ERR(cros_class); | 306 | return ret; |
236 | } | 307 | } |
237 | 308 | ||
238 | /* Get a range of minor numbers (starting with 0) to work with */ | 309 | /* Get a range of minor numbers (starting with 0) to work with */ |
@@ -254,7 +325,7 @@ static int __init cros_ec_dev_init(void) | |||
254 | failed_devreg: | 325 | failed_devreg: |
255 | unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV); | 326 | unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV); |
256 | failed_chrdevreg: | 327 | failed_chrdevreg: |
257 | class_destroy(cros_class); | 328 | class_unregister(&cros_class); |
258 | return ret; | 329 | return ret; |
259 | } | 330 | } |
260 | 331 | ||
@@ -262,7 +333,7 @@ static void __exit cros_ec_dev_exit(void) | |||
262 | { | 333 | { |
263 | platform_driver_unregister(&cros_ec_dev_driver); | 334 | platform_driver_unregister(&cros_ec_dev_driver); |
264 | unregister_chrdev(ec_major, CROS_EC_DEV_NAME); | 335 | unregister_chrdev(ec_major, CROS_EC_DEV_NAME); |
265 | class_destroy(cros_class); | 336 | class_unregister(&cros_class); |
266 | } | 337 | } |
267 | 338 | ||
268 | module_init(cros_ec_dev_init); | 339 | module_init(cros_ec_dev_init); |
diff --git a/drivers/platform/chrome/cros_ec_dev.h b/drivers/platform/chrome/cros_ec_dev.h index 45d67f7e518c..bfd2c84c3571 100644 --- a/drivers/platform/chrome/cros_ec_dev.h +++ b/drivers/platform/chrome/cros_ec_dev.h | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/mfd/cros_ec.h> | 25 | #include <linux/mfd/cros_ec.h> |
26 | 26 | ||
27 | #define CROS_EC_DEV_NAME "cros_ec" | ||
28 | #define CROS_EC_DEV_VERSION "1.0.0" | 27 | #define CROS_EC_DEV_VERSION "1.0.0" |
29 | 28 | ||
30 | /* | 29 | /* |
@@ -44,10 +43,4 @@ struct cros_ec_readmem { | |||
44 | #define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command) | 43 | #define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command) |
45 | #define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem) | 44 | #define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem) |
46 | 45 | ||
47 | void ec_dev_sysfs_init(struct cros_ec_device *); | ||
48 | void ec_dev_sysfs_remove(struct cros_ec_device *); | ||
49 | |||
50 | void ec_dev_lightbar_init(struct cros_ec_device *); | ||
51 | void ec_dev_lightbar_remove(struct cros_ec_device *); | ||
52 | |||
53 | #endif /* _CROS_EC_DEV_H_ */ | 46 | #endif /* _CROS_EC_DEV_H_ */ |
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index b4ff47a9069a..144e09df9b84 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
34 | #include <linux/slab.h> | ||
34 | 35 | ||
35 | #include "cros_ec_dev.h" | 36 | #include "cros_ec_dev.h" |
36 | 37 | ||
@@ -91,55 +92,81 @@ out: | |||
91 | return ret; | 92 | return ret; |
92 | } | 93 | } |
93 | 94 | ||
94 | #define INIT_MSG(P, R) { \ | 95 | static struct cros_ec_command *alloc_lightbar_cmd_msg(struct cros_ec_dev *ec) |
95 | .command = EC_CMD_LIGHTBAR_CMD, \ | 96 | { |
96 | .outsize = sizeof(*P), \ | 97 | struct cros_ec_command *msg; |
97 | .insize = sizeof(*R), \ | 98 | int len; |
98 | } | 99 | |
100 | len = max(sizeof(struct ec_params_lightbar), | ||
101 | sizeof(struct ec_response_lightbar)); | ||
102 | |||
103 | msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL); | ||
104 | if (!msg) | ||
105 | return NULL; | ||
106 | |||
107 | msg->version = 0; | ||
108 | msg->command = EC_CMD_LIGHTBAR_CMD + ec->cmd_offset; | ||
109 | msg->outsize = sizeof(struct ec_params_lightbar); | ||
110 | msg->insize = sizeof(struct ec_response_lightbar); | ||
111 | |||
112 | return msg; | ||
113 | } | ||
99 | 114 | ||
100 | static int get_lightbar_version(struct cros_ec_device *ec, | 115 | static int get_lightbar_version(struct cros_ec_dev *ec, |
101 | uint32_t *ver_ptr, uint32_t *flg_ptr) | 116 | uint32_t *ver_ptr, uint32_t *flg_ptr) |
102 | { | 117 | { |
103 | struct ec_params_lightbar *param; | 118 | struct ec_params_lightbar *param; |
104 | struct ec_response_lightbar *resp; | 119 | struct ec_response_lightbar *resp; |
105 | struct cros_ec_command msg = INIT_MSG(param, resp); | 120 | struct cros_ec_command *msg; |
106 | int ret; | 121 | int ret; |
107 | 122 | ||
108 | param = (struct ec_params_lightbar *)msg.outdata; | 123 | msg = alloc_lightbar_cmd_msg(ec); |
109 | param->cmd = LIGHTBAR_CMD_VERSION; | 124 | if (!msg) |
110 | ret = cros_ec_cmd_xfer(ec, &msg); | ||
111 | if (ret < 0) | ||
112 | return 0; | 125 | return 0; |
113 | 126 | ||
114 | switch (msg.result) { | 127 | param = (struct ec_params_lightbar *)msg->data; |
128 | param->cmd = LIGHTBAR_CMD_VERSION; | ||
129 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); | ||
130 | if (ret < 0) { | ||
131 | ret = 0; | ||
132 | goto exit; | ||
133 | } | ||
134 | |||
135 | switch (msg->result) { | ||
115 | case EC_RES_INVALID_PARAM: | 136 | case EC_RES_INVALID_PARAM: |
116 | /* Pixel had no version command. */ | 137 | /* Pixel had no version command. */ |
117 | if (ver_ptr) | 138 | if (ver_ptr) |
118 | *ver_ptr = 0; | 139 | *ver_ptr = 0; |
119 | if (flg_ptr) | 140 | if (flg_ptr) |
120 | *flg_ptr = 0; | 141 | *flg_ptr = 0; |
121 | return 1; | 142 | ret = 1; |
143 | goto exit; | ||
122 | 144 | ||
123 | case EC_RES_SUCCESS: | 145 | case EC_RES_SUCCESS: |
124 | resp = (struct ec_response_lightbar *)msg.indata; | 146 | resp = (struct ec_response_lightbar *)msg->data; |
125 | 147 | ||
126 | /* Future devices w/lightbars should implement this command */ | 148 | /* Future devices w/lightbars should implement this command */ |
127 | if (ver_ptr) | 149 | if (ver_ptr) |
128 | *ver_ptr = resp->version.num; | 150 | *ver_ptr = resp->version.num; |
129 | if (flg_ptr) | 151 | if (flg_ptr) |
130 | *flg_ptr = resp->version.flags; | 152 | *flg_ptr = resp->version.flags; |
131 | return 1; | 153 | ret = 1; |
154 | goto exit; | ||
132 | } | 155 | } |
133 | 156 | ||
134 | /* Anything else (ie, EC_RES_INVALID_COMMAND) - no lightbar */ | 157 | /* Anything else (ie, EC_RES_INVALID_COMMAND) - no lightbar */ |
135 | return 0; | 158 | ret = 0; |
159 | exit: | ||
160 | kfree(msg); | ||
161 | return ret; | ||
136 | } | 162 | } |
137 | 163 | ||
138 | static ssize_t version_show(struct device *dev, | 164 | static ssize_t version_show(struct device *dev, |
139 | struct device_attribute *attr, char *buf) | 165 | struct device_attribute *attr, char *buf) |
140 | { | 166 | { |
141 | uint32_t version, flags; | 167 | uint32_t version = 0, flags = 0; |
142 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 168 | struct cros_ec_dev *ec = container_of(dev, |
169 | struct cros_ec_dev, class_dev); | ||
143 | int ret; | 170 | int ret; |
144 | 171 | ||
145 | ret = lb_throttle(); | 172 | ret = lb_throttle(); |
@@ -158,30 +185,39 @@ static ssize_t brightness_store(struct device *dev, | |||
158 | const char *buf, size_t count) | 185 | const char *buf, size_t count) |
159 | { | 186 | { |
160 | struct ec_params_lightbar *param; | 187 | struct ec_params_lightbar *param; |
161 | struct ec_response_lightbar *resp; | 188 | struct cros_ec_command *msg; |
162 | struct cros_ec_command msg = INIT_MSG(param, resp); | ||
163 | int ret; | 189 | int ret; |
164 | unsigned int val; | 190 | unsigned int val; |
165 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 191 | struct cros_ec_dev *ec = container_of(dev, |
192 | struct cros_ec_dev, class_dev); | ||
166 | 193 | ||
167 | if (kstrtouint(buf, 0, &val)) | 194 | if (kstrtouint(buf, 0, &val)) |
168 | return -EINVAL; | 195 | return -EINVAL; |
169 | 196 | ||
170 | param = (struct ec_params_lightbar *)msg.outdata; | 197 | msg = alloc_lightbar_cmd_msg(ec); |
171 | param->cmd = LIGHTBAR_CMD_BRIGHTNESS; | 198 | if (!msg) |
172 | param->brightness.num = val; | 199 | return -ENOMEM; |
200 | |||
201 | param = (struct ec_params_lightbar *)msg->data; | ||
202 | param->cmd = LIGHTBAR_CMD_SET_BRIGHTNESS; | ||
203 | param->set_brightness.num = val; | ||
173 | ret = lb_throttle(); | 204 | ret = lb_throttle(); |
174 | if (ret) | 205 | if (ret) |
175 | return ret; | 206 | goto exit; |
176 | 207 | ||
177 | ret = cros_ec_cmd_xfer(ec, &msg); | 208 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); |
178 | if (ret < 0) | 209 | if (ret < 0) |
179 | return ret; | 210 | goto exit; |
180 | 211 | ||
181 | if (msg.result != EC_RES_SUCCESS) | 212 | if (msg->result != EC_RES_SUCCESS) { |
182 | return -EINVAL; | 213 | ret = -EINVAL; |
214 | goto exit; | ||
215 | } | ||
183 | 216 | ||
184 | return count; | 217 | ret = count; |
218 | exit: | ||
219 | kfree(msg); | ||
220 | return ret; | ||
185 | } | 221 | } |
186 | 222 | ||
187 | 223 | ||
@@ -196,12 +232,16 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
196 | const char *buf, size_t count) | 232 | const char *buf, size_t count) |
197 | { | 233 | { |
198 | struct ec_params_lightbar *param; | 234 | struct ec_params_lightbar *param; |
199 | struct ec_response_lightbar *resp; | 235 | struct cros_ec_command *msg; |
200 | struct cros_ec_command msg = INIT_MSG(param, resp); | 236 | struct cros_ec_dev *ec = container_of(dev, |
201 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 237 | struct cros_ec_dev, class_dev); |
202 | unsigned int val[4]; | 238 | unsigned int val[4]; |
203 | int ret, i = 0, j = 0, ok = 0; | 239 | int ret, i = 0, j = 0, ok = 0; |
204 | 240 | ||
241 | msg = alloc_lightbar_cmd_msg(ec); | ||
242 | if (!msg) | ||
243 | return -ENOMEM; | ||
244 | |||
205 | do { | 245 | do { |
206 | /* Skip any whitespace */ | 246 | /* Skip any whitespace */ |
207 | while (*buf && isspace(*buf)) | 247 | while (*buf && isspace(*buf)) |
@@ -215,12 +255,12 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
215 | return -EINVAL; | 255 | return -EINVAL; |
216 | 256 | ||
217 | if (i == 4) { | 257 | if (i == 4) { |
218 | param = (struct ec_params_lightbar *)msg.outdata; | 258 | param = (struct ec_params_lightbar *)msg->data; |
219 | param->cmd = LIGHTBAR_CMD_RGB; | 259 | param->cmd = LIGHTBAR_CMD_SET_RGB; |
220 | param->rgb.led = val[0]; | 260 | param->set_rgb.led = val[0]; |
221 | param->rgb.red = val[1]; | 261 | param->set_rgb.red = val[1]; |
222 | param->rgb.green = val[2]; | 262 | param->set_rgb.green = val[2]; |
223 | param->rgb.blue = val[3]; | 263 | param->set_rgb.blue = val[3]; |
224 | /* | 264 | /* |
225 | * Throttle only the first of every four transactions, | 265 | * Throttle only the first of every four transactions, |
226 | * so that the user can update all four LEDs at once. | 266 | * so that the user can update all four LEDs at once. |
@@ -231,12 +271,14 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
231 | return ret; | 271 | return ret; |
232 | } | 272 | } |
233 | 273 | ||
234 | ret = cros_ec_cmd_xfer(ec, &msg); | 274 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); |
235 | if (ret < 0) | 275 | if (ret < 0) |
236 | return ret; | 276 | goto exit; |
237 | 277 | ||
238 | if (msg.result != EC_RES_SUCCESS) | 278 | if (msg->result != EC_RES_SUCCESS) { |
239 | return -EINVAL; | 279 | ret = -EINVAL; |
280 | goto exit; | ||
281 | } | ||
240 | 282 | ||
241 | i = 0; | 283 | i = 0; |
242 | ok = 1; | 284 | ok = 1; |
@@ -248,6 +290,8 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
248 | 290 | ||
249 | } while (*buf); | 291 | } while (*buf); |
250 | 292 | ||
293 | exit: | ||
294 | kfree(msg); | ||
251 | return (ok && i == 0) ? count : -EINVAL; | 295 | return (ok && i == 0) ? count : -EINVAL; |
252 | } | 296 | } |
253 | 297 | ||
@@ -261,41 +305,56 @@ static ssize_t sequence_show(struct device *dev, | |||
261 | { | 305 | { |
262 | struct ec_params_lightbar *param; | 306 | struct ec_params_lightbar *param; |
263 | struct ec_response_lightbar *resp; | 307 | struct ec_response_lightbar *resp; |
264 | struct cros_ec_command msg = INIT_MSG(param, resp); | 308 | struct cros_ec_command *msg; |
265 | int ret; | 309 | int ret; |
266 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 310 | struct cros_ec_dev *ec = container_of(dev, |
311 | struct cros_ec_dev, class_dev); | ||
312 | |||
313 | msg = alloc_lightbar_cmd_msg(ec); | ||
314 | if (!msg) | ||
315 | return -ENOMEM; | ||
267 | 316 | ||
268 | param = (struct ec_params_lightbar *)msg.outdata; | 317 | param = (struct ec_params_lightbar *)msg->data; |
269 | param->cmd = LIGHTBAR_CMD_GET_SEQ; | 318 | param->cmd = LIGHTBAR_CMD_GET_SEQ; |
270 | ret = lb_throttle(); | 319 | ret = lb_throttle(); |
271 | if (ret) | 320 | if (ret) |
272 | return ret; | 321 | goto exit; |
273 | 322 | ||
274 | ret = cros_ec_cmd_xfer(ec, &msg); | 323 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); |
275 | if (ret < 0) | 324 | if (ret < 0) |
276 | return ret; | 325 | goto exit; |
277 | 326 | ||
278 | if (msg.result != EC_RES_SUCCESS) | 327 | if (msg->result != EC_RES_SUCCESS) { |
279 | return scnprintf(buf, PAGE_SIZE, | 328 | ret = scnprintf(buf, PAGE_SIZE, |
280 | "ERROR: EC returned %d\n", msg.result); | 329 | "ERROR: EC returned %d\n", msg->result); |
330 | goto exit; | ||
331 | } | ||
281 | 332 | ||
282 | resp = (struct ec_response_lightbar *)msg.indata; | 333 | resp = (struct ec_response_lightbar *)msg->data; |
283 | if (resp->get_seq.num >= ARRAY_SIZE(seqname)) | 334 | if (resp->get_seq.num >= ARRAY_SIZE(seqname)) |
284 | return scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num); | 335 | ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num); |
285 | else | 336 | else |
286 | return scnprintf(buf, PAGE_SIZE, "%s\n", | 337 | ret = scnprintf(buf, PAGE_SIZE, "%s\n", |
287 | seqname[resp->get_seq.num]); | 338 | seqname[resp->get_seq.num]); |
339 | |||
340 | exit: | ||
341 | kfree(msg); | ||
342 | return ret; | ||
288 | } | 343 | } |
289 | 344 | ||
290 | static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, | 345 | static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, |
291 | const char *buf, size_t count) | 346 | const char *buf, size_t count) |
292 | { | 347 | { |
293 | struct ec_params_lightbar *param; | 348 | struct ec_params_lightbar *param; |
294 | struct ec_response_lightbar *resp; | 349 | struct cros_ec_command *msg; |
295 | struct cros_ec_command msg = INIT_MSG(param, resp); | ||
296 | unsigned int num; | 350 | unsigned int num; |
297 | int ret, len; | 351 | int ret, len; |
298 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 352 | struct cros_ec_dev *ec = container_of(dev, |
353 | struct cros_ec_dev, class_dev); | ||
354 | |||
355 | msg = alloc_lightbar_cmd_msg(ec); | ||
356 | if (!msg) | ||
357 | return -ENOMEM; | ||
299 | 358 | ||
300 | for (len = 0; len < count; len++) | 359 | for (len = 0; len < count; len++) |
301 | if (!isalnum(buf[len])) | 360 | if (!isalnum(buf[len])) |
@@ -311,18 +370,18 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, | |||
311 | return ret; | 370 | return ret; |
312 | } | 371 | } |
313 | 372 | ||
314 | param = (struct ec_params_lightbar *)msg.outdata; | 373 | param = (struct ec_params_lightbar *)msg->data; |
315 | param->cmd = LIGHTBAR_CMD_SEQ; | 374 | param->cmd = LIGHTBAR_CMD_SEQ; |
316 | param->seq.num = num; | 375 | param->seq.num = num; |
317 | ret = lb_throttle(); | 376 | ret = lb_throttle(); |
318 | if (ret) | 377 | if (ret) |
319 | return ret; | 378 | return ret; |
320 | 379 | ||
321 | ret = cros_ec_cmd_xfer(ec, &msg); | 380 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); |
322 | if (ret < 0) | 381 | if (ret < 0) |
323 | return ret; | 382 | return ret; |
324 | 383 | ||
325 | if (msg.result != EC_RES_SUCCESS) | 384 | if (msg->result != EC_RES_SUCCESS) |
326 | return -EINVAL; | 385 | return -EINVAL; |
327 | 386 | ||
328 | return count; | 387 | return count; |
@@ -343,25 +402,27 @@ static struct attribute *__lb_cmds_attrs[] = { | |||
343 | &dev_attr_sequence.attr, | 402 | &dev_attr_sequence.attr, |
344 | NULL, | 403 | NULL, |
345 | }; | 404 | }; |
346 | static struct attribute_group lb_cmds_attr_group = { | ||
347 | .name = "lightbar", | ||
348 | .attrs = __lb_cmds_attrs, | ||
349 | }; | ||
350 | 405 | ||
351 | void ec_dev_lightbar_init(struct cros_ec_device *ec) | 406 | static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj, |
407 | struct attribute *a, int n) | ||
352 | { | 408 | { |
353 | int ret = 0; | 409 | struct device *dev = container_of(kobj, struct device, kobj); |
410 | struct cros_ec_dev *ec = container_of(dev, | ||
411 | struct cros_ec_dev, class_dev); | ||
412 | struct platform_device *pdev = container_of(ec->dev, | ||
413 | struct platform_device, dev); | ||
414 | if (pdev->id != 0) | ||
415 | return 0; | ||
354 | 416 | ||
355 | /* Only instantiate this stuff if the EC has a lightbar */ | 417 | /* Only instantiate this stuff if the EC has a lightbar */ |
356 | if (!get_lightbar_version(ec, NULL, NULL)) | 418 | if (get_lightbar_version(ec, NULL, NULL)) |
357 | return; | 419 | return a->mode; |
358 | 420 | else | |
359 | ret = sysfs_create_group(&ec->vdev->kobj, &lb_cmds_attr_group); | 421 | return 0; |
360 | if (ret) | ||
361 | pr_warn("sysfs_create_group() failed: %d\n", ret); | ||
362 | } | 422 | } |
363 | 423 | ||
364 | void ec_dev_lightbar_remove(struct cros_ec_device *ec) | 424 | struct attribute_group cros_ec_lightbar_attr_group = { |
365 | { | 425 | .name = "lightbar", |
366 | sysfs_remove_group(&ec->vdev->kobj, &lb_cmds_attr_group); | 426 | .attrs = __lb_cmds_attrs, |
367 | } | 427 | .is_visible = cros_ec_lightbar_attrs_are_visible, |
428 | }; | ||
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 8f9ac4d7bbd0..bdd77ce45f05 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c | |||
@@ -46,6 +46,77 @@ static int ec_response_timed_out(void) | |||
46 | return 1; | 46 | return 1; |
47 | } | 47 | } |
48 | 48 | ||
49 | static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, | ||
50 | struct cros_ec_command *msg) | ||
51 | { | ||
52 | struct ec_host_request *request; | ||
53 | struct ec_host_response response; | ||
54 | u8 sum = 0; | ||
55 | int i; | ||
56 | int ret = 0; | ||
57 | u8 *dout; | ||
58 | |||
59 | ret = cros_ec_prepare_tx(ec, msg); | ||
60 | |||
61 | /* Write buffer */ | ||
62 | for (i = 0; i < ret; i++) | ||
63 | outb(ec->dout[i], EC_LPC_ADDR_HOST_PACKET + i); | ||
64 | |||
65 | request = (struct ec_host_request *)ec->dout; | ||
66 | |||
67 | /* Here we go */ | ||
68 | outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD); | ||
69 | |||
70 | if (ec_response_timed_out()) { | ||
71 | dev_warn(ec->dev, "EC responsed timed out\n"); | ||
72 | ret = -EIO; | ||
73 | goto done; | ||
74 | } | ||
75 | |||
76 | /* Check result */ | ||
77 | msg->result = inb(EC_LPC_ADDR_HOST_DATA); | ||
78 | ret = cros_ec_check_result(ec, msg); | ||
79 | if (ret) | ||
80 | goto done; | ||
81 | |||
82 | /* Read back response */ | ||
83 | dout = (u8 *)&response; | ||
84 | for (i = 0; i < sizeof(response); i++) { | ||
85 | dout[i] = inb(EC_LPC_ADDR_HOST_PACKET + i); | ||
86 | sum += dout[i]; | ||
87 | } | ||
88 | |||
89 | msg->result = response.result; | ||
90 | |||
91 | if (response.data_len > msg->insize) { | ||
92 | dev_err(ec->dev, | ||
93 | "packet too long (%d bytes, expected %d)", | ||
94 | response.data_len, msg->insize); | ||
95 | ret = -EMSGSIZE; | ||
96 | goto done; | ||
97 | } | ||
98 | |||
99 | /* Read response and process checksum */ | ||
100 | for (i = 0; i < response.data_len; i++) { | ||
101 | msg->data[i] = | ||
102 | inb(EC_LPC_ADDR_HOST_PACKET + sizeof(response) + i); | ||
103 | sum += msg->data[i]; | ||
104 | } | ||
105 | |||
106 | if (sum) { | ||
107 | dev_err(ec->dev, | ||
108 | "bad packet checksum %02x\n", | ||
109 | response.checksum); | ||
110 | ret = -EBADMSG; | ||
111 | goto done; | ||
112 | } | ||
113 | |||
114 | /* Return actual amount of data received */ | ||
115 | ret = response.data_len; | ||
116 | done: | ||
117 | return ret; | ||
118 | } | ||
119 | |||
49 | static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, | 120 | static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, |
50 | struct cros_ec_command *msg) | 121 | struct cros_ec_command *msg) |
51 | { | 122 | { |
@@ -73,8 +144,8 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, | |||
73 | 144 | ||
74 | /* Copy data and update checksum */ | 145 | /* Copy data and update checksum */ |
75 | for (i = 0; i < msg->outsize; i++) { | 146 | for (i = 0; i < msg->outsize; i++) { |
76 | outb(msg->outdata[i], EC_LPC_ADDR_HOST_PARAM + i); | 147 | outb(msg->data[i], EC_LPC_ADDR_HOST_PARAM + i); |
77 | csum += msg->outdata[i]; | 148 | csum += msg->data[i]; |
78 | } | 149 | } |
79 | 150 | ||
80 | /* Finalize checksum and write args */ | 151 | /* Finalize checksum and write args */ |
@@ -129,8 +200,8 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, | |||
129 | 200 | ||
130 | /* Read response and update checksum */ | 201 | /* Read response and update checksum */ |
131 | for (i = 0; i < args.data_size; i++) { | 202 | for (i = 0; i < args.data_size; i++) { |
132 | msg->indata[i] = inb(EC_LPC_ADDR_HOST_PARAM + i); | 203 | msg->data[i] = inb(EC_LPC_ADDR_HOST_PARAM + i); |
133 | csum += msg->indata[i]; | 204 | csum += msg->data[i]; |
134 | } | 205 | } |
135 | 206 | ||
136 | /* Verify checksum */ | 207 | /* Verify checksum */ |
@@ -212,11 +283,13 @@ static int cros_ec_lpc_probe(struct platform_device *pdev) | |||
212 | 283 | ||
213 | platform_set_drvdata(pdev, ec_dev); | 284 | platform_set_drvdata(pdev, ec_dev); |
214 | ec_dev->dev = dev; | 285 | ec_dev->dev = dev; |
215 | ec_dev->ec_name = pdev->name; | ||
216 | ec_dev->phys_name = dev_name(dev); | 286 | ec_dev->phys_name = dev_name(dev); |
217 | ec_dev->parent = dev; | ||
218 | ec_dev->cmd_xfer = cros_ec_cmd_xfer_lpc; | 287 | ec_dev->cmd_xfer = cros_ec_cmd_xfer_lpc; |
288 | ec_dev->pkt_xfer = cros_ec_pkt_xfer_lpc; | ||
219 | ec_dev->cmd_readmem = cros_ec_lpc_readmem; | 289 | ec_dev->cmd_readmem = cros_ec_lpc_readmem; |
290 | ec_dev->din_size = sizeof(struct ec_host_response) + | ||
291 | sizeof(struct ec_response_get_protocol_info); | ||
292 | ec_dev->dout_size = sizeof(struct ec_host_request); | ||
220 | 293 | ||
221 | ret = cros_ec_register(ec_dev); | 294 | ret = cros_ec_register(ec_dev); |
222 | if (ret) { | 295 | if (ret) { |
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c new file mode 100644 index 000000000000..990308ca384f --- /dev/null +++ b/drivers/platform/chrome/cros_ec_proto.c | |||
@@ -0,0 +1,382 @@ | |||
1 | /* | ||
2 | * ChromeOS EC communication protocol helper functions | ||
3 | * | ||
4 | * Copyright (C) 2015 Google, Inc | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/mfd/cros_ec.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #define EC_COMMAND_RETRIES 50 | ||
24 | |||
25 | static int prepare_packet(struct cros_ec_device *ec_dev, | ||
26 | struct cros_ec_command *msg) | ||
27 | { | ||
28 | struct ec_host_request *request; | ||
29 | u8 *out; | ||
30 | int i; | ||
31 | u8 csum = 0; | ||
32 | |||
33 | BUG_ON(ec_dev->proto_version != EC_HOST_REQUEST_VERSION); | ||
34 | BUG_ON(msg->outsize + sizeof(*request) > ec_dev->dout_size); | ||
35 | |||
36 | out = ec_dev->dout; | ||
37 | request = (struct ec_host_request *)out; | ||
38 | request->struct_version = EC_HOST_REQUEST_VERSION; | ||
39 | request->checksum = 0; | ||
40 | request->command = msg->command; | ||
41 | request->command_version = msg->version; | ||
42 | request->reserved = 0; | ||
43 | request->data_len = msg->outsize; | ||
44 | |||
45 | for (i = 0; i < sizeof(*request); i++) | ||
46 | csum += out[i]; | ||
47 | |||
48 | /* Copy data and update checksum */ | ||
49 | memcpy(out + sizeof(*request), msg->data, msg->outsize); | ||
50 | for (i = 0; i < msg->outsize; i++) | ||
51 | csum += msg->data[i]; | ||
52 | |||
53 | request->checksum = -csum; | ||
54 | |||
55 | return sizeof(*request) + msg->outsize; | ||
56 | } | ||
57 | |||
58 | static int send_command(struct cros_ec_device *ec_dev, | ||
59 | struct cros_ec_command *msg) | ||
60 | { | ||
61 | int ret; | ||
62 | |||
63 | if (ec_dev->proto_version > 2) | ||
64 | ret = ec_dev->pkt_xfer(ec_dev, msg); | ||
65 | else | ||
66 | ret = ec_dev->cmd_xfer(ec_dev, msg); | ||
67 | |||
68 | if (msg->result == EC_RES_IN_PROGRESS) { | ||
69 | int i; | ||
70 | struct cros_ec_command *status_msg; | ||
71 | struct ec_response_get_comms_status *status; | ||
72 | |||
73 | status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status), | ||
74 | GFP_KERNEL); | ||
75 | if (!status_msg) | ||
76 | return -ENOMEM; | ||
77 | |||
78 | status_msg->version = 0; | ||
79 | status_msg->command = EC_CMD_GET_COMMS_STATUS; | ||
80 | status_msg->insize = sizeof(*status); | ||
81 | status_msg->outsize = 0; | ||
82 | |||
83 | /* | ||
84 | * Query the EC's status until it's no longer busy or | ||
85 | * we encounter an error. | ||
86 | */ | ||
87 | for (i = 0; i < EC_COMMAND_RETRIES; i++) { | ||
88 | usleep_range(10000, 11000); | ||
89 | |||
90 | ret = ec_dev->cmd_xfer(ec_dev, status_msg); | ||
91 | if (ret < 0) | ||
92 | break; | ||
93 | |||
94 | msg->result = status_msg->result; | ||
95 | if (status_msg->result != EC_RES_SUCCESS) | ||
96 | break; | ||
97 | |||
98 | status = (struct ec_response_get_comms_status *) | ||
99 | status_msg->data; | ||
100 | if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) | ||
101 | break; | ||
102 | } | ||
103 | |||
104 | kfree(status_msg); | ||
105 | } | ||
106 | |||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, | ||
111 | struct cros_ec_command *msg) | ||
112 | { | ||
113 | u8 *out; | ||
114 | u8 csum; | ||
115 | int i; | ||
116 | |||
117 | if (ec_dev->proto_version > 2) | ||
118 | return prepare_packet(ec_dev, msg); | ||
119 | |||
120 | BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE); | ||
121 | out = ec_dev->dout; | ||
122 | out[0] = EC_CMD_VERSION0 + msg->version; | ||
123 | out[1] = msg->command; | ||
124 | out[2] = msg->outsize; | ||
125 | csum = out[0] + out[1] + out[2]; | ||
126 | for (i = 0; i < msg->outsize; i++) | ||
127 | csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i]; | ||
128 | out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = csum; | ||
129 | |||
130 | return EC_MSG_TX_PROTO_BYTES + msg->outsize; | ||
131 | } | ||
132 | EXPORT_SYMBOL(cros_ec_prepare_tx); | ||
133 | |||
134 | int cros_ec_check_result(struct cros_ec_device *ec_dev, | ||
135 | struct cros_ec_command *msg) | ||
136 | { | ||
137 | switch (msg->result) { | ||
138 | case EC_RES_SUCCESS: | ||
139 | return 0; | ||
140 | case EC_RES_IN_PROGRESS: | ||
141 | dev_dbg(ec_dev->dev, "command 0x%02x in progress\n", | ||
142 | msg->command); | ||
143 | return -EAGAIN; | ||
144 | default: | ||
145 | dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n", | ||
146 | msg->command, msg->result); | ||
147 | return 0; | ||
148 | } | ||
149 | } | ||
150 | EXPORT_SYMBOL(cros_ec_check_result); | ||
151 | |||
152 | static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev, | ||
153 | int devidx, | ||
154 | struct cros_ec_command *msg) | ||
155 | { | ||
156 | /* | ||
157 | * Try using v3+ to query for supported protocols. If this | ||
158 | * command fails, fall back to v2. Returns the highest protocol | ||
159 | * supported by the EC. | ||
160 | * Also sets the max request/response/passthru size. | ||
161 | */ | ||
162 | int ret; | ||
163 | |||
164 | if (!ec_dev->pkt_xfer) | ||
165 | return -EPROTONOSUPPORT; | ||
166 | |||
167 | memset(msg, 0, sizeof(*msg)); | ||
168 | msg->command = EC_CMD_PASSTHRU_OFFSET(devidx) | EC_CMD_GET_PROTOCOL_INFO; | ||
169 | msg->insize = sizeof(struct ec_response_get_protocol_info); | ||
170 | |||
171 | ret = send_command(ec_dev, msg); | ||
172 | |||
173 | if (ret < 0) { | ||
174 | dev_dbg(ec_dev->dev, | ||
175 | "failed to check for EC[%d] protocol version: %d\n", | ||
176 | devidx, ret); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | if (devidx > 0 && msg->result == EC_RES_INVALID_COMMAND) | ||
181 | return -ENODEV; | ||
182 | else if (msg->result != EC_RES_SUCCESS) | ||
183 | return msg->result; | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev) | ||
189 | { | ||
190 | struct cros_ec_command *msg; | ||
191 | struct ec_params_hello *hello_params; | ||
192 | struct ec_response_hello *hello_response; | ||
193 | int ret; | ||
194 | int len = max(sizeof(*hello_params), sizeof(*hello_response)); | ||
195 | |||
196 | msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL); | ||
197 | if (!msg) | ||
198 | return -ENOMEM; | ||
199 | |||
200 | msg->version = 0; | ||
201 | msg->command = EC_CMD_HELLO; | ||
202 | hello_params = (struct ec_params_hello *)msg->data; | ||
203 | msg->outsize = sizeof(*hello_params); | ||
204 | hello_response = (struct ec_response_hello *)msg->data; | ||
205 | msg->insize = sizeof(*hello_response); | ||
206 | |||
207 | hello_params->in_data = 0xa0b0c0d0; | ||
208 | |||
209 | ret = send_command(ec_dev, msg); | ||
210 | |||
211 | if (ret < 0) { | ||
212 | dev_dbg(ec_dev->dev, | ||
213 | "EC failed to respond to v2 hello: %d\n", | ||
214 | ret); | ||
215 | goto exit; | ||
216 | } else if (msg->result != EC_RES_SUCCESS) { | ||
217 | dev_err(ec_dev->dev, | ||
218 | "EC responded to v2 hello with error: %d\n", | ||
219 | msg->result); | ||
220 | ret = msg->result; | ||
221 | goto exit; | ||
222 | } else if (hello_response->out_data != 0xa1b2c3d4) { | ||
223 | dev_err(ec_dev->dev, | ||
224 | "EC responded to v2 hello with bad result: %u\n", | ||
225 | hello_response->out_data); | ||
226 | ret = -EBADMSG; | ||
227 | goto exit; | ||
228 | } | ||
229 | |||
230 | ret = 0; | ||
231 | |||
232 | exit: | ||
233 | kfree(msg); | ||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | int cros_ec_query_all(struct cros_ec_device *ec_dev) | ||
238 | { | ||
239 | struct device *dev = ec_dev->dev; | ||
240 | struct cros_ec_command *proto_msg; | ||
241 | struct ec_response_get_protocol_info *proto_info; | ||
242 | int ret; | ||
243 | |||
244 | proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info), | ||
245 | GFP_KERNEL); | ||
246 | if (!proto_msg) | ||
247 | return -ENOMEM; | ||
248 | |||
249 | /* First try sending with proto v3. */ | ||
250 | ec_dev->proto_version = 3; | ||
251 | ret = cros_ec_host_command_proto_query(ec_dev, 0, proto_msg); | ||
252 | |||
253 | if (ret == 0) { | ||
254 | proto_info = (struct ec_response_get_protocol_info *) | ||
255 | proto_msg->data; | ||
256 | ec_dev->max_request = proto_info->max_request_packet_size - | ||
257 | sizeof(struct ec_host_request); | ||
258 | ec_dev->max_response = proto_info->max_response_packet_size - | ||
259 | sizeof(struct ec_host_response); | ||
260 | ec_dev->proto_version = | ||
261 | min(EC_HOST_REQUEST_VERSION, | ||
262 | fls(proto_info->protocol_versions) - 1); | ||
263 | dev_dbg(ec_dev->dev, | ||
264 | "using proto v%u\n", | ||
265 | ec_dev->proto_version); | ||
266 | |||
267 | ec_dev->din_size = ec_dev->max_response + | ||
268 | sizeof(struct ec_host_response) + | ||
269 | EC_MAX_RESPONSE_OVERHEAD; | ||
270 | ec_dev->dout_size = ec_dev->max_request + | ||
271 | sizeof(struct ec_host_request) + | ||
272 | EC_MAX_REQUEST_OVERHEAD; | ||
273 | |||
274 | /* | ||
275 | * Check for PD | ||
276 | */ | ||
277 | ret = cros_ec_host_command_proto_query(ec_dev, 1, proto_msg); | ||
278 | |||
279 | if (ret) { | ||
280 | dev_dbg(ec_dev->dev, "no PD chip found: %d\n", ret); | ||
281 | ec_dev->max_passthru = 0; | ||
282 | } else { | ||
283 | dev_dbg(ec_dev->dev, "found PD chip\n"); | ||
284 | ec_dev->max_passthru = | ||
285 | proto_info->max_request_packet_size - | ||
286 | sizeof(struct ec_host_request); | ||
287 | } | ||
288 | } else { | ||
289 | /* Try querying with a v2 hello message. */ | ||
290 | ec_dev->proto_version = 2; | ||
291 | ret = cros_ec_host_command_proto_query_v2(ec_dev); | ||
292 | |||
293 | if (ret == 0) { | ||
294 | /* V2 hello succeeded. */ | ||
295 | dev_dbg(ec_dev->dev, "falling back to proto v2\n"); | ||
296 | |||
297 | ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE; | ||
298 | ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE; | ||
299 | ec_dev->max_passthru = 0; | ||
300 | ec_dev->pkt_xfer = NULL; | ||
301 | ec_dev->din_size = EC_MSG_BYTES; | ||
302 | ec_dev->dout_size = EC_MSG_BYTES; | ||
303 | } else { | ||
304 | /* | ||
305 | * It's possible for a test to occur too early when | ||
306 | * the EC isn't listening. If this happens, we'll | ||
307 | * test later when the first command is run. | ||
308 | */ | ||
309 | ec_dev->proto_version = EC_PROTO_VERSION_UNKNOWN; | ||
310 | dev_dbg(ec_dev->dev, "EC query failed: %d\n", ret); | ||
311 | goto exit; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | devm_kfree(dev, ec_dev->din); | ||
316 | devm_kfree(dev, ec_dev->dout); | ||
317 | |||
318 | ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL); | ||
319 | if (!ec_dev->din) { | ||
320 | ret = -ENOMEM; | ||
321 | goto exit; | ||
322 | } | ||
323 | |||
324 | ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL); | ||
325 | if (!ec_dev->dout) { | ||
326 | devm_kfree(dev, ec_dev->din); | ||
327 | ret = -ENOMEM; | ||
328 | goto exit; | ||
329 | } | ||
330 | |||
331 | exit: | ||
332 | kfree(proto_msg); | ||
333 | return ret; | ||
334 | } | ||
335 | EXPORT_SYMBOL(cros_ec_query_all); | ||
336 | |||
337 | int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, | ||
338 | struct cros_ec_command *msg) | ||
339 | { | ||
340 | int ret; | ||
341 | |||
342 | mutex_lock(&ec_dev->lock); | ||
343 | if (ec_dev->proto_version == EC_PROTO_VERSION_UNKNOWN) { | ||
344 | ret = cros_ec_query_all(ec_dev); | ||
345 | if (ret) { | ||
346 | dev_err(ec_dev->dev, | ||
347 | "EC version unknown and query failed; aborting command\n"); | ||
348 | mutex_unlock(&ec_dev->lock); | ||
349 | return ret; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | if (msg->insize > ec_dev->max_response) { | ||
354 | dev_dbg(ec_dev->dev, "clamping message receive buffer\n"); | ||
355 | msg->insize = ec_dev->max_response; | ||
356 | } | ||
357 | |||
358 | if (msg->command < EC_CMD_PASSTHRU_OFFSET(1)) { | ||
359 | if (msg->outsize > ec_dev->max_request) { | ||
360 | dev_err(ec_dev->dev, | ||
361 | "request of size %u is too big (max: %u)\n", | ||
362 | msg->outsize, | ||
363 | ec_dev->max_request); | ||
364 | mutex_unlock(&ec_dev->lock); | ||
365 | return -EMSGSIZE; | ||
366 | } | ||
367 | } else { | ||
368 | if (msg->outsize > ec_dev->max_passthru) { | ||
369 | dev_err(ec_dev->dev, | ||
370 | "passthru rq of size %u is too big (max: %u)\n", | ||
371 | msg->outsize, | ||
372 | ec_dev->max_passthru); | ||
373 | mutex_unlock(&ec_dev->lock); | ||
374 | return -EMSGSIZE; | ||
375 | } | ||
376 | } | ||
377 | ret = send_command(ec_dev, msg); | ||
378 | mutex_unlock(&ec_dev->lock); | ||
379 | |||
380 | return ret; | ||
381 | } | ||
382 | EXPORT_SYMBOL(cros_ec_cmd_xfer); | ||
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index fb62ab6cc659..f3baf9973989 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/printk.h> | 31 | #include <linux/printk.h> |
32 | #include <linux/slab.h> | ||
32 | #include <linux/stat.h> | 33 | #include <linux/stat.h> |
33 | #include <linux/types.h> | 34 | #include <linux/types.h> |
34 | #include <linux/uaccess.h> | 35 | #include <linux/uaccess.h> |
@@ -66,13 +67,19 @@ static ssize_t store_ec_reboot(struct device *dev, | |||
66 | {"hibernate", EC_REBOOT_HIBERNATE, 0}, | 67 | {"hibernate", EC_REBOOT_HIBERNATE, 0}, |
67 | {"at-shutdown", -1, EC_REBOOT_FLAG_ON_AP_SHUTDOWN}, | 68 | {"at-shutdown", -1, EC_REBOOT_FLAG_ON_AP_SHUTDOWN}, |
68 | }; | 69 | }; |
69 | struct cros_ec_command msg = { 0 }; | 70 | struct cros_ec_command *msg; |
70 | struct ec_params_reboot_ec *param = | 71 | struct ec_params_reboot_ec *param; |
71 | (struct ec_params_reboot_ec *)msg.outdata; | ||
72 | int got_cmd = 0, offset = 0; | 72 | int got_cmd = 0, offset = 0; |
73 | int i; | 73 | int i; |
74 | int ret; | 74 | int ret; |
75 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 75 | struct cros_ec_dev *ec = container_of(dev, |
76 | struct cros_ec_dev, class_dev); | ||
77 | |||
78 | msg = kmalloc(sizeof(*msg) + sizeof(*param), GFP_KERNEL); | ||
79 | if (!msg) | ||
80 | return -ENOMEM; | ||
81 | |||
82 | param = (struct ec_params_reboot_ec *)msg->data; | ||
76 | 83 | ||
77 | param->flags = 0; | 84 | param->flags = 0; |
78 | while (1) { | 85 | while (1) { |
@@ -100,19 +107,26 @@ static ssize_t store_ec_reboot(struct device *dev, | |||
100 | offset++; | 107 | offset++; |
101 | } | 108 | } |
102 | 109 | ||
103 | if (!got_cmd) | 110 | if (!got_cmd) { |
104 | return -EINVAL; | 111 | count = -EINVAL; |
105 | 112 | goto exit; | |
106 | msg.command = EC_CMD_REBOOT_EC; | ||
107 | msg.outsize = sizeof(param); | ||
108 | ret = cros_ec_cmd_xfer(ec, &msg); | ||
109 | if (ret < 0) | ||
110 | return ret; | ||
111 | if (msg.result != EC_RES_SUCCESS) { | ||
112 | dev_dbg(ec->dev, "EC result %d\n", msg.result); | ||
113 | return -EINVAL; | ||
114 | } | 113 | } |
115 | 114 | ||
115 | msg->version = 0; | ||
116 | msg->command = EC_CMD_REBOOT_EC + ec->cmd_offset; | ||
117 | msg->outsize = sizeof(*param); | ||
118 | msg->insize = 0; | ||
119 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); | ||
120 | if (ret < 0) { | ||
121 | count = ret; | ||
122 | goto exit; | ||
123 | } | ||
124 | if (msg->result != EC_RES_SUCCESS) { | ||
125 | dev_dbg(ec->dev, "EC result %d\n", msg->result); | ||
126 | count = -EINVAL; | ||
127 | } | ||
128 | exit: | ||
129 | kfree(msg); | ||
116 | return count; | 130 | return count; |
117 | } | 131 | } |
118 | 132 | ||
@@ -123,22 +137,33 @@ static ssize_t show_ec_version(struct device *dev, | |||
123 | struct ec_response_get_version *r_ver; | 137 | struct ec_response_get_version *r_ver; |
124 | struct ec_response_get_chip_info *r_chip; | 138 | struct ec_response_get_chip_info *r_chip; |
125 | struct ec_response_board_version *r_board; | 139 | struct ec_response_board_version *r_board; |
126 | struct cros_ec_command msg = { 0 }; | 140 | struct cros_ec_command *msg; |
127 | int ret; | 141 | int ret; |
128 | int count = 0; | 142 | int count = 0; |
129 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 143 | struct cros_ec_dev *ec = container_of(dev, |
144 | struct cros_ec_dev, class_dev); | ||
145 | |||
146 | msg = kmalloc(sizeof(*msg) + EC_HOST_PARAM_SIZE, GFP_KERNEL); | ||
147 | if (!msg) | ||
148 | return -ENOMEM; | ||
130 | 149 | ||
131 | /* Get versions. RW may change. */ | 150 | /* Get versions. RW may change. */ |
132 | msg.command = EC_CMD_GET_VERSION; | 151 | msg->version = 0; |
133 | msg.insize = sizeof(*r_ver); | 152 | msg->command = EC_CMD_GET_VERSION + ec->cmd_offset; |
134 | ret = cros_ec_cmd_xfer(ec, &msg); | 153 | msg->insize = sizeof(*r_ver); |
135 | if (ret < 0) | 154 | msg->outsize = 0; |
136 | return ret; | 155 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); |
137 | if (msg.result != EC_RES_SUCCESS) | 156 | if (ret < 0) { |
138 | return scnprintf(buf, PAGE_SIZE, | 157 | count = ret; |
139 | "ERROR: EC returned %d\n", msg.result); | 158 | goto exit; |
159 | } | ||
160 | if (msg->result != EC_RES_SUCCESS) { | ||
161 | count = scnprintf(buf, PAGE_SIZE, | ||
162 | "ERROR: EC returned %d\n", msg->result); | ||
163 | goto exit; | ||
164 | } | ||
140 | 165 | ||
141 | r_ver = (struct ec_response_get_version *)msg.indata; | 166 | r_ver = (struct ec_response_get_version *)msg->data; |
142 | /* Strings should be null-terminated, but let's be sure. */ | 167 | /* Strings should be null-terminated, but let's be sure. */ |
143 | r_ver->version_string_ro[sizeof(r_ver->version_string_ro) - 1] = '\0'; | 168 | r_ver->version_string_ro[sizeof(r_ver->version_string_ro) - 1] = '\0'; |
144 | r_ver->version_string_rw[sizeof(r_ver->version_string_rw) - 1] = '\0'; | 169 | r_ver->version_string_rw[sizeof(r_ver->version_string_rw) - 1] = '\0'; |
@@ -152,33 +177,33 @@ static ssize_t show_ec_version(struct device *dev, | |||
152 | image_names[r_ver->current_image] : "?")); | 177 | image_names[r_ver->current_image] : "?")); |
153 | 178 | ||
154 | /* Get build info. */ | 179 | /* Get build info. */ |
155 | msg.command = EC_CMD_GET_BUILD_INFO; | 180 | msg->command = EC_CMD_GET_BUILD_INFO + ec->cmd_offset; |
156 | msg.insize = sizeof(msg.indata); | 181 | msg->insize = EC_HOST_PARAM_SIZE; |
157 | ret = cros_ec_cmd_xfer(ec, &msg); | 182 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); |
158 | if (ret < 0) | 183 | if (ret < 0) |
159 | count += scnprintf(buf + count, PAGE_SIZE - count, | 184 | count += scnprintf(buf + count, PAGE_SIZE - count, |
160 | "Build info: XFER ERROR %d\n", ret); | 185 | "Build info: XFER ERROR %d\n", ret); |
161 | else if (msg.result != EC_RES_SUCCESS) | 186 | else if (msg->result != EC_RES_SUCCESS) |
162 | count += scnprintf(buf + count, PAGE_SIZE - count, | 187 | count += scnprintf(buf + count, PAGE_SIZE - count, |
163 | "Build info: EC error %d\n", msg.result); | 188 | "Build info: EC error %d\n", msg->result); |
164 | else { | 189 | else { |
165 | msg.indata[sizeof(msg.indata) - 1] = '\0'; | 190 | msg->data[sizeof(msg->data) - 1] = '\0'; |
166 | count += scnprintf(buf + count, PAGE_SIZE - count, | 191 | count += scnprintf(buf + count, PAGE_SIZE - count, |
167 | "Build info: %s\n", msg.indata); | 192 | "Build info: %s\n", msg->data); |
168 | } | 193 | } |
169 | 194 | ||
170 | /* Get chip info. */ | 195 | /* Get chip info. */ |
171 | msg.command = EC_CMD_GET_CHIP_INFO; | 196 | msg->command = EC_CMD_GET_CHIP_INFO + ec->cmd_offset; |
172 | msg.insize = sizeof(*r_chip); | 197 | msg->insize = sizeof(*r_chip); |
173 | ret = cros_ec_cmd_xfer(ec, &msg); | 198 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); |
174 | if (ret < 0) | 199 | if (ret < 0) |
175 | count += scnprintf(buf + count, PAGE_SIZE - count, | 200 | count += scnprintf(buf + count, PAGE_SIZE - count, |
176 | "Chip info: XFER ERROR %d\n", ret); | 201 | "Chip info: XFER ERROR %d\n", ret); |
177 | else if (msg.result != EC_RES_SUCCESS) | 202 | else if (msg->result != EC_RES_SUCCESS) |
178 | count += scnprintf(buf + count, PAGE_SIZE - count, | 203 | count += scnprintf(buf + count, PAGE_SIZE - count, |
179 | "Chip info: EC error %d\n", msg.result); | 204 | "Chip info: EC error %d\n", msg->result); |
180 | else { | 205 | else { |
181 | r_chip = (struct ec_response_get_chip_info *)msg.indata; | 206 | r_chip = (struct ec_response_get_chip_info *)msg->data; |
182 | 207 | ||
183 | r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0'; | 208 | r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0'; |
184 | r_chip->name[sizeof(r_chip->name) - 1] = '\0'; | 209 | r_chip->name[sizeof(r_chip->name) - 1] = '\0'; |
@@ -192,23 +217,25 @@ static ssize_t show_ec_version(struct device *dev, | |||
192 | } | 217 | } |
193 | 218 | ||
194 | /* Get board version */ | 219 | /* Get board version */ |
195 | msg.command = EC_CMD_GET_BOARD_VERSION; | 220 | msg->command = EC_CMD_GET_BOARD_VERSION + ec->cmd_offset; |
196 | msg.insize = sizeof(*r_board); | 221 | msg->insize = sizeof(*r_board); |
197 | ret = cros_ec_cmd_xfer(ec, &msg); | 222 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); |
198 | if (ret < 0) | 223 | if (ret < 0) |
199 | count += scnprintf(buf + count, PAGE_SIZE - count, | 224 | count += scnprintf(buf + count, PAGE_SIZE - count, |
200 | "Board version: XFER ERROR %d\n", ret); | 225 | "Board version: XFER ERROR %d\n", ret); |
201 | else if (msg.result != EC_RES_SUCCESS) | 226 | else if (msg->result != EC_RES_SUCCESS) |
202 | count += scnprintf(buf + count, PAGE_SIZE - count, | 227 | count += scnprintf(buf + count, PAGE_SIZE - count, |
203 | "Board version: EC error %d\n", msg.result); | 228 | "Board version: EC error %d\n", msg->result); |
204 | else { | 229 | else { |
205 | r_board = (struct ec_response_board_version *)msg.indata; | 230 | r_board = (struct ec_response_board_version *)msg->data; |
206 | 231 | ||
207 | count += scnprintf(buf + count, PAGE_SIZE - count, | 232 | count += scnprintf(buf + count, PAGE_SIZE - count, |
208 | "Board version: %d\n", | 233 | "Board version: %d\n", |
209 | r_board->board_version); | 234 | r_board->board_version); |
210 | } | 235 | } |
211 | 236 | ||
237 | exit: | ||
238 | kfree(msg); | ||
212 | return count; | 239 | return count; |
213 | } | 240 | } |
214 | 241 | ||
@@ -216,27 +243,39 @@ static ssize_t show_ec_flashinfo(struct device *dev, | |||
216 | struct device_attribute *attr, char *buf) | 243 | struct device_attribute *attr, char *buf) |
217 | { | 244 | { |
218 | struct ec_response_flash_info *resp; | 245 | struct ec_response_flash_info *resp; |
219 | struct cros_ec_command msg = { 0 }; | 246 | struct cros_ec_command *msg; |
220 | int ret; | 247 | int ret; |
221 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 248 | struct cros_ec_dev *ec = container_of(dev, |
249 | struct cros_ec_dev, class_dev); | ||
250 | |||
251 | msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); | ||
252 | if (!msg) | ||
253 | return -ENOMEM; | ||
222 | 254 | ||
223 | /* The flash info shouldn't ever change, but ask each time anyway. */ | 255 | /* The flash info shouldn't ever change, but ask each time anyway. */ |
224 | msg.command = EC_CMD_FLASH_INFO; | 256 | msg->version = 0; |
225 | msg.insize = sizeof(*resp); | 257 | msg->command = EC_CMD_FLASH_INFO + ec->cmd_offset; |
226 | ret = cros_ec_cmd_xfer(ec, &msg); | 258 | msg->insize = sizeof(*resp); |
259 | msg->outsize = 0; | ||
260 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); | ||
227 | if (ret < 0) | 261 | if (ret < 0) |
228 | return ret; | 262 | goto exit; |
229 | if (msg.result != EC_RES_SUCCESS) | 263 | if (msg->result != EC_RES_SUCCESS) { |
230 | return scnprintf(buf, PAGE_SIZE, | 264 | ret = scnprintf(buf, PAGE_SIZE, |
231 | "ERROR: EC returned %d\n", msg.result); | 265 | "ERROR: EC returned %d\n", msg->result); |
232 | 266 | goto exit; | |
233 | resp = (struct ec_response_flash_info *)msg.indata; | 267 | } |
234 | 268 | ||
235 | return scnprintf(buf, PAGE_SIZE, | 269 | resp = (struct ec_response_flash_info *)msg->data; |
236 | "FlashSize %d\nWriteSize %d\n" | 270 | |
237 | "EraseSize %d\nProtectSize %d\n", | 271 | ret = scnprintf(buf, PAGE_SIZE, |
238 | resp->flash_size, resp->write_block_size, | 272 | "FlashSize %d\nWriteSize %d\n" |
239 | resp->erase_block_size, resp->protect_block_size); | 273 | "EraseSize %d\nProtectSize %d\n", |
274 | resp->flash_size, resp->write_block_size, | ||
275 | resp->erase_block_size, resp->protect_block_size); | ||
276 | exit: | ||
277 | kfree(msg); | ||
278 | return ret; | ||
240 | } | 279 | } |
241 | 280 | ||
242 | /* Module initialization */ | 281 | /* Module initialization */ |
@@ -252,20 +291,7 @@ static struct attribute *__ec_attrs[] = { | |||
252 | NULL, | 291 | NULL, |
253 | }; | 292 | }; |
254 | 293 | ||
255 | static struct attribute_group ec_attr_group = { | 294 | struct attribute_group cros_ec_attr_group = { |
256 | .attrs = __ec_attrs, | 295 | .attrs = __ec_attrs, |
257 | }; | 296 | }; |
258 | 297 | ||
259 | void ec_dev_sysfs_init(struct cros_ec_device *ec) | ||
260 | { | ||
261 | int error; | ||
262 | |||
263 | error = sysfs_create_group(&ec->vdev->kobj, &ec_attr_group); | ||
264 | if (error) | ||
265 | pr_warn("failed to create group: %d\n", error); | ||
266 | } | ||
267 | |||
268 | void ec_dev_sysfs_remove(struct cros_ec_device *ec) | ||
269 | { | ||
270 | sysfs_remove_group(&ec->vdev->kobj, &ec_attr_group); | ||
271 | } | ||
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index e4331f5e5d7d..646829132b59 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c | |||
@@ -27,20 +27,24 @@ | |||
27 | #define AXP20X_IO_ENABLED 0x03 | 27 | #define AXP20X_IO_ENABLED 0x03 |
28 | #define AXP20X_IO_DISABLED 0x07 | 28 | #define AXP20X_IO_DISABLED 0x07 |
29 | 29 | ||
30 | #define AXP22X_IO_ENABLED 0x04 | ||
31 | #define AXP22X_IO_DISABLED 0x03 | ||
32 | |||
30 | #define AXP20X_WORKMODE_DCDC2_MASK BIT(2) | 33 | #define AXP20X_WORKMODE_DCDC2_MASK BIT(2) |
31 | #define AXP20X_WORKMODE_DCDC3_MASK BIT(1) | 34 | #define AXP20X_WORKMODE_DCDC3_MASK BIT(1) |
35 | #define AXP22X_WORKMODE_DCDCX_MASK(x) BIT(x) | ||
32 | 36 | ||
33 | #define AXP20X_FREQ_DCDC_MASK 0x0f | 37 | #define AXP20X_FREQ_DCDC_MASK 0x0f |
34 | 38 | ||
35 | #define AXP20X_DESC_IO(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \ | 39 | #define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ |
36 | _ereg, _emask, _enable_val, _disable_val) \ | 40 | _vmask, _ereg, _emask, _enable_val, _disable_val) \ |
37 | [AXP20X_##_id] = { \ | 41 | [_family##_##_id] = { \ |
38 | .name = #_id, \ | 42 | .name = #_id, \ |
39 | .supply_name = (_supply), \ | 43 | .supply_name = (_supply), \ |
40 | .of_match = of_match_ptr(_match), \ | 44 | .of_match = of_match_ptr(_match), \ |
41 | .regulators_node = of_match_ptr("regulators"), \ | 45 | .regulators_node = of_match_ptr("regulators"), \ |
42 | .type = REGULATOR_VOLTAGE, \ | 46 | .type = REGULATOR_VOLTAGE, \ |
43 | .id = AXP20X_##_id, \ | 47 | .id = _family##_##_id, \ |
44 | .n_voltages = (((_max) - (_min)) / (_step) + 1), \ | 48 | .n_voltages = (((_max) - (_min)) / (_step) + 1), \ |
45 | .owner = THIS_MODULE, \ | 49 | .owner = THIS_MODULE, \ |
46 | .min_uV = (_min) * 1000, \ | 50 | .min_uV = (_min) * 1000, \ |
@@ -54,15 +58,15 @@ | |||
54 | .ops = &axp20x_ops, \ | 58 | .ops = &axp20x_ops, \ |
55 | } | 59 | } |
56 | 60 | ||
57 | #define AXP20X_DESC(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \ | 61 | #define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ |
58 | _ereg, _emask) \ | 62 | _vmask, _ereg, _emask) \ |
59 | [AXP20X_##_id] = { \ | 63 | [_family##_##_id] = { \ |
60 | .name = #_id, \ | 64 | .name = #_id, \ |
61 | .supply_name = (_supply), \ | 65 | .supply_name = (_supply), \ |
62 | .of_match = of_match_ptr(_match), \ | 66 | .of_match = of_match_ptr(_match), \ |
63 | .regulators_node = of_match_ptr("regulators"), \ | 67 | .regulators_node = of_match_ptr("regulators"), \ |
64 | .type = REGULATOR_VOLTAGE, \ | 68 | .type = REGULATOR_VOLTAGE, \ |
65 | .id = AXP20X_##_id, \ | 69 | .id = _family##_##_id, \ |
66 | .n_voltages = (((_max) - (_min)) / (_step) + 1), \ | 70 | .n_voltages = (((_max) - (_min)) / (_step) + 1), \ |
67 | .owner = THIS_MODULE, \ | 71 | .owner = THIS_MODULE, \ |
68 | .min_uV = (_min) * 1000, \ | 72 | .min_uV = (_min) * 1000, \ |
@@ -74,29 +78,49 @@ | |||
74 | .ops = &axp20x_ops, \ | 78 | .ops = &axp20x_ops, \ |
75 | } | 79 | } |
76 | 80 | ||
77 | #define AXP20X_DESC_FIXED(_id, _match, _supply, _volt) \ | 81 | #define AXP_DESC_SW(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ |
78 | [AXP20X_##_id] = { \ | 82 | _vmask, _ereg, _emask) \ |
83 | [_family##_##_id] = { \ | ||
79 | .name = #_id, \ | 84 | .name = #_id, \ |
80 | .supply_name = (_supply), \ | 85 | .supply_name = (_supply), \ |
81 | .of_match = of_match_ptr(_match), \ | 86 | .of_match = of_match_ptr(_match), \ |
82 | .regulators_node = of_match_ptr("regulators"), \ | 87 | .regulators_node = of_match_ptr("regulators"), \ |
83 | .type = REGULATOR_VOLTAGE, \ | 88 | .type = REGULATOR_VOLTAGE, \ |
84 | .id = AXP20X_##_id, \ | 89 | .id = _family##_##_id, \ |
90 | .n_voltages = (((_max) - (_min)) / (_step) + 1), \ | ||
91 | .owner = THIS_MODULE, \ | ||
92 | .min_uV = (_min) * 1000, \ | ||
93 | .uV_step = (_step) * 1000, \ | ||
94 | .vsel_reg = (_vreg), \ | ||
95 | .vsel_mask = (_vmask), \ | ||
96 | .enable_reg = (_ereg), \ | ||
97 | .enable_mask = (_emask), \ | ||
98 | .ops = &axp20x_ops_sw, \ | ||
99 | } | ||
100 | |||
101 | #define AXP_DESC_FIXED(_family, _id, _match, _supply, _volt) \ | ||
102 | [_family##_##_id] = { \ | ||
103 | .name = #_id, \ | ||
104 | .supply_name = (_supply), \ | ||
105 | .of_match = of_match_ptr(_match), \ | ||
106 | .regulators_node = of_match_ptr("regulators"), \ | ||
107 | .type = REGULATOR_VOLTAGE, \ | ||
108 | .id = _family##_##_id, \ | ||
85 | .n_voltages = 1, \ | 109 | .n_voltages = 1, \ |
86 | .owner = THIS_MODULE, \ | 110 | .owner = THIS_MODULE, \ |
87 | .min_uV = (_volt) * 1000, \ | 111 | .min_uV = (_volt) * 1000, \ |
88 | .ops = &axp20x_ops_fixed \ | 112 | .ops = &axp20x_ops_fixed \ |
89 | } | 113 | } |
90 | 114 | ||
91 | #define AXP20X_DESC_TABLE(_id, _match, _supply, _table, _vreg, _vmask, _ereg, \ | 115 | #define AXP_DESC_TABLE(_family, _id, _match, _supply, _table, _vreg, _vmask, \ |
92 | _emask) \ | 116 | _ereg, _emask) \ |
93 | [AXP20X_##_id] = { \ | 117 | [_family##_##_id] = { \ |
94 | .name = #_id, \ | 118 | .name = #_id, \ |
95 | .supply_name = (_supply), \ | 119 | .supply_name = (_supply), \ |
96 | .of_match = of_match_ptr(_match), \ | 120 | .of_match = of_match_ptr(_match), \ |
97 | .regulators_node = of_match_ptr("regulators"), \ | 121 | .regulators_node = of_match_ptr("regulators"), \ |
98 | .type = REGULATOR_VOLTAGE, \ | 122 | .type = REGULATOR_VOLTAGE, \ |
99 | .id = AXP20X_##_id, \ | 123 | .id = _family##_##_id, \ |
100 | .n_voltages = ARRAY_SIZE(_table), \ | 124 | .n_voltages = ARRAY_SIZE(_table), \ |
101 | .owner = THIS_MODULE, \ | 125 | .owner = THIS_MODULE, \ |
102 | .vsel_reg = (_vreg), \ | 126 | .vsel_reg = (_vreg), \ |
@@ -135,38 +159,118 @@ static struct regulator_ops axp20x_ops = { | |||
135 | .is_enabled = regulator_is_enabled_regmap, | 159 | .is_enabled = regulator_is_enabled_regmap, |
136 | }; | 160 | }; |
137 | 161 | ||
162 | static struct regulator_ops axp20x_ops_sw = { | ||
163 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | ||
164 | .list_voltage = regulator_list_voltage_linear, | ||
165 | .enable = regulator_enable_regmap, | ||
166 | .disable = regulator_disable_regmap, | ||
167 | .is_enabled = regulator_is_enabled_regmap, | ||
168 | }; | ||
169 | |||
138 | static const struct regulator_desc axp20x_regulators[] = { | 170 | static const struct regulator_desc axp20x_regulators[] = { |
139 | AXP20X_DESC(DCDC2, "dcdc2", "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, | 171 | AXP_DESC(AXP20X, DCDC2, "dcdc2", "vin2", 700, 2275, 25, |
140 | 0x3f, AXP20X_PWR_OUT_CTRL, 0x10), | 172 | AXP20X_DCDC2_V_OUT, 0x3f, AXP20X_PWR_OUT_CTRL, 0x10), |
141 | AXP20X_DESC(DCDC3, "dcdc3", "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, | 173 | AXP_DESC(AXP20X, DCDC3, "dcdc3", "vin3", 700, 3500, 25, |
142 | 0x7f, AXP20X_PWR_OUT_CTRL, 0x02), | 174 | AXP20X_DCDC3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x02), |
143 | AXP20X_DESC_FIXED(LDO1, "ldo1", "acin", 1300), | 175 | AXP_DESC_FIXED(AXP20X, LDO1, "ldo1", "acin", 1300), |
144 | AXP20X_DESC(LDO2, "ldo2", "ldo24in", 1800, 3300, 100, | 176 | AXP_DESC(AXP20X, LDO2, "ldo2", "ldo24in", 1800, 3300, 100, |
145 | AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04), | 177 | AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04), |
146 | AXP20X_DESC(LDO3, "ldo3", "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, | 178 | AXP_DESC(AXP20X, LDO3, "ldo3", "ldo3in", 700, 3500, 25, |
147 | 0x7f, AXP20X_PWR_OUT_CTRL, 0x40), | 179 | AXP20X_LDO3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x40), |
148 | AXP20X_DESC_TABLE(LDO4, "ldo4", "ldo24in", axp20x_ldo4_data, | 180 | AXP_DESC_TABLE(AXP20X, LDO4, "ldo4", "ldo24in", axp20x_ldo4_data, |
149 | AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08), | 181 | AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08), |
150 | AXP20X_DESC_IO(LDO5, "ldo5", "ldo5in", 1800, 3300, 100, | 182 | AXP_DESC_IO(AXP20X, LDO5, "ldo5", "ldo5in", 1800, 3300, 100, |
151 | AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07, | 183 | AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07, |
152 | AXP20X_IO_ENABLED, AXP20X_IO_DISABLED), | 184 | AXP20X_IO_ENABLED, AXP20X_IO_DISABLED), |
185 | }; | ||
186 | |||
187 | static const struct regulator_desc axp22x_regulators[] = { | ||
188 | AXP_DESC(AXP22X, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, | ||
189 | AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)), | ||
190 | AXP_DESC(AXP22X, DCDC2, "dcdc2", "vin2", 600, 1540, 20, | ||
191 | AXP22X_DCDC2_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(2)), | ||
192 | AXP_DESC(AXP22X, DCDC3, "dcdc3", "vin3", 600, 1860, 20, | ||
193 | AXP22X_DCDC3_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)), | ||
194 | AXP_DESC(AXP22X, DCDC4, "dcdc4", "vin4", 600, 1540, 20, | ||
195 | AXP22X_DCDC4_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)), | ||
196 | AXP_DESC(AXP22X, DCDC5, "dcdc5", "vin5", 1000, 2550, 50, | ||
197 | AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(4)), | ||
198 | /* secondary switchable output of DCDC1 */ | ||
199 | AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", "dcdc1", 1600, 3400, 100, | ||
200 | AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(7)), | ||
201 | /* LDO regulator internally chained to DCDC5 */ | ||
202 | AXP_DESC(AXP22X, DC5LDO, "dc5ldo", "dcdc5", 700, 1400, 100, | ||
203 | AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)), | ||
204 | AXP_DESC(AXP22X, ALDO1, "aldo1", "aldoin", 700, 3300, 100, | ||
205 | AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)), | ||
206 | AXP_DESC(AXP22X, ALDO2, "aldo2", "aldoin", 700, 3300, 100, | ||
207 | AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), | ||
208 | AXP_DESC(AXP22X, ALDO3, "aldo3", "aldoin", 700, 3300, 100, | ||
209 | AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)), | ||
210 | AXP_DESC(AXP22X, DLDO1, "dldo1", "dldoin", 700, 3300, 100, | ||
211 | AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)), | ||
212 | AXP_DESC(AXP22X, DLDO2, "dldo2", "dldoin", 700, 3300, 100, | ||
213 | AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(4)), | ||
214 | AXP_DESC(AXP22X, DLDO3, "dldo3", "dldoin", 700, 3300, 100, | ||
215 | AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), | ||
216 | AXP_DESC(AXP22X, DLDO4, "dldo4", "dldoin", 700, 3300, 100, | ||
217 | AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)), | ||
218 | AXP_DESC(AXP22X, ELDO1, "eldo1", "eldoin", 700, 3300, 100, | ||
219 | AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)), | ||
220 | AXP_DESC(AXP22X, ELDO2, "eldo2", "eldoin", 700, 3300, 100, | ||
221 | AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)), | ||
222 | AXP_DESC(AXP22X, ELDO3, "eldo3", "eldoin", 700, 3300, 100, | ||
223 | AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)), | ||
224 | AXP_DESC_IO(AXP22X, LDO_IO0, "ldo_io0", "ips", 1800, 3300, 100, | ||
225 | AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07, | ||
226 | AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), | ||
227 | AXP_DESC_IO(AXP22X, LDO_IO1, "ldo_io1", "ips", 1800, 3300, 100, | ||
228 | AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07, | ||
229 | AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), | ||
230 | AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000), | ||
153 | }; | 231 | }; |
154 | 232 | ||
155 | static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) | 233 | static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) |
156 | { | 234 | { |
157 | struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); | 235 | struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); |
236 | u32 min, max, def, step; | ||
237 | |||
238 | switch (axp20x->variant) { | ||
239 | case AXP202_ID: | ||
240 | case AXP209_ID: | ||
241 | min = 750; | ||
242 | max = 1875; | ||
243 | def = 1500; | ||
244 | step = 75; | ||
245 | break; | ||
246 | case AXP221_ID: | ||
247 | min = 1800; | ||
248 | max = 4050; | ||
249 | def = 3000; | ||
250 | step = 150; | ||
251 | break; | ||
252 | default: | ||
253 | dev_err(&pdev->dev, | ||
254 | "Setting DCDC frequency for unsupported AXP variant\n"); | ||
255 | return -EINVAL; | ||
256 | } | ||
257 | |||
258 | if (dcdcfreq == 0) | ||
259 | dcdcfreq = def; | ||
158 | 260 | ||
159 | if (dcdcfreq < 750) { | 261 | if (dcdcfreq < min) { |
160 | dcdcfreq = 750; | 262 | dcdcfreq = min; |
161 | dev_warn(&pdev->dev, "DCDC frequency too low. Set to 750kHz\n"); | 263 | dev_warn(&pdev->dev, "DCDC frequency too low. Set to %ukHz\n", |
264 | min); | ||
162 | } | 265 | } |
163 | 266 | ||
164 | if (dcdcfreq > 1875) { | 267 | if (dcdcfreq > max) { |
165 | dcdcfreq = 1875; | 268 | dcdcfreq = max; |
166 | dev_warn(&pdev->dev, "DCDC frequency too high. Set to 1875kHz\n"); | 269 | dev_warn(&pdev->dev, "DCDC frequency too high. Set to %ukHz\n", |
270 | max); | ||
167 | } | 271 | } |
168 | 272 | ||
169 | dcdcfreq = (dcdcfreq - 750) / 75; | 273 | dcdcfreq = (dcdcfreq - min) / step; |
170 | 274 | ||
171 | return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ, | 275 | return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ, |
172 | AXP20X_FREQ_DCDC_MASK, dcdcfreq); | 276 | AXP20X_FREQ_DCDC_MASK, dcdcfreq); |
@@ -176,7 +280,7 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev) | |||
176 | { | 280 | { |
177 | struct device_node *np, *regulators; | 281 | struct device_node *np, *regulators; |
178 | int ret; | 282 | int ret; |
179 | u32 dcdcfreq; | 283 | u32 dcdcfreq = 0; |
180 | 284 | ||
181 | np = of_node_get(pdev->dev.parent->of_node); | 285 | np = of_node_get(pdev->dev.parent->of_node); |
182 | if (!np) | 286 | if (!np) |
@@ -186,7 +290,6 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev) | |||
186 | if (!regulators) { | 290 | if (!regulators) { |
187 | dev_warn(&pdev->dev, "regulators node not found\n"); | 291 | dev_warn(&pdev->dev, "regulators node not found\n"); |
188 | } else { | 292 | } else { |
189 | dcdcfreq = 1500; | ||
190 | of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq); | 293 | of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq); |
191 | ret = axp20x_set_dcdc_freq(pdev, dcdcfreq); | 294 | ret = axp20x_set_dcdc_freq(pdev, dcdcfreq); |
192 | if (ret < 0) { | 295 | if (ret < 0) { |
@@ -202,15 +305,35 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev) | |||
202 | 305 | ||
203 | static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode) | 306 | static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode) |
204 | { | 307 | { |
205 | unsigned int mask = AXP20X_WORKMODE_DCDC2_MASK; | 308 | struct axp20x_dev *axp20x = rdev_get_drvdata(rdev); |
309 | unsigned int mask; | ||
206 | 310 | ||
207 | if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3)) | 311 | switch (axp20x->variant) { |
208 | return -EINVAL; | 312 | case AXP202_ID: |
313 | case AXP209_ID: | ||
314 | if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3)) | ||
315 | return -EINVAL; | ||
316 | |||
317 | mask = AXP20X_WORKMODE_DCDC2_MASK; | ||
318 | if (id == AXP20X_DCDC3) | ||
319 | mask = AXP20X_WORKMODE_DCDC3_MASK; | ||
320 | |||
321 | workmode <<= ffs(mask) - 1; | ||
322 | break; | ||
209 | 323 | ||
210 | if (id == AXP20X_DCDC3) | 324 | case AXP221_ID: |
211 | mask = AXP20X_WORKMODE_DCDC3_MASK; | 325 | if (id < AXP22X_DCDC1 || id > AXP22X_DCDC5) |
326 | return -EINVAL; | ||
212 | 327 | ||
213 | workmode <<= ffs(mask) - 1; | 328 | mask = AXP22X_WORKMODE_DCDCX_MASK(id - AXP22X_DCDC1); |
329 | workmode <<= id - AXP22X_DCDC1; | ||
330 | break; | ||
331 | |||
332 | default: | ||
333 | /* should not happen */ | ||
334 | WARN_ON(1); | ||
335 | return -EINVAL; | ||
336 | } | ||
214 | 337 | ||
215 | return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode); | 338 | return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode); |
216 | } | 339 | } |
@@ -219,22 +342,40 @@ static int axp20x_regulator_probe(struct platform_device *pdev) | |||
219 | { | 342 | { |
220 | struct regulator_dev *rdev; | 343 | struct regulator_dev *rdev; |
221 | struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); | 344 | struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); |
345 | const struct regulator_desc *regulators; | ||
222 | struct regulator_config config = { | 346 | struct regulator_config config = { |
223 | .dev = pdev->dev.parent, | 347 | .dev = pdev->dev.parent, |
224 | .regmap = axp20x->regmap, | 348 | .regmap = axp20x->regmap, |
349 | .driver_data = axp20x, | ||
225 | }; | 350 | }; |
226 | int ret, i; | 351 | int ret, i, nregulators; |
227 | u32 workmode; | 352 | u32 workmode; |
228 | 353 | ||
354 | switch (axp20x->variant) { | ||
355 | case AXP202_ID: | ||
356 | case AXP209_ID: | ||
357 | regulators = axp20x_regulators; | ||
358 | nregulators = AXP20X_REG_ID_MAX; | ||
359 | break; | ||
360 | case AXP221_ID: | ||
361 | regulators = axp22x_regulators; | ||
362 | nregulators = AXP22X_REG_ID_MAX; | ||
363 | break; | ||
364 | default: | ||
365 | dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n", | ||
366 | axp20x->variant); | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
229 | /* This only sets the dcdc freq. Ignore any errors */ | 370 | /* This only sets the dcdc freq. Ignore any errors */ |
230 | axp20x_regulator_parse_dt(pdev); | 371 | axp20x_regulator_parse_dt(pdev); |
231 | 372 | ||
232 | for (i = 0; i < AXP20X_REG_ID_MAX; i++) { | 373 | for (i = 0; i < nregulators; i++) { |
233 | rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i], | 374 | rdev = devm_regulator_register(&pdev->dev, ®ulators[i], |
234 | &config); | 375 | &config); |
235 | if (IS_ERR(rdev)) { | 376 | if (IS_ERR(rdev)) { |
236 | dev_err(&pdev->dev, "Failed to register %s\n", | 377 | dev_err(&pdev->dev, "Failed to register %s\n", |
237 | axp20x_regulators[i].name); | 378 | regulators[i].name); |
238 | 379 | ||
239 | return PTR_ERR(rdev); | 380 | return PTR_ERR(rdev); |
240 | } | 381 | } |
@@ -245,7 +386,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) | |||
245 | if (!ret) { | 386 | if (!ret) { |
246 | if (axp20x_set_dcdc_workmode(rdev, i, workmode)) | 387 | if (axp20x_set_dcdc_workmode(rdev, i, workmode)) |
247 | dev_err(&pdev->dev, "Failed to set workmode on %s\n", | 388 | dev_err(&pdev->dev, "Failed to set workmode on %s\n", |
248 | axp20x_regulators[i].name); | 389 | rdev->desc->name); |
249 | } | 390 | } |
250 | } | 391 | } |
251 | 392 | ||
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 0fe4ad8826b2..5e963df9e565 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -1520,6 +1520,17 @@ config RTC_DRV_SIRFSOC | |||
1520 | Say "yes" here to support the real time clock on SiRF SOC chips. | 1520 | Say "yes" here to support the real time clock on SiRF SOC chips. |
1521 | This driver can also be built as a module called rtc-sirfsoc. | 1521 | This driver can also be built as a module called rtc-sirfsoc. |
1522 | 1522 | ||
1523 | config RTC_DRV_ST_LPC | ||
1524 | tristate "STMicroelectronics LPC RTC" | ||
1525 | depends on ARCH_STI | ||
1526 | depends on OF | ||
1527 | help | ||
1528 | Say Y here to include STMicroelectronics Low Power Controller | ||
1529 | (LPC) based RTC support. | ||
1530 | |||
1531 | To compile this driver as a module, choose M here: the | ||
1532 | module will be called rtc-st-lpc. | ||
1533 | |||
1523 | config RTC_DRV_MOXART | 1534 | config RTC_DRV_MOXART |
1524 | tristate "MOXA ART RTC" | 1535 | tristate "MOXA ART RTC" |
1525 | depends on ARCH_MOXART || COMPILE_TEST | 1536 | depends on ARCH_MOXART || COMPILE_TEST |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 2b82e2b0311b..ebe2c085d01c 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -154,4 +154,5 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o | |||
154 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o | 154 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o |
155 | obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o | 155 | obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o |
156 | obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o | 156 | obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o |
157 | obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o | ||
157 | obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o | 158 | obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o |
diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c new file mode 100644 index 000000000000..3f9d0acb81c7 --- /dev/null +++ b/drivers/rtc/rtc-st-lpc.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | * rtc-st-lpc.c - ST's LPC RTC, powered by the Low Power Timer | ||
3 | * | ||
4 | * Copyright (C) 2014 STMicroelectronics Limited | ||
5 | * | ||
6 | * Author: David Paris <david.paris@st.com> for STMicroelectronics | ||
7 | * Lee Jones <lee.jones@linaro.org> for STMicroelectronics | ||
8 | * | ||
9 | * Based on the original driver written by Stuart Menefy. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public Licence | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the Licence, or (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/of_irq.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/rtc.h> | ||
28 | |||
29 | #include <dt-bindings/mfd/st-lpc.h> | ||
30 | |||
31 | /* Low Power Timer */ | ||
32 | #define LPC_LPT_LSB_OFF 0x400 | ||
33 | #define LPC_LPT_MSB_OFF 0x404 | ||
34 | #define LPC_LPT_START_OFF 0x408 | ||
35 | |||
36 | /* Low Power Alarm */ | ||
37 | #define LPC_LPA_LSB_OFF 0x410 | ||
38 | #define LPC_LPA_MSB_OFF 0x414 | ||
39 | #define LPC_LPA_START_OFF 0x418 | ||
40 | |||
41 | /* LPC as WDT */ | ||
42 | #define LPC_WDT_OFF 0x510 | ||
43 | #define LPC_WDT_FLAG_OFF 0x514 | ||
44 | |||
45 | struct st_rtc { | ||
46 | struct rtc_device *rtc_dev; | ||
47 | struct rtc_wkalrm alarm; | ||
48 | struct resource *res; | ||
49 | struct clk *clk; | ||
50 | unsigned long clkrate; | ||
51 | void __iomem *ioaddr; | ||
52 | bool irq_enabled:1; | ||
53 | spinlock_t lock; | ||
54 | short irq; | ||
55 | }; | ||
56 | |||
57 | static void st_rtc_set_hw_alarm(struct st_rtc *rtc, | ||
58 | unsigned long msb, unsigned long lsb) | ||
59 | { | ||
60 | unsigned long flags; | ||
61 | |||
62 | spin_lock_irqsave(&rtc->lock, flags); | ||
63 | |||
64 | writel_relaxed(1, rtc->ioaddr + LPC_WDT_OFF); | ||
65 | |||
66 | writel_relaxed(msb, rtc->ioaddr + LPC_LPA_MSB_OFF); | ||
67 | writel_relaxed(lsb, rtc->ioaddr + LPC_LPA_LSB_OFF); | ||
68 | writel_relaxed(1, rtc->ioaddr + LPC_LPA_START_OFF); | ||
69 | |||
70 | writel_relaxed(0, rtc->ioaddr + LPC_WDT_OFF); | ||
71 | |||
72 | spin_unlock_irqrestore(&rtc->lock, flags); | ||
73 | } | ||
74 | |||
75 | static irqreturn_t st_rtc_handler(int this_irq, void *data) | ||
76 | { | ||
77 | struct st_rtc *rtc = (struct st_rtc *)data; | ||
78 | |||
79 | rtc_update_irq(rtc->rtc_dev, 1, RTC_AF); | ||
80 | |||
81 | return IRQ_HANDLED; | ||
82 | } | ||
83 | |||
84 | static int st_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
85 | { | ||
86 | struct st_rtc *rtc = dev_get_drvdata(dev); | ||
87 | unsigned long lpt_lsb, lpt_msb; | ||
88 | unsigned long long lpt; | ||
89 | unsigned long flags; | ||
90 | |||
91 | spin_lock_irqsave(&rtc->lock, flags); | ||
92 | |||
93 | do { | ||
94 | lpt_msb = readl_relaxed(rtc->ioaddr + LPC_LPT_MSB_OFF); | ||
95 | lpt_lsb = readl_relaxed(rtc->ioaddr + LPC_LPT_LSB_OFF); | ||
96 | } while (readl_relaxed(rtc->ioaddr + LPC_LPT_MSB_OFF) != lpt_msb); | ||
97 | |||
98 | spin_unlock_irqrestore(&rtc->lock, flags); | ||
99 | |||
100 | lpt = ((unsigned long long)lpt_msb << 32) | lpt_lsb; | ||
101 | do_div(lpt, rtc->clkrate); | ||
102 | rtc_time_to_tm(lpt, tm); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int st_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
108 | { | ||
109 | struct st_rtc *rtc = dev_get_drvdata(dev); | ||
110 | unsigned long long lpt; | ||
111 | unsigned long secs, flags; | ||
112 | int ret; | ||
113 | |||
114 | ret = rtc_tm_to_time(tm, &secs); | ||
115 | if (ret) | ||
116 | return ret; | ||
117 | |||
118 | lpt = (unsigned long long)secs * rtc->clkrate; | ||
119 | |||
120 | spin_lock_irqsave(&rtc->lock, flags); | ||
121 | |||
122 | writel_relaxed(lpt >> 32, rtc->ioaddr + LPC_LPT_MSB_OFF); | ||
123 | writel_relaxed(lpt, rtc->ioaddr + LPC_LPT_LSB_OFF); | ||
124 | writel_relaxed(1, rtc->ioaddr + LPC_LPT_START_OFF); | ||
125 | |||
126 | spin_unlock_irqrestore(&rtc->lock, flags); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int st_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) | ||
132 | { | ||
133 | struct st_rtc *rtc = dev_get_drvdata(dev); | ||
134 | unsigned long flags; | ||
135 | |||
136 | spin_lock_irqsave(&rtc->lock, flags); | ||
137 | |||
138 | memcpy(wkalrm, &rtc->alarm, sizeof(struct rtc_wkalrm)); | ||
139 | |||
140 | spin_unlock_irqrestore(&rtc->lock, flags); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int st_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
146 | { | ||
147 | struct st_rtc *rtc = dev_get_drvdata(dev); | ||
148 | |||
149 | if (enabled && !rtc->irq_enabled) { | ||
150 | enable_irq(rtc->irq); | ||
151 | rtc->irq_enabled = true; | ||
152 | } else if (!enabled && rtc->irq_enabled) { | ||
153 | disable_irq(rtc->irq); | ||
154 | rtc->irq_enabled = false; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) | ||
161 | { | ||
162 | struct st_rtc *rtc = dev_get_drvdata(dev); | ||
163 | struct rtc_time now; | ||
164 | unsigned long now_secs; | ||
165 | unsigned long alarm_secs; | ||
166 | unsigned long long lpa; | ||
167 | |||
168 | st_rtc_read_time(dev, &now); | ||
169 | rtc_tm_to_time(&now, &now_secs); | ||
170 | rtc_tm_to_time(&t->time, &alarm_secs); | ||
171 | |||
172 | /* Invalid alarm time */ | ||
173 | if (now_secs > alarm_secs) | ||
174 | return -EINVAL; | ||
175 | |||
176 | memcpy(&rtc->alarm, t, sizeof(struct rtc_wkalrm)); | ||
177 | |||
178 | /* Now many secs to fire */ | ||
179 | alarm_secs -= now_secs; | ||
180 | lpa = (unsigned long long)alarm_secs * rtc->clkrate; | ||
181 | |||
182 | st_rtc_set_hw_alarm(rtc, lpa >> 32, lpa); | ||
183 | st_rtc_alarm_irq_enable(dev, t->enabled); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static struct rtc_class_ops st_rtc_ops = { | ||
189 | .read_time = st_rtc_read_time, | ||
190 | .set_time = st_rtc_set_time, | ||
191 | .read_alarm = st_rtc_read_alarm, | ||
192 | .set_alarm = st_rtc_set_alarm, | ||
193 | .alarm_irq_enable = st_rtc_alarm_irq_enable, | ||
194 | }; | ||
195 | |||
196 | static int st_rtc_probe(struct platform_device *pdev) | ||
197 | { | ||
198 | struct device_node *np = pdev->dev.of_node; | ||
199 | struct st_rtc *rtc; | ||
200 | struct resource *res; | ||
201 | struct rtc_time tm_check; | ||
202 | uint32_t mode; | ||
203 | int ret = 0; | ||
204 | |||
205 | ret = of_property_read_u32(np, "st,lpc-mode", &mode); | ||
206 | if (ret) { | ||
207 | dev_err(&pdev->dev, "An LPC mode must be provided\n"); | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | |||
211 | /* LPC can either run in RTC or WDT mode */ | ||
212 | if (mode != ST_LPC_MODE_RTC) | ||
213 | return -ENODEV; | ||
214 | |||
215 | rtc = devm_kzalloc(&pdev->dev, sizeof(struct st_rtc), GFP_KERNEL); | ||
216 | if (!rtc) | ||
217 | return -ENOMEM; | ||
218 | |||
219 | spin_lock_init(&rtc->lock); | ||
220 | |||
221 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
222 | rtc->ioaddr = devm_ioremap_resource(&pdev->dev, res); | ||
223 | if (IS_ERR(rtc->ioaddr)) | ||
224 | return PTR_ERR(rtc->ioaddr); | ||
225 | |||
226 | rtc->irq = irq_of_parse_and_map(np, 0); | ||
227 | if (!rtc->irq) { | ||
228 | dev_err(&pdev->dev, "IRQ missing or invalid\n"); | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | |||
232 | ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler, 0, | ||
233 | pdev->name, rtc); | ||
234 | if (ret) { | ||
235 | dev_err(&pdev->dev, "Failed to request irq %i\n", rtc->irq); | ||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | enable_irq_wake(rtc->irq); | ||
240 | disable_irq(rtc->irq); | ||
241 | |||
242 | rtc->clk = clk_get(&pdev->dev, NULL); | ||
243 | if (IS_ERR(rtc->clk)) { | ||
244 | dev_err(&pdev->dev, "Unable to request clock\n"); | ||
245 | return PTR_ERR(rtc->clk); | ||
246 | } | ||
247 | |||
248 | clk_prepare_enable(rtc->clk); | ||
249 | |||
250 | rtc->clkrate = clk_get_rate(rtc->clk); | ||
251 | if (!rtc->clkrate) { | ||
252 | dev_err(&pdev->dev, "Unable to fetch clock rate\n"); | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | device_set_wakeup_capable(&pdev->dev, 1); | ||
257 | |||
258 | platform_set_drvdata(pdev, rtc); | ||
259 | |||
260 | /* | ||
261 | * The RTC-LPC is able to manage date.year > 2038 | ||
262 | * but currently the kernel can not manage this date! | ||
263 | * If the RTC-LPC has a date.year > 2038 then | ||
264 | * it's set to the epoch "Jan 1st 2000" | ||
265 | */ | ||
266 | st_rtc_read_time(&pdev->dev, &tm_check); | ||
267 | |||
268 | if (tm_check.tm_year >= (2038 - 1900)) { | ||
269 | memset(&tm_check, 0, sizeof(tm_check)); | ||
270 | tm_check.tm_year = 100; | ||
271 | tm_check.tm_mday = 1; | ||
272 | st_rtc_set_time(&pdev->dev, &tm_check); | ||
273 | } | ||
274 | |||
275 | rtc->rtc_dev = rtc_device_register("st-lpc-rtc", &pdev->dev, | ||
276 | &st_rtc_ops, THIS_MODULE); | ||
277 | if (IS_ERR(rtc->rtc_dev)) { | ||
278 | clk_disable_unprepare(rtc->clk); | ||
279 | return PTR_ERR(rtc->rtc_dev); | ||
280 | } | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int st_rtc_remove(struct platform_device *pdev) | ||
286 | { | ||
287 | struct st_rtc *rtc = platform_get_drvdata(pdev); | ||
288 | |||
289 | if (likely(rtc->rtc_dev)) | ||
290 | rtc_device_unregister(rtc->rtc_dev); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | #ifdef CONFIG_PM_SLEEP | ||
296 | static int st_rtc_suspend(struct device *dev) | ||
297 | { | ||
298 | struct st_rtc *rtc = dev_get_drvdata(dev); | ||
299 | |||
300 | if (device_may_wakeup(dev)) | ||
301 | return 0; | ||
302 | |||
303 | writel_relaxed(1, rtc->ioaddr + LPC_WDT_OFF); | ||
304 | writel_relaxed(0, rtc->ioaddr + LPC_LPA_START_OFF); | ||
305 | writel_relaxed(0, rtc->ioaddr + LPC_WDT_OFF); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int st_rtc_resume(struct device *dev) | ||
311 | { | ||
312 | struct st_rtc *rtc = dev_get_drvdata(dev); | ||
313 | |||
314 | rtc_alarm_irq_enable(rtc->rtc_dev, 0); | ||
315 | |||
316 | /* | ||
317 | * clean 'rtc->alarm' to allow a new | ||
318 | * .set_alarm to the upper RTC layer | ||
319 | */ | ||
320 | memset(&rtc->alarm, 0, sizeof(struct rtc_wkalrm)); | ||
321 | |||
322 | writel_relaxed(0, rtc->ioaddr + LPC_LPA_MSB_OFF); | ||
323 | writel_relaxed(0, rtc->ioaddr + LPC_LPA_LSB_OFF); | ||
324 | writel_relaxed(1, rtc->ioaddr + LPC_WDT_OFF); | ||
325 | writel_relaxed(1, rtc->ioaddr + LPC_LPA_START_OFF); | ||
326 | writel_relaxed(0, rtc->ioaddr + LPC_WDT_OFF); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | #endif | ||
331 | |||
332 | static SIMPLE_DEV_PM_OPS(st_rtc_pm_ops, st_rtc_suspend, st_rtc_resume); | ||
333 | |||
334 | static const struct of_device_id st_rtc_match[] = { | ||
335 | { .compatible = "st,stih407-lpc" }, | ||
336 | {} | ||
337 | }; | ||
338 | MODULE_DEVICE_TABLE(of, st_rtc_match); | ||
339 | |||
340 | static struct platform_driver st_rtc_platform_driver = { | ||
341 | .driver = { | ||
342 | .name = "st-lpc-rtc", | ||
343 | .pm = &st_rtc_pm_ops, | ||
344 | .of_match_table = st_rtc_match, | ||
345 | }, | ||
346 | .probe = st_rtc_probe, | ||
347 | .remove = st_rtc_remove, | ||
348 | }; | ||
349 | |||
350 | module_platform_driver(st_rtc_platform_driver); | ||
351 | |||
352 | MODULE_DESCRIPTION("STMicroelectronics LPC RTC driver"); | ||
353 | MODULE_AUTHOR("David Paris <david.paris@st.com>"); | ||
354 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index e5e7c5505de7..262647bbc614 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -470,6 +470,18 @@ config SIRFSOC_WATCHDOG | |||
470 | Support for CSR SiRFprimaII and SiRFatlasVI watchdog. When | 470 | Support for CSR SiRFprimaII and SiRFatlasVI watchdog. When |
471 | the watchdog triggers the system will be reset. | 471 | the watchdog triggers the system will be reset. |
472 | 472 | ||
473 | config ST_LPC_WATCHDOG | ||
474 | tristate "STMicroelectronics LPC Watchdog" | ||
475 | depends on ARCH_STI | ||
476 | depends on OF | ||
477 | select WATCHDOG_CORE | ||
478 | help | ||
479 | Say Y here to include STMicroelectronics Low Power Controller | ||
480 | (LPC) based Watchdog timer support. | ||
481 | |||
482 | To compile this driver as a module, choose M here: the | ||
483 | module will be called st_lpc_wdt. | ||
484 | |||
473 | config TEGRA_WATCHDOG | 485 | config TEGRA_WATCHDOG |
474 | tristate "Tegra watchdog" | 486 | tristate "Tegra watchdog" |
475 | depends on (ARCH_TEGRA || COMPILE_TEST) && HAS_IOMEM | 487 | depends on (ARCH_TEGRA || COMPILE_TEST) && HAS_IOMEM |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 5c19294d1c30..d98768c7d928 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
@@ -59,6 +59,7 @@ obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o | |||
59 | obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o | 59 | obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o |
60 | obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o | 60 | obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o |
61 | obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o | 61 | obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o |
62 | obj-$(CONFIG_ST_LPC_WATCHDOG) += st_lpc_wdt.o | ||
62 | obj-$(CONFIG_QCOM_WDT) += qcom-wdt.o | 63 | obj-$(CONFIG_QCOM_WDT) += qcom-wdt.o |
63 | obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o | 64 | obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o |
64 | obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o | 65 | obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o |
diff --git a/drivers/watchdog/st_lpc_wdt.c b/drivers/watchdog/st_lpc_wdt.c new file mode 100644 index 000000000000..f32be155212a --- /dev/null +++ b/drivers/watchdog/st_lpc_wdt.c | |||
@@ -0,0 +1,344 @@ | |||
1 | /* | ||
2 | * ST's LPC Watchdog | ||
3 | * | ||
4 | * Copyright (C) 2014 STMicroelectronics -- All Rights Reserved | ||
5 | * | ||
6 | * Author: David Paris <david.paris@st.com> for STMicroelectronics | ||
7 | * Lee Jones <lee.jones@linaro.org> for STMicroelectronics | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public Licence | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the Licence, or (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/mfd/syscon.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/of_platform.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/regmap.h> | ||
25 | #include <linux/watchdog.h> | ||
26 | |||
27 | #include <dt-bindings/mfd/st-lpc.h> | ||
28 | |||
29 | /* Low Power Alarm */ | ||
30 | #define LPC_LPA_LSB_OFF 0x410 | ||
31 | #define LPC_LPA_START_OFF 0x418 | ||
32 | |||
33 | /* LPC as WDT */ | ||
34 | #define LPC_WDT_OFF 0x510 | ||
35 | |||
36 | static struct watchdog_device st_wdog_dev; | ||
37 | |||
38 | struct st_wdog_syscfg { | ||
39 | unsigned int reset_type_reg; | ||
40 | unsigned int reset_type_mask; | ||
41 | unsigned int enable_reg; | ||
42 | unsigned int enable_mask; | ||
43 | }; | ||
44 | |||
45 | struct st_wdog { | ||
46 | void __iomem *base; | ||
47 | struct device *dev; | ||
48 | struct regmap *regmap; | ||
49 | struct st_wdog_syscfg *syscfg; | ||
50 | struct clk *clk; | ||
51 | unsigned long clkrate; | ||
52 | bool warm_reset; | ||
53 | }; | ||
54 | |||
55 | static struct st_wdog_syscfg stid127_syscfg = { | ||
56 | .reset_type_reg = 0x004, | ||
57 | .reset_type_mask = BIT(2), | ||
58 | .enable_reg = 0x000, | ||
59 | .enable_mask = BIT(2), | ||
60 | }; | ||
61 | |||
62 | static struct st_wdog_syscfg stih415_syscfg = { | ||
63 | .reset_type_reg = 0x0B8, | ||
64 | .reset_type_mask = BIT(6), | ||
65 | .enable_reg = 0x0B4, | ||
66 | .enable_mask = BIT(7), | ||
67 | }; | ||
68 | |||
69 | static struct st_wdog_syscfg stih416_syscfg = { | ||
70 | .reset_type_reg = 0x88C, | ||
71 | .reset_type_mask = BIT(6), | ||
72 | .enable_reg = 0x888, | ||
73 | .enable_mask = BIT(7), | ||
74 | }; | ||
75 | |||
76 | static struct st_wdog_syscfg stih407_syscfg = { | ||
77 | .enable_reg = 0x204, | ||
78 | .enable_mask = BIT(19), | ||
79 | }; | ||
80 | |||
81 | static const struct of_device_id st_wdog_match[] = { | ||
82 | { | ||
83 | .compatible = "st,stih407-lpc", | ||
84 | .data = &stih407_syscfg, | ||
85 | }, | ||
86 | { | ||
87 | .compatible = "st,stih416-lpc", | ||
88 | .data = &stih416_syscfg, | ||
89 | }, | ||
90 | { | ||
91 | .compatible = "st,stih415-lpc", | ||
92 | .data = &stih415_syscfg, | ||
93 | }, | ||
94 | { | ||
95 | .compatible = "st,stid127-lpc", | ||
96 | .data = &stid127_syscfg, | ||
97 | }, | ||
98 | {}, | ||
99 | }; | ||
100 | MODULE_DEVICE_TABLE(of, st_wdog_match); | ||
101 | |||
102 | static void st_wdog_setup(struct st_wdog *st_wdog, bool enable) | ||
103 | { | ||
104 | /* Type of watchdog reset - 0: Cold 1: Warm */ | ||
105 | if (st_wdog->syscfg->reset_type_reg) | ||
106 | regmap_update_bits(st_wdog->regmap, | ||
107 | st_wdog->syscfg->reset_type_reg, | ||
108 | st_wdog->syscfg->reset_type_mask, | ||
109 | st_wdog->warm_reset); | ||
110 | |||
111 | /* Mask/unmask watchdog reset */ | ||
112 | regmap_update_bits(st_wdog->regmap, | ||
113 | st_wdog->syscfg->enable_reg, | ||
114 | st_wdog->syscfg->enable_mask, | ||
115 | enable ? 0 : st_wdog->syscfg->enable_mask); | ||
116 | } | ||
117 | |||
118 | static void st_wdog_load_timer(struct st_wdog *st_wdog, unsigned int timeout) | ||
119 | { | ||
120 | unsigned long clkrate = st_wdog->clkrate; | ||
121 | |||
122 | writel_relaxed(timeout * clkrate, st_wdog->base + LPC_LPA_LSB_OFF); | ||
123 | writel_relaxed(1, st_wdog->base + LPC_LPA_START_OFF); | ||
124 | } | ||
125 | |||
126 | static int st_wdog_start(struct watchdog_device *wdd) | ||
127 | { | ||
128 | struct st_wdog *st_wdog = watchdog_get_drvdata(wdd); | ||
129 | |||
130 | writel_relaxed(1, st_wdog->base + LPC_WDT_OFF); | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int st_wdog_stop(struct watchdog_device *wdd) | ||
136 | { | ||
137 | struct st_wdog *st_wdog = watchdog_get_drvdata(wdd); | ||
138 | |||
139 | writel_relaxed(0, st_wdog->base + LPC_WDT_OFF); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int st_wdog_set_timeout(struct watchdog_device *wdd, | ||
145 | unsigned int timeout) | ||
146 | { | ||
147 | struct st_wdog *st_wdog = watchdog_get_drvdata(wdd); | ||
148 | |||
149 | wdd->timeout = timeout; | ||
150 | st_wdog_load_timer(st_wdog, timeout); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static int st_wdog_keepalive(struct watchdog_device *wdd) | ||
156 | { | ||
157 | struct st_wdog *st_wdog = watchdog_get_drvdata(wdd); | ||
158 | |||
159 | st_wdog_load_timer(st_wdog, wdd->timeout); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static const struct watchdog_info st_wdog_info = { | ||
165 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | ||
166 | .identity = "ST LPC WDT", | ||
167 | }; | ||
168 | |||
169 | static const struct watchdog_ops st_wdog_ops = { | ||
170 | .owner = THIS_MODULE, | ||
171 | .start = st_wdog_start, | ||
172 | .stop = st_wdog_stop, | ||
173 | .ping = st_wdog_keepalive, | ||
174 | .set_timeout = st_wdog_set_timeout, | ||
175 | }; | ||
176 | |||
177 | static struct watchdog_device st_wdog_dev = { | ||
178 | .info = &st_wdog_info, | ||
179 | .ops = &st_wdog_ops, | ||
180 | }; | ||
181 | |||
182 | static int st_wdog_probe(struct platform_device *pdev) | ||
183 | { | ||
184 | const struct of_device_id *match; | ||
185 | struct device_node *np = pdev->dev.of_node; | ||
186 | struct st_wdog *st_wdog; | ||
187 | struct regmap *regmap; | ||
188 | struct resource *res; | ||
189 | struct clk *clk; | ||
190 | void __iomem *base; | ||
191 | uint32_t mode; | ||
192 | int ret; | ||
193 | |||
194 | ret = of_property_read_u32(np, "st,lpc-mode", &mode); | ||
195 | if (ret) { | ||
196 | dev_err(&pdev->dev, "An LPC mode must be provided\n"); | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | /* LPC can either run in RTC or WDT mode */ | ||
201 | if (mode != ST_LPC_MODE_WDT) | ||
202 | return -ENODEV; | ||
203 | |||
204 | st_wdog = devm_kzalloc(&pdev->dev, sizeof(*st_wdog), GFP_KERNEL); | ||
205 | if (!st_wdog) | ||
206 | return -ENOMEM; | ||
207 | |||
208 | match = of_match_device(st_wdog_match, &pdev->dev); | ||
209 | if (!match) { | ||
210 | dev_err(&pdev->dev, "Couldn't match device\n"); | ||
211 | return -ENODEV; | ||
212 | } | ||
213 | st_wdog->syscfg = (struct st_wdog_syscfg *)match->data; | ||
214 | |||
215 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
216 | base = devm_ioremap_resource(&pdev->dev, res); | ||
217 | if (IS_ERR(base)) | ||
218 | return PTR_ERR(base); | ||
219 | |||
220 | regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); | ||
221 | if (IS_ERR(regmap)) { | ||
222 | dev_err(&pdev->dev, "No syscfg phandle specified\n"); | ||
223 | return PTR_ERR(regmap); | ||
224 | } | ||
225 | |||
226 | clk = devm_clk_get(&pdev->dev, NULL); | ||
227 | if (IS_ERR(clk)) { | ||
228 | dev_err(&pdev->dev, "Unable to request clock\n"); | ||
229 | return PTR_ERR(clk); | ||
230 | } | ||
231 | |||
232 | st_wdog->dev = &pdev->dev; | ||
233 | st_wdog->base = base; | ||
234 | st_wdog->clk = clk; | ||
235 | st_wdog->regmap = regmap; | ||
236 | st_wdog->warm_reset = of_property_read_bool(np, "st,warm_reset"); | ||
237 | st_wdog->clkrate = clk_get_rate(st_wdog->clk); | ||
238 | |||
239 | if (!st_wdog->clkrate) { | ||
240 | dev_err(&pdev->dev, "Unable to fetch clock rate\n"); | ||
241 | return -EINVAL; | ||
242 | } | ||
243 | st_wdog_dev.max_timeout = 0xFFFFFFFF / st_wdog->clkrate; | ||
244 | |||
245 | ret = clk_prepare_enable(clk); | ||
246 | if (ret) { | ||
247 | dev_err(&pdev->dev, "Unable to enable clock\n"); | ||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | watchdog_set_drvdata(&st_wdog_dev, st_wdog); | ||
252 | watchdog_set_nowayout(&st_wdog_dev, WATCHDOG_NOWAYOUT); | ||
253 | |||
254 | /* Init Watchdog timeout with value in DT */ | ||
255 | ret = watchdog_init_timeout(&st_wdog_dev, 0, &pdev->dev); | ||
256 | if (ret) { | ||
257 | dev_err(&pdev->dev, "Unable to initialise watchdog timeout\n"); | ||
258 | clk_disable_unprepare(clk); | ||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | ret = watchdog_register_device(&st_wdog_dev); | ||
263 | if (ret) { | ||
264 | dev_err(&pdev->dev, "Unable to register watchdog\n"); | ||
265 | clk_disable_unprepare(clk); | ||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | st_wdog_setup(st_wdog, true); | ||
270 | |||
271 | dev_info(&pdev->dev, "LPC Watchdog driver registered, reset type is %s", | ||
272 | st_wdog->warm_reset ? "warm" : "cold"); | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | static int st_wdog_remove(struct platform_device *pdev) | ||
278 | { | ||
279 | struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev); | ||
280 | |||
281 | st_wdog_setup(st_wdog, false); | ||
282 | watchdog_unregister_device(&st_wdog_dev); | ||
283 | clk_disable_unprepare(st_wdog->clk); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | #ifdef CONFIG_PM_SLEEP | ||
289 | static int st_wdog_suspend(struct device *dev) | ||
290 | { | ||
291 | struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev); | ||
292 | |||
293 | if (watchdog_active(&st_wdog_dev)) | ||
294 | st_wdog_stop(&st_wdog_dev); | ||
295 | |||
296 | st_wdog_setup(st_wdog, false); | ||
297 | |||
298 | clk_disable(st_wdog->clk); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int st_wdog_resume(struct device *dev) | ||
304 | { | ||
305 | struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev); | ||
306 | int ret; | ||
307 | |||
308 | ret = clk_enable(st_wdog->clk); | ||
309 | if (ret) { | ||
310 | dev_err(dev, "Unable to re-enable clock\n"); | ||
311 | watchdog_unregister_device(&st_wdog_dev); | ||
312 | clk_unprepare(st_wdog->clk); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | st_wdog_setup(st_wdog, true); | ||
317 | |||
318 | if (watchdog_active(&st_wdog_dev)) { | ||
319 | st_wdog_load_timer(st_wdog, st_wdog_dev.timeout); | ||
320 | st_wdog_start(&st_wdog_dev); | ||
321 | } | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | #endif | ||
326 | |||
327 | static SIMPLE_DEV_PM_OPS(st_wdog_pm_ops, | ||
328 | st_wdog_suspend, | ||
329 | st_wdog_resume); | ||
330 | |||
331 | static struct platform_driver st_wdog_driver = { | ||
332 | .driver = { | ||
333 | .name = "st-lpc-wdt", | ||
334 | .pm = &st_wdog_pm_ops, | ||
335 | .of_match_table = st_wdog_match, | ||
336 | }, | ||
337 | .probe = st_wdog_probe, | ||
338 | .remove = st_wdog_remove, | ||
339 | }; | ||
340 | module_platform_driver(st_wdog_driver); | ||
341 | |||
342 | MODULE_AUTHOR("David Paris <david.paris@st.com>"); | ||
343 | MODULE_DESCRIPTION("ST LPC Watchdog Driver"); | ||
344 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/dt-bindings/mfd/arizona.h b/include/dt-bindings/mfd/arizona.h index c7af7c7ef793..555609910acb 100644 --- a/include/dt-bindings/mfd/arizona.h +++ b/include/dt-bindings/mfd/arizona.h | |||
@@ -90,4 +90,18 @@ | |||
90 | #define ARIZONA_INMODE_SE 1 | 90 | #define ARIZONA_INMODE_SE 1 |
91 | #define ARIZONA_INMODE_DMIC 2 | 91 | #define ARIZONA_INMODE_DMIC 2 |
92 | 92 | ||
93 | #define ARIZONA_MICD_TIME_CONTINUOUS 0 | ||
94 | #define ARIZONA_MICD_TIME_250US 1 | ||
95 | #define ARIZONA_MICD_TIME_500US 2 | ||
96 | #define ARIZONA_MICD_TIME_1MS 3 | ||
97 | #define ARIZONA_MICD_TIME_2MS 4 | ||
98 | #define ARIZONA_MICD_TIME_4MS 5 | ||
99 | #define ARIZONA_MICD_TIME_8MS 6 | ||
100 | #define ARIZONA_MICD_TIME_16MS 7 | ||
101 | #define ARIZONA_MICD_TIME_32MS 8 | ||
102 | #define ARIZONA_MICD_TIME_64MS 9 | ||
103 | #define ARIZONA_MICD_TIME_128MS 10 | ||
104 | #define ARIZONA_MICD_TIME_256MS 11 | ||
105 | #define ARIZONA_MICD_TIME_512MS 12 | ||
106 | |||
93 | #endif | 107 | #endif |
diff --git a/include/dt-bindings/mfd/st-lpc.h b/include/dt-bindings/mfd/st-lpc.h new file mode 100644 index 000000000000..e3e6c75d8822 --- /dev/null +++ b/include/dt-bindings/mfd/st-lpc.h | |||
@@ -0,0 +1,15 @@ | |||
1 | /* | ||
2 | * This header provides shared DT/Driver defines for ST's LPC device | ||
3 | * | ||
4 | * Copyright (C) 2014 STMicroelectronics -- All Rights Reserved | ||
5 | * | ||
6 | * Author: Lee Jones <lee.jones@linaro.org> for STMicroelectronics | ||
7 | */ | ||
8 | |||
9 | #ifndef __DT_BINDINGS_ST_LPC_H__ | ||
10 | #define __DT_BINDINGS_ST_LPC_H__ | ||
11 | |||
12 | #define ST_LPC_MODE_RTC 0 | ||
13 | #define ST_LPC_MODE_WDT 1 | ||
14 | |||
15 | #endif /* __DT_BINDINGS_ST_LPC_H__ */ | ||
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 0bc03f100d04..9ad7828d9d34 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h | |||
@@ -675,6 +675,7 @@ struct twl4030_power_data { | |||
675 | struct twl4030_resconfig *board_config; | 675 | struct twl4030_resconfig *board_config; |
676 | #define TWL4030_RESCONFIG_UNDEF ((u8)-1) | 676 | #define TWL4030_RESCONFIG_UNDEF ((u8)-1) |
677 | bool use_poweroff; /* Board is wired for TWL poweroff */ | 677 | bool use_poweroff; /* Board is wired for TWL poweroff */ |
678 | bool ac_charger_quirk; /* Disable AC charger on board */ | ||
678 | }; | 679 | }; |
679 | 680 | ||
680 | extern int twl4030_remove_script(u8 flags); | 681 | extern int twl4030_remove_script(u8 flags); |
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index 16a498f48169..2f434f4f79a1 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h | |||
@@ -117,6 +117,7 @@ struct arizona { | |||
117 | int num_core_supplies; | 117 | int num_core_supplies; |
118 | struct regulator_bulk_data core_supplies[ARIZONA_MAX_CORE_SUPPLIES]; | 118 | struct regulator_bulk_data core_supplies[ARIZONA_MAX_CORE_SUPPLIES]; |
119 | struct regulator *dcvdd; | 119 | struct regulator *dcvdd; |
120 | bool has_fully_powered_off; | ||
120 | 121 | ||
121 | struct arizona_pdata pdata; | 122 | struct arizona_pdata pdata; |
122 | 123 | ||
@@ -153,7 +154,15 @@ int arizona_request_irq(struct arizona *arizona, int irq, char *name, | |||
153 | void arizona_free_irq(struct arizona *arizona, int irq, void *data); | 154 | void arizona_free_irq(struct arizona *arizona, int irq, void *data); |
154 | int arizona_set_irq_wake(struct arizona *arizona, int irq, int on); | 155 | int arizona_set_irq_wake(struct arizona *arizona, int irq, int on); |
155 | 156 | ||
157 | #ifdef CONFIG_MFD_WM5102 | ||
156 | int wm5102_patch(struct arizona *arizona); | 158 | int wm5102_patch(struct arizona *arizona); |
159 | #else | ||
160 | static inline int wm5102_patch(struct arizona *arizona) | ||
161 | { | ||
162 | return 0; | ||
163 | } | ||
164 | #endif | ||
165 | |||
157 | int wm5110_patch(struct arizona *arizona); | 166 | int wm5110_patch(struct arizona *arizona); |
158 | int wm8997_patch(struct arizona *arizona); | 167 | int wm8997_patch(struct arizona *arizona); |
159 | 168 | ||
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h index 1789cb0f4f17..f6722677e6d0 100644 --- a/include/linux/mfd/arizona/pdata.h +++ b/include/linux/mfd/arizona/pdata.h | |||
@@ -156,7 +156,10 @@ struct arizona_pdata { | |||
156 | /** MICBIAS configurations */ | 156 | /** MICBIAS configurations */ |
157 | struct arizona_micbias micbias[ARIZONA_MAX_MICBIAS]; | 157 | struct arizona_micbias micbias[ARIZONA_MAX_MICBIAS]; |
158 | 158 | ||
159 | /** Mode of input structures */ | 159 | /** |
160 | * Mode of input structures | ||
161 | * One of the ARIZONA_INMODE_xxx values | ||
162 | */ | ||
160 | int inmode[ARIZONA_MAX_INPUT]; | 163 | int inmode[ARIZONA_MAX_INPUT]; |
161 | 164 | ||
162 | /** Mode for outputs */ | 165 | /** Mode for outputs */ |
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index aacc10d7789c..3499d36e6067 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h | |||
@@ -2515,9 +2515,12 @@ | |||
2515 | #define ARIZONA_IN1_DMIC_SUP_MASK 0x1800 /* IN1_DMIC_SUP - [12:11] */ | 2515 | #define ARIZONA_IN1_DMIC_SUP_MASK 0x1800 /* IN1_DMIC_SUP - [12:11] */ |
2516 | #define ARIZONA_IN1_DMIC_SUP_SHIFT 11 /* IN1_DMIC_SUP - [12:11] */ | 2516 | #define ARIZONA_IN1_DMIC_SUP_SHIFT 11 /* IN1_DMIC_SUP - [12:11] */ |
2517 | #define ARIZONA_IN1_DMIC_SUP_WIDTH 2 /* IN1_DMIC_SUP - [12:11] */ | 2517 | #define ARIZONA_IN1_DMIC_SUP_WIDTH 2 /* IN1_DMIC_SUP - [12:11] */ |
2518 | #define ARIZONA_IN1_MODE_MASK 0x0600 /* IN1_MODE - [10:9] */ | 2518 | #define ARIZONA_IN1_MODE_MASK 0x0400 /* IN1_MODE - [10] */ |
2519 | #define ARIZONA_IN1_MODE_SHIFT 9 /* IN1_MODE - [10:9] */ | 2519 | #define ARIZONA_IN1_MODE_SHIFT 10 /* IN1_MODE - [10] */ |
2520 | #define ARIZONA_IN1_MODE_WIDTH 2 /* IN1_MODE - [10:9] */ | 2520 | #define ARIZONA_IN1_MODE_WIDTH 1 /* IN1_MODE - [10] */ |
2521 | #define ARIZONA_IN1_SINGLE_ENDED_MASK 0x0200 /* IN1_MODE - [9] */ | ||
2522 | #define ARIZONA_IN1_SINGLE_ENDED_SHIFT 9 /* IN1_MODE - [9] */ | ||
2523 | #define ARIZONA_IN1_SINGLE_ENDED_WIDTH 1 /* IN1_MODE - [9] */ | ||
2521 | #define ARIZONA_IN1L_PGA_VOL_MASK 0x00FE /* IN1L_PGA_VOL - [7:1] */ | 2524 | #define ARIZONA_IN1L_PGA_VOL_MASK 0x00FE /* IN1L_PGA_VOL - [7:1] */ |
2522 | #define ARIZONA_IN1L_PGA_VOL_SHIFT 1 /* IN1L_PGA_VOL - [7:1] */ | 2525 | #define ARIZONA_IN1L_PGA_VOL_SHIFT 1 /* IN1L_PGA_VOL - [7:1] */ |
2523 | #define ARIZONA_IN1L_PGA_VOL_WIDTH 7 /* IN1L_PGA_VOL - [7:1] */ | 2526 | #define ARIZONA_IN1L_PGA_VOL_WIDTH 7 /* IN1L_PGA_VOL - [7:1] */ |
@@ -2588,9 +2591,12 @@ | |||
2588 | #define ARIZONA_IN2_DMIC_SUP_MASK 0x1800 /* IN2_DMIC_SUP - [12:11] */ | 2591 | #define ARIZONA_IN2_DMIC_SUP_MASK 0x1800 /* IN2_DMIC_SUP - [12:11] */ |
2589 | #define ARIZONA_IN2_DMIC_SUP_SHIFT 11 /* IN2_DMIC_SUP - [12:11] */ | 2592 | #define ARIZONA_IN2_DMIC_SUP_SHIFT 11 /* IN2_DMIC_SUP - [12:11] */ |
2590 | #define ARIZONA_IN2_DMIC_SUP_WIDTH 2 /* IN2_DMIC_SUP - [12:11] */ | 2593 | #define ARIZONA_IN2_DMIC_SUP_WIDTH 2 /* IN2_DMIC_SUP - [12:11] */ |
2591 | #define ARIZONA_IN2_MODE_MASK 0x0600 /* IN2_MODE - [10:9] */ | 2594 | #define ARIZONA_IN2_MODE_MASK 0x0400 /* IN2_MODE - [10] */ |
2592 | #define ARIZONA_IN2_MODE_SHIFT 9 /* IN2_MODE - [10:9] */ | 2595 | #define ARIZONA_IN2_MODE_SHIFT 10 /* IN2_MODE - [10] */ |
2593 | #define ARIZONA_IN2_MODE_WIDTH 2 /* IN2_MODE - [10:9] */ | 2596 | #define ARIZONA_IN2_MODE_WIDTH 1 /* IN2_MODE - [10] */ |
2597 | #define ARIZONA_IN2_SINGLE_ENDED_MASK 0x0200 /* IN2_MODE - [9] */ | ||
2598 | #define ARIZONA_IN2_SINGLE_ENDED_SHIFT 9 /* IN2_MODE - [9] */ | ||
2599 | #define ARIZONA_IN2_SINGLE_ENDED_WIDTH 1 /* IN2_MODE - [9] */ | ||
2594 | #define ARIZONA_IN2L_PGA_VOL_MASK 0x00FE /* IN2L_PGA_VOL - [7:1] */ | 2600 | #define ARIZONA_IN2L_PGA_VOL_MASK 0x00FE /* IN2L_PGA_VOL - [7:1] */ |
2595 | #define ARIZONA_IN2L_PGA_VOL_SHIFT 1 /* IN2L_PGA_VOL - [7:1] */ | 2601 | #define ARIZONA_IN2L_PGA_VOL_SHIFT 1 /* IN2L_PGA_VOL - [7:1] */ |
2596 | #define ARIZONA_IN2L_PGA_VOL_WIDTH 7 /* IN2L_PGA_VOL - [7:1] */ | 2602 | #define ARIZONA_IN2L_PGA_VOL_WIDTH 7 /* IN2L_PGA_VOL - [7:1] */ |
@@ -2661,9 +2667,12 @@ | |||
2661 | #define ARIZONA_IN3_DMIC_SUP_MASK 0x1800 /* IN3_DMIC_SUP - [12:11] */ | 2667 | #define ARIZONA_IN3_DMIC_SUP_MASK 0x1800 /* IN3_DMIC_SUP - [12:11] */ |
2662 | #define ARIZONA_IN3_DMIC_SUP_SHIFT 11 /* IN3_DMIC_SUP - [12:11] */ | 2668 | #define ARIZONA_IN3_DMIC_SUP_SHIFT 11 /* IN3_DMIC_SUP - [12:11] */ |
2663 | #define ARIZONA_IN3_DMIC_SUP_WIDTH 2 /* IN3_DMIC_SUP - [12:11] */ | 2669 | #define ARIZONA_IN3_DMIC_SUP_WIDTH 2 /* IN3_DMIC_SUP - [12:11] */ |
2664 | #define ARIZONA_IN3_MODE_MASK 0x0600 /* IN3_MODE - [10:9] */ | 2670 | #define ARIZONA_IN3_MODE_MASK 0x0400 /* IN3_MODE - [10] */ |
2665 | #define ARIZONA_IN3_MODE_SHIFT 9 /* IN3_MODE - [10:9] */ | 2671 | #define ARIZONA_IN3_MODE_SHIFT 10 /* IN3_MODE - [10] */ |
2666 | #define ARIZONA_IN3_MODE_WIDTH 2 /* IN3_MODE - [10:9] */ | 2672 | #define ARIZONA_IN3_MODE_WIDTH 1 /* IN3_MODE - [10] */ |
2673 | #define ARIZONA_IN3_SINGLE_ENDED_MASK 0x0200 /* IN3_MODE - [9] */ | ||
2674 | #define ARIZONA_IN3_SINGLE_ENDED_SHIFT 9 /* IN3_MODE - [9] */ | ||
2675 | #define ARIZONA_IN3_SINGLE_ENDED_WIDTH 1 /* IN3_MODE - [9] */ | ||
2667 | #define ARIZONA_IN3L_PGA_VOL_MASK 0x00FE /* IN3L_PGA_VOL - [7:1] */ | 2676 | #define ARIZONA_IN3L_PGA_VOL_MASK 0x00FE /* IN3L_PGA_VOL - [7:1] */ |
2668 | #define ARIZONA_IN3L_PGA_VOL_SHIFT 1 /* IN3L_PGA_VOL - [7:1] */ | 2677 | #define ARIZONA_IN3L_PGA_VOL_SHIFT 1 /* IN3L_PGA_VOL - [7:1] */ |
2669 | #define ARIZONA_IN3L_PGA_VOL_WIDTH 7 /* IN3L_PGA_VOL - [7:1] */ | 2678 | #define ARIZONA_IN3L_PGA_VOL_WIDTH 7 /* IN3L_PGA_VOL - [7:1] */ |
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index f9030df5acd1..02f97dc568ac 100644 --- a/include/linux/mfd/axp20x.h +++ b/include/linux/mfd/axp20x.h | |||
@@ -14,6 +14,7 @@ | |||
14 | enum { | 14 | enum { |
15 | AXP202_ID = 0, | 15 | AXP202_ID = 0, |
16 | AXP209_ID, | 16 | AXP209_ID, |
17 | AXP221_ID, | ||
17 | AXP288_ID, | 18 | AXP288_ID, |
18 | NR_AXP20X_VARIANTS, | 19 | NR_AXP20X_VARIANTS, |
19 | }; | 20 | }; |
@@ -45,6 +46,28 @@ enum { | |||
45 | #define AXP20X_V_LTF_DISCHRG 0x3c | 46 | #define AXP20X_V_LTF_DISCHRG 0x3c |
46 | #define AXP20X_V_HTF_DISCHRG 0x3d | 47 | #define AXP20X_V_HTF_DISCHRG 0x3d |
47 | 48 | ||
49 | #define AXP22X_PWR_OUT_CTRL1 0x10 | ||
50 | #define AXP22X_PWR_OUT_CTRL2 0x12 | ||
51 | #define AXP22X_PWR_OUT_CTRL3 0x13 | ||
52 | #define AXP22X_DLDO1_V_OUT 0x15 | ||
53 | #define AXP22X_DLDO2_V_OUT 0x16 | ||
54 | #define AXP22X_DLDO3_V_OUT 0x17 | ||
55 | #define AXP22X_DLDO4_V_OUT 0x18 | ||
56 | #define AXP22X_ELDO1_V_OUT 0x19 | ||
57 | #define AXP22X_ELDO2_V_OUT 0x1a | ||
58 | #define AXP22X_ELDO3_V_OUT 0x1b | ||
59 | #define AXP22X_DC5LDO_V_OUT 0x1c | ||
60 | #define AXP22X_DCDC1_V_OUT 0x21 | ||
61 | #define AXP22X_DCDC2_V_OUT 0x22 | ||
62 | #define AXP22X_DCDC3_V_OUT 0x23 | ||
63 | #define AXP22X_DCDC4_V_OUT 0x24 | ||
64 | #define AXP22X_DCDC5_V_OUT 0x25 | ||
65 | #define AXP22X_DCDC23_V_RAMP_CTRL 0x27 | ||
66 | #define AXP22X_ALDO1_V_OUT 0x28 | ||
67 | #define AXP22X_ALDO2_V_OUT 0x29 | ||
68 | #define AXP22X_ALDO3_V_OUT 0x2a | ||
69 | #define AXP22X_CHRG_CTRL3 0x35 | ||
70 | |||
48 | /* Interrupt */ | 71 | /* Interrupt */ |
49 | #define AXP20X_IRQ1_EN 0x40 | 72 | #define AXP20X_IRQ1_EN 0x40 |
50 | #define AXP20X_IRQ2_EN 0x41 | 73 | #define AXP20X_IRQ2_EN 0x41 |
@@ -100,6 +123,9 @@ enum { | |||
100 | #define AXP20X_VBUS_MON 0x8b | 123 | #define AXP20X_VBUS_MON 0x8b |
101 | #define AXP20X_OVER_TMP 0x8f | 124 | #define AXP20X_OVER_TMP 0x8f |
102 | 125 | ||
126 | #define AXP22X_PWREN_CTRL1 0x8c | ||
127 | #define AXP22X_PWREN_CTRL2 0x8d | ||
128 | |||
103 | /* GPIO */ | 129 | /* GPIO */ |
104 | #define AXP20X_GPIO0_CTRL 0x90 | 130 | #define AXP20X_GPIO0_CTRL 0x90 |
105 | #define AXP20X_LDO5_V_OUT 0x91 | 131 | #define AXP20X_LDO5_V_OUT 0x91 |
@@ -108,6 +134,11 @@ enum { | |||
108 | #define AXP20X_GPIO20_SS 0x94 | 134 | #define AXP20X_GPIO20_SS 0x94 |
109 | #define AXP20X_GPIO3_CTRL 0x95 | 135 | #define AXP20X_GPIO3_CTRL 0x95 |
110 | 136 | ||
137 | #define AXP22X_LDO_IO0_V_OUT 0x91 | ||
138 | #define AXP22X_LDO_IO1_V_OUT 0x93 | ||
139 | #define AXP22X_GPIO_STATE 0x94 | ||
140 | #define AXP22X_GPIO_PULL_DOWN 0x95 | ||
141 | |||
111 | /* Battery */ | 142 | /* Battery */ |
112 | #define AXP20X_CHRG_CC_31_24 0xb0 | 143 | #define AXP20X_CHRG_CC_31_24 0xb0 |
113 | #define AXP20X_CHRG_CC_23_16 0xb1 | 144 | #define AXP20X_CHRG_CC_23_16 0xb1 |
@@ -120,6 +151,9 @@ enum { | |||
120 | #define AXP20X_CC_CTRL 0xb8 | 151 | #define AXP20X_CC_CTRL 0xb8 |
121 | #define AXP20X_FG_RES 0xb9 | 152 | #define AXP20X_FG_RES 0xb9 |
122 | 153 | ||
154 | /* AXP22X specific registers */ | ||
155 | #define AXP22X_BATLOW_THRES1 0xe6 | ||
156 | |||
123 | /* AXP288 specific registers */ | 157 | /* AXP288 specific registers */ |
124 | #define AXP288_PMIC_ADC_H 0x56 | 158 | #define AXP288_PMIC_ADC_H 0x56 |
125 | #define AXP288_PMIC_ADC_L 0x57 | 159 | #define AXP288_PMIC_ADC_L 0x57 |
@@ -158,6 +192,30 @@ enum { | |||
158 | AXP20X_REG_ID_MAX, | 192 | AXP20X_REG_ID_MAX, |
159 | }; | 193 | }; |
160 | 194 | ||
195 | enum { | ||
196 | AXP22X_DCDC1 = 0, | ||
197 | AXP22X_DCDC2, | ||
198 | AXP22X_DCDC3, | ||
199 | AXP22X_DCDC4, | ||
200 | AXP22X_DCDC5, | ||
201 | AXP22X_DC1SW, | ||
202 | AXP22X_DC5LDO, | ||
203 | AXP22X_ALDO1, | ||
204 | AXP22X_ALDO2, | ||
205 | AXP22X_ALDO3, | ||
206 | AXP22X_ELDO1, | ||
207 | AXP22X_ELDO2, | ||
208 | AXP22X_ELDO3, | ||
209 | AXP22X_DLDO1, | ||
210 | AXP22X_DLDO2, | ||
211 | AXP22X_DLDO3, | ||
212 | AXP22X_DLDO4, | ||
213 | AXP22X_RTC_LDO, | ||
214 | AXP22X_LDO_IO0, | ||
215 | AXP22X_LDO_IO1, | ||
216 | AXP22X_REG_ID_MAX, | ||
217 | }; | ||
218 | |||
161 | /* IRQs */ | 219 | /* IRQs */ |
162 | enum { | 220 | enum { |
163 | AXP20X_IRQ_ACIN_OVER_V = 1, | 221 | AXP20X_IRQ_ACIN_OVER_V = 1, |
@@ -199,6 +257,34 @@ enum { | |||
199 | AXP20X_IRQ_GPIO0_INPUT, | 257 | AXP20X_IRQ_GPIO0_INPUT, |
200 | }; | 258 | }; |
201 | 259 | ||
260 | enum axp22x_irqs { | ||
261 | AXP22X_IRQ_ACIN_OVER_V = 1, | ||
262 | AXP22X_IRQ_ACIN_PLUGIN, | ||
263 | AXP22X_IRQ_ACIN_REMOVAL, | ||
264 | AXP22X_IRQ_VBUS_OVER_V, | ||
265 | AXP22X_IRQ_VBUS_PLUGIN, | ||
266 | AXP22X_IRQ_VBUS_REMOVAL, | ||
267 | AXP22X_IRQ_VBUS_V_LOW, | ||
268 | AXP22X_IRQ_BATT_PLUGIN, | ||
269 | AXP22X_IRQ_BATT_REMOVAL, | ||
270 | AXP22X_IRQ_BATT_ENT_ACT_MODE, | ||
271 | AXP22X_IRQ_BATT_EXIT_ACT_MODE, | ||
272 | AXP22X_IRQ_CHARG, | ||
273 | AXP22X_IRQ_CHARG_DONE, | ||
274 | AXP22X_IRQ_BATT_TEMP_HIGH, | ||
275 | AXP22X_IRQ_BATT_TEMP_LOW, | ||
276 | AXP22X_IRQ_DIE_TEMP_HIGH, | ||
277 | AXP22X_IRQ_PEK_SHORT, | ||
278 | AXP22X_IRQ_PEK_LONG, | ||
279 | AXP22X_IRQ_LOW_PWR_LVL1, | ||
280 | AXP22X_IRQ_LOW_PWR_LVL2, | ||
281 | AXP22X_IRQ_TIMER, | ||
282 | AXP22X_IRQ_PEK_RIS_EDGE, | ||
283 | AXP22X_IRQ_PEK_FAL_EDGE, | ||
284 | AXP22X_IRQ_GPIO1_INPUT, | ||
285 | AXP22X_IRQ_GPIO0_INPUT, | ||
286 | }; | ||
287 | |||
202 | enum axp288_irqs { | 288 | enum axp288_irqs { |
203 | AXP288_IRQ_VBUS_FALL = 2, | 289 | AXP288_IRQ_VBUS_FALL = 2, |
204 | AXP288_IRQ_VBUS_RISE, | 290 | AXP288_IRQ_VBUS_RISE, |
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h index 324a34683971..da72671a42fa 100644 --- a/include/linux/mfd/cros_ec.h +++ b/include/linux/mfd/cros_ec.h | |||
@@ -17,10 +17,29 @@ | |||
17 | #define __LINUX_MFD_CROS_EC_H | 17 | #define __LINUX_MFD_CROS_EC_H |
18 | 18 | ||
19 | #include <linux/cdev.h> | 19 | #include <linux/cdev.h> |
20 | #include <linux/device.h> | ||
20 | #include <linux/notifier.h> | 21 | #include <linux/notifier.h> |
21 | #include <linux/mfd/cros_ec_commands.h> | 22 | #include <linux/mfd/cros_ec_commands.h> |
22 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
23 | 24 | ||
25 | #define CROS_EC_DEV_NAME "cros_ec" | ||
26 | #define CROS_EC_DEV_PD_NAME "cros_pd" | ||
27 | |||
28 | /* | ||
29 | * The EC is unresponsive for a time after a reboot command. Add a | ||
30 | * simple delay to make sure that the bus stays locked. | ||
31 | */ | ||
32 | #define EC_REBOOT_DELAY_MS 50 | ||
33 | |||
34 | /* | ||
35 | * Max bus-specific overhead incurred by request/responses. | ||
36 | * I2C requires 1 additional byte for requests. | ||
37 | * I2C requires 2 additional bytes for responses. | ||
38 | * */ | ||
39 | #define EC_PROTO_VERSION_UNKNOWN 0 | ||
40 | #define EC_MAX_REQUEST_OVERHEAD 1 | ||
41 | #define EC_MAX_RESPONSE_OVERHEAD 2 | ||
42 | |||
24 | /* | 43 | /* |
25 | * Command interface between EC and AP, for LPC, I2C and SPI interfaces. | 44 | * Command interface between EC and AP, for LPC, I2C and SPI interfaces. |
26 | */ | 45 | */ |
@@ -42,8 +61,7 @@ enum { | |||
42 | * @outsize: Outgoing length in bytes | 61 | * @outsize: Outgoing length in bytes |
43 | * @insize: Max number of bytes to accept from EC | 62 | * @insize: Max number of bytes to accept from EC |
44 | * @result: EC's response to the command (separate from communication failure) | 63 | * @result: EC's response to the command (separate from communication failure) |
45 | * @outdata: Outgoing data to EC | 64 | * @data: Where to put the incoming data from EC and outgoing data to EC |
46 | * @indata: Where to put the incoming data from EC | ||
47 | */ | 65 | */ |
48 | struct cros_ec_command { | 66 | struct cros_ec_command { |
49 | uint32_t version; | 67 | uint32_t version; |
@@ -51,18 +69,14 @@ struct cros_ec_command { | |||
51 | uint32_t outsize; | 69 | uint32_t outsize; |
52 | uint32_t insize; | 70 | uint32_t insize; |
53 | uint32_t result; | 71 | uint32_t result; |
54 | uint8_t outdata[EC_PROTO2_MAX_PARAM_SIZE]; | 72 | uint8_t data[0]; |
55 | uint8_t indata[EC_PROTO2_MAX_PARAM_SIZE]; | ||
56 | }; | 73 | }; |
57 | 74 | ||
58 | /** | 75 | /** |
59 | * struct cros_ec_device - Information about a ChromeOS EC device | 76 | * struct cros_ec_device - Information about a ChromeOS EC device |
60 | * | 77 | * |
61 | * @ec_name: name of EC device (e.g. 'chromeos-ec') | ||
62 | * @phys_name: name of physical comms layer (e.g. 'i2c-4') | 78 | * @phys_name: name of physical comms layer (e.g. 'i2c-4') |
63 | * @dev: Device pointer for physical comms device | 79 | * @dev: Device pointer for physical comms device |
64 | * @vdev: Device pointer for virtual comms device | ||
65 | * @cdev: Character device structure for virtual comms device | ||
66 | * @was_wake_device: true if this device was set to wake the system from | 80 | * @was_wake_device: true if this device was set to wake the system from |
67 | * sleep at the last suspend | 81 | * sleep at the last suspend |
68 | * @cmd_readmem: direct read of the EC memory-mapped region, if supported | 82 | * @cmd_readmem: direct read of the EC memory-mapped region, if supported |
@@ -74,6 +88,7 @@ struct cros_ec_command { | |||
74 | * | 88 | * |
75 | * @priv: Private data | 89 | * @priv: Private data |
76 | * @irq: Interrupt to use | 90 | * @irq: Interrupt to use |
91 | * @id: Device id | ||
77 | * @din: input buffer (for data from EC) | 92 | * @din: input buffer (for data from EC) |
78 | * @dout: output buffer (for data to EC) | 93 | * @dout: output buffer (for data to EC) |
79 | * \note | 94 | * \note |
@@ -85,41 +100,72 @@ struct cros_ec_command { | |||
85 | * to using dword. | 100 | * to using dword. |
86 | * @din_size: size of din buffer to allocate (zero to use static din) | 101 | * @din_size: size of din buffer to allocate (zero to use static din) |
87 | * @dout_size: size of dout buffer to allocate (zero to use static dout) | 102 | * @dout_size: size of dout buffer to allocate (zero to use static dout) |
88 | * @parent: pointer to parent device (e.g. i2c or spi device) | ||
89 | * @wake_enabled: true if this device can wake the system from sleep | 103 | * @wake_enabled: true if this device can wake the system from sleep |
90 | * @cmd_xfer: send command to EC and get response | 104 | * @cmd_xfer: send command to EC and get response |
91 | * Returns the number of bytes received if the communication succeeded, but | 105 | * Returns the number of bytes received if the communication succeeded, but |
92 | * that doesn't mean the EC was happy with the command. The caller | 106 | * that doesn't mean the EC was happy with the command. The caller |
93 | * should check msg.result for the EC's result code. | 107 | * should check msg.result for the EC's result code. |
108 | * @pkt_xfer: send packet to EC and get response | ||
94 | * @lock: one transaction at a time | 109 | * @lock: one transaction at a time |
95 | */ | 110 | */ |
96 | struct cros_ec_device { | 111 | struct cros_ec_device { |
97 | 112 | ||
98 | /* These are used by other drivers that want to talk to the EC */ | 113 | /* These are used by other drivers that want to talk to the EC */ |
99 | const char *ec_name; | ||
100 | const char *phys_name; | 114 | const char *phys_name; |
101 | struct device *dev; | 115 | struct device *dev; |
102 | struct device *vdev; | ||
103 | struct cdev cdev; | ||
104 | bool was_wake_device; | 116 | bool was_wake_device; |
105 | struct class *cros_class; | 117 | struct class *cros_class; |
106 | int (*cmd_readmem)(struct cros_ec_device *ec, unsigned int offset, | 118 | int (*cmd_readmem)(struct cros_ec_device *ec, unsigned int offset, |
107 | unsigned int bytes, void *dest); | 119 | unsigned int bytes, void *dest); |
108 | 120 | ||
109 | /* These are used to implement the platform-specific interface */ | 121 | /* These are used to implement the platform-specific interface */ |
122 | u16 max_request; | ||
123 | u16 max_response; | ||
124 | u16 max_passthru; | ||
125 | u16 proto_version; | ||
110 | void *priv; | 126 | void *priv; |
111 | int irq; | 127 | int irq; |
112 | uint8_t *din; | 128 | u8 *din; |
113 | uint8_t *dout; | 129 | u8 *dout; |
114 | int din_size; | 130 | int din_size; |
115 | int dout_size; | 131 | int dout_size; |
116 | struct device *parent; | ||
117 | bool wake_enabled; | 132 | bool wake_enabled; |
118 | int (*cmd_xfer)(struct cros_ec_device *ec, | 133 | int (*cmd_xfer)(struct cros_ec_device *ec, |
119 | struct cros_ec_command *msg); | 134 | struct cros_ec_command *msg); |
135 | int (*pkt_xfer)(struct cros_ec_device *ec, | ||
136 | struct cros_ec_command *msg); | ||
120 | struct mutex lock; | 137 | struct mutex lock; |
121 | }; | 138 | }; |
122 | 139 | ||
140 | /* struct cros_ec_platform - ChromeOS EC platform information | ||
141 | * | ||
142 | * @ec_name: name of EC device (e.g. 'cros-ec', 'cros-pd', ...) | ||
143 | * used in /dev/ and sysfs. | ||
144 | * @cmd_offset: offset to apply for each command. Set when | ||
145 | * registering a devicde behind another one. | ||
146 | */ | ||
147 | struct cros_ec_platform { | ||
148 | const char *ec_name; | ||
149 | u16 cmd_offset; | ||
150 | }; | ||
151 | |||
152 | /* | ||
153 | * struct cros_ec_dev - ChromeOS EC device entry point | ||
154 | * | ||
155 | * @class_dev: Device structure used in sysfs | ||
156 | * @cdev: Character device structure in /dev | ||
157 | * @ec_dev: cros_ec_device structure to talk to the physical device | ||
158 | * @dev: pointer to the platform device | ||
159 | * @cmd_offset: offset to apply for each command. | ||
160 | */ | ||
161 | struct cros_ec_dev { | ||
162 | struct device class_dev; | ||
163 | struct cdev cdev; | ||
164 | struct cros_ec_device *ec_dev; | ||
165 | struct device *dev; | ||
166 | u16 cmd_offset; | ||
167 | }; | ||
168 | |||
123 | /** | 169 | /** |
124 | * cros_ec_suspend - Handle a suspend operation for the ChromeOS EC device | 170 | * cros_ec_suspend - Handle a suspend operation for the ChromeOS EC device |
125 | * | 171 | * |
@@ -198,4 +244,16 @@ int cros_ec_remove(struct cros_ec_device *ec_dev); | |||
198 | */ | 244 | */ |
199 | int cros_ec_register(struct cros_ec_device *ec_dev); | 245 | int cros_ec_register(struct cros_ec_device *ec_dev); |
200 | 246 | ||
247 | /** | ||
248 | * cros_ec_register - Query the protocol version supported by the ChromeOS EC | ||
249 | * | ||
250 | * @ec_dev: Device to register | ||
251 | * @return 0 if ok, -ve on error | ||
252 | */ | ||
253 | int cros_ec_query_all(struct cros_ec_device *ec_dev); | ||
254 | |||
255 | /* sysfs stuff */ | ||
256 | extern struct attribute_group cros_ec_attr_group; | ||
257 | extern struct attribute_group cros_ec_lightbar_attr_group; | ||
258 | |||
201 | #endif /* __LINUX_MFD_CROS_EC_H */ | 259 | #endif /* __LINUX_MFD_CROS_EC_H */ |
diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h index a49cd41feea7..13b630c10d4c 100644 --- a/include/linux/mfd/cros_ec_commands.h +++ b/include/linux/mfd/cros_ec_commands.h | |||
@@ -515,7 +515,7 @@ struct ec_host_response { | |||
515 | /* | 515 | /* |
516 | * Notes on commands: | 516 | * Notes on commands: |
517 | * | 517 | * |
518 | * Each command is an 8-byte command value. Commands which take params or | 518 | * Each command is an 16-bit command value. Commands which take params or |
519 | * return response data specify structs for that data. If no struct is | 519 | * return response data specify structs for that data. If no struct is |
520 | * specified, the command does not input or output data, respectively. | 520 | * specified, the command does not input or output data, respectively. |
521 | * Parameter/response length is implicit in the structs. Some underlying | 521 | * Parameter/response length is implicit in the structs. Some underlying |
@@ -966,7 +966,7 @@ struct rgb_s { | |||
966 | /* List of tweakable parameters. NOTE: It's __packed so it can be sent in a | 966 | /* List of tweakable parameters. NOTE: It's __packed so it can be sent in a |
967 | * host command, but the alignment is the same regardless. Keep it that way. | 967 | * host command, but the alignment is the same regardless. Keep it that way. |
968 | */ | 968 | */ |
969 | struct lightbar_params { | 969 | struct lightbar_params_v0 { |
970 | /* Timing */ | 970 | /* Timing */ |
971 | int32_t google_ramp_up; | 971 | int32_t google_ramp_up; |
972 | int32_t google_ramp_down; | 972 | int32_t google_ramp_down; |
@@ -1000,32 +1000,81 @@ struct lightbar_params { | |||
1000 | struct rgb_s color[8]; /* 0-3 are Google colors */ | 1000 | struct rgb_s color[8]; /* 0-3 are Google colors */ |
1001 | } __packed; | 1001 | } __packed; |
1002 | 1002 | ||
1003 | struct lightbar_params_v1 { | ||
1004 | /* Timing */ | ||
1005 | int32_t google_ramp_up; | ||
1006 | int32_t google_ramp_down; | ||
1007 | int32_t s3s0_ramp_up; | ||
1008 | int32_t s0_tick_delay[2]; /* AC=0/1 */ | ||
1009 | int32_t s0a_tick_delay[2]; /* AC=0/1 */ | ||
1010 | int32_t s0s3_ramp_down; | ||
1011 | int32_t s3_sleep_for; | ||
1012 | int32_t s3_ramp_up; | ||
1013 | int32_t s3_ramp_down; | ||
1014 | int32_t tap_tick_delay; | ||
1015 | int32_t tap_display_time; | ||
1016 | |||
1017 | /* Tap-for-battery params */ | ||
1018 | uint8_t tap_pct_red; | ||
1019 | uint8_t tap_pct_green; | ||
1020 | uint8_t tap_seg_min_on; | ||
1021 | uint8_t tap_seg_max_on; | ||
1022 | uint8_t tap_seg_osc; | ||
1023 | uint8_t tap_idx[3]; | ||
1024 | |||
1025 | /* Oscillation */ | ||
1026 | uint8_t osc_min[2]; /* AC=0/1 */ | ||
1027 | uint8_t osc_max[2]; /* AC=0/1 */ | ||
1028 | uint8_t w_ofs[2]; /* AC=0/1 */ | ||
1029 | |||
1030 | /* Brightness limits based on the backlight and AC. */ | ||
1031 | uint8_t bright_bl_off_fixed[2]; /* AC=0/1 */ | ||
1032 | uint8_t bright_bl_on_min[2]; /* AC=0/1 */ | ||
1033 | uint8_t bright_bl_on_max[2]; /* AC=0/1 */ | ||
1034 | |||
1035 | /* Battery level thresholds */ | ||
1036 | uint8_t battery_threshold[LB_BATTERY_LEVELS - 1]; | ||
1037 | |||
1038 | /* Map [AC][battery_level] to color index */ | ||
1039 | uint8_t s0_idx[2][LB_BATTERY_LEVELS]; /* AP is running */ | ||
1040 | uint8_t s3_idx[2][LB_BATTERY_LEVELS]; /* AP is sleeping */ | ||
1041 | |||
1042 | /* Color palette */ | ||
1043 | struct rgb_s color[8]; /* 0-3 are Google colors */ | ||
1044 | } __packed; | ||
1045 | |||
1003 | struct ec_params_lightbar { | 1046 | struct ec_params_lightbar { |
1004 | uint8_t cmd; /* Command (see enum lightbar_command) */ | 1047 | uint8_t cmd; /* Command (see enum lightbar_command) */ |
1005 | union { | 1048 | union { |
1006 | struct { | 1049 | struct { |
1007 | /* no args */ | 1050 | /* no args */ |
1008 | } dump, off, on, init, get_seq, get_params, version; | 1051 | } dump, off, on, init, get_seq, get_params_v0, get_params_v1, |
1052 | version, get_brightness, get_demo; | ||
1009 | 1053 | ||
1010 | struct num { | 1054 | struct { |
1011 | uint8_t num; | 1055 | uint8_t num; |
1012 | } brightness, seq, demo; | 1056 | } set_brightness, seq, demo; |
1013 | 1057 | ||
1014 | struct reg { | 1058 | struct { |
1015 | uint8_t ctrl, reg, value; | 1059 | uint8_t ctrl, reg, value; |
1016 | } reg; | 1060 | } reg; |
1017 | 1061 | ||
1018 | struct rgb { | 1062 | struct { |
1019 | uint8_t led, red, green, blue; | 1063 | uint8_t led, red, green, blue; |
1020 | } rgb; | 1064 | } set_rgb; |
1065 | |||
1066 | struct { | ||
1067 | uint8_t led; | ||
1068 | } get_rgb; | ||
1021 | 1069 | ||
1022 | struct lightbar_params set_params; | 1070 | struct lightbar_params_v0 set_params_v0; |
1071 | struct lightbar_params_v1 set_params_v1; | ||
1023 | }; | 1072 | }; |
1024 | } __packed; | 1073 | } __packed; |
1025 | 1074 | ||
1026 | struct ec_response_lightbar { | 1075 | struct ec_response_lightbar { |
1027 | union { | 1076 | union { |
1028 | struct dump { | 1077 | struct { |
1029 | struct { | 1078 | struct { |
1030 | uint8_t reg; | 1079 | uint8_t reg; |
1031 | uint8_t ic0; | 1080 | uint8_t ic0; |
@@ -1033,20 +1082,26 @@ struct ec_response_lightbar { | |||
1033 | } vals[23]; | 1082 | } vals[23]; |
1034 | } dump; | 1083 | } dump; |
1035 | 1084 | ||
1036 | struct get_seq { | 1085 | struct { |
1037 | uint8_t num; | 1086 | uint8_t num; |
1038 | } get_seq; | 1087 | } get_seq, get_brightness, get_demo; |
1039 | 1088 | ||
1040 | struct lightbar_params get_params; | 1089 | struct lightbar_params_v0 get_params_v0; |
1090 | struct lightbar_params_v1 get_params_v1; | ||
1041 | 1091 | ||
1042 | struct version { | 1092 | struct { |
1043 | uint32_t num; | 1093 | uint32_t num; |
1044 | uint32_t flags; | 1094 | uint32_t flags; |
1045 | } version; | 1095 | } version; |
1046 | 1096 | ||
1047 | struct { | 1097 | struct { |
1098 | uint8_t red, green, blue; | ||
1099 | } get_rgb; | ||
1100 | |||
1101 | struct { | ||
1048 | /* no return params */ | 1102 | /* no return params */ |
1049 | } off, on, init, brightness, seq, reg, rgb, demo, set_params; | 1103 | } off, on, init, set_brightness, seq, reg, set_rgb, |
1104 | demo, set_params_v0, set_params_v1; | ||
1050 | }; | 1105 | }; |
1051 | } __packed; | 1106 | } __packed; |
1052 | 1107 | ||
@@ -1056,15 +1111,20 @@ enum lightbar_command { | |||
1056 | LIGHTBAR_CMD_OFF = 1, | 1111 | LIGHTBAR_CMD_OFF = 1, |
1057 | LIGHTBAR_CMD_ON = 2, | 1112 | LIGHTBAR_CMD_ON = 2, |
1058 | LIGHTBAR_CMD_INIT = 3, | 1113 | LIGHTBAR_CMD_INIT = 3, |
1059 | LIGHTBAR_CMD_BRIGHTNESS = 4, | 1114 | LIGHTBAR_CMD_SET_BRIGHTNESS = 4, |
1060 | LIGHTBAR_CMD_SEQ = 5, | 1115 | LIGHTBAR_CMD_SEQ = 5, |
1061 | LIGHTBAR_CMD_REG = 6, | 1116 | LIGHTBAR_CMD_REG = 6, |
1062 | LIGHTBAR_CMD_RGB = 7, | 1117 | LIGHTBAR_CMD_SET_RGB = 7, |
1063 | LIGHTBAR_CMD_GET_SEQ = 8, | 1118 | LIGHTBAR_CMD_GET_SEQ = 8, |
1064 | LIGHTBAR_CMD_DEMO = 9, | 1119 | LIGHTBAR_CMD_DEMO = 9, |
1065 | LIGHTBAR_CMD_GET_PARAMS = 10, | 1120 | LIGHTBAR_CMD_GET_PARAMS_V0 = 10, |
1066 | LIGHTBAR_CMD_SET_PARAMS = 11, | 1121 | LIGHTBAR_CMD_SET_PARAMS_V0 = 11, |
1067 | LIGHTBAR_CMD_VERSION = 12, | 1122 | LIGHTBAR_CMD_VERSION = 12, |
1123 | LIGHTBAR_CMD_GET_BRIGHTNESS = 13, | ||
1124 | LIGHTBAR_CMD_GET_RGB = 14, | ||
1125 | LIGHTBAR_CMD_GET_DEMO = 15, | ||
1126 | LIGHTBAR_CMD_GET_PARAMS_V1 = 16, | ||
1127 | LIGHTBAR_CMD_SET_PARAMS_V1 = 17, | ||
1068 | LIGHTBAR_NUM_CMDS | 1128 | LIGHTBAR_NUM_CMDS |
1069 | }; | 1129 | }; |
1070 | 1130 | ||
@@ -1421,8 +1481,40 @@ struct ec_response_rtc { | |||
1421 | /*****************************************************************************/ | 1481 | /*****************************************************************************/ |
1422 | /* Port80 log access */ | 1482 | /* Port80 log access */ |
1423 | 1483 | ||
1484 | /* Maximum entries that can be read/written in a single command */ | ||
1485 | #define EC_PORT80_SIZE_MAX 32 | ||
1486 | |||
1424 | /* Get last port80 code from previous boot */ | 1487 | /* Get last port80 code from previous boot */ |
1425 | #define EC_CMD_PORT80_LAST_BOOT 0x48 | 1488 | #define EC_CMD_PORT80_LAST_BOOT 0x48 |
1489 | #define EC_CMD_PORT80_READ 0x48 | ||
1490 | |||
1491 | enum ec_port80_subcmd { | ||
1492 | EC_PORT80_GET_INFO = 0, | ||
1493 | EC_PORT80_READ_BUFFER, | ||
1494 | }; | ||
1495 | |||
1496 | struct ec_params_port80_read { | ||
1497 | uint16_t subcmd; | ||
1498 | union { | ||
1499 | struct { | ||
1500 | uint32_t offset; | ||
1501 | uint32_t num_entries; | ||
1502 | } read_buffer; | ||
1503 | }; | ||
1504 | } __packed; | ||
1505 | |||
1506 | struct ec_response_port80_read { | ||
1507 | union { | ||
1508 | struct { | ||
1509 | uint32_t writes; | ||
1510 | uint32_t history_size; | ||
1511 | uint32_t last_boot; | ||
1512 | } get_info; | ||
1513 | struct { | ||
1514 | uint16_t codes[EC_PORT80_SIZE_MAX]; | ||
1515 | } data; | ||
1516 | }; | ||
1517 | } __packed; | ||
1426 | 1518 | ||
1427 | struct ec_response_port80_last_boot { | 1519 | struct ec_response_port80_last_boot { |
1428 | uint16_t code; | 1520 | uint16_t code; |
@@ -1782,6 +1874,7 @@ struct ec_params_gpio_set { | |||
1782 | /* Get GPIO value */ | 1874 | /* Get GPIO value */ |
1783 | #define EC_CMD_GPIO_GET 0x93 | 1875 | #define EC_CMD_GPIO_GET 0x93 |
1784 | 1876 | ||
1877 | /* Version 0 of input params and response */ | ||
1785 | struct ec_params_gpio_get { | 1878 | struct ec_params_gpio_get { |
1786 | char name[32]; | 1879 | char name[32]; |
1787 | } __packed; | 1880 | } __packed; |
@@ -1789,6 +1882,38 @@ struct ec_response_gpio_get { | |||
1789 | uint8_t val; | 1882 | uint8_t val; |
1790 | } __packed; | 1883 | } __packed; |
1791 | 1884 | ||
1885 | /* Version 1 of input params and response */ | ||
1886 | struct ec_params_gpio_get_v1 { | ||
1887 | uint8_t subcmd; | ||
1888 | union { | ||
1889 | struct { | ||
1890 | char name[32]; | ||
1891 | } get_value_by_name; | ||
1892 | struct { | ||
1893 | uint8_t index; | ||
1894 | } get_info; | ||
1895 | }; | ||
1896 | } __packed; | ||
1897 | |||
1898 | struct ec_response_gpio_get_v1 { | ||
1899 | union { | ||
1900 | struct { | ||
1901 | uint8_t val; | ||
1902 | } get_value_by_name, get_count; | ||
1903 | struct { | ||
1904 | uint8_t val; | ||
1905 | char name[32]; | ||
1906 | uint32_t flags; | ||
1907 | } get_info; | ||
1908 | }; | ||
1909 | } __packed; | ||
1910 | |||
1911 | enum gpio_get_subcmd { | ||
1912 | EC_GPIO_GET_BY_NAME = 0, | ||
1913 | EC_GPIO_GET_COUNT = 1, | ||
1914 | EC_GPIO_GET_INFO = 2, | ||
1915 | }; | ||
1916 | |||
1792 | /*****************************************************************************/ | 1917 | /*****************************************************************************/ |
1793 | /* I2C commands. Only available when flash write protect is unlocked. */ | 1918 | /* I2C commands. Only available when flash write protect is unlocked. */ |
1794 | 1919 | ||
@@ -1857,13 +1982,21 @@ struct ec_params_charge_control { | |||
1857 | /*****************************************************************************/ | 1982 | /*****************************************************************************/ |
1858 | 1983 | ||
1859 | /* | 1984 | /* |
1860 | * Cut off battery power output if the battery supports. | 1985 | * Cut off battery power immediately or after the host has shut down. |
1861 | * | 1986 | * |
1862 | * For unsupported battery, just don't implement this command and lets EC | 1987 | * return EC_RES_INVALID_COMMAND if unsupported by a board/battery. |
1863 | * return EC_RES_INVALID_COMMAND. | 1988 | * EC_RES_SUCCESS if the command was successful. |
1989 | * EC_RES_ERROR if the cut off command failed. | ||
1864 | */ | 1990 | */ |
1991 | |||
1865 | #define EC_CMD_BATTERY_CUT_OFF 0x99 | 1992 | #define EC_CMD_BATTERY_CUT_OFF 0x99 |
1866 | 1993 | ||
1994 | #define EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN (1 << 0) | ||
1995 | |||
1996 | struct ec_params_battery_cutoff { | ||
1997 | uint8_t flags; | ||
1998 | } __packed; | ||
1999 | |||
1867 | /*****************************************************************************/ | 2000 | /*****************************************************************************/ |
1868 | /* USB port mux control. */ | 2001 | /* USB port mux control. */ |
1869 | 2002 | ||
@@ -2142,6 +2275,32 @@ struct ec_params_sb_wr_block { | |||
2142 | } __packed; | 2275 | } __packed; |
2143 | 2276 | ||
2144 | /*****************************************************************************/ | 2277 | /*****************************************************************************/ |
2278 | /* Battery vendor parameters | ||
2279 | * | ||
2280 | * Get or set vendor-specific parameters in the battery. Implementations may | ||
2281 | * differ between boards or batteries. On a set operation, the response | ||
2282 | * contains the actual value set, which may be rounded or clipped from the | ||
2283 | * requested value. | ||
2284 | */ | ||
2285 | |||
2286 | #define EC_CMD_BATTERY_VENDOR_PARAM 0xb4 | ||
2287 | |||
2288 | enum ec_battery_vendor_param_mode { | ||
2289 | BATTERY_VENDOR_PARAM_MODE_GET = 0, | ||
2290 | BATTERY_VENDOR_PARAM_MODE_SET, | ||
2291 | }; | ||
2292 | |||
2293 | struct ec_params_battery_vendor_param { | ||
2294 | uint32_t param; | ||
2295 | uint32_t value; | ||
2296 | uint8_t mode; | ||
2297 | } __packed; | ||
2298 | |||
2299 | struct ec_response_battery_vendor_param { | ||
2300 | uint32_t value; | ||
2301 | } __packed; | ||
2302 | |||
2303 | /*****************************************************************************/ | ||
2145 | /* System commands */ | 2304 | /* System commands */ |
2146 | 2305 | ||
2147 | /* | 2306 | /* |
@@ -2338,6 +2497,80 @@ struct ec_params_reboot_ec { | |||
2338 | 2497 | ||
2339 | /*****************************************************************************/ | 2498 | /*****************************************************************************/ |
2340 | /* | 2499 | /* |
2500 | * PD commands | ||
2501 | * | ||
2502 | * These commands are for PD MCU communication. | ||
2503 | */ | ||
2504 | |||
2505 | /* EC to PD MCU exchange status command */ | ||
2506 | #define EC_CMD_PD_EXCHANGE_STATUS 0x100 | ||
2507 | |||
2508 | /* Status of EC being sent to PD */ | ||
2509 | struct ec_params_pd_status { | ||
2510 | int8_t batt_soc; /* battery state of charge */ | ||
2511 | } __packed; | ||
2512 | |||
2513 | /* Status of PD being sent back to EC */ | ||
2514 | struct ec_response_pd_status { | ||
2515 | int8_t status; /* PD MCU status */ | ||
2516 | uint32_t curr_lim_ma; /* input current limit */ | ||
2517 | } __packed; | ||
2518 | |||
2519 | /* Set USB type-C port role and muxes */ | ||
2520 | #define EC_CMD_USB_PD_CONTROL 0x101 | ||
2521 | |||
2522 | enum usb_pd_control_role { | ||
2523 | USB_PD_CTRL_ROLE_NO_CHANGE = 0, | ||
2524 | USB_PD_CTRL_ROLE_TOGGLE_ON = 1, /* == AUTO */ | ||
2525 | USB_PD_CTRL_ROLE_TOGGLE_OFF = 2, | ||
2526 | USB_PD_CTRL_ROLE_FORCE_SINK = 3, | ||
2527 | USB_PD_CTRL_ROLE_FORCE_SOURCE = 4, | ||
2528 | }; | ||
2529 | |||
2530 | enum usb_pd_control_mux { | ||
2531 | USB_PD_CTRL_MUX_NO_CHANGE = 0, | ||
2532 | USB_PD_CTRL_MUX_NONE = 1, | ||
2533 | USB_PD_CTRL_MUX_USB = 2, | ||
2534 | USB_PD_CTRL_MUX_DP = 3, | ||
2535 | USB_PD_CTRL_MUX_DOCK = 4, | ||
2536 | USB_PD_CTRL_MUX_AUTO = 5, | ||
2537 | }; | ||
2538 | |||
2539 | struct ec_params_usb_pd_control { | ||
2540 | uint8_t port; | ||
2541 | uint8_t role; | ||
2542 | uint8_t mux; | ||
2543 | } __packed; | ||
2544 | |||
2545 | /*****************************************************************************/ | ||
2546 | /* | ||
2547 | * Passthru commands | ||
2548 | * | ||
2549 | * Some platforms have sub-processors chained to each other. For example. | ||
2550 | * | ||
2551 | * AP <--> EC <--> PD MCU | ||
2552 | * | ||
2553 | * The top 2 bits of the command number are used to indicate which device the | ||
2554 | * command is intended for. Device 0 is always the device receiving the | ||
2555 | * command; other device mapping is board-specific. | ||
2556 | * | ||
2557 | * When a device receives a command to be passed to a sub-processor, it passes | ||
2558 | * it on with the device number set back to 0. This allows the sub-processor | ||
2559 | * to remain blissfully unaware of whether the command originated on the next | ||
2560 | * device up the chain, or was passed through from the AP. | ||
2561 | * | ||
2562 | * In the above example, if the AP wants to send command 0x0002 to the PD MCU, | ||
2563 | * AP sends command 0x4002 to the EC | ||
2564 | * EC sends command 0x0002 to the PD MCU | ||
2565 | * EC forwards PD MCU response back to the AP | ||
2566 | */ | ||
2567 | |||
2568 | /* Offset and max command number for sub-device n */ | ||
2569 | #define EC_CMD_PASSTHRU_OFFSET(n) (0x4000 * (n)) | ||
2570 | #define EC_CMD_PASSTHRU_MAX(n) (EC_CMD_PASSTHRU_OFFSET(n) + 0x3fff) | ||
2571 | |||
2572 | /*****************************************************************************/ | ||
2573 | /* | ||
2341 | * Deprecated constants. These constants have been renamed for clarity. The | 2574 | * Deprecated constants. These constants have been renamed for clarity. The |
2342 | * meaning and size has not changed. Programs that use the old names should | 2575 | * meaning and size has not changed. Programs that use the old names should |
2343 | * switch to the new names soon, as the old names may not be carried forward | 2576 | * switch to the new names soon, as the old names may not be carried forward |
diff --git a/include/linux/mfd/da9055/core.h b/include/linux/mfd/da9055/core.h index 956afa445998..5dc743fd63a6 100644 --- a/include/linux/mfd/da9055/core.h +++ b/include/linux/mfd/da9055/core.h | |||
@@ -89,6 +89,6 @@ static inline int da9055_reg_update(struct da9055 *da9055, unsigned char reg, | |||
89 | int da9055_device_init(struct da9055 *da9055); | 89 | int da9055_device_init(struct da9055 *da9055); |
90 | void da9055_device_exit(struct da9055 *da9055); | 90 | void da9055_device_exit(struct da9055 *da9055); |
91 | 91 | ||
92 | extern struct regmap_config da9055_regmap_config; | 92 | extern const struct regmap_config da9055_regmap_config; |
93 | 93 | ||
94 | #endif /* __DA9055_CORE_H */ | 94 | #endif /* __DA9055_CORE_H */ |
diff --git a/include/linux/mfd/max77686.h b/include/linux/mfd/max77686.h index bb995ab9a575..d4b72d519115 100644 --- a/include/linux/mfd/max77686.h +++ b/include/linux/mfd/max77686.h | |||
@@ -125,9 +125,4 @@ enum max77686_opmode { | |||
125 | MAX77686_OPMODE_STANDBY, | 125 | MAX77686_OPMODE_STANDBY, |
126 | }; | 126 | }; |
127 | 127 | ||
128 | struct max77686_opmode_data { | ||
129 | int id; | ||
130 | int mode; | ||
131 | }; | ||
132 | |||
133 | #endif /* __LINUX_MFD_MAX77686_H */ | 128 | #endif /* __LINUX_MFD_MAX77686_H */ |