blob: 6575f9517ca2e6a04ac7d8c16f7fd7d485bd60b4 [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>
Kiran Gunda11938522018-10-16 17:54:00 +053039#include <pm_vib.h>
40
41#define QPNP_VIB_EN BIT(7)
Deepa Dinamani22799652012-07-21 12:26:22 -070042
Channagoud Kadabi9089da62014-11-10 13:19:55 -080043/* Enable LN BB CLK */
44static uint32_t ln_bb_clk[][8] = {
45 {
46 RPM_CLK_BUFFER_A_REQ, LNBB_CLK_ID,
47 KEY_SOFTWARE_ENABLE, 4, GENERIC_DISABLE,
48 RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY, 4, RPM_CLK_BUFFER_PIN_CONTROL_ENABLE_NONE,
49 },
50 {
51 RPM_CLK_BUFFER_A_REQ, LNBB_CLK_ID,
52 KEY_SOFTWARE_ENABLE, 4, GENERIC_ENABLE,
53 RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY, 4, RPM_CLK_BUFFER_PIN_CONTROL_ENABLE_NONE,
54 },
55};
56
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053057static uint8_t mpp_slave_id;
58
vijay kumar9ec33942014-08-08 17:25:46 +053059void pmi8994_config_mpp_slave_id(uint8_t slave_id)
Aparna Mallavarapu083766b2014-07-21 21:04:48 +053060{
61 mpp_slave_id = slave_id;
62}
Channagoud Kadabid091f702013-01-07 16:17:37 -080063/* SPMI helper functions */
64uint8_t pm8x41_reg_read(uint32_t addr)
Deepa Dinamani9a612932012-08-14 16:15:03 -070065{
66 uint8_t val = 0;
67 struct pmic_arb_cmd cmd;
68 struct pmic_arb_param param;
69
70 cmd.address = PERIPH_ID(addr);
71 cmd.offset = REG_OFFSET(addr);
72 cmd.slave_id = SLAVE_ID(addr);
73 cmd.priority = 0;
74
75 param.buffer = &val;
76 param.size = 1;
77
78 pmic_arb_read_cmd(&cmd, &param);
79
80 return val;
81}
82
Channagoud Kadabi56a6b522015-04-24 17:23:27 -070083uint32_t spmi_reg_read(uint32_t slave_id, uint16_t addr, uint8_t *data, uint8_t priority)
84{
85 struct pmic_arb_cmd cmd;
86 struct pmic_arb_param param;
87
88 cmd.address = PERIPH_ID(addr);
89 cmd.offset = REG_OFFSET(addr);
90 cmd.slave_id = slave_id;
91
92 cmd.priority = priority;
93
94 param.buffer = data;
95 param.size = 1;
96
97 return pmic_arb_read_cmd(&cmd, &param);
98}
99
100uint32_t spmi_reg_write(uint32_t slave_id, uint16_t addr, uint8_t *data, uint8_t priority)
101{
102 struct pmic_arb_cmd cmd;
103 struct pmic_arb_param param;
104
105 cmd.address = PERIPH_ID(addr);
106 cmd.offset = REG_OFFSET(addr);
107 cmd.slave_id = slave_id;
108
109 cmd.priority = priority;
110
111 param.buffer = data;
112 param.size = 1;
113
114 return pmic_arb_write_cmd(&cmd, &param);
115}
116
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800117/* SPMI helper function which takes slave id as the i/p */
118void pm8xxx_reg_write(uint8_t slave_id, uint32_t addr, uint8_t val)
119{
120 struct pmic_arb_cmd cmd;
121 struct pmic_arb_param param;
122
123 cmd.address = PERIPH_ID(addr);
124 cmd.offset = REG_OFFSET(addr);
125 cmd.slave_id = slave_id;
126
127 cmd.priority = 0;
128
129 param.buffer = &val;
130 param.size = 1;
131
132 pmic_arb_write_cmd(&cmd, &param);
133}
134
Channagoud Kadabid091f702013-01-07 16:17:37 -0800135void pm8x41_reg_write(uint32_t addr, uint8_t val)
Deepa Dinamani22799652012-07-21 12:26:22 -0700136{
137 struct pmic_arb_cmd cmd;
138 struct pmic_arb_param param;
Deepa Dinamani22799652012-07-21 12:26:22 -0700139
Deepa Dinamani9a612932012-08-14 16:15:03 -0700140 cmd.address = PERIPH_ID(addr);
141 cmd.offset = REG_OFFSET(addr);
142 cmd.slave_id = SLAVE_ID(addr);
Deepa Dinamani22799652012-07-21 12:26:22 -0700143 cmd.priority = 0;
Deepa Dinamani22799652012-07-21 12:26:22 -0700144
Deepa Dinamani9a612932012-08-14 16:15:03 -0700145 param.buffer = &val;
146 param.size = 1;
Deepa Dinamani22799652012-07-21 12:26:22 -0700147
Deepa Dinamani9a612932012-08-14 16:15:03 -0700148 pmic_arb_write_cmd(&cmd, &param);
149}
Deepa Dinamani22799652012-07-21 12:26:22 -0700150
Deepa Dinamani9a612932012-08-14 16:15:03 -0700151/* Exported functions */
152
153/* Set the boot done flag */
154void pm8x41_set_boot_done()
155{
156 uint8_t val;
157
158 val = REG_READ(SMBB_MISC_BOOT_DONE);
159 val |= BIT(BOOT_DONE_BIT);
160 REG_WRITE(SMBB_MISC_BOOT_DONE, val);
161}
162
163/* Configure GPIO */
164int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
165{
166 uint8_t val;
167 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
168
169 /* Disable the GPIO */
170 val = REG_READ(gpio_base + GPIO_EN_CTL);
171 val &= ~BIT(PERPH_EN_BIT);
172 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
173
174 /* Select the mode */
175 val = config->function | (config->direction << 4);
176 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
177
178 /* Set the right pull */
179 val = config->pull;
180 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
181
182 /* Select the VIN */
183 val = config->vin_sel;
184 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
185
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800186 if (config->direction == PM_GPIO_DIR_OUT) {
187 /* Set the right dig out control */
188 val = config->out_strength | (config->output_buffer << 4);
189 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
190 }
191
Ashish Garg44992472017-08-07 14:36:59 +0530192 /* Output source sel and output invert */
193 val = config->inv_int_pol << 7;
194 REG_WRITE(gpio_base + GPIO_DIG_OUT_SRC_CTL, val);
195
Deepa Dinamani9a612932012-08-14 16:15:03 -0700196 /* Enable the GPIO */
197 val = REG_READ(gpio_base + GPIO_EN_CTL);
198 val |= BIT(PERPH_EN_BIT);
199 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
200
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800201 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700202}
203
204/* Reads the status of requested gpio */
205int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
206{
207 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
208
209 *status = REG_READ(gpio_base + GPIO_STATUS);
210
211 /* Return the value of the GPIO pin */
212 *status &= BIT(GPIO_STATUS_VAL_BIT);
213
214 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
215
Siddhartha Agrawald61f81e2012-12-17 19:20:35 -0800216 return 0;
217}
218
219/* Write the output value of the requested gpio */
220int pm8x41_gpio_set(uint8_t gpio, uint8_t value)
221{
222 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
223 uint8_t val;
224
225 /* Set the output value of the gpio */
226 val = REG_READ(gpio_base + GPIO_MODE_CTL);
227 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
228 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
229
230 return 0;
Deepa Dinamani9a612932012-08-14 16:15:03 -0700231}
232
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700233/* Configure PM and PMI GPIO with slave id */
234int pm8x41_gpio_config_sid(uint8_t sid, uint8_t gpio, struct pm8x41_gpio *config)
235{
236 uint8_t val;
237 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
238
239 gpio_base &= 0x0ffff; /* clear sid */
240 gpio_base |= (sid << 16); /* add sid */
241
242 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
243
244 /* Disable the GPIO */
245 val = REG_READ(gpio_base + GPIO_EN_CTL);
246 val &= ~BIT(PERPH_EN_BIT);
247 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
248
249 /* Select the mode */
250 val = config->function | (config->direction << 4);
251 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
252
253 /* Set the right pull */
254 val = config->pull;
255 REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
256
257 /* Select the VIN */
258 val = config->vin_sel;
259 REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
260
261 if (config->direction == PM_GPIO_DIR_OUT) {
262 /* Set the right dig out control */
263 val = config->out_strength | (config->output_buffer << 4);
264 REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
265 }
266
267 /* Enable the GPIO */
268 val = REG_READ(gpio_base + GPIO_EN_CTL);
269 val |= BIT(PERPH_EN_BIT);
270 REG_WRITE(gpio_base + GPIO_EN_CTL, val);
271
272 return 0;
273}
274
275/* Reads the status of requested gpio */
276int pm8x41_gpio_get_sid(uint8_t sid, uint8_t gpio, uint8_t *status)
277{
278 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
279
280 gpio_base &= 0x0ffff; /* clear sid */
281 gpio_base |= (sid << 16); /* add sid */
282
283 *status = REG_READ(gpio_base + GPIO_STATUS);
284
285 /* Return the value of the GPIO pin */
286 *status &= BIT(GPIO_STATUS_VAL_BIT);
287
288 dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
289
290 return 0;
291}
292
293/* Write the output value of the requested gpio */
294int pm8x41_gpio_set_sid(uint8_t sid, uint8_t gpio, uint8_t value)
295{
296 uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
297 uint8_t val;
298
299 gpio_base &= 0x0ffff; /* clear sid */
300 gpio_base |= (sid << 16); /* add sid */
301
302 dprintf(SPEW, "%s: gpio=%d base=%x\n", __func__, gpio, gpio_base);
303
304 /* Set the output value of the gpio */
305 val = REG_READ(gpio_base + GPIO_MODE_CTL);
306 val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
307 REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
308
309 return 0;
310}
311
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800312/* Prepare PON RESIN S2 reset (bite) */
313void pm8x41_resin_s2_reset_enable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700314{
315 uint8_t val;
316
317 /* disable s2 reset */
318 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
319
Amol Jadi7ec52b42012-08-16 14:12:45 -0700320 /* Delay needed for disable to kick in. */
321 udelay(300);
322
Deepa Dinamani9a612932012-08-14 16:15:03 -0700323 /* configure s1 timer to 0 */
324 REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
325
326 /* configure s2 timer to 2s */
327 REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
328
329 /* configure reset type */
330 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
331
332 val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
333
334 /* enable s2 reset */
335 val |= BIT(S2_RESET_EN_BIT);
336 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
337}
338
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800339/* Disable PON RESIN S2 reset. (bite)*/
340void pm8x41_resin_s2_reset_disable()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700341{
342 /* disable s2 reset */
343 REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
Amol Jadi7ec52b42012-08-16 14:12:45 -0700344
345 /* Delay needed for disable to kick in. */
346 udelay(300);
Deepa Dinamani9a612932012-08-14 16:15:03 -0700347}
348
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800349/* Resin irq status for faulty pmic*/
Channagoud Kadabi36c19ea2013-07-05 16:28:44 -0700350uint32_t pm8x41_v2_resin_status()
Deepa Dinamani9a612932012-08-14 16:15:03 -0700351{
352 uint8_t rt_sts = 0;
353
354 /* Enable S2 reset so we can detect the volume down key press */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800355 pm8x41_resin_s2_reset_enable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700356
357 /* Delay before interrupt triggering.
358 * See PON_DEBOUNCE_CTL reg.
359 */
360 mdelay(100);
361
362 rt_sts = REG_READ(PON_INT_RT_STS);
363
364 /* Must disable S2 reset otherwise PMIC will reset if key
365 * is held longer than S2 timer.
366 */
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800367 pm8x41_resin_s2_reset_disable();
Deepa Dinamani9a612932012-08-14 16:15:03 -0700368
369 return (rt_sts & BIT(RESIN_BARK_INT_BIT));
Deepa Dinamani22799652012-07-21 12:26:22 -0700370}
Neeti Desai120b55d2012-08-20 17:15:56 -0700371
Deepa Dinamanic7f87582013-02-01 15:24:49 -0800372/* Resin pin status */
373uint32_t pm8x41_resin_status()
374{
375 uint8_t rt_sts = 0;
376
377 rt_sts = REG_READ(PON_INT_RT_STS);
378
379 return (rt_sts & BIT(RESIN_ON_INT_BIT));
380}
381
Matthew Qin3aa87052014-02-21 10:32:34 +0800382/* Return 1 if power key is pressed */
383uint32_t pm8x41_get_pwrkey_is_pressed()
384{
385 uint8_t pwr_sts = 0;
386
387 pwr_sts = REG_READ(PON_INT_RT_STS);
388
389 if (pwr_sts & BIT(KPDPWR_ON_INT_BIT))
390 return 1;
391 else
392 return 0;
393}
394
Umang Agrawal89f6dcb2018-01-03 19:07:47 +0530395void pmi632_reset_configure(uint8_t reset_type)
396{
397 /* Slave ID of pm8953 and pmi632 */
398 uint8_t slave_id[] = {0, 2};
399 uint8_t i;
400
401 /* Reset sequence
402 1. Disable the ps hold for pm8953 and pmi632
403 2. set reset type for both pm8953 & pmi632
404 3. Enable ps hold for pm8953 to trigger the reset
405 */
406 /* disable PS_HOLD_RESET */
407 pm8xxx_reg_write(slave_id[0], PON_PS_HOLD_RESET_CTL2, 0x0);
408 pm8xxx_reg_write(slave_id[1], PON_PS_HOLD_RESET_CTL2, 0x0);
409
410 /* Delay needed for disable to kick in. */
411 udelay(300);
412
413 /* configure reset type */
414 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
415 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL, reset_type);
416
417 if (reset_type == PON_PSHOLD_WARM_RESET)
418 {
419 /* enable PS_HOLD_RESET */
420 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
421 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
422 }
423 else
424 {
425 pm8xxx_reg_write(slave_id[0], PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
426 }
427}
428
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800429void pm8994_reset_configure(uint8_t reset_type)
430{
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700431 /* Slave ID of pm8994 and pmi8994 */
432 uint8_t slave_id[] = {0, 2};
433 uint8_t i;
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800434
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700435 /* Reset sequence
436 1. Disable the ps hold for pm8994
437 2. set reset type for both pm8994 & pmi8994
438 3. Enable ps hold for pm8994 to trigger the reset
439 */
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800440 /* disable PS_HOLD_RESET */
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700441 pm8xxx_reg_write(slave_id[0], PON_PS_HOLD_RESET_CTL2, 0x0);
Channagoud Kadabi085ae312015-06-25 23:12:47 -0700442 pm8xxx_reg_write(slave_id[1], PON_PS_HOLD_RESET_CTL2, 0x0);
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800443
444 /* Delay needed for disable to kick in. */
445 udelay(300);
446
447 /* configure reset type */
Channagoud Kadabi4b07aa72015-03-23 17:22:36 -0700448 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
449 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL, reset_type);
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800450
451 /* enable PS_HOLD_RESET */
Channagoud Kadabi085ae312015-06-25 23:12:47 -0700452 for (i = 0; i < ARRAY_SIZE(slave_id); i++)
453 pm8xxx_reg_write(slave_id[i], PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
Channagoud Kadabi1312b5d2015-01-28 23:28:47 -0800454}
455
Vamshi Krishna B V82af8482018-03-09 21:02:42 +0530456void pm8996_reset_configure(uint8_t slave_id, uint8_t reset_type)
457{
458 /* Reset sequence
459 1. Disable the ps hold
460 2. set reset type
461 3. Enable ps hold to trigger the reset
462 */
463 /* disable PS_HOLD_RESET */
464 pm8xxx_reg_write(slave_id, PON_PS_HOLD_RESET_CTL2, 0x0);
465
466 /* Delay needed for disable to kick in. */
467 udelay(300);
468
469 /* configure reset type */
470 pm8xxx_reg_write(slave_id, PON_PS_HOLD_RESET_CTL, reset_type);
471 /* enable PS_HOLD_RESET */
472 pm8xxx_reg_write(slave_id, PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
473}
474
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800475void pm8x41_v2_reset_configure(uint8_t reset_type)
Neeti Desai120b55d2012-08-20 17:15:56 -0700476{
477 uint8_t val;
478
479 /* disable PS_HOLD_RESET */
480 REG_WRITE(PON_PS_HOLD_RESET_CTL, 0x0);
481
482 /* Delay needed for disable to kick in. */
483 udelay(300);
484
485 /* configure reset type */
486 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
487
488 val = REG_READ(PON_PS_HOLD_RESET_CTL);
489
490 /* enable PS_HOLD_RESET */
491 val |= BIT(S2_RESET_EN_BIT);
492 REG_WRITE(PON_PS_HOLD_RESET_CTL, val);
493}
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530494
Deepa Dinamani3c9865d2013-03-08 14:03:19 -0800495void pm8x41_reset_configure(uint8_t reset_type)
496{
497 /* disable PS_HOLD_RESET */
498 REG_WRITE(PON_PS_HOLD_RESET_CTL2, 0x0);
499
500 /* Delay needed for disable to kick in. */
501 udelay(300);
502
503 /* configure reset type */
504 REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
505
506 /* enable PS_HOLD_RESET */
507 REG_WRITE(PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
508}
509
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530510/*
511 * LDO set voltage, takes ldo name & voltage in UV as input
512 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700513int pm8x41_ldo_set_voltage(struct pm8x41_ldo *ldo, uint32_t voltage)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530514{
515 uint32_t range = 0;
516 uint32_t step = 0;
517 uint32_t mult = 0;
518 uint32_t val = 0;
519 uint32_t vmin = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530520
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700521 if (!ldo)
522 {
523 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530524 return 1;
525 }
526
527 /* Program Normal power mode */
528 val = 0x0;
529 val = (1 << LDO_NORMAL_PWR_BIT);
530 REG_WRITE((ldo->base + LDO_POWER_MODE), val);
531
532 /*
533 * Select range, step & vmin based on input voltage & type of LDO
534 * LDO can operate in low, mid, high power mode
535 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700536 if (ldo->type == PLDO_TYPE)
537 {
538 if (voltage < PLDO_UV_MIN)
539 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530540 range = 2;
541 step = PLDO_UV_STEP_LOW;
542 vmin = PLDO_UV_VMIN_LOW;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700543 }
544 else if (voltage < PDLO_UV_MID)
545 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530546 range = 3;
547 step = PLDO_UV_STEP_MID;
548 vmin = PLDO_UV_VMIN_MID;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700549 }
550 else
551 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530552 range = 4;
553 step = PLDO_UV_STEP_HIGH;
554 vmin = PLDO_UV_VMIN_HIGH;
555 }
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700556 }
557 else
558 {
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530559 range = 2;
560 step = NLDO_UV_STEP;
561 vmin = NLDO_UV_VMIN_LOW;
562 }
563
564 mult = (voltage - vmin) / step;
565
566 /* Set Range in voltage ctrl register */
567 val = 0x0;
568 val = range << LDO_RANGE_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700569 REG_WRITE((ldo->base + LDO_RANGE_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530570
571 /* Set multiplier in voltage ctrl register */
572 val = 0x0;
573 val = mult << LDO_VSET_SEL_BIT;
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700574 REG_WRITE((ldo->base + LDO_STEP_CTRL), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530575
576 return 0;
577}
578
579/*
580 * Enable or Disable LDO
581 */
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700582int pm8x41_ldo_control(struct pm8x41_ldo *ldo, uint8_t enable)
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530583{
584 uint32_t val = 0;
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530585
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700586 if (!ldo)
587 {
588 dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530589 return 1;
590 }
591
592 /* Enable LDO */
593 if (enable)
594 val = (1 << LDO_VREG_ENABLE_BIT);
595 else
596 val = (0 << LDO_VREG_ENABLE_BIT);
597
Deepa Dinamanie69ba612013-06-03 16:10:09 -0700598 REG_WRITE((ldo->base + LDO_EN_CTL_REG), val);
Channagoud Kadabi0e60b7d2012-11-01 22:56:08 +0530599
600 return 0;
601}
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800602
Kuogee Hsieh11835112013-10-04 15:50:36 -0700603/*
604 * lpg channel register write:
605 */
606void pm8x41_lpg_write(uint8_t chan, uint8_t off, uint8_t val)
607{
608 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
609
610 REG_WRITE(lpg_base + off, val);
611}
612
Kuogee Hsieh383a5ae2014-09-02 16:31:39 -0700613/*
614 * pmi lpg channel register write with slave_id:
615 */
616void pm8x41_lpg_write_sid(uint8_t sid, uint8_t chan, uint8_t off, uint8_t val)
617{
618 uint32_t lpg_base = LPG_N_PERIPHERAL_BASE(chan);
619
620 lpg_base &= 0x0ffff; /* clear sid */
621 lpg_base |= (sid << 16); /* add sid */
622
623 dprintf(SPEW, "%s: lpg=%d base=%x\n", __func__, chan, lpg_base);
624
625 REG_WRITE(lpg_base + off, val);
626}
627
Parth Dixit1a963d72015-10-20 01:08:57 +0530628uint8_t pmi8950_get_pmi_subtype()
629{
630 uint8_t subtype;
631 spmi_reg_read((PMI8950_SLAVE_ID >> 16), REVID_REV_ID_SPARE_0, &subtype, 0);
632 return subtype;
633}
634
Deepa Dinamani7564f2a2013-02-05 17:55:51 -0800635uint8_t pm8x41_get_pmic_rev()
636{
637 return REG_READ(REVID_REVISION4);
638}
639
Mayank Grover8bf68ac2017-12-05 10:27:36 +0530640uint8_t pm660_get_pon_reason()
641{
642 return REG_READ(PM660_PON_REASON1);
643}
644
sundarajan srinivasand0f59e82013-02-12 19:17:02 -0800645uint8_t pm8x41_get_pon_reason()
646{
647 return REG_READ(PON_PON_REASON1);
648}
Deepa Dinamanic342f122013-06-12 15:41:31 -0700649
Parth Dixitc2e6dfe2015-06-19 15:57:47 +0530650uint8_t pm8950_get_pon_reason()
651{
652 uint8_t pon_reason = 0;
653
Parth Dixit746b6bb2015-07-09 19:29:44 +0530654 pon_reason = REG_READ(SMBCHGL_USB_ICL_STS_2|PMI8950_SLAVE_ID);
Parth Dixitc2e6dfe2015-06-19 15:57:47 +0530655 /* check usbin/dcin status on pmi and set the corresponding bits for pon */
656 pon_reason = (pon_reason & (USBIN_ACTIVE_PWR_SRC|DCIN_ACTIVE_PWR_SRC)) << 3 ;
657 pon_reason |= REG_READ(PON_PON_REASON1);
658
659 return pon_reason;
660}
661
Umang Agrawalfa38b2e2018-02-19 15:32:46 +0530662uint8_t pmi632_get_pon_reason()
663{
664 uint8_t pon_reason = 0;
665
666 pon_reason = REG_READ(SCHG_USB_INT_RT_STS|PMI8950_SLAVE_ID);
667 /* Check USBIN status on PMI and set the corresponding bits for pon */
668 pon_reason = (pon_reason & USBIN_PLUGIN_RT_STS);
669 pon_reason |= REG_READ(PON_PON_REASON1);
670
671 return pon_reason;
672}
673
Matthew Qin5e90d832014-07-11 11:15:22 +0800674uint8_t pm8x41_get_pon_poff_reason1()
675{
676 return REG_READ(PON_POFF_REASON1);
677}
678
679uint8_t pm8x41_get_pon_poff_reason2()
680{
681 return REG_READ(PON_POFF_REASON2);
682}
683
Ajay Singh Parmar502ed712014-07-23 22:58:43 -0700684void pm8x41_enable_mvs(struct pm8x41_mvs *mvs, enum mvs_en_ctl enable)
685{
686 ASSERT(mvs);
687
688 REG_WRITE(mvs->base + MVS_EN_CTL, enable << MVS_EN_CTL_ENABLE_SHIFT);
689}
690
Deepa Dinamanic342f122013-06-12 15:41:31 -0700691void pm8x41_enable_mpp(struct pm8x41_mpp *mpp, enum mpp_en_ctl enable)
692{
693 ASSERT(mpp);
694
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530695 REG_WRITE(((mpp->base + MPP_EN_CTL) + (mpp_slave_id << 16)), enable << MPP_EN_CTL_ENABLE_SHIFT);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700696}
697
698void pm8x41_config_output_mpp(struct pm8x41_mpp *mpp)
699{
700 ASSERT(mpp);
701
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530702 REG_WRITE(((mpp->base + MPP_DIG_VIN_CTL) + (mpp_slave_id << 16)), mpp->vin);
Deepa Dinamanic342f122013-06-12 15:41:31 -0700703
Aparna Mallavarapu083766b2014-07-21 21:04:48 +0530704 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 -0700705}
Ameya Thakurb0a62ab2013-06-25 13:43:10 -0700706
Mayank Grover8bf68ac2017-12-05 10:27:36 +0530707uint8_t pm660_get_is_cold_boot()
708{
709 if (REG_READ(PM660_PON_WARMBOOT_STATUS1)) {
710 dprintf(INFO,"%s: Warm boot\n", __func__);
711 return 0;
712 }
713 return 1;
714}
715
Ameya Thakurb0a62ab2013-06-25 13:43:10 -0700716uint8_t pm8x41_get_is_cold_boot()
717{
718 if (REG_READ(PON_WARMBOOT_STATUS1) || REG_READ(PON_WARMBOOT_STATUS2)) {
719 dprintf(INFO,"%s: Warm boot\n", __func__);
720 return 0;
721 }
722 dprintf(INFO,"%s: cold boot\n", __func__);
723 return 1;
724}
Amol Jadic3231ff2013-07-23 14:35:31 -0700725
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800726/* api to control lnbb clock */
727void pm8x41_lnbb_clock_ctrl(uint8_t enable)
728{
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800729 if (enable)
730 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800731 rpm_clk_enable(&ln_bb_clk[GENERIC_ENABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800732 }
733 else
734 {
Channagoud Kadabi9089da62014-11-10 13:19:55 -0800735 rpm_clk_enable(&ln_bb_clk[GENERIC_DISABLE][0], 24);
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800736 }
Channagoud Kadabi7ec7a082014-02-04 15:47:13 -0800737}
738
Amol Jadic3231ff2013-07-23 14:35:31 -0700739/* api to control diff clock */
740void pm8x41_diff_clock_ctrl(uint8_t enable)
741{
742 uint8_t reg;
743
744 reg = REG_READ(DIFF_CLK1_EN_CTL);
745
746 if (enable)
747 {
748 reg |= BIT(DIFF_CLK1_EN_BIT);
749 }
750 else
751 {
752 reg &= ~BIT(DIFF_CLK1_EN_BIT);
753 }
754
755 REG_WRITE(DIFF_CLK1_EN_CTL, reg);
756}
Xiaocheng Li73c57122013-09-14 17:32:00 +0800757
758void pm8x41_clear_pmic_watchdog(void)
759{
760 pm8x41_reg_write(PMIC_WD_RESET_S2_CTL2, 0x0);
761}
Channagoud Kadabi1372b902013-10-28 16:20:51 -0700762
763/* API to check for borken battery */
764int pm8xxx_is_battery_broken()
765{
766 uint8_t trkl_default = 0;
767 uint8_t vbat_det_default = 0;
768 int batt_is_broken = 0;
769
770 /* Store original trickle charging current setting */
771 trkl_default = pm8x41_reg_read(PM8XXX_IBAT_ATC_A);
772 /* Store original VBAT_DET_LO setting */
773 vbat_det_default = pm8x41_reg_read(PM8XXX_VBAT_DET);
774
775 /*Set trickle charge current to 50mA (IBAT_ATC_A = 0x00) */
776 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, 0x00);
777 /* Set VBAT_DET_LO to 4.3V so that VBAT_DET_HI = 4.52V (VBAT_DET_LO = 0x35) */
778 pm8x41_reg_write(PM8XXX_VBAT_DET, VBAT_DET_LO_4_30V);
779 /* Unlock SMBBP Secured Register */
780 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
781 /* Disable VTRKL_FAULT comp (SMBBP_CHGR_COMP_OVR0 = 0x08) */
782 pm8x41_reg_write(PM8XXX_COMP_OVR0, OVR0_DIS_VTRKL_FAULT);
783 /* Disable VCP (SMBB_BAT_IF_VCP = 0x00) */
784 pm8x41_reg_write(PM8XXX_VCP, 0x00);
785 /* Unlock SMBBP Secured Register */
786 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
787 /* Force trickle charging (SMBB_CHGR_TRKL_CHG_TEST = 0x01) */
788 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, CHG_TRICKLE_FORCED_ON);
789 /* Wait for vbat to rise */
790 mdelay(12);
791
792 /* Check Above VBAT_DET_HIGH status */
793 if (pm8x41_reg_read(PM8XXX_VBAT_IN_TSTS) & VBAT_DET_HI_RT_STS)
794 batt_is_broken = 1;
795 else
796 batt_is_broken = 0;
797
798 /* Unlock SMBBP Secured Register */
799 pm8x41_reg_write(PM8XXX_SEC_ACCESS, SEC_ACCESS);
800
801 /* Disable force trickle charging */
802 pm8x41_reg_write(PM8XXX_TRKL_CHG_TEST, 0x00);
803 /* re-enable VCP */
804 pm8x41_reg_write(PM8XXX_VCP, VCP_ENABLE);
805 /* restore trickle charging default current */
806 pm8x41_reg_write(PM8XXX_IBAT_ATC_A, trkl_default);
807 /* restore VBAT_DET_LO setting to original value */
808 pm8x41_reg_write(PM8XXX_VBAT_DET, vbat_det_default);
809
810 return batt_is_broken;
811}
Channagoud Kadabi8ceb7382014-11-14 11:25:35 -0800812
813/* Detect broken battery for pmi 8994*/
814bool pmi8994_is_battery_broken()
815{
816 bool batt_is_broken;
817 uint8_t fast_charge = 0;
818
819 /* Disable the input missing ppoller */
820 REG_WRITE(PMI8994_CHGR_TRIM_OPTIONS_7_0, REG_READ(PMI8994_CHGR_TRIM_OPTIONS_7_0) & ~INPUT_MISSING_POLLER_EN);
821 /* Disable current termination */
822 REG_WRITE(PMI8994_CHGR_CFG2, REG_READ(PMI8994_CHGR_CFG2) & ~CURRENT_TERM_EN);
823 /* Fast-charge current to 300 mA */
824 fast_charge = REG_READ(PMI8994_FCC_CFG);
825 REG_WRITE(PMI8994_FCC_CFG, 0x0);
826 /* Change the float voltage to 4.50V */
827 REG_WRITE(PMI8994_FV_CFG, 0x3F);
828
829 mdelay(5);
830
831 if (REG_READ(PMI8994_INT_RT_STS) & BAT_TAPER_MODE_CHARGING_RT_STS)
832 batt_is_broken = true;
833 else
834 batt_is_broken = false;
835
836 /* Set float voltage back to 4.35V */
837 REG_WRITE(PMI8994_FV_CFG, 0x2B);
838 /* Enable current termination */
839 REG_WRITE(PMI8994_CHGR_CFG2, REG_READ(PMI8994_CHGR_CFG2) | CURRENT_TERM_EN);
840 /* Fast-charge current back to default mA */
841 REG_WRITE(PMI8994_FCC_CFG, fast_charge);
842 /* Re-enable the input missing poller */
843 REG_WRITE(PMI8994_CHGR_TRIM_OPTIONS_7_0, REG_READ(PMI8994_CHGR_TRIM_OPTIONS_7_0) | INPUT_MISSING_POLLER_EN);
844
845 return batt_is_broken;
846}
Kiran Gunda11938522018-10-16 17:54:00 +0530847
848void pm8x41_vib_turn_on(void)
849{
850 uint8_t val;
851
852 val = pm8x41_reg_read(QPNP_VIB_VTG_CTL);
853 val &= ~QPNP_VIB_VTG_SET_MASK;
854 val |= (QPNP_VIB_DEFAULT_VTG_LVL & QPNP_VIB_VTG_SET_MASK);
855 pm8x41_reg_write(QPNP_VIB_VTG_CTL, val);
856
857 val = pm8x41_reg_read(QPNP_VIB_EN_CTL);
858 val |= QPNP_VIB_EN;
859 pm8x41_reg_write(QPNP_VIB_EN_CTL, val);
860}
861
862/* Turn off vibrator */
863void pm8x41_vib_turn_off(void)
864{
865 uint8_t val;
866
867 val = pm8x41_reg_read(QPNP_VIB_EN_CTL);
868 val &= ~QPNP_VIB_EN;
869 pm8x41_reg_write(QPNP_VIB_EN_CTL, val);
870}