pm8921.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*
  2. * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  3. *
  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.
  13. * * Neither the name of Code Aurora Forum, Inc. nor the names of its
  14. * 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>
  30. #include <sys/types.h>
  31. #include <err.h>
  32. #include <dev/pm8921.h>
  33. #include "pm8921_hw.h"
  34. static pm8921_dev_t *dev;
  35. static uint8_t ldo_n_voltage_mult[LDO_VOLTAGE_ENTRIES] = {
  36. 18, /* 1.2V */
  37. 0,
  38. 0,
  39. };
  40. static uint8_t ldo_p_voltage_mult[LDO_VOLTAGE_ENTRIES] = {
  41. 0,
  42. 6, /* 1.8V */
  43. 30, /* 3.0V */
  44. };
  45. /* Intialize the pmic driver */
  46. void pm8921_init(pm8921_dev_t *pmic)
  47. {
  48. ASSERT(pmic);
  49. ASSERT(pmic->read);
  50. ASSERT(pmic->write);
  51. dev = pmic;
  52. dev->initialized = 1;
  53. }
  54. static int pm8921_masked_write(uint16_t addr,
  55. uint8_t mask, uint8_t val)
  56. {
  57. int rc;
  58. uint8_t reg;
  59. rc = dev->read(&reg, 1, addr);
  60. if (rc)
  61. {
  62. return rc;
  63. }
  64. reg &= ~mask;
  65. reg |= val & mask;
  66. rc = dev->write(&reg, 1, addr);
  67. return rc;
  68. }
  69. /* Set the BOOT_DONE flag */
  70. void pm8921_boot_done(void)
  71. {
  72. uint8_t val;
  73. ASSERT(dev);
  74. ASSERT(dev->initialized);
  75. dev->read(&val, 1, PBL_ACCESS_2);
  76. val |= PBL_ACCESS_2_ENUM_TIMER_STOP;
  77. /* TODO: Remove next line when h/w is rewired for battery simulation.*/
  78. val |= (0x7 << 2);
  79. dev->write(&val, 1, PBL_ACCESS_2);
  80. dev->read(&val, 1, SYS_CONFIG_2);
  81. val |= (SYS_CONFIG_2_BOOT_DONE | SYS_CONFIG_2_ADAPTIVE_BOOT_DISABLE);
  82. dev->write(&val, 1, SYS_CONFIG_2);
  83. }
  84. /* Configure PMIC GPIO */
  85. int pm8921_gpio_config(int gpio, struct pm8921_gpio *param)
  86. {
  87. int ret;
  88. uint8_t bank[6];
  89. uint8_t output_buf_config;
  90. uint8_t output_value;
  91. static uint8_t dir_map[] = {
  92. PM_GPIO_MODE_OFF,
  93. PM_GPIO_MODE_OUTPUT,
  94. PM_GPIO_MODE_INPUT,
  95. PM_GPIO_MODE_BOTH,
  96. };
  97. if (param == NULL) {
  98. dprintf (CRITICAL, "pm8291_gpio struct not defined\n");
  99. return -1;
  100. }
  101. /* Select banks and configure the gpio */
  102. bank[0] = PM_GPIO_WRITE |
  103. ((param->vin_sel << PM_GPIO_VIN_SHIFT) &
  104. PM_GPIO_VIN_MASK) |
  105. PM_GPIO_MODE_ENABLE;
  106. /* bank1 */
  107. if ((param->direction & PM_GPIO_DIR_OUT) && param->output_buffer)
  108. output_buf_config = PM_GPIO_OUT_BUFFER_OPEN_DRAIN;
  109. else
  110. output_buf_config = 0;
  111. if ((param->direction & PM_GPIO_DIR_OUT) && param->output_value)
  112. output_value = 1;
  113. else
  114. output_value = 0;
  115. bank[1] = PM_GPIO_WRITE |
  116. ((1 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
  117. ((dir_map[param->direction] << PM_GPIO_MODE_SHIFT)
  118. & PM_GPIO_MODE_MASK) |
  119. output_buf_config |
  120. output_value;
  121. bank[2] = PM_GPIO_WRITE |
  122. ((2 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
  123. ((param->pull << PM_GPIO_PULL_SHIFT) &
  124. PM_GPIO_PULL_MASK);
  125. bank[3] = PM_GPIO_WRITE |
  126. ((3 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
  127. ((param->out_strength << PM_GPIO_OUT_STRENGTH_SHIFT) &
  128. PM_GPIO_OUT_STRENGTH_MASK) |
  129. (param->disable_pin ? PM_GPIO_PIN_DISABLE : PM_GPIO_PIN_ENABLE);
  130. bank[4] = PM_GPIO_WRITE |
  131. ((4 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
  132. ((param->function << PM_GPIO_FUNC_SHIFT) &
  133. PM_GPIO_FUNC_MASK);
  134. bank[5] = PM_GPIO_WRITE |
  135. ((5 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
  136. (param->inv_int_pol ? 0 : PM_GPIO_NON_INT_POL_INV);
  137. ret = dev->write(bank, 6, GPIO_CNTL(gpio));
  138. if (ret) {
  139. dprintf(CRITICAL, "Failed to write to PM8921 ret=%d.\n", ret);
  140. return -1;
  141. }
  142. return 0;
  143. }
  144. /* Reads the value of the irq status for the requested block */
  145. int pm8921_irq_get_block_status(uint8_t block, uint8_t *status)
  146. {
  147. int ret = 0;
  148. /* Select the irq block to be read */
  149. ret = dev->write(&block, 1, IRQ_BLOCK_SEL_USR_ADDR);
  150. if(!ret)
  151. {
  152. /* Read the real time irq status value for the block */
  153. ret = dev->read(status, 1, IRQ_STATUS_RT_USR_ADDR);
  154. }
  155. return ret;
  156. }
  157. /* Reads the status of requested gpio */
  158. int pm8921_gpio_get(uint8_t gpio, uint8_t *status)
  159. {
  160. int ret = 0;
  161. uint8_t block_status;
  162. ret = pm8921_irq_get_block_status(PM_GPIO_BLOCK_ID(gpio), &block_status);
  163. if(!ret)
  164. {
  165. if(block_status & PM_GPIO_ID_TO_BIT_MASK(gpio))
  166. *status = 1;
  167. else
  168. *status = 0;
  169. }
  170. return ret;
  171. }
  172. int pm8921_pwrkey_status(uint8_t *is_pwrkey_pressed)
  173. {
  174. int ret = 0;
  175. uint8_t block_status;
  176. ret = pm8921_irq_get_block_status(PM_PWRKEY_BLOCK_ID, &block_status);
  177. if (!ret)
  178. {
  179. if(block_status & PM_PWRKEY_PRESS_BIT)
  180. *is_pwrkey_pressed = 1;
  181. else
  182. *is_pwrkey_pressed = 0;
  183. }
  184. return ret;
  185. }
  186. int pm8921_ldo_set_voltage(uint32_t ldo_id, uint32_t voltage)
  187. {
  188. uint8_t mult;
  189. uint8_t val = 0;
  190. uint32_t ldo_number = (ldo_id & ~LDO_P_MASK);
  191. int32_t ret = 0;
  192. /* Find the voltage multiplying factor */
  193. if(ldo_id & LDO_P_MASK)
  194. mult = ldo_p_voltage_mult[voltage];
  195. else
  196. mult = ldo_n_voltage_mult[voltage];
  197. /* Program the TEST reg */
  198. if (ldo_id & LDO_P_MASK){
  199. /* Bank 2, only for p ldo, use 1.25V reference */
  200. val = 0x0;
  201. val |= ( 1 << PM8921_LDO_TEST_REG_RW );
  202. val |= ( 2 << PM8921_LDO_TEST_REG_BANK_SEL);
  203. ret = dev->write(&val, 1, PM8921_LDO_TEST_REG(ldo_number));
  204. if (ret) {
  205. dprintf(CRITICAL, "Failed to write to PM8921 LDO Test Reg ret=%d.\n", ret);
  206. return -1;
  207. }
  208. /* Bank 4, only for p ldo, disable output range ext, normal capacitance */
  209. val = 0x0;
  210. val |= ( 1 << PM8921_LDO_TEST_REG_RW );
  211. val |= ( 4 << PM8921_LDO_TEST_REG_BANK_SEL);
  212. ret = dev->write(&val, 1, PM8921_LDO_TEST_REG(ldo_number));
  213. if (ret) {
  214. dprintf(CRITICAL, "Failed to write to PM8921 LDO Test Reg ret=%d.\n", ret);
  215. return -1;
  216. }
  217. }
  218. /* Program the CTRL reg */
  219. val = 0x0;
  220. val |= ( 1 << PM8921_LDO_CTRL_REG_ENABLE);
  221. val |= ( 1 << PM8921_LDO_CTRL_REG_PULL_DOWN);
  222. val |= ( 0 << PM8921_LDO_CTRL_REG_POWER_MODE);
  223. val |= ( mult << PM8921_LDO_CTRL_REG_VOLTAGE);
  224. ret = dev->write(&val, 1, PM8921_LDO_CTRL_REG(ldo_number));
  225. if (ret) {
  226. dprintf(CRITICAL, "Failed to write to PM8921 LDO Ctrl Reg ret=%d.\n", ret);
  227. return -1;
  228. }
  229. return 0;
  230. }
  231. /*
  232. * Configure PMIC for reset and power off.
  233. * reset = 1: Configure reset.
  234. * reset = 0: Configure power off.
  235. */
  236. int pm8921_config_reset_pwr_off(unsigned reset)
  237. {
  238. int rc;
  239. /* Enable SMPL(Short Momentary Power Loss) if resetting is desired. */
  240. rc = pm8921_masked_write(PM8921_SLEEP_CTRL_REG,
  241. SLEEP_CTRL_SMPL_EN_MASK,
  242. (reset ? SLEEP_CTRL_SMPL_EN_RESET : SLEEP_CTRL_SMPL_EN_PWR_OFF));
  243. if (rc)
  244. {
  245. goto read_write_err;
  246. }
  247. /*
  248. * Select action to perform (reset or shutdown) when PS_HOLD goes low.
  249. * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that
  250. * USB charging is enabled.
  251. */
  252. rc = pm8921_masked_write(PM8921_PON_CTRL_1_REG,
  253. PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
  254. | PON_CTRL_1_WD_EN_MASK,
  255. PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
  256. | (reset ? PON_CTRL_1_WD_EN_RESET : PON_CTRL_1_WD_EN_PWR_OFF));
  257. if (rc)
  258. {
  259. goto read_write_err;
  260. }
  261. read_write_err:
  262. return rc;
  263. }
  264. /* A wrapper function to configure PMIC PWM
  265. * pwm_id : Channel number to configure
  266. * duty_us : duty cycle for output waveform in micro seconds
  267. * period_us : period for output waveform in micro seconds
  268. */
  269. int pm8921_set_pwm_config(uint8_t pwm_id, uint32_t duty_us, uint32_t period_us)
  270. {
  271. int rc;
  272. rc = pm8921_pwm_config(pwm_id, duty_us, period_us, dev);
  273. return rc;
  274. }
  275. /* A wrapper function to enable PMIC PWM
  276. * pwm_id : Channel number to enable
  277. */
  278. int pm8921_pwm_channel_enable(uint8_t pwm_id)
  279. {
  280. int rc;
  281. rc = pm8921_pwm_enable(pwm_id, dev);
  282. return rc;
  283. }
  284. /* Configure LED's for current sinks
  285. * enable = 1: Configure external signal detection
  286. * for the sink with the current level
  287. * enable = 0: Turn off external signal detection
  288. *
  289. * Values for sink are defined as follows:
  290. * 0 = MANUAL, turn on LED when curent [00000, 10100]
  291. * 1 = PWM1
  292. * 2 = PWM2
  293. * 3 = PWM3
  294. * 4 = DBUS1
  295. * 5 = DBUS2
  296. * 6 = DBUS3
  297. * 7 = DBUS4
  298. *
  299. * Current settings are calculated as per the equation:
  300. * [00000, 10100]: Iout = current * 2 mA
  301. * [10101, 11111]: invalid settings
  302. */
  303. int pm8921_config_led_current(enum pm8921_leds led_num,
  304. uint8_t current,
  305. enum led_mode sink,
  306. int enable)
  307. {
  308. uint8_t val;
  309. int ret;
  310. /* Program the CTRL reg */
  311. val = 0x0;
  312. if (enable != 0)
  313. {
  314. if (current > 0x15)
  315. {
  316. dprintf(CRITICAL, "Invalid current settings for PM8921 LED Ctrl Reg \
  317. current=%d.\n", current);
  318. return -1;
  319. }
  320. if (sink > 0x7)
  321. {
  322. dprintf(CRITICAL, "Invalid signal selection for PM8921 LED Ctrl Reg \
  323. sink=%d.\n", sink);
  324. return -1;
  325. }
  326. val |= LED_CURRENT_SET(current);
  327. val |= LED_SIGNAL_SELECT(sink);
  328. }
  329. ret = dev->write(&val, 1, PM8921_LED_CNTL_REG(led_num));
  330. if (ret)
  331. dprintf(CRITICAL, "Failed to write to PM8921 LED Ctrl Reg ret=%d.\n", ret);
  332. return ret;
  333. }
  334. /* Configure DRV_KEYPAD
  335. *drv_flash_sel:
  336. * 0000 = off
  337. * Iout = drv_flash_sel * 20 mA (300 mA driver)
  338. * Iout = drv_flash_sel * 40 mA (600 mA driver)
  339. *
  340. * flash_logic = 0 : flash is on when DTEST is high
  341. * flash_logic = 0 : flash is off when DTEST is high
  342. *
  343. * flash_ensel = 0 : manual mode, turn on flash when drv_flash_sel > 0
  344. * flash_ensel = 1 : DBUS1
  345. * flash_ensel = 2 : DBUS2
  346. * flash_ensel = 3 : enable flash from LPG
  347. */
  348. int pm8921_config_drv_keypad(unsigned int drv_flash_sel, unsigned int flash_logic, unsigned int flash_ensel)
  349. {
  350. uint8_t val;
  351. int ret;
  352. /* Program the CTRL reg */
  353. val = 0x0;
  354. if (drv_flash_sel != 0)
  355. {
  356. if (drv_flash_sel > 0x0F)
  357. {
  358. dprintf(CRITICAL, "Invalid current settings for PM8921 \
  359. KEYPAD_DRV Ctrl Reg drv_flash_sel=%d.\n", drv_flash_sel);
  360. return -1;
  361. }
  362. if (flash_logic > 1)
  363. {
  364. dprintf(CRITICAL, "Invalid signal selection for PM8921 \
  365. KEYPAD_DRV Ctrl Reg flash_logic=%d.\n", flash_logic);
  366. return -1;
  367. }
  368. if (flash_ensel > 3)
  369. {
  370. dprintf(CRITICAL, "Invalid signal selection for PM8921 \
  371. KEYPAD_DRV Ctrl Reg flash_ensel=%d.\n", flash_ensel);
  372. return -1;
  373. }
  374. val |= DRV_FLASH_SEL(drv_flash_sel);
  375. val |= FLASH_LOGIC_SEL(flash_logic);
  376. val |= FLASH_ENSEL(flash_ensel);
  377. }
  378. ret = dev->write(&val, 1, PM8921_DRV_KEYPAD_CNTL_REG);
  379. if (ret)
  380. dprintf(CRITICAL, "Failed to write to PM8921 KEYPAD_DRV Ctrl Reg ret=%d.\n", ret);
  381. return ret;
  382. }
  383. int pm8921_low_voltage_switch_enable(uint8_t lvs_id)
  384. {
  385. int ret = NO_ERROR;
  386. uint8_t val;
  387. if (lvs_id < lvs_start || lvs_id > lvs_end) {
  388. dprintf(CRITICAL, "Requested unsupported LVS.\n");
  389. return ERROR;
  390. }
  391. if (lvs_id == lvs_2) {
  392. dprintf(CRITICAL, "No support for LVS2 yet!\n");
  393. return ERROR;
  394. }
  395. /* Read LVS_TEST Reg first*/
  396. ret = dev->read(&val, 1, PM8921_LVS_TEST_REG(lvs_id));
  397. if (ret) {
  398. dprintf(CRITICAL, "Failed to read LVS_TEST Reg ret=%d.\n", ret);
  399. return ret;
  400. }
  401. /* Check if switch is already ON */
  402. val = val & PM8921_LVS_100_TEST_VOUT_OK;
  403. if (val)
  404. return ret;
  405. /* Turn on switch in normal mode */
  406. val = 0;
  407. val |= PM8921_LVS_100_CTRL_SW_EN; /* Enable Switch */
  408. val |= PM8921_LVS_100_CTRL_SLEEP_B_IGNORE; /* Ignore sleep mode pin */
  409. ret = dev->write(&val, 1, PM8921_LVS_CTRL_REG(lvs_id));
  410. if (ret)
  411. dprintf(CRITICAL, "Failed to write LVS_CTRL Reg ret=%d.\n", ret);
  412. return ret;
  413. }
  414. int pm8921_mpp_set_digital_output(uint8_t mpp_id)
  415. {
  416. int ret = NO_ERROR;
  417. uint8_t val;
  418. if (mpp_id < mpp_start || mpp_id > mpp_end) {
  419. dprintf(CRITICAL, "Requested unsupported MPP.\n");
  420. return ERROR;
  421. }
  422. val = 0;
  423. /* Configure in digital output mode */
  424. val |= PM8921_MPP_CTRL_DIGITAL_OUTPUT;
  425. val |= PM8921_MPP_CTRL_VIO_1; /* Set input voltage to 1.8V */
  426. val |= PM8921_MPP_CTRL_OUTPUT_HIGH; /* Set mpp to high */
  427. ret = dev->write(&val, 1, PM8921_MPP_CTRL_REG(mpp_id));
  428. if (ret) {
  429. dprintf(CRITICAL, "Failed to write MPP_CTRL Reg ret=%d.\n",
  430. ret);
  431. }
  432. return ret;
  433. }