blob: 4e0b85a5b1194d9cb8f33c77b3c24a54a5d34247 [file] [log] [blame]
Umang Agrawal89f6dcb2018-01-03 19:07:47 +05301/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation. All rights reserved.
Deepa Dinamani22799652012-07-21 12:26:22 -07002
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
Parth Dixitc2e6dfe2015-06-19 15:57:47 +053012 * * Neither the name of The Linux Foundation, nor the names of its
Deepa Dinamani22799652012-07-21 12:26:22 -070013 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
Deepa Dinamani9a612932012-08-14 16:15:03 -070029#include <bits.h>
Deepa Dinamani22799652012-07-21 12:26:22 -070030#include <debug.h>
31#include <reg.h>
32#include <spmi.h>
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +053033#include <string.h>
Deepa Dinamani22799652012-07-21 12:26:22 -070034#include <pm8x41_hw.h>
Deepa Dinamani9a612932012-08-14 16:15:03 -070035#include <pm8x41.h>
Sridhar Parasuram92f87282015-02-05 09:58:18 -080036#include <rpm-ipc.h>
Channagoud Kadabi9089da62014-11-10 13:19:55 -080037#include <regulator.h>
Deepa Dinamani9a612932012-08-14 16:15:03 -070038#include <platform/timer.h>
Deepa Dinamani22799652012-07-21 12:26:22 -070039
Channagoud Kadabi9089da62014-11-10 13:19:55 -080040/* Enable LN BB CLK */
41static uint32_t ln_bb_clk[][8] = {
42 {
43 RPM_CLK_BUFFER_A_REQ, LNBB_CLK_ID,
44 KEY_SOFTWARE_ENABLE, 4, GENERIC_DISABLE,
45 RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY, 4, RPM_CLK_BUFFER_PIN_CONTROL_ENABLE_NONE,
46 },
47 {
48 RPM_CLK_BUFFER_A_REQ, LNBB_CLK_ID,
49 KEY_SOFTWARE_ENABLE, 4, GENERIC_ENABLE,
50 RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY, 4, RPM_CLK_BUFFER_PIN_CONTROL_ENABLE_NONE,
51 },
52};
53
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053054static uint8_t mpp_slave_id;
55
vijay kumar9ec33942014-08-08 17:25:46 +053056void pmi8994_config_mpp_slave_id(uint8_t slave_id)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053057{
58 mpp_slave_id = slave_id;
59}
Channagoud Kadabid091f702013-01-07 16:17:37 -080060/* SPMI helper functions */
61uint8_t pm8x41_reg_read(uint32_t addr)
Deepa Dinamani9a612932012-08-14 16:15:03 -070062{
63 uint8_t val = 0;
64 struct pmic_arb_cmd cmd;
65 struct pmic_arb_param param;
66
67 cmd.address = PERIPH_ID(addr);
68 cmd.offset = REG_OFFSET(addr);
69 cmd.slave_id = SLAVE_ID(addr);
70 cmd.priority = 0;
71
72 param.buffer = &val;
73 param.size = 1;
74
75 pmic_arb_read_cmd(&cmd, &param);
76
77 return val;
78}
79
Channagoud Kadabi56a6b522015-04-24 17:23:27 -070080uint32_t spmi_reg_read(uint32_t slave_id, uint16_t addr, uint8_t *data, uint8_t priority)
81{
82 struct pmic_arb_cmd cmd;
83 struct pmic_arb_param param;
84
85 cmd.address = PERIPH_ID(addr);
86 cmd.offset = REG_OFFSET(addr);
87 cmd.slave_id = slave_id;
88
89 cmd.priority = priority;
90
91 param.buffer = data;
92 param.size = 1;
93
94 return pmic_arb_read_cmd(&cmd, &param);
95}
96
97uint32_t spmi_reg_write(uint32_t slave_id, uint16_t addr, uint8_t *data, uint8_t priority)
98{
99 struct pmic_arb_cmd cmd;
100 struct pmic_arb_param param;
101
102 cmd.address = PERIPH_ID(addr);
103 cmd.offset = REG_OFFSET(addr);
104 cmd.slave_id = slave_id;
105
106 cmd.priority = priority;
107
108 param.buffer = data;
109 param.size = 1;
110
111 return pmic_arb_write_cmd(&cmd, &param);
112}
113
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800114/* SPMI helper function which takes slave id as the i/p */
115void pm8xxx_reg_write(uint8_t slave_id, uint32_t addr, uint8_t val)
116{
117 struct pmic_arb_cmd cmd;
118 struct pmic_arb_param param;
119
120 cmd.address = PERIPH_ID(addr);
121 cmd.offset = REG_OFFSET(addr);
122 cmd.slave_id = slave_id;
123
124 cmd.priority = 0;
125
126 param.buffer = &val;
127 param.size = 1;
128
129 pmic_arb_write_cmd(&cmd, &param);
130}
131
Channagoud Kadabid091f702013-01-07 16:17:37 -0800132void pm8x41_reg_write(uint32_t addr, uint8_t val)
Deepa Dinamani22799652012-07-21 12:26:22 -0700133{
134 struct pmic_arb_cmd cmd;
135 struct pmic_arb_param param;
Deepa Dinamani22799652012-07-21 12:26:22 -0700136
Deepa Dinamani9a612932012-08-14 16:15:03 -0700137 cmd.address = PERIPH_ID(addr);
138 cmd.offset = REG_OFFSET(addr);
139 cmd.slave_id = SLAVE_ID(addr);
Deepa Dinamani22799652012-07-21 12:26:22 -0700140 cmd.priority = 0;
Deepa Dinamani22799652012-07-21 12:26:22 -0700141
Deepa Dinamani9a612932012-08-14 16:15:03 -0700142 param.buffer = &val;
143 param.size = 1;
Deepa Dinamani22799652012-07-21 12:26:22 -0700144
Deepa Dinamani9a612932012-08-14 16:15:03 -0700145 pmic_arb_write_cmd(&cmd, &param);
146}
Deepa Dinamani22799652012-07-21 12:26:22 -0700147
Deepa Dinamani9a612932012-08-14 16:15:03 -0700148/* Exported functions */
149
150/* Set the boot done flag */
151void pm8x41_set_boot_done()
152{
153 uint8_t val;
154
155 val = REG_READ(SMBB_MISC_BOOT_DONE);
156 val |= BIT(BOOT_DONE_BIT);
157 REG_WRITE(SMBB_MISC_BOOT_DONE, val);
158}
159
160/* Configure GPIO */
161int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
162{
163 uint8_t val;
164 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
165
166 /* Disable the GPIO */
167 val = REG_READ(gpio_base + GPIO_EN_CTL);
168 val &= ~BIT(PERPH_EN_BIT);
169 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
170
171 /* Select the mode */
172 val = config->function | (config->direction << 4);
173 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
174
175 /* Set the right pull */
176 val = config->pull;
177 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
178
179 /* Select the VIN */
180 val = config->vin_sel;
181 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
182
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800183 if (config->direction == PM_GPIO_DIR_OUT) {
184 /* Set the right dig out control */
185 val = config->out_strength | (config->output_buffer << 4);
186 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
187 }
188
Ashish Garg44992472017-08-07 14:36:59 +0530189 /* Output source sel and output invert */
190 val = config->inv_int_pol << 7;
191 REG_WRITE(gpio_base + GPIO_DIG_OUT_SRC_CTL, val);
192
Deepa Dinamani9a612932012-08-14 16:15:03 -0700193 /* Enable the GPIO */
194 val = REG_READ(gpio_base + GPIO_EN_CTL);
195 val |= BIT(PERPH_EN_BIT);
196 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
197
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800198 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700199}
200
201/* Reads the status of requested gpio */
202int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
203{
204 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
205
206 *status = REG_READ(gpio_base + GPIO_STATUS);
207
208 /* Return the value of the GPIO pin */
209 *status &= BIT(GPIO_STATUS_VAL_BIT);
210
211 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
212
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800213 return 0;
214}
215
216/* Write the output value of the requested gpio */
217int pm8x41_gpio_set(uint8_t gpio, uint8_t value)
218{
219 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
220 uint8_t val;
221
222 /* Set the output value of the gpio */
223 val = REG_READ(gpio_base + GPIO_MODE_CTL);
224 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
225 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
226
227 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700228}
229
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700230/* Configure PM and PMI GPIO with slave id */
231int pm8x41_gpio_config_sid(uint8_t sid, uint8_t gpio, struct pm8x41_gpio *config)
232{
233 uint8_t val;
234 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
235
236 gpio_base &= 0x0ffff; /* clear sid */
237 gpio_base |= (sid << 16); /* add sid */
238
239 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
240
241 /* Disable the GPIO */
242 val = REG_READ(gpio_base + GPIO_EN_CTL);
243 val &= ~BIT(PERPH_EN_BIT);
244 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
245
246 /* Select the mode */
247 val = config->function | (config->direction << 4);
248 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
249
250 /* Set the right pull */
251 val = config->pull;
252 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
253
254 /* Select the VIN */
255 val = config->vin_sel;
256 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
257
258 if (config->direction == PM_GPIO_DIR_OUT) {
259 /* Set the right dig out control */
260 val = config->out_strength | (config->output_buffer << 4);
261 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
262 }
263
264 /* Enable the GPIO */
265 val = REG_READ(gpio_base + GPIO_EN_CTL);
266 val |= BIT(PERPH_EN_BIT);
267 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
268
269 return 0;
270}
271
272/* Reads the status of requested gpio */
273int pm8x41_gpio_get_sid(uint8_t sid, uint8_t gpio, uint8_t *status)
274{
275 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
276
277 gpio_base &= 0x0ffff; /* clear sid */
278 gpio_base |= (sid << 16); /* add sid */
279
280 *status = REG_READ(gpio_base + GPIO_STATUS);
281
282 /* Return the value of the GPIO pin */
283 *status &= BIT(GPIO_STATUS_VAL_BIT);
284
285 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
286
287 return 0;
288}
289
290/* Write the output value of the requested gpio */
291int pm8x41_gpio_set_sid(uint8_t sid, uint8_t gpio, uint8_t value)
292{
293 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
294 uint8_t val;
295
296 gpio_base &= 0x0ffff; /* clear sid */
297 gpio_base |= (sid << 16); /* add sid */
298
299 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
300
301 /* Set the output value of the gpio */
302 val = REG_READ(gpio_base + GPIO_MODE_CTL);
303 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
304 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
305
306 return 0;
307}
308
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800309/* Prepare PON RESIN S2 reset (bite) */
310void pm8x41_resin_s2_reset_enable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700311{
312 uint8_t val;
313
314 /* disable s2 reset */
315 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
316
Amol Jadi7ec52b42012-08-16 14:12:45 -0700317 /* Delay needed for disable to kick in. */
318 udelay(300);
319
Deepa Dinamani9a612932012-08-14 16:15:03 -0700320 /* configure s1 timer to 0 */
321 REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
322
323 /* configure s2 timer to 2s */
324 REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
325
326 /* configure reset type */
327 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
328
329 val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
330
331 /* enable s2 reset */
332 val |= BIT(S2_RESET_EN_BIT);
333 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
334}
335
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800336/* Disable PON RESIN S2 reset. (bite)*/
337void pm8x41_resin_s2_reset_disable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700338{
339 /* disable s2 reset */
340 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
Amol Jadi7ec52b42012-08-16 14:12:45 -0700341
342 /* Delay needed for disable to kick in. */
343 udelay(300);
Deepa Dinamani9a612932012-08-14 16:15:03 -0700344}
345
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800346/* Resin irq status for faulty pmic*/
Channagoud Kadabi36c19ea2013-07-05 16:28:44 -0700347uint32_t pm8x41_v2_resin_status()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700348{
349 uint8_t rt_sts = 0;
350
351 /* Enable S2 reset so we can detect the volume down key press */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800352 pm8x41_resin_s2_reset_enable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700353
354 /* Delay before interrupt triggering.
355 * See PON_DEBOUNCE_CTL reg.
356 */
357 mdelay(100);
358
359 rt_sts = REG_READ(PON_INT_RT_STS);
360
361 /* Must disable S2 reset otherwise PMIC will reset if key
362 * is held longer than S2 timer.
363 */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800364 pm8x41_resin_s2_reset_disable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700365
366 return (rt_sts & BIT(RESIN_BARK_INT_BIT));
Deepa Dinamani22799652012-07-21 12:26:22 -0700367}
Neeti Desai120b55d2012-08-20 17:15:56 -0700368
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800369/* Resin pin status */
370uint32_t pm8x41_resin_status()
371{
372 uint8_t rt_sts = 0;
373
374 rt_sts = REG_READ(PON_INT_RT_STS);
375
376 return (rt_sts & BIT(RESIN_ON_INT_BIT));
377}
378
Matthew Qin3aa87052014-02-21 10:32:34 +0800379/* Return 1 if power key is pressed */
380uint32_t pm8x41_get_pwrkey_is_pressed()
381{
382 uint8_t pwr_sts = 0;
383
384 pwr_sts = REG_READ(PON_INT_RT_STS);
385
386 if (pwr_sts & BIT(KPDPWR_ON_INT_BIT))
387 return 1;
388 else
389 return 0;
390}
391
Umang Agrawal89f6dcb2018-01-03 19:07:47 +0530392void pmi632_reset_configure(uint8_t reset_type)
393{
394 /* Slave ID of pm8953 and pmi632 */
395 uint8_t slave_id[] = {0, 2};
396 uint8_t i;
397
398 /* Reset sequence
399 1. Disable the ps hold for pm8953 and pmi632
400 2. set reset type for both pm8953 & pmi632
401 3. Enable ps hold for pm8953 to trigger the reset
402 */
403 /* disable PS_HOLD_RESET */
404 pm8xxx_reg_write(slave_id[0], PON_PS_HOLD_RESET_CTL2, 0x0);
405 pm8xxx_reg_write(slave_id[1], PON_PS_HOLD_RESET_CTL2, 0x0);
406
407 /* Delay needed for disable to kick in. */
408 udelay(300);
409
410 /* configure reset type */
411 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
412 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL, reset_type);
413
414 if (reset_type == PON_PSHOLD_WARM_RESET)
415 {
416 /* enable PS_HOLD_RESET */
417 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
418 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
419 }
420 else
421 {
422 pm8xxx_reg_write(slave_id[0], PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
423 }
424}
425
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800426void pm8994_reset_configure(uint8_t reset_type)
427{
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700428 /* Slave ID of pm8994 and pmi8994 */
429 uint8_t slave_id[] = {0, 2};
430 uint8_t i;
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800431
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700432 /* Reset sequence
433 1. Disable the ps hold for pm8994
434 2. set reset type for both pm8994 & pmi8994
435 3. Enable ps hold for pm8994 to trigger the reset
436 */
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800437 /* disable PS_HOLD_RESET */
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700438 pm8xxx_reg_write(slave_id[0], PON_PS_HOLD_RESET_CTL2, 0x0);
Channagoud Kadabi085ae312015-06-25 23:12:47 -0700439 pm8xxx_reg_write(slave_id[1], PON_PS_HOLD_RESET_CTL2, 0x0);
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800440
441 /* Delay needed for disable to kick in. */
442 udelay(300);
443
444 /* configure reset type */
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700445 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
446 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL, reset_type);
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800447
448 /* enable PS_HOLD_RESET */
Channagoud Kadabi085ae312015-06-25 23:12:47 -0700449 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
450 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800451}
452
Vamshi Krishna B V82af8482018-03-09 21:02:42 +0530453void pm8996_reset_configure(uint8_t slave_id, uint8_t reset_type)
454{
455 /* Reset sequence
456 1. Disable the ps hold
457 2. set reset type
458 3. Enable ps hold to trigger the reset
459 */
460 /* disable PS_HOLD_RESET */
461 pm8xxx_reg_write(slave_id, PON_PS_HOLD_RESET_CTL2, 0x0);
462
463 /* Delay needed for disable to kick in. */
464 udelay(300);
465
466 /* configure reset type */
467 pm8xxx_reg_write(slave_id, PON_PS_HOLD_RESET_CTL, reset_type);
468 /* enable PS_HOLD_RESET */
469 pm8xxx_reg_write(slave_id, PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
470}
471
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800472void pm8x41_v2_reset_configure(uint8_t reset_type)
Neeti Desai120b55d2012-08-20 17:15:56 -0700473{
474 uint8_t val;
475
476 /* disable PS_HOLD_RESET */
477 REG_WRITE(PON_PS_HOLD_RESET_CTL, 0x0);
478
479 /* Delay needed for disable to kick in. */
480 udelay(300);
481
482 /* configure reset type */
483 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
484
485 val = REG_READ(PON_PS_HOLD_RESET_CTL);
486
487 /* enable PS_HOLD_RESET */
488 val |= BIT(S2_RESET_EN_BIT);
489 REG_WRITE(PON_PS_HOLD_RESET_CTL, val);
490}
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530491
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800492void pm8x41_reset_configure(uint8_t reset_type)
493{
494 /* disable PS_HOLD_RESET */
495 REG_WRITE(PON_PS_HOLD_RESET_CTL2, 0x0);
496
497 /* Delay needed for disable to kick in. */
498 udelay(300);
499
500 /* configure reset type */
501 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
502
503 /* enable PS_HOLD_RESET */
504 REG_WRITE(PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
505}
506
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530507/*
508 * LDO set voltage, takes ldo name & voltage in UV as input
509 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700510int pm8x41_ldo_set_voltage(struct pm8x41_ldo *ldo, uint32_t voltage)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530511{
512 uint32_t range = 0;
513 uint32_t step = 0;
514 uint32_t mult = 0;
515 uint32_t val = 0;
516 uint32_t vmin = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530517
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700518 if (!ldo)
519 {
520 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530521 return 1;
522 }
523
524 /* Program Normal power mode */
525 val = 0x0;
526 val = (1 << LDO_NORMAL_PWR_BIT);
527 REG_WRITE((ldo->base + LDO_POWER_MODE), val);
528
529 /*
530 * Select range, step & vmin based on input voltage & type of LDO
531 * LDO can operate in low, mid, high power mode
532 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700533 if (ldo->type == PLDO_TYPE)
534 {
535 if (voltage < PLDO_UV_MIN)
536 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530537 range = 2;
538 step = PLDO_UV_STEP_LOW;
539 vmin = PLDO_UV_VMIN_LOW;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700540 }
541 else if (voltage < PDLO_UV_MID)
542 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530543 range = 3;
544 step = PLDO_UV_STEP_MID;
545 vmin = PLDO_UV_VMIN_MID;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700546 }
547 else
548 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530549 range = 4;
550 step = PLDO_UV_STEP_HIGH;
551 vmin = PLDO_UV_VMIN_HIGH;
552 }
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700553 }
554 else
555 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530556 range = 2;
557 step = NLDO_UV_STEP;
558 vmin = NLDO_UV_VMIN_LOW;
559 }
560
561 mult = (voltage - vmin) / step;
562
563 /* Set Range in voltage ctrl register */
564 val = 0x0;
565 val = range << LDO_RANGE_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700566 REG_WRITE((ldo->base + LDO_RANGE_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530567
568 /* Set multiplier in voltage ctrl register */
569 val = 0x0;
570 val = mult << LDO_VSET_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700571 REG_WRITE((ldo->base + LDO_STEP_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530572
573 return 0;
574}
575
576/*
577 * Enable or Disable LDO
578 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700579int pm8x41_ldo_control(struct pm8x41_ldo *ldo, uint8_t enable)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530580{
581 uint32_t val = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530582
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700583 if (!ldo)
584 {
585 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530586 return 1;
587 }
588
589 /* Enable LDO */
590 if (enable)
591 val = (1 << LDO_VREG_ENABLE_BIT);
592 else
593 val = (0 << LDO_VREG_ENABLE_BIT);
594
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700595 REG_WRITE((ldo->base + LDO_EN_CTL_REG), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530596
597 return 0;
598}
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800599
Kuogee Hsieh11835112013-10-04 15:50:36 -0700600/*
601 * lpg channel register write:
602 */
603void pm8x41_lpg_write(uint8_t chan, uint8_t off, uint8_t val)
604{
605 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
606
607 REG_WRITE(lpg_base + off, val);
608}
609
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700610/*
611 * pmi lpg channel register write with slave_id:
612 */
613void pm8x41_lpg_write_sid(uint8_t sid, uint8_t chan, uint8_t off, uint8_t val)
614{
615 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
616
617 lpg_base &= 0x0ffff; /* clear sid */
618 lpg_base |= (sid << 16); /* add sid */
619
620 dprintf(SPEW, "%s: lpg=%d base=%x\n", __func__, chan, lpg_base);
621
622 REG_WRITE(lpg_base + off, val);
623}
624
Parth Dixit1a963d72015-10-20 01:08:57 +0530625uint8_t pmi8950_get_pmi_subtype()
626{
627 uint8_t subtype;
628 spmi_reg_read((PMI8950_SLAVE_ID >> 16), REVID_REV_ID_SPARE_0, &subtype, 0);
629 return subtype;
630}
631
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800632uint8_t pm8x41_get_pmic_rev()
633{
634 return REG_READ(REVID_REVISION4);
635}
636
Mayank Grover8bf68ac2017-12-05 10:27:36 +0530637uint8_t pm660_get_pon_reason()
638{
639 return REG_READ(PM660_PON_REASON1);
640}
641
sundarajan srinivasand0f59e82013-02-12 19:17:02 -0800642uint8_t pm8x41_get_pon_reason()
643{
644 return REG_READ(PON_PON_REASON1);
645}
Deepa Dinamanic342f122013-06-12 15:41:31 -0700646
Parth Dixitc2e6dfe2015-06-19 15:57:47 +0530647uint8_t pm8950_get_pon_reason()
648{
649 uint8_t pon_reason = 0;
650
Parth Dixit746b6bb2015-07-09 19:29:44 +0530651 pon_reason = REG_READ(SMBCHGL_USB_ICL_STS_2|PMI8950_SLAVE_ID);
Parth Dixitc2e6dfe2015-06-19 15:57:47 +0530652 /* check usbin/dcin status on pmi and set the corresponding bits for pon */
653 pon_reason = (pon_reason & (USBIN_ACTIVE_PWR_SRC|DCIN_ACTIVE_PWR_SRC)) << 3 ;
654 pon_reason |= REG_READ(PON_PON_REASON1);
655
656 return pon_reason;
657}
658
Umang Agrawalfa38b2e2018-02-19 15:32:46 +0530659uint8_t pmi632_get_pon_reason()
660{
661 uint8_t pon_reason = 0;
662
663 pon_reason = REG_READ(SCHG_USB_INT_RT_STS|PMI8950_SLAVE_ID);
664 /* Check USBIN status on PMI and set the corresponding bits for pon */
665 pon_reason = (pon_reason & USBIN_PLUGIN_RT_STS);
666 pon_reason |= REG_READ(PON_PON_REASON1);
667
668 return pon_reason;
669}
670
Matthew Qin5e90d832014-07-11 11:15:22 +0800671uint8_t pm8x41_get_pon_poff_reason1()
672{
673 return REG_READ(PON_POFF_REASON1);
674}
675
676uint8_t pm8x41_get_pon_poff_reason2()
677{
678 return REG_READ(PON_POFF_REASON2);
679}
680
Ajay Singh Parmar502ed712014-07-23 22:58:43 -0700681void pm8x41_enable_mvs(struct pm8x41_mvs *mvs, enum mvs_en_ctl enable)
682{
683 ASSERT(mvs);
684
685 REG_WRITE(mvs->base + MVS_EN_CTL, enable << MVS_EN_CTL_ENABLE_SHIFT);
686}
687
Deepa Dinamanic342f122013-06-12 15:41:31 -0700688void pm8x41_enable_mpp(struct pm8x41_mpp *mpp, enum mpp_en_ctl enable)
689{
690 ASSERT(mpp);
691
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530692 REG_WRITE(((mpp->base + MPP_EN_CTL) + (mpp_slave_id << 16)), enable << MPP_EN_CTL_ENABLE_SHIFT);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700693}
694
695void pm8x41_config_output_mpp(struct pm8x41_mpp *mpp)
696{
697 ASSERT(mpp);
698
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530699 REG_WRITE(((mpp->base + MPP_DIG_VIN_CTL) + (mpp_slave_id << 16)), mpp->vin);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700700
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530701 REG_WRITE(((mpp->base + MPP_MODE_CTL) + (mpp_slave_id << 16)), mpp->mode | (MPP_DIGITAL_OUTPUT << MPP_MODE_CTL_MODE_SHIFT));
Deepa Dinamanic342f122013-06-12 15:41:31 -0700702}
Ameya Thakurb0a62ab2013-06-25 13:43:10 -0700703
Mayank Grover8bf68ac2017-12-05 10:27:36 +0530704uint8_t pm660_get_is_cold_boot()
705{
706 if (REG_READ(PM660_PON_WARMBOOT_STATUS1)) {
707 dprintf(INFO,"%s: Warm boot\n", __func__);
708 return 0;
709 }
710 return 1;
711}
712
Ameya Thakurb0a62ab2013-06-25 13:43:10 -0700713uint8_t pm8x41_get_is_cold_boot()
714{
715 if (REG_READ(PON_WARMBOOT_STATUS1) || REG_READ(PON_WARMBOOT_STATUS2)) {
716 dprintf(INFO,"%s: Warm boot\n", __func__);
717 return 0;
718 }
719 dprintf(INFO,"%s: cold boot\n", __func__);
720 return 1;
721}
Amol Jadic3231ff2013-07-23 14:35:31 -0700722
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800723/* api to control lnbb clock */
724void pm8x41_lnbb_clock_ctrl(uint8_t enable)
725{
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800726 if (enable)
727 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800728 rpm_clk_enable(&ln_bb_clk[GENERIC_ENABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800729 }
730 else
731 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800732 rpm_clk_enable(&ln_bb_clk[GENERIC_DISABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800733 }
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800734}
735
Amol Jadic3231ff2013-07-23 14:35:31 -0700736/* api to control diff clock */
737void pm8x41_diff_clock_ctrl(uint8_t enable)
738{
739 uint8_t reg;
740
741 reg = REG_READ(DIFF_CLK1_EN_CTL);
742
743 if (enable)
744 {
745 reg |= BIT(DIFF_CLK1_EN_BIT);
746 }
747 else
748 {
749 reg &= ~BIT(DIFF_CLK1_EN_BIT);
750 }
751
752 REG_WRITE(DIFF_CLK1_EN_CTL, reg);
753}
Xiaocheng Li73c57122013-09-14 17:32:00 +0800754
755void pm8x41_clear_pmic_watchdog(void)
756{
757 pm8x41_reg_write(PMIC_WD_RESET_S2_CTL2, 0x0);
758}
Channagoud Kadabi1372b902013-10-28 16:20:51 -0700759
760/* API to check for borken battery */
761int pm8xxx_is_battery_broken()
762{
763 uint8_t trkl_default = 0;
764 uint8_t vbat_det_default = 0;
765 int batt_is_broken = 0;
766
767 /* Store original trickle charging current setting */
768 trkl_default = pm8x41_reg_read(PM8XXX_IBAT_ATC_A);
769 /* Store original VBAT_DET_LO setting */
770 vbat_det_default = pm8x41_reg_read(PM8XXX_VBAT_DET);
771
772 /*Set trickle charge current to 50mA (IBAT_ATC_A = 0x00) */
773 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, 0x00);
774 /* Set VBAT_DET_LO to 4.3V so that VBAT_DET_HI = 4.52V (VBAT_DET_LO = 0x35) */
775 pm8x41_reg_write(PM8XXX_VBAT_DET, VBAT_DET_LO_4_30V);
776 /* Unlock SMBBP Secured Register */
777 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
778 /* Disable VTRKL_FAULT comp (SMBBP_CHGR_COMP_OVR0 = 0x08) */
779 pm8x41_reg_write(PM8XXX_COMP_OVR0, OVR0_DIS_VTRKL_FAULT);
780 /* Disable VCP (SMBB_BAT_IF_VCP = 0x00) */
781 pm8x41_reg_write(PM8XXX_VCP, 0x00);
782 /* Unlock SMBBP Secured Register */
783 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
784 /* Force trickle charging (SMBB_CHGR_TRKL_CHG_TEST = 0x01) */
785 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, CHG_TRICKLE_FORCED_ON);
786 /* Wait for vbat to rise */
787 mdelay(12);
788
789 /* Check Above VBAT_DET_HIGH status */
790 if (pm8x41_reg_read(PM8XXX_VBAT_IN_TSTS) & VBAT_DET_HI_RT_STS)
791 batt_is_broken = 1;
792 else
793 batt_is_broken = 0;
794
795 /* Unlock SMBBP Secured Register */
796 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
797
798 /* Disable force trickle charging */
799 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, 0x00);
800 /* re-enable VCP */
801 pm8x41_reg_write(PM8XXX_VCP, VCP_ENABLE);
802 /* restore trickle charging default current */
803 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, trkl_default);
804 /* restore VBAT_DET_LO setting to original value */
805 pm8x41_reg_write(PM8XXX_VBAT_DET, vbat_det_default);
806
807 return batt_is_broken;
808}
Channagoud Kadabi8ceb7382014-11-14 11:25:35 -0800809
810/* Detect broken battery for pmi 8994*/
811bool pmi8994_is_battery_broken()
812{
813 bool batt_is_broken;
814 uint8_t fast_charge = 0;
815
816 /* Disable the input missing ppoller */
817 REG_WRITE(PMI8994_CHGR_TRIM_OPTIONS_7_0, REG_READ(PMI8994_CHGR_TRIM_OPTIONS_7_0) & ~INPUT_MISSING_POLLER_EN);
818 /* Disable current termination */
819 REG_WRITE(PMI8994_CHGR_CFG2, REG_READ(PMI8994_CHGR_CFG2) & ~CURRENT_TERM_EN);
820 /* Fast-charge current to 300 mA */
821 fast_charge = REG_READ(PMI8994_FCC_CFG);
822 REG_WRITE(PMI8994_FCC_CFG, 0x0);
823 /* Change the float voltage to 4.50V */
824 REG_WRITE(PMI8994_FV_CFG, 0x3F);
825
826 mdelay(5);
827
828 if (REG_READ(PMI8994_INT_RT_STS) & BAT_TAPER_MODE_CHARGING_RT_STS)
829 batt_is_broken = true;
830 else
831 batt_is_broken = false;
832
833 /* Set float voltage back to 4.35V */
834 REG_WRITE(PMI8994_FV_CFG, 0x2B);
835 /* Enable current termination */
836 REG_WRITE(PMI8994_CHGR_CFG2, REG_READ(PMI8994_CHGR_CFG2) | CURRENT_TERM_EN);
837 /* Fast-charge current back to default mA */
838 REG_WRITE(PMI8994_FCC_CFG, fast_charge);
839 /* Re-enable the input missing poller */
840 REG_WRITE(PMI8994_CHGR_TRIM_OPTIONS_7_0, REG_READ(PMI8994_CHGR_TRIM_OPTIONS_7_0) | INPUT_MISSING_POLLER_EN);
841
842 return batt_is_broken;
843}