blob: 7367e6618a4e423ccde64fefc2039a07407da406 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/slab.h>
18#include <linux/spinlock.h>
19#include <linux/platform_device.h>
20#include <linux/mfd/pm8xxx/core.h>
21#include <linux/mfd/pm8xxx/misc.h>
22
23/* PON CTRL 1 register */
24#define REG_PM8058_PON_CTRL_1 0x01C
25#define REG_PM8921_PON_CTRL_1 0x01C
Jay Chokshi86580f22011-10-17 12:27:52 -070026#define REG_PM8018_PON_CTRL_1 0x01C
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027
28#define PON_CTRL_1_PULL_UP_MASK 0xE0
29#define PON_CTRL_1_USB_PWR_EN 0x10
30
31#define PON_CTRL_1_WD_EN_MASK 0x08
32#define PON_CTRL_1_WD_EN_RESET 0x08
33#define PON_CTRL_1_WD_EN_PWR_OFF 0x00
34
35/* Regulator L22 control register */
36#define REG_PM8058_L22_CTRL 0x121
37
38/* SLEEP CTRL register */
39#define REG_PM8058_SLEEP_CTRL 0x02B
40#define REG_PM8921_SLEEP_CTRL 0x10A
Jay Chokshi86580f22011-10-17 12:27:52 -070041#define REG_PM8018_SLEEP_CTRL 0x10A
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042
43#define SLEEP_CTRL_SMPL_EN_MASK 0x04
44#define SLEEP_CTRL_SMPL_EN_RESET 0x04
45#define SLEEP_CTRL_SMPL_EN_PWR_OFF 0x00
46
47/* FTS regulator PMR registers */
48#define REG_PM8901_REGULATOR_S1_PMR 0xA7
49#define REG_PM8901_REGULATOR_S2_PMR 0xA8
50#define REG_PM8901_REGULATOR_S3_PMR 0xA9
51#define REG_PM8901_REGULATOR_S4_PMR 0xAA
52
53#define PM8901_REGULATOR_PMR_STATE_MASK 0x60
54#define PM8901_REGULATOR_PMR_STATE_OFF 0x20
55
Anirudh Ghayal5213eb82011-10-24 14:44:58 +053056/* GPIO UART MUX CTRL registers */
57#define REG_PM8XXX_GPIO_MUX_CTRL 0x1CC
58
59#define UART_PATH_SEL_MASK 0x60
60#define UART_PATH_SEL_SHIFT 0x5
61
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062struct pm8xxx_misc_chip {
63 struct list_head link;
64 struct pm8xxx_misc_platform_data pdata;
65 struct device *dev;
66 enum pm8xxx_version version;
67};
68
69static LIST_HEAD(pm8xxx_misc_chips);
70static DEFINE_SPINLOCK(pm8xxx_misc_chips_lock);
71
72static int pm8xxx_misc_masked_write(struct pm8xxx_misc_chip *chip, u16 addr,
73 u8 mask, u8 val)
74{
75 int rc;
76 u8 reg;
77
78 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
79 if (rc) {
80 pr_err("pm8xxx_readb(0x%03X) failed, rc=%d\n", addr, rc);
81 return rc;
82 }
83 reg &= ~mask;
84 reg |= val & mask;
85 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
86 if (rc)
87 pr_err("pm8xxx_writeb(0x%03X)=0x%02X failed, rc=%d\n", addr,
88 reg, rc);
89 return rc;
90}
91
Jay Chokshi86580f22011-10-17 12:27:52 -070092static int __pm8018_reset_pwr_off(struct pm8xxx_misc_chip *chip, int reset)
93{
94 int rc;
95
96 /* Enable SMPL if resetting is desired. */
97 rc = pm8xxx_misc_masked_write(chip, REG_PM8018_SLEEP_CTRL,
98 SLEEP_CTRL_SMPL_EN_MASK,
99 (reset ? SLEEP_CTRL_SMPL_EN_RESET : SLEEP_CTRL_SMPL_EN_PWR_OFF));
100 if (rc) {
101 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
102 return rc;
103 }
104
105 /*
106 * Select action to perform (reset or shutdown) when PS_HOLD goes low.
107 * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that
108 * USB charging is enabled.
109 */
110 rc = pm8xxx_misc_masked_write(chip, REG_PM8018_PON_CTRL_1,
111 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
112 | PON_CTRL_1_WD_EN_MASK,
113 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
114 | (reset ? PON_CTRL_1_WD_EN_RESET : PON_CTRL_1_WD_EN_PWR_OFF));
115 if (rc)
116 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
117
118 return rc;
119}
120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121static int __pm8058_reset_pwr_off(struct pm8xxx_misc_chip *chip, int reset)
122{
123 int rc;
124
125 /*
126 * Fix-up: Set regulator LDO22 to 1.225 V in high power mode. Leave its
127 * pull-down state intact. This ensures a safe shutdown.
128 */
129 rc = pm8xxx_misc_masked_write(chip, REG_PM8058_L22_CTRL, 0xBF, 0x93);
130 if (rc) {
131 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
132 goto read_write_err;
133 }
134
135 /* Enable SMPL if resetting is desired. */
136 rc = pm8xxx_misc_masked_write(chip, REG_PM8058_SLEEP_CTRL,
137 SLEEP_CTRL_SMPL_EN_MASK,
138 (reset ? SLEEP_CTRL_SMPL_EN_RESET : SLEEP_CTRL_SMPL_EN_PWR_OFF));
139 if (rc) {
140 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
141 goto read_write_err;
142 }
143
144 /*
145 * Select action to perform (reset or shutdown) when PS_HOLD goes low.
146 * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that
147 * USB charging is enabled.
148 */
149 rc = pm8xxx_misc_masked_write(chip, REG_PM8058_PON_CTRL_1,
150 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
151 | PON_CTRL_1_WD_EN_MASK,
152 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
153 | (reset ? PON_CTRL_1_WD_EN_RESET : PON_CTRL_1_WD_EN_PWR_OFF));
154 if (rc) {
155 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
156 goto read_write_err;
157 }
158
159read_write_err:
160 return rc;
161}
162
163static int __pm8901_reset_pwr_off(struct pm8xxx_misc_chip *chip, int reset)
164{
165 int rc = 0, i;
166 u8 pmr_addr[4] = {
167 REG_PM8901_REGULATOR_S2_PMR,
168 REG_PM8901_REGULATOR_S3_PMR,
169 REG_PM8901_REGULATOR_S4_PMR,
170 REG_PM8901_REGULATOR_S1_PMR,
171 };
172
173 /* Fix-up: Turn off regulators S1, S2, S3, S4 when shutting down. */
174 if (!reset) {
175 for (i = 0; i < 4; i++) {
176 rc = pm8xxx_misc_masked_write(chip, pmr_addr[i],
177 PM8901_REGULATOR_PMR_STATE_MASK,
178 PM8901_REGULATOR_PMR_STATE_OFF);
179 if (rc) {
180 pr_err("pm8xxx_misc_masked_write failed, "
181 "rc=%d\n", rc);
182 goto read_write_err;
183 }
184 }
185 }
186
187read_write_err:
188 return rc;
189}
190
191static int __pm8921_reset_pwr_off(struct pm8xxx_misc_chip *chip, int reset)
192{
193 int rc;
194
195 /* Enable SMPL if resetting is desired. */
196 rc = pm8xxx_misc_masked_write(chip, REG_PM8921_SLEEP_CTRL,
197 SLEEP_CTRL_SMPL_EN_MASK,
198 (reset ? SLEEP_CTRL_SMPL_EN_RESET : SLEEP_CTRL_SMPL_EN_PWR_OFF));
199 if (rc) {
200 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
201 goto read_write_err;
202 }
203
204 /*
205 * Select action to perform (reset or shutdown) when PS_HOLD goes low.
206 * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that
207 * USB charging is enabled.
208 */
209 rc = pm8xxx_misc_masked_write(chip, REG_PM8921_PON_CTRL_1,
210 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
211 | PON_CTRL_1_WD_EN_MASK,
212 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
213 | (reset ? PON_CTRL_1_WD_EN_RESET : PON_CTRL_1_WD_EN_PWR_OFF));
214 if (rc) {
215 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
216 goto read_write_err;
217 }
218
219read_write_err:
220 return rc;
221}
222
223/**
224 * pm8xxx_reset_pwr_off - switch all PM8XXX PMIC chips attached to the system to
225 * either reset or shutdown when they are turned off
226 * @reset: 0 = shudown the PMICs, 1 = shutdown and then restart the PMICs
227 *
228 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
229 */
230int pm8xxx_reset_pwr_off(int reset)
231{
232 struct pm8xxx_misc_chip *chip;
233 unsigned long flags;
234 int rc = 0;
235
236 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
237
238 /* Loop over all attached PMICs and call specific functions for them. */
239 list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
240 switch (chip->version) {
Jay Chokshi86580f22011-10-17 12:27:52 -0700241 case PM8XXX_VERSION_8018:
242 rc = __pm8018_reset_pwr_off(chip, reset);
243 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244 case PM8XXX_VERSION_8058:
245 rc = __pm8058_reset_pwr_off(chip, reset);
246 break;
247 case PM8XXX_VERSION_8901:
248 rc = __pm8901_reset_pwr_off(chip, reset);
249 break;
250 case PM8XXX_VERSION_8921:
251 rc = __pm8921_reset_pwr_off(chip, reset);
252 break;
253 default:
254 /* PMIC doesn't have reset_pwr_off; do nothing. */
255 break;
256 }
257 if (rc) {
258 pr_err("reset_pwr_off failed, rc=%d\n", rc);
259 break;
260 }
261 }
262
263 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
264
265 return rc;
266}
267EXPORT_SYMBOL_GPL(pm8xxx_reset_pwr_off);
268
Anirudh Ghayal5213eb82011-10-24 14:44:58 +0530269/**
270 * pm8xxx_uart_gpio_mux_ctrl - Mux configuration to select the UART
271 *
272 * @uart_path_sel: Input argument to select either UART1/2/3
273 *
274 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
275 */
276int pm8xxx_uart_gpio_mux_ctrl(enum pm8xxx_uart_path_sel uart_path_sel)
277{
278 struct pm8xxx_misc_chip *chip;
279 unsigned long flags;
280 int rc = 0;
281
282 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
283
284 /* Loop over all attached PMICs and call specific functions for them. */
285 list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
286 switch (chip->version) {
287 case PM8XXX_VERSION_8018:
288 case PM8XXX_VERSION_8058:
289 case PM8XXX_VERSION_8921:
290 rc = pm8xxx_misc_masked_write(chip,
291 REG_PM8XXX_GPIO_MUX_CTRL, UART_PATH_SEL_MASK,
292 uart_path_sel << UART_PATH_SEL_SHIFT);
293 break;
294 default:
295 /* Functionality not supported */
296 break;
297 }
298 if (rc) {
299 pr_err("uart_gpio_mux_ctrl failed, rc=%d\n", rc);
300 break;
301 }
302 }
303
304 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
305
306 return rc;
307}
308EXPORT_SYMBOL(pm8xxx_uart_gpio_mux_ctrl);
309
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310static int __devinit pm8xxx_misc_probe(struct platform_device *pdev)
311{
312 const struct pm8xxx_misc_platform_data *pdata = pdev->dev.platform_data;
313 struct pm8xxx_misc_chip *chip;
314 struct pm8xxx_misc_chip *sibling;
315 struct list_head *prev;
316 unsigned long flags;
317 int rc = 0;
318
319 if (!pdata) {
320 pr_err("missing platform data\n");
321 return -EINVAL;
322 }
323
324 chip = kzalloc(sizeof(struct pm8xxx_misc_chip), GFP_KERNEL);
325 if (!chip) {
326 pr_err("Cannot allocate %d bytes\n",
327 sizeof(struct pm8xxx_misc_chip));
328 return -ENOMEM;
329 }
330
331 chip->dev = &pdev->dev;
332 chip->version = pm8xxx_get_version(chip->dev->parent);
333 memcpy(&(chip->pdata), pdata, sizeof(struct pm8xxx_misc_platform_data));
334
335 /* Insert PMICs in priority order (lowest value first). */
336 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
337 prev = &pm8xxx_misc_chips;
338 list_for_each_entry(sibling, &pm8xxx_misc_chips, link) {
339 if (chip->pdata.priority < sibling->pdata.priority)
340 break;
341 else
342 prev = &sibling->link;
343 }
344 list_add(&chip->link, prev);
345 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
346
347 platform_set_drvdata(pdev, chip);
348
349 return rc;
350}
351
352static int __devexit pm8xxx_misc_remove(struct platform_device *pdev)
353{
354 struct pm8xxx_misc_chip *chip = platform_get_drvdata(pdev);
355 unsigned long flags;
356
357 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
358 list_del(&chip->link);
359 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
360
361 platform_set_drvdata(pdev, NULL);
362 kfree(chip);
363
364 return 0;
365}
366
367static struct platform_driver pm8xxx_misc_driver = {
368 .probe = pm8xxx_misc_probe,
369 .remove = __devexit_p(pm8xxx_misc_remove),
370 .driver = {
371 .name = PM8XXX_MISC_DEV_NAME,
372 .owner = THIS_MODULE,
373 },
374};
375
376static int __init pm8xxx_misc_init(void)
377{
378 return platform_driver_register(&pm8xxx_misc_driver);
379}
380postcore_initcall(pm8xxx_misc_init);
381
382static void __exit pm8xxx_misc_exit(void)
383{
384 platform_driver_unregister(&pm8xxx_misc_driver);
385}
386module_exit(pm8xxx_misc_exit);
387
388MODULE_LICENSE("GPL v2");
389MODULE_DESCRIPTION("PMIC 8XXX misc driver");
390MODULE_VERSION("1.0");
391MODULE_ALIAS("platform:" PM8XXX_MISC_DEV_NAME);