blob: 9cf5e91febb2e03f652c296436a5a38bed57e381 [file] [log] [blame]
Amol Jadif2f45602011-05-24 15:46:01 -07001/*
Ajay Singh Parmarcc6345a2013-02-13 20:30:49 +05302 * Copyright (c) 2011-2013, Linux Foundation. All rights reserved.
Amol Jadif2f45602011-05-24 15:46:01 -07003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
Channagoud Kadabic7b90912012-10-25 14:17:42 +053013 * * Neither the name of Linux Foundation, Inc. nor the names of its
Amol Jadif2f45602011-05-24 15:46:01 -070014 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29#include <assert.h>
Channagoud Kadabic7b90912012-10-25 14:17:42 +053030#include <string.h>
Amol Jadif2f45602011-05-24 15:46:01 -070031#include <sys/types.h>
Shashank Mittal1e2aad72012-03-08 17:10:14 -080032#include <err.h>
Amol Jadif2f45602011-05-24 15:46:01 -070033#include <dev/pm8921.h>
Channagoud Kadabic7b90912012-10-25 14:17:42 +053034#include <platform/timer.h>
Amol Jadif2f45602011-05-24 15:46:01 -070035#include "pm8921_hw.h"
36
Amol Jadif2f45602011-05-24 15:46:01 -070037static pm8921_dev_t *dev;
38
Amol Jadi60a55972011-06-10 18:50:47 -070039static uint8_t ldo_n_voltage_mult[LDO_VOLTAGE_ENTRIES] = {
40 18, /* 1.2V */
41 0,
42 0,
43 };
44
45static uint8_t ldo_p_voltage_mult[LDO_VOLTAGE_ENTRIES] = {
46 0,
47 6, /* 1.8V */
48 30, /* 3.0V */
49 };
Amol Jadif2f45602011-05-24 15:46:01 -070050
51/* Intialize the pmic driver */
52void pm8921_init(pm8921_dev_t *pmic)
53{
54 ASSERT(pmic);
55 ASSERT(pmic->read);
56 ASSERT(pmic->write);
57
58 dev = pmic;
59
60 dev->initialized = 1;
61}
62
Shashank Mittal39503262011-07-19 11:41:35 -070063static int pm8921_masked_write(uint16_t addr,
64 uint8_t mask, uint8_t val)
65{
66 int rc;
67 uint8_t reg;
68
69 rc = dev->read(&reg, 1, addr);
70 if (rc)
71 {
72 return rc;
73 }
74
75 reg &= ~mask;
76 reg |= val & mask;
77 rc = dev->write(&reg, 1, addr);
78
79 return rc;
80}
81
Amol Jadif2f45602011-05-24 15:46:01 -070082/* Set the BOOT_DONE flag */
83void pm8921_boot_done(void)
84{
85 uint8_t val;
86
87 ASSERT(dev);
88 ASSERT(dev->initialized);
89
90 dev->read(&val, 1, PBL_ACCESS_2);
91 val |= PBL_ACCESS_2_ENUM_TIMER_STOP;
92 /* TODO: Remove next line when h/w is rewired for battery simulation.*/
93 val |= (0x7 << 2);
94 dev->write(&val, 1, PBL_ACCESS_2);
95
96 dev->read(&val, 1, SYS_CONFIG_2);
97 val |= (SYS_CONFIG_2_BOOT_DONE | SYS_CONFIG_2_ADAPTIVE_BOOT_DISABLE);
98 dev->write(&val, 1, SYS_CONFIG_2);
99}
Amol Jadi3570f9d2011-05-27 13:57:44 -0700100
101/* Configure PMIC GPIO */
102int pm8921_gpio_config(int gpio, struct pm8921_gpio *param)
103{
104 int ret;
105 uint8_t bank[6];
106 uint8_t output_buf_config;
107 uint8_t output_value;
108
109 static uint8_t dir_map[] = {
110 PM_GPIO_MODE_OFF,
111 PM_GPIO_MODE_OUTPUT,
112 PM_GPIO_MODE_INPUT,
113 PM_GPIO_MODE_BOTH,
114 };
115
116 if (param == NULL) {
Kinson Chikef7b9432011-06-29 08:44:31 -0700117 dprintf (CRITICAL, "pm8291_gpio struct not defined\n");
Amol Jadi3570f9d2011-05-27 13:57:44 -0700118 return -1;
119 }
120
121 /* Select banks and configure the gpio */
122 bank[0] = PM_GPIO_WRITE |
123 ((param->vin_sel << PM_GPIO_VIN_SHIFT) &
124 PM_GPIO_VIN_MASK) |
125 PM_GPIO_MODE_ENABLE;
126
127 /* bank1 */
128 if ((param->direction & PM_GPIO_DIR_OUT) && param->output_buffer)
129 output_buf_config = PM_GPIO_OUT_BUFFER_OPEN_DRAIN;
130 else
131 output_buf_config = 0;
132
133 if ((param->direction & PM_GPIO_DIR_OUT) && param->output_value)
134 output_value = 1;
135 else
136 output_value = 0;
137
138 bank[1] = PM_GPIO_WRITE |
139 ((1 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
140 ((dir_map[param->direction] << PM_GPIO_MODE_SHIFT)
141 & PM_GPIO_MODE_MASK) |
142 output_buf_config |
143 output_value;
144
145 bank[2] = PM_GPIO_WRITE |
146 ((2 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
147 ((param->pull << PM_GPIO_PULL_SHIFT) &
148 PM_GPIO_PULL_MASK);
149
150 bank[3] = PM_GPIO_WRITE |
151 ((3 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
152 ((param->out_strength << PM_GPIO_OUT_STRENGTH_SHIFT) &
153 PM_GPIO_OUT_STRENGTH_MASK) |
154 (param->disable_pin ? PM_GPIO_PIN_DISABLE : PM_GPIO_PIN_ENABLE);
155
156 bank[4] = PM_GPIO_WRITE |
157 ((4 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
158 ((param->function << PM_GPIO_FUNC_SHIFT) &
159 PM_GPIO_FUNC_MASK);
160
161 bank[5] = PM_GPIO_WRITE |
162 ((5 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
163 (param->inv_int_pol ? 0 : PM_GPIO_NON_INT_POL_INV);
164
165 ret = dev->write(bank, 6, GPIO_CNTL(gpio));
166 if (ret) {
Kinson Chikef7b9432011-06-29 08:44:31 -0700167 dprintf(CRITICAL, "Failed to write to PM8921 ret=%d.\n", ret);
Amol Jadi3570f9d2011-05-27 13:57:44 -0700168 return -1;
169 }
170 return 0;
171}
Amol Jadi60a55972011-06-10 18:50:47 -0700172
Amol Jadi63f3da32011-09-15 18:57:40 -0700173/* Reads the value of the irq status for the requested block */
174int pm8921_irq_get_block_status(uint8_t block, uint8_t *status)
175{
176 int ret = 0;
177
178 /* Select the irq block to be read */
179 ret = dev->write(&block, 1, IRQ_BLOCK_SEL_USR_ADDR);
180
181 if(!ret)
182 {
183 /* Read the real time irq status value for the block */
184 ret = dev->read(status, 1, IRQ_STATUS_RT_USR_ADDR);
185 }
186
187 return ret;
188}
189
190/* Reads the status of requested gpio */
191int pm8921_gpio_get(uint8_t gpio, uint8_t *status)
192{
193 int ret = 0;
194 uint8_t block_status;
195
196 ret = pm8921_irq_get_block_status(PM_GPIO_BLOCK_ID(gpio), &block_status);
197
198 if(!ret)
199 {
200 if(block_status & PM_GPIO_ID_TO_BIT_MASK(gpio))
201 *status = 1;
202 else
203 *status = 0;
204 }
205
206 return ret;
207}
208
Hanumante1dc4db2012-01-26 11:52:20 -0800209int pm8921_pwrkey_status(uint8_t *is_pwrkey_pressed)
210{
211 int ret = 0;
212 uint8_t block_status;
213
214 ret = pm8921_irq_get_block_status(PM_PWRKEY_BLOCK_ID, &block_status);
215
216 if (!ret)
217 {
218 if(block_status & PM_PWRKEY_PRESS_BIT)
219 *is_pwrkey_pressed = 1;
220 else
221 *is_pwrkey_pressed = 0;
222 }
223 return ret;
224}
225
Amol Jadi60a55972011-06-10 18:50:47 -0700226int pm8921_ldo_set_voltage(uint32_t ldo_id, uint32_t voltage)
227{
228 uint8_t mult;
229 uint8_t val = 0;
230 uint32_t ldo_number = (ldo_id & ~LDO_P_MASK);
231 int32_t ret = 0;
232
233 /* Find the voltage multiplying factor */
234 if(ldo_id & LDO_P_MASK)
235 mult = ldo_p_voltage_mult[voltage];
236 else
237 mult = ldo_n_voltage_mult[voltage];
238
239 /* Program the TEST reg */
240 if (ldo_id & LDO_P_MASK){
241 /* Bank 2, only for p ldo, use 1.25V reference */
242 val = 0x0;
243 val |= ( 1 << PM8921_LDO_TEST_REG_RW );
244 val |= ( 2 << PM8921_LDO_TEST_REG_BANK_SEL);
245 ret = dev->write(&val, 1, PM8921_LDO_TEST_REG(ldo_number));
246 if (ret) {
247 dprintf(CRITICAL, "Failed to write to PM8921 LDO Test Reg ret=%d.\n", ret);
248 return -1;
249 }
250
251 /* Bank 4, only for p ldo, disable output range ext, normal capacitance */
252 val = 0x0;
253 val |= ( 1 << PM8921_LDO_TEST_REG_RW );
254 val |= ( 4 << PM8921_LDO_TEST_REG_BANK_SEL);
255 ret = dev->write(&val, 1, PM8921_LDO_TEST_REG(ldo_number));
256 if (ret) {
257 dprintf(CRITICAL, "Failed to write to PM8921 LDO Test Reg ret=%d.\n", ret);
258 return -1;
259 }
260 }
261
262 /* Program the CTRL reg */
Ajay Dudaniafc5b112011-08-24 13:25:37 -0700263 val = 0x0;
Amol Jadi60a55972011-06-10 18:50:47 -0700264 val |= ( 1 << PM8921_LDO_CTRL_REG_ENABLE);
265 val |= ( 1 << PM8921_LDO_CTRL_REG_PULL_DOWN);
266 val |= ( 0 << PM8921_LDO_CTRL_REG_POWER_MODE);
267 val |= ( mult << PM8921_LDO_CTRL_REG_VOLTAGE);
268 ret = dev->write(&val, 1, PM8921_LDO_CTRL_REG(ldo_number));
269 if (ret) {
270 dprintf(CRITICAL, "Failed to write to PM8921 LDO Ctrl Reg ret=%d.\n", ret);
271 return -1;
272 }
273
274 return 0;
275}
Shashank Mittal39503262011-07-19 11:41:35 -0700276
277/*
278 * Configure PMIC for reset and power off.
279 * reset = 1: Configure reset.
280 * reset = 0: Configure power off.
281 */
282int pm8921_config_reset_pwr_off(unsigned reset)
283{
284 int rc;
285
286 /* Enable SMPL(Short Momentary Power Loss) if resetting is desired. */
287 rc = pm8921_masked_write(PM8921_SLEEP_CTRL_REG,
288 SLEEP_CTRL_SMPL_EN_MASK,
289 (reset ? SLEEP_CTRL_SMPL_EN_RESET : SLEEP_CTRL_SMPL_EN_PWR_OFF));
290 if (rc)
291 {
292 goto read_write_err;
293 }
294
295 /*
296 * Select action to perform (reset or shutdown) when PS_HOLD goes low.
297 * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that
298 * USB charging is enabled.
299 */
300 rc = pm8921_masked_write(PM8921_PON_CTRL_1_REG,
301 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
302 | PON_CTRL_1_WD_EN_MASK,
303 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
304 | (reset ? PON_CTRL_1_WD_EN_RESET : PON_CTRL_1_WD_EN_PWR_OFF));
305 if (rc)
306 {
307 goto read_write_err;
308 }
309
310read_write_err:
311 return rc;
312}
313
Deepa Dinamani0bb64ff2011-12-06 10:45:44 -0800314/* A wrapper function to configure PMIC PWM
315 * pwm_id : Channel number to configure
316 * duty_us : duty cycle for output waveform in micro seconds
317 * period_us : period for output waveform in micro seconds
318 */
319int pm8921_set_pwm_config(uint8_t pwm_id, uint32_t duty_us, uint32_t period_us)
320{
321 int rc;
322
323 rc = pm8921_pwm_config(pwm_id, duty_us, period_us, dev);
324
325 return rc;
326}
327
328/* A wrapper function to enable PMIC PWM
329 * pwm_id : Channel number to enable
330 */
331int pm8921_pwm_channel_enable(uint8_t pwm_id)
332{
333 int rc;
334
335 rc = pm8921_pwm_enable(pwm_id, dev);
336
337 return rc;
338}
Deepa Dinamaniad4752a2011-12-08 17:51:21 -0800339
340/* Configure LED's for current sinks
341 * enable = 1: Configure external signal detection
342 * for the sink with the current level
343 * enable = 0: Turn off external signal detection
344 *
345 * Values for sink are defined as follows:
346 * 0 = MANUAL, turn on LED when curent [00000, 10100]
347 * 1 = PWM1
348 * 2 = PWM2
349 * 3 = PWM3
350 * 4 = DBUS1
351 * 5 = DBUS2
352 * 6 = DBUS3
353 * 7 = DBUS4
354 *
355 * Current settings are calculated as per the equation:
356 * [00000, 10100]: Iout = current * 2 mA
357 * [10101, 11111]: invalid settings
358 */
359
360int pm8921_config_led_current(enum pm8921_leds led_num,
361 uint8_t current,
362 enum led_mode sink,
363 int enable)
364{
365 uint8_t val;
366 int ret;
367
368 /* Program the CTRL reg */
369 val = 0x0;
370
371 if (enable != 0)
372 {
373
374 if (current > 0x15)
375 {
376 dprintf(CRITICAL, "Invalid current settings for PM8921 LED Ctrl Reg \
377 current=%d.\n", current);
378 return -1;
379 }
380
381 if (sink > 0x7)
382 {
383 dprintf(CRITICAL, "Invalid signal selection for PM8921 LED Ctrl Reg \
384 sink=%d.\n", sink);
385 return -1;
386 }
387
388 val |= LED_CURRENT_SET(current);
389 val |= LED_SIGNAL_SELECT(sink);
390 }
391
392 ret = dev->write(&val, 1, PM8921_LED_CNTL_REG(led_num));
393
394 if (ret)
395 dprintf(CRITICAL, "Failed to write to PM8921 LED Ctrl Reg ret=%d.\n", ret);
396
397 return ret;
398
399}
400
401/* Configure DRV_KEYPAD
402 *drv_flash_sel:
403 * 0000 = off
404 * Iout = drv_flash_sel * 20 mA (300 mA driver)
405 * Iout = drv_flash_sel * 40 mA (600 mA driver)
406 *
407 * flash_logic = 0 : flash is on when DTEST is high
408 * flash_logic = 0 : flash is off when DTEST is high
409 *
410 * flash_ensel = 0 : manual mode, turn on flash when drv_flash_sel > 0
411 * flash_ensel = 1 : DBUS1
412 * flash_ensel = 2 : DBUS2
413 * flash_ensel = 3 : enable flash from LPG
414 */
415
416int pm8921_config_drv_keypad(unsigned int drv_flash_sel, unsigned int flash_logic, unsigned int flash_ensel)
417{
418 uint8_t val;
419 int ret;
420
421 /* Program the CTRL reg */
422 val = 0x0;
423
424 if (drv_flash_sel != 0)
425 {
426 if (drv_flash_sel > 0x0F)
427 {
428 dprintf(CRITICAL, "Invalid current settings for PM8921 \
429 KEYPAD_DRV Ctrl Reg drv_flash_sel=%d.\n", drv_flash_sel);
430 return -1;
431 }
432
433 if (flash_logic > 1)
434 {
435 dprintf(CRITICAL, "Invalid signal selection for PM8921 \
436 KEYPAD_DRV Ctrl Reg flash_logic=%d.\n", flash_logic);
437 return -1;
438 }
439
440 if (flash_ensel > 3)
441 {
442 dprintf(CRITICAL, "Invalid signal selection for PM8921 \
443 KEYPAD_DRV Ctrl Reg flash_ensel=%d.\n", flash_ensel);
444 return -1;
445 }
446
447 val |= DRV_FLASH_SEL(drv_flash_sel);
448 val |= FLASH_LOGIC_SEL(flash_logic);
449 val |= FLASH_ENSEL(flash_ensel);
450 }
451
452 ret = dev->write(&val, 1, PM8921_DRV_KEYPAD_CNTL_REG);
453
454 if (ret)
455 dprintf(CRITICAL, "Failed to write to PM8921 KEYPAD_DRV Ctrl Reg ret=%d.\n", ret);
456
457 return ret;
458
459}
Shashank Mittal1e2aad72012-03-08 17:10:14 -0800460
461int pm8921_low_voltage_switch_enable(uint8_t lvs_id)
462{
463 int ret = NO_ERROR;
464 uint8_t val;
465
466 if (lvs_id < lvs_start || lvs_id > lvs_end) {
Amol Jadi041d6722012-05-29 10:28:51 -0700467 dprintf(CRITICAL, "Requested unsupported LVS.\n");
Shashank Mittal1e2aad72012-03-08 17:10:14 -0800468 return ERROR;
469 }
470
471 if (lvs_id == lvs_2) {
Amol Jadi041d6722012-05-29 10:28:51 -0700472 dprintf(CRITICAL, "No support for LVS2 yet!\n");
Shashank Mittal1e2aad72012-03-08 17:10:14 -0800473 return ERROR;
474 }
475
476 /* Read LVS_TEST Reg first*/
477 ret = dev->read(&val, 1, PM8921_LVS_TEST_REG(lvs_id));
478 if (ret) {
Amol Jadi041d6722012-05-29 10:28:51 -0700479 dprintf(CRITICAL, "Failed to read LVS_TEST Reg ret=%d.\n", ret);
Shashank Mittal1e2aad72012-03-08 17:10:14 -0800480 return ret;
481 }
482
483 /* Check if switch is already ON */
484 val = val & PM8921_LVS_100_TEST_VOUT_OK;
485 if (val)
486 return ret;
487
488 /* Turn on switch in normal mode */
489 val = 0;
490 val |= PM8921_LVS_100_CTRL_SW_EN; /* Enable Switch */
491 val |= PM8921_LVS_100_CTRL_SLEEP_B_IGNORE; /* Ignore sleep mode pin */
492 ret = dev->write(&val, 1, PM8921_LVS_CTRL_REG(lvs_id));
493 if (ret)
Amol Jadi041d6722012-05-29 10:28:51 -0700494 dprintf(CRITICAL, "Failed to write LVS_CTRL Reg ret=%d.\n", ret);
Shashank Mittal1e2aad72012-03-08 17:10:14 -0800495
496 return ret;
497}
498
499int pm8921_mpp_set_digital_output(uint8_t mpp_id)
500{
501 int ret = NO_ERROR;
502 uint8_t val;
503
504 if (mpp_id < mpp_start || mpp_id > mpp_end) {
Amol Jadi041d6722012-05-29 10:28:51 -0700505 dprintf(CRITICAL, "Requested unsupported MPP.\n");
Shashank Mittal1e2aad72012-03-08 17:10:14 -0800506 return ERROR;
507 }
508
509 val = 0;
510 /* Configure in digital output mode */
511 val |= PM8921_MPP_CTRL_DIGITAL_OUTPUT;
512 val |= PM8921_MPP_CTRL_VIO_1; /* Set input voltage to 1.8V */
513 val |= PM8921_MPP_CTRL_OUTPUT_HIGH; /* Set mpp to high */
514
515 ret = dev->write(&val, 1, PM8921_MPP_CTRL_REG(mpp_id));
516 if (ret) {
Amol Jadi041d6722012-05-29 10:28:51 -0700517 dprintf(CRITICAL, "Failed to write MPP_CTRL Reg ret=%d.\n",
Shashank Mittal1e2aad72012-03-08 17:10:14 -0800518 ret);
519 }
520
521 return ret;
522}
Channagoud Kadabid1412be2012-06-07 16:47:57 +0530523
Ajay Singh Parmarcc6345a2013-02-13 20:30:49 +0530524int pm8921_HDMI_Switch(void)
525{
526 int ret = NO_ERROR;
527 uint8_t val;
528
529 /* Value for HDMI MVS 5V Switch */
530 val = 0x068;
531
532 /* Turn on MVS 5V HDMI switch */
533 ret = dev->write(&val, 1, PM8921_MVS_5V_HDMI_SWITCH);
534 if (ret) {
535 dprintf(CRITICAL,
536 "Failed to turn ON MVS 5V hdmi switch ret=%d.\n", ret);
537 }
538
539 return ret;
540}
541
Channagoud Kadabid1412be2012-06-07 16:47:57 +0530542int pm8921_rtc_alarm_disable(void)
543{
544 int rc;
545 uint8_t reg;
546
547 rc = dev->read(&reg, 1, PM8921_RTC_CTRL);
548 if (rc) {
549 dprintf(CRITICAL,"Failed to read RTC_CTRL reg = %d\n",rc);
550 return rc;
551 }
552 reg = (reg & ~PM8921_RTC_ALARM_ENABLE);
553
554 rc = dev->write(&reg, 1, PM8921_RTC_CTRL);
555 if (rc) {
556 dprintf(CRITICAL,"Failed to write RTC_CTRL reg = %d\n",rc);
557 return rc;
558 }
559
560 return rc;
561}
Channagoud Kadabic7b90912012-10-25 14:17:42 +0530562
563/*
564 * Set battery alarm with low & high threshold values
565 */
566int pm89xx_bat_alarm_set(bat_vol_t up_thresh_vol, bat_vol_t low_thresh_vol)
567{
568 int rc;
569 uint8_t reg = 0;
570
571 if ((up_thresh_vol > BAT_VOL_4_3) || (low_thresh_vol > BAT_VOL_4_3)) {
572 dprintf(CRITICAL, "Input voltage not in permissible range\n");
573 return 1;
574 }
575
576 /*
577 * Write upper & lower threshold values
578 */
579 reg = (up_thresh_vol << PM89XX_BAT_UP_THRESH_VOL) | low_thresh_vol;
580
581 rc = dev->write(&reg, 1, PM89XX_BAT_ALRM_THRESH);
582 if (rc) {
583 dprintf(CRITICAL, "Failed to set BAT_THRESH reg = %d\n", rc);
584 return rc;
585 }
586
587 /* Read Alarm control to use the existing hysteresis values */
588 rc = dev->read(&reg, 1, PM89XX_BAT_ALRM_CTRL);
589 if (rc) {
590 dprintf(CRITICAL, "Failed to read BAT_ALARM reg = %d\n", rc);
591 return rc;
592 }
593
594 /* Enable battery alarm */
595 reg |= PM89XX_BAT_ALRM_ENABLE;
596 rc = dev->write(&reg, 1, PM89XX_BAT_ALRM_CTRL);
597 if (rc) {
598 dprintf(CRITICAL, "Failed to enable BAT_ALARM reg = %d\n", rc);
599 return rc;
600 }
601
602 /* Wait for the comparator o/p to settle */
603 mdelay(10);
604
605 return rc;
606}
607
608/*
609 * API to return status of battery
610 * if the vbatt is below upper threshold return 0
611 * if the vbatt is below lower threshold return 1
612 */
613int pm89xx_bat_alarm_status(uint8_t *high_status, uint8_t *low_status)
614{
615 int rc = 0;
616 uint8_t reg = 0;
617
618 /* Read the battery status */
619 rc = dev->read(&reg, 1, PM89XX_BAT_ALRM_CTRL);
620 if (rc) {
621 dprintf(CRITICAL, "Failed to read BAT_ALARM reg = %d\n", rc);
622 return rc;
623 }
624
625 /* Return the status if battery alarm is enabled */
626 if (reg & PM89XX_BAT_ALRM_ENABLE) {
627 *high_status = (reg & PM89XX_BAT_UPR_STATUS);
628 *low_status = (reg & PM89XX_BAT_LWR_STATUS);
629 } else {
630 dprintf(CRITICAL, "Battery alarm is not enabled\n");
631 return 1;
632 }
633
634 return rc;
635}
636
637/*
638 * Return 1 if VBUS is connected, 0 otherwise
639 */
640int pm89xx_vbus_status(void)
641{
642 int rc;
643 uint8_t reg = 0;
644
645 rc = dev->read(&reg, 1, PM89XX_USB_OVP_CTRL);
646 if (rc) {
647 dprintf(CRITICAL, "Failed to read USB OVP CTRL = %d\n", rc);
648 return rc;
649 }
650
651 reg &= PM89XX_VBUS_INPUT_STATUS;
652
653 return reg;
654}
655
656static struct pm89xx_vreg *ldo_get(const char *ldo_name)
657{
658 uint8_t i;
659 struct pm89xx_vreg *ldo = NULL;
660
661 for (i = 0; i < ARRAY_SIZE(ldo_data); i++) {
662 ldo = &ldo_data[i];
663 if (!strncmp(ldo->name, ldo_name, strlen(ldo_name)))
664 break;
665 }
666
667 return ldo;
668}
669
670/*
671 * API takes LDO name & voltage as input
672 * Input voltage is taken in mVs
673 * PLDO voltage ranging from 1500mV to 3000mV
674 * NLDO voltage ranging from 750mV to 1525mV
675 */
676int pm89xx_ldo_set_voltage(const char *ldo_name, uint32_t voltage)
677{
678 uint8_t mult;
679 uint8_t val = 0;
680 int32_t ret = 0;
681 struct pm89xx_vreg *ldo;
682
683 /* Find the LDO info from table */
684 ldo = ldo_get(ldo_name);
685
686 if (!ldo) {
687 dprintf(CRITICAL, "Requested LDO is not supported : \
688 %s\n", ldo_name);
689 return -1;
690 }
691
692 /* Find the voltage multiplying factor */
693 if (ldo->type == PLDO_TYPE) {
694 if (voltage < PLDO_MV_VMIN)
695 voltage = PLDO_MV_VMIN;
696 else if (voltage > PLDO_MV_VMAX)
697 voltage = PLDO_MV_VMAX;
698 mult = (voltage - PLDO_MV_VMIN) / PLDO_MV_VSTEP;
699 } else {
700 if (voltage < NLDO_MV_VMIN)
701 voltage = NLDO_MV_VMIN;
702 else if (voltage > NLDO_MV_VMAX)
703 voltage = NLDO_MV_VMAX;
704 mult = (voltage - NLDO_MV_VMIN) / NLDO_MV_VSTEP;
705 }
706
707 /* Program the TEST reg */
708 if (ldo->type == PLDO_TYPE) {
709 /* Bank 2, only for p ldo, use 1.25V reference */
710 val = 0x0;
711 val |= (1 << PM8921_LDO_TEST_REG_RW);
712 val |= (2 << PM8921_LDO_TEST_REG_BANK_SEL);
713 ret = dev->write(&val, 1, ldo->test_reg);
714 if (ret) {
715 dprintf(CRITICAL, "Failed to write to PM8921 LDO Test \
716 Reg ret=%d.\n", ret);
717 return -1;
718 }
719
720 /*
721 * Bank 4, only for p ldo, disable output range ext,
722 * normal capacitance
723 */
724 val = 0x0;
725 val |= (1 << PM8921_LDO_TEST_REG_RW);
726 val |= (4 << PM8921_LDO_TEST_REG_BANK_SEL);
727 ret = dev->write(&val, 1, ldo->test_reg);
728 if (ret) {
729 dprintf(CRITICAL, "Failed to write to PM8921 LDO Test \
730 Reg ret=%d.\n", ret);
731 return -1;
732 }
733 }
734
735 /* Program the CTRL reg */
736 val = 0x0;
737 val |= (1 << PM8921_LDO_CTRL_REG_ENABLE);
738 val |= (1 << PM8921_LDO_CTRL_REG_PULL_DOWN);
739 val |= (0 << PM8921_LDO_CTRL_REG_POWER_MODE);
740 val |= (mult << PM8921_LDO_CTRL_REG_VOLTAGE);
741 ret = dev->write(&val, 1, ldo->ctrl_reg);
742 if (ret) {
743 dprintf(CRITICAL, "Failed to write to PM8921 LDO Ctrl Reg \
744 ret=%d.\n", ret);
745 return -1;
746 }
747
748 return 0;
749}
Sangani Suryanarayana Raju6a2e9df2013-06-07 16:44:01 +0530750
751int pm8921_configure_wled(void)
752{
753 pm8921_masked_write(WLED_BOOST_CFG_REG, 0xFF, 0x47);
754 pm8921_masked_write(WLED_HIGH_POLE_CAP_REG, 0xFF, 0x2c);
755 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(2), 0xFF, 0x19);
756 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(3), 0xFF, 0x59);
757 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(4), 0xFF, 0x59);
758 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(5), 0xFF, 0x66);
759 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(6), 0xFF, 0x66);
760 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(7), 0xFF, 0x0f);
761 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(8), 0xFF, 0xff);
762 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(9), 0xFF, 0x0f);
763 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(10), 0xFF, 0xff);
764 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(12), 0xFF, 0x16);
765 pm8921_masked_write(SSBI_REG_ADDR_WLED_CTRL(13), 0xFF, 0x55);
766 pm8921_masked_write(WLED_MOD_CTRL_REG, 0xFF, 0x7f);
767 pm8921_masked_write(WLED_SYNC_REG, WLED_SYNC_MASK, WLED_SYNC_VAL);
768 pm8921_masked_write(WLED_SYNC_REG, WLED_SYNC_MASK, WLED_SYNC_RESET_VAL);
769}