summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/atmel-at91.txt59
-rw-r--r--MAINTAINERS5
-rw-r--r--drivers/power/ipaq_micro_battery.c2
-rw-r--r--drivers/power/max8925_power.c10
-rw-r--r--drivers/power/reset/Kconfig8
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/at91-sama5d2_shdwc.c282
-rw-r--r--drivers/power/sbs-battery.c4
8 files changed, 361 insertions, 10 deletions
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
index 1d8004633479..e1f5ad855f14 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt
@@ -151,6 +151,65 @@ Example:
151 clocks = <&clk32k>; 151 clocks = <&clk32k>;
152 }; 152 };
153 153
154SHDWC SAMA5D2-Compatible Shutdown Controller
155
1561) shdwc node
157
158required properties:
159- compatible: should be "atmel,sama5d2-shdwc".
160- reg: should contain registers location and length
161- clocks: phandle to input clock.
162- #address-cells: should be one. The cell is the wake-up input index.
163- #size-cells: should be zero.
164
165optional properties:
166
167- debounce-delay-us: minimum wake-up inputs debouncer period in
168 microseconds. It's usually a board-related property.
169- atmel,wakeup-rtc-timer: boolean to enable Real-Time Clock wake-up.
170
171The node contains child nodes for each wake-up input that the platform uses.
172
1732) input nodes
174
175Wake-up input nodes are usually described in the "board" part of the Device
176Tree. Note also that input 0 is linked to the wake-up pin and is frequently
177used.
178
179Required properties:
180- reg: should contain the wake-up input index [0 - 15].
181
182Optional properties:
183- atmel,wakeup-active-high: boolean, the corresponding wake-up input described
184 by the child, forces the wake-up of the core power supply on a high level.
185 The default is to be active low.
186
187Example:
188
189On the SoC side:
190 shdwc@f8048010 {
191 compatible = "atmel,sama5d2-shdwc";
192 reg = <0xf8048010 0x10>;
193 clocks = <&clk32k>;
194 #address-cells = <1>;
195 #size-cells = <0>;
196 atmel,wakeup-rtc-timer;
197 };
198
199On the board side:
200 shdwc@f8048010 {
201 debounce-delay-us = <976>;
202
203 input@0 {
204 reg = <0>;
205 };
206
207 input@1 {
208 reg = <1>;
209 atmel,wakeup-active-high;
210 };
211 };
212
154Special Function Registers (SFR) 213Special Function Registers (SFR)
155 214
156Special Function Registers (SFR) manage specific aspects of the integrated 215Special Function Registers (SFR) manage specific aspects of the integrated
diff --git a/MAINTAINERS b/MAINTAINERS
index 374ffa2d81b7..bb176dbfe81f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2048,6 +2048,11 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com>
2048S: Supported 2048S: Supported
2049F: drivers/tty/serial/atmel_serial.c 2049F: drivers/tty/serial/atmel_serial.c
2050 2050
2051ATMEL AT91 SAMA5D2-Compatible Shutdown Controller
2052M: Nicolas Ferre <nicolas.ferre@atmel.com>
2053S: Supported
2054F: drivers/power/reset/at91-sama5d2_shdwc.c
2055
2051ATMEL SAMA5D2 ADC DRIVER 2056ATMEL SAMA5D2 ADC DRIVER
2052M: Ludovic Desroches <ludovic.desroches@atmel.com> 2057M: Ludovic Desroches <ludovic.desroches@atmel.com>
2053L: linux-iio@vger.kernel.org 2058L: linux-iio@vger.kernel.org
diff --git a/drivers/power/ipaq_micro_battery.c b/drivers/power/ipaq_micro_battery.c
index 3f314b1a30d7..35b01c7d775b 100644
--- a/drivers/power/ipaq_micro_battery.c
+++ b/drivers/power/ipaq_micro_battery.c
@@ -261,7 +261,7 @@ static int micro_batt_probe(struct platform_device *pdev)
261 return 0; 261 return 0;
262 262
263ac_err: 263ac_err:
264 power_supply_unregister(micro_ac_power); 264 power_supply_unregister(micro_batt_power);
265batt_err: 265batt_err:
266 cancel_delayed_work_sync(&mb->update); 266 cancel_delayed_work_sync(&mb->update);
267 destroy_workqueue(mb->wq); 267 destroy_workqueue(mb->wq);
diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c
index 57eb5c2bfc21..3b94620ce5c1 100644
--- a/drivers/power/max8925_power.c
+++ b/drivers/power/max8925_power.c
@@ -540,14 +540,14 @@ static int max8925_power_probe(struct platform_device *pdev)
540 info->usb = power_supply_register(&pdev->dev, &usb_desc, &psy_cfg); 540 info->usb = power_supply_register(&pdev->dev, &usb_desc, &psy_cfg);
541 if (IS_ERR(info->usb)) { 541 if (IS_ERR(info->usb)) {
542 ret = PTR_ERR(info->usb); 542 ret = PTR_ERR(info->usb);
543 goto out_usb; 543 goto out_unregister_ac;
544 } 544 }
545 info->usb->dev.parent = &pdev->dev; 545 info->usb->dev.parent = &pdev->dev;
546 546
547 info->battery = power_supply_register(&pdev->dev, &battery_desc, NULL); 547 info->battery = power_supply_register(&pdev->dev, &battery_desc, NULL);
548 if (IS_ERR(info->battery)) { 548 if (IS_ERR(info->battery)) {
549 ret = PTR_ERR(info->battery); 549 ret = PTR_ERR(info->battery);
550 goto out_battery; 550 goto out_unregister_usb;
551 } 551 }
552 info->battery->dev.parent = &pdev->dev; 552 info->battery->dev.parent = &pdev->dev;
553 553
@@ -560,9 +560,9 @@ static int max8925_power_probe(struct platform_device *pdev)
560 560
561 max8925_init_charger(chip, info); 561 max8925_init_charger(chip, info);
562 return 0; 562 return 0;
563out_battery: 563out_unregister_usb:
564 power_supply_unregister(info->battery); 564 power_supply_unregister(info->usb);
565out_usb: 565out_unregister_ac:
566 power_supply_unregister(info->ac); 566 power_supply_unregister(info->ac);
567out: 567out:
568 return ret; 568 return ret;
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 0a6408a39c66..9bb2622c23bf 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -30,6 +30,14 @@ config POWER_RESET_AT91_RESET
30 This driver supports restart for Atmel AT91SAM9 and SAMA5 30 This driver supports restart for Atmel AT91SAM9 and SAMA5
31 SoCs 31 SoCs
32 32
33config POWER_RESET_AT91_SAMA5D2_SHDWC
34 tristate "Atmel AT91 SAMA5D2-Compatible shutdown controller driver"
35 depends on ARCH_AT91 || COMPILE_TEST
36 default SOC_SAMA5
37 help
38 This driver supports the alternate shutdown controller for some Atmel
39 SAMA5 SoCs. It is present for example on SAMA5D2 SoC.
40
33config POWER_RESET_AXXIA 41config POWER_RESET_AXXIA
34 bool "LSI Axxia reset driver" 42 bool "LSI Axxia reset driver"
35 depends on ARCH_AXXIA 43 depends on ARCH_AXXIA
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 096fa67047f6..ab7aa8614d1f 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -1,6 +1,7 @@
1obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o 1obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o
2obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o 2obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o
3obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o 3obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o
4obj-$(CONFIG_POWER_RESET_AT91_SAMA5D2_SHDWC) += at91-sama5d2_shdwc.o
4obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o 5obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
5obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o 6obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
6obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o 7obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c
new file mode 100644
index 000000000000..8a5ac9706c9c
--- /dev/null
+++ b/drivers/power/reset/at91-sama5d2_shdwc.c
@@ -0,0 +1,282 @@
1/*
2 * Atmel SAMA5D2-Compatible Shutdown Controller (SHDWC) driver.
3 * Found on some SoCs as the sama5d2 (obviously).
4 *
5 * Copyright (C) 2015 Atmel Corporation,
6 * Nicolas Ferre <nicolas.ferre@atmel.com>
7 *
8 * Evolved from driver at91-poweroff.c.
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 *
14 * TODO:
15 * - addition to status of other wake-up inputs [1 - 15]
16 * - Analog Comparator wake-up alarm
17 * - Serial RX wake-up alarm
18 * - low power debouncer
19 */
20
21#include <linux/clk.h>
22#include <linux/io.h>
23#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/platform_device.h>
26#include <linux/printk.h>
27
28#define SLOW_CLOCK_FREQ 32768
29
30#define AT91_SHDW_CR 0x00 /* Shut Down Control Register */
31#define AT91_SHDW_SHDW BIT(0) /* Shut Down command */
32#define AT91_SHDW_KEY (0xa5UL << 24) /* KEY Password */
33
34#define AT91_SHDW_MR 0x04 /* Shut Down Mode Register */
35#define AT91_SHDW_WKUPDBC_SHIFT 24
36#define AT91_SHDW_WKUPDBC_MASK GENMASK(31, 16)
37#define AT91_SHDW_WKUPDBC(x) (((x) << AT91_SHDW_WKUPDBC_SHIFT) \
38 & AT91_SHDW_WKUPDBC_MASK)
39
40#define AT91_SHDW_SR 0x08 /* Shut Down Status Register */
41#define AT91_SHDW_WKUPIS_SHIFT 16
42#define AT91_SHDW_WKUPIS_MASK GENMASK(31, 16)
43#define AT91_SHDW_WKUPIS(x) ((1 << (x)) << AT91_SHDW_WKUPIS_SHIFT \
44 & AT91_SHDW_WKUPIS_MASK)
45
46#define AT91_SHDW_WUIR 0x0c /* Shutdown Wake-up Inputs Register */
47#define AT91_SHDW_WKUPEN_MASK GENMASK(15, 0)
48#define AT91_SHDW_WKUPEN(x) ((1 << (x)) & AT91_SHDW_WKUPEN_MASK)
49#define AT91_SHDW_WKUPT_SHIFT 16
50#define AT91_SHDW_WKUPT_MASK GENMASK(31, 16)
51#define AT91_SHDW_WKUPT(x) ((1 << (x)) << AT91_SHDW_WKUPT_SHIFT \
52 & AT91_SHDW_WKUPT_MASK)
53
54#define SHDW_WK_PIN(reg, cfg) ((reg) & AT91_SHDW_WKUPIS((cfg)->wkup_pin_input))
55#define SHDW_RTCWK(reg, cfg) (((reg) >> ((cfg)->sr_rtcwk_shift)) & 0x1)
56#define SHDW_RTCWKEN(cfg) (1 << ((cfg)->mr_rtcwk_shift))
57
58#define DBC_PERIOD_US(x) DIV_ROUND_UP_ULL((1000000 * (x)), \
59 SLOW_CLOCK_FREQ)
60
61struct shdwc_config {
62 u8 wkup_pin_input;
63 u8 mr_rtcwk_shift;
64 u8 sr_rtcwk_shift;
65};
66
67struct shdwc {
68 struct shdwc_config *cfg;
69 void __iomem *at91_shdwc_base;
70};
71
72/*
73 * Hold configuration here, cannot be more than one instance of the driver
74 * since pm_power_off itself is global.
75 */
76static struct shdwc *at91_shdwc;
77static struct clk *sclk;
78
79static const unsigned long long sdwc_dbc_period[] = {
80 0, 3, 32, 512, 4096, 32768,
81};
82
83static void __init at91_wakeup_status(struct platform_device *pdev)
84{
85 struct shdwc *shdw = platform_get_drvdata(pdev);
86 u32 reg;
87 char *reason = "unknown";
88
89 reg = readl(shdw->at91_shdwc_base + AT91_SHDW_SR);
90
91 dev_dbg(&pdev->dev, "%s: status = %#x\n", __func__, reg);
92
93 /* Simple power-on, just bail out */
94 if (!reg)
95 return;
96
97 if (SHDW_WK_PIN(reg, shdw->cfg))
98 reason = "WKUP pin";
99 else if (SHDW_RTCWK(reg, shdw->cfg))
100 reason = "RTC";
101
102 pr_info("AT91: Wake-Up source: %s\n", reason);
103}
104
105static void at91_poweroff(void)
106{
107 writel(AT91_SHDW_KEY | AT91_SHDW_SHDW,
108 at91_shdwc->at91_shdwc_base + AT91_SHDW_CR);
109}
110
111static u32 at91_shdwc_debouncer_value(struct platform_device *pdev,
112 u32 in_period_us)
113{
114 int i;
115 int max_idx = ARRAY_SIZE(sdwc_dbc_period) - 1;
116 unsigned long long period_us;
117 unsigned long long max_period_us = DBC_PERIOD_US(sdwc_dbc_period[max_idx]);
118
119 if (in_period_us > max_period_us) {
120 dev_warn(&pdev->dev,
121 "debouncer period %u too big, reduced to %llu us\n",
122 in_period_us, max_period_us);
123 return max_idx;
124 }
125
126 for (i = max_idx - 1; i > 0; i--) {
127 period_us = DBC_PERIOD_US(sdwc_dbc_period[i]);
128 dev_dbg(&pdev->dev, "%s: ref[%d] = %llu\n",
129 __func__, i, period_us);
130 if (in_period_us > period_us)
131 break;
132 }
133
134 return i + 1;
135}
136
137static u32 at91_shdwc_get_wakeup_input(struct platform_device *pdev,
138 struct device_node *np)
139{
140 struct device_node *cnp;
141 u32 wk_input_mask;
142 u32 wuir = 0;
143 u32 wk_input;
144
145 for_each_child_of_node(np, cnp) {
146 if (of_property_read_u32(cnp, "reg", &wk_input)) {
147 dev_warn(&pdev->dev, "reg property is missing for %s\n",
148 cnp->full_name);
149 continue;
150 }
151
152 wk_input_mask = 1 << wk_input;
153 if (!(wk_input_mask & AT91_SHDW_WKUPEN_MASK)) {
154 dev_warn(&pdev->dev,
155 "wake-up input %d out of bounds ignore\n",
156 wk_input);
157 continue;
158 }
159 wuir |= wk_input_mask;
160
161 if (of_property_read_bool(cnp, "atmel,wakeup-active-high"))
162 wuir |= AT91_SHDW_WKUPT(wk_input);
163
164 dev_dbg(&pdev->dev, "%s: (child %d) wuir = %#x\n",
165 __func__, wk_input, wuir);
166 }
167
168 return wuir;
169}
170
171static void at91_shdwc_dt_configure(struct platform_device *pdev)
172{
173 struct shdwc *shdw = platform_get_drvdata(pdev);
174 struct device_node *np = pdev->dev.of_node;
175 u32 mode = 0, tmp, input;
176
177 if (!np) {
178 dev_err(&pdev->dev, "device node not found\n");
179 return;
180 }
181
182 if (!of_property_read_u32(np, "debounce-delay-us", &tmp))
183 mode |= AT91_SHDW_WKUPDBC(at91_shdwc_debouncer_value(pdev, tmp));
184
185 if (of_property_read_bool(np, "atmel,wakeup-rtc-timer"))
186 mode |= SHDW_RTCWKEN(shdw->cfg);
187
188 dev_dbg(&pdev->dev, "%s: mode = %#x\n", __func__, mode);
189 writel(mode, shdw->at91_shdwc_base + AT91_SHDW_MR);
190
191 input = at91_shdwc_get_wakeup_input(pdev, np);
192 writel(input, shdw->at91_shdwc_base + AT91_SHDW_WUIR);
193}
194
195static const struct shdwc_config sama5d2_shdwc_config = {
196 .wkup_pin_input = 0,
197 .mr_rtcwk_shift = 17,
198 .sr_rtcwk_shift = 5,
199};
200
201static const struct of_device_id at91_shdwc_of_match[] = {
202 {
203 .compatible = "atmel,sama5d2-shdwc",
204 .data = &sama5d2_shdwc_config,
205 }, {
206 /*sentinel*/
207 }
208};
209MODULE_DEVICE_TABLE(of, at91_shdwc_of_match);
210
211static int __init at91_shdwc_probe(struct platform_device *pdev)
212{
213 struct resource *res;
214 const struct of_device_id *match;
215 int ret;
216
217 if (!pdev->dev.of_node)
218 return -ENODEV;
219
220 at91_shdwc = devm_kzalloc(&pdev->dev, sizeof(*at91_shdwc), GFP_KERNEL);
221 if (!at91_shdwc)
222 return -ENOMEM;
223
224 platform_set_drvdata(pdev, at91_shdwc);
225
226 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
227 at91_shdwc->at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res);
228 if (IS_ERR(at91_shdwc->at91_shdwc_base)) {
229 dev_err(&pdev->dev, "Could not map reset controller address\n");
230 return PTR_ERR(at91_shdwc->at91_shdwc_base);
231 }
232
233 match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node);
234 at91_shdwc->cfg = (struct shdwc_config *)(match->data);
235
236 sclk = devm_clk_get(&pdev->dev, NULL);
237 if (IS_ERR(sclk))
238 return PTR_ERR(sclk);
239
240 ret = clk_prepare_enable(sclk);
241 if (ret) {
242 dev_err(&pdev->dev, "Could not enable slow clock\n");
243 return ret;
244 }
245
246 at91_wakeup_status(pdev);
247
248 at91_shdwc_dt_configure(pdev);
249
250 pm_power_off = at91_poweroff;
251
252 return 0;
253}
254
255static int __exit at91_shdwc_remove(struct platform_device *pdev)
256{
257 struct shdwc *shdw = platform_get_drvdata(pdev);
258
259 if (pm_power_off == at91_poweroff)
260 pm_power_off = NULL;
261
262 /* Reset values to disable wake-up features */
263 writel(0, shdw->at91_shdwc_base + AT91_SHDW_MR);
264 writel(0, shdw->at91_shdwc_base + AT91_SHDW_WUIR);
265
266 clk_disable_unprepare(sclk);
267
268 return 0;
269}
270
271static struct platform_driver at91_shdwc_driver = {
272 .remove = __exit_p(at91_shdwc_remove),
273 .driver = {
274 .name = "at91-shdwc",
275 .of_match_table = at91_shdwc_of_match,
276 },
277};
278module_platform_driver_probe(at91_shdwc_driver, at91_shdwc_probe);
279
280MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
281MODULE_DESCRIPTION("Atmel shutdown controller driver");
282MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c
index d6226d68b574..768b9fcb58ea 100644
--- a/drivers/power/sbs-battery.c
+++ b/drivers/power/sbs-battery.c
@@ -382,8 +382,6 @@ static int sbs_get_battery_property(struct i2c_client *client,
382 382
383 if (ret & BATTERY_FULL_CHARGED) 383 if (ret & BATTERY_FULL_CHARGED)
384 val->intval = POWER_SUPPLY_STATUS_FULL; 384 val->intval = POWER_SUPPLY_STATUS_FULL;
385 else if (ret & BATTERY_FULL_DISCHARGED)
386 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
387 else if (ret & BATTERY_DISCHARGING) 385 else if (ret & BATTERY_DISCHARGING)
388 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 386 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
389 else 387 else
@@ -702,8 +700,6 @@ static void sbs_delayed_work(struct work_struct *work)
702 700
703 if (ret & BATTERY_FULL_CHARGED) 701 if (ret & BATTERY_FULL_CHARGED)
704 ret = POWER_SUPPLY_STATUS_FULL; 702 ret = POWER_SUPPLY_STATUS_FULL;
705 else if (ret & BATTERY_FULL_DISCHARGED)
706 ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
707 else if (ret & BATTERY_DISCHARGING) 703 else if (ret & BATTERY_DISCHARGING)
708 ret = POWER_SUPPLY_STATUS_DISCHARGING; 704 ret = POWER_SUPPLY_STATUS_DISCHARGING;
709 else 705 else