diff options
Diffstat (limited to 'drivers/power/twl4030.c')
-rw-r--r-- | drivers/power/twl4030.c | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/drivers/power/twl4030.c b/drivers/power/twl4030.c index 5a7323a715..cf79161aaf 100644 --- a/drivers/power/twl4030.c +++ b/drivers/power/twl4030.c @@ -103,3 +103,520 @@ void twl4030_power_mmc_init(void) TWL4030_PM_RECEIVER_VMMC1_DEV_GRP, TWL4030_PM_RECEIVER_DEV_GRP_P1); } + +void twl4030_power_off(void) +{ + u8 val = 0; + if (twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER, &val, + TWL4030_PM_MASTER_P1_SW_EVENTS)) { + printf("Error:TWL4030: failed to read the power register\n"); + } else { + val |= TWL4030_PM_MASTER_SW_EVENTS_DEVOFF; + if (twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, val, + TWL4030_PM_MASTER_P1_SW_EVENTS)) { + printf("Error:TWL4030: failed to write the power register\n"); + printf("Could not power off\n"); + } + } +} + +int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + printf("Power down.\n"); + twl4030_power_off(); + return 0; +} + +U_BOOT_CMD(poweroff, 1, 1, do_poweroff, + "Power down board", + "" +); + +#ifdef CONFIG_TWL4030_CHARGING +int twl4030_enable_charging(void) +{ + u8 val = 0; + /* write 0x57 to 0x4a, 0x85 (BCIMFKEY)*/ + /* Enabel access to BCIMFEN1 register access */ + if (twl4030_i2c_write_u8(TWL4030_CHIP_MAIN_CHARGE, 0x57, + TWL4030_MAIN_CHARGE_BCIMFKEY)) { + printf("Error:TWL4030: failed to write BCIMFKEY\n"); + return 1; + } + + /* read 0x4a, 0x86 */ + if (twl4030_i2c_read_u8(TWL4030_CHIP_MAIN_CHARGE, &val, + TWL4030_MAIN_CHARGE_BCIMFEN1)) { + printf("Error:TWL4030: failed to read BCIMFEN1\n"); + return 1; + } + + /* or in 0x80 */ + /* write to 0x4a, 0x86 (TWL_BCIMFEN1) */ + val |= TWL4030_MAIN_CHARGE_BCIMFEN1_VBATOV1EN; + if (twl4030_i2c_write_u8(TWL4030_CHIP_MAIN_CHARGE, val, + TWL4030_MAIN_CHARGE_BCIMFEN1)) { + printf("Error:TWL4030: failed to write BCIMFEN1\n"); + return 1; + } + + /* write 0xd2 to 0x4a, 0x85 (BCIMFKEY) */ + val = TWL4030_MAIN_CHARGE_BCIMFKEY_MFKEY5; + if (twl4030_i2c_write_u8(TWL4030_CHIP_MAIN_CHARGE, + val, + TWL4030_MAIN_CHARGE_BCIMFKEY)) { + printf("Error:TWL4030: failed to write BCIMFKEY\n"); + return 1; + } + + /* clear low four bits in 0x4a, 0x8a (BCIMFTH1) */ + if (twl4030_i2c_read_u8(TWL4030_CHIP_MAIN_CHARGE, &val, + TWL4030_MAIN_CHARGE_BCIMFTH1)) { + printf("Error:TWL4030: failed to read BCIMFTH1\n"); + return 1; + } + val = (val & ~TWL4030_MAIN_CHARGE_BCIMFTH1_VBATOV1TH_MASK) | + TWL4030_MAIN_CHARGE_BCIMFTH1_VBATOV1TH_2636_mV; + /* clear low four bits in 0x4a, 0x8a (BCIMFTH1) */ + if (twl4030_i2c_write_u8(TWL4030_CHIP_MAIN_CHARGE, val, + TWL4030_MAIN_CHARGE_BCIMFTH1)) { + printf("Error:TWL4030: failed to write BCIMFTH1\n"); + return 1; + } + + /* read 0x4a, 0x86; 0x4a, 0x8a (???) */ + + /* Turn on AC charging */ + /* write 0x90 to 0x49, 0x91 (MADC_HFCLK_EN, DEFAULTMADC_CLK_EN) */ + val = TWL4030_INTBR_GPBR1_MADC_HFCLK_EN; + val |= TWL4030_INTBR_GPBR1_DEFAULT_MADC_CLK_EN; + if (twl4030_i2c_write_u8(TWL4030_CHIP_INTBR, val, + TWL4030_INTBR_GPBR1)) { + printf("Error:TWL4030: failed to write BCIMFTH1\n"); + return 1; + } + return 0; +} + + +struct { + u8 idx; + u8 reg_base; + char *str; + u16 mul; +} adc_regs[] = { + { + 0, + 0x37, + "(GP analog input/Bat type)", + 1466 + }, + { + 1, + 0x39, + "(GP analog input/Bat temp)", + 1446 + }, + { + 2, + 0x3b, + "(GP analog input)\t", + 2444, + }, + { + 3, + 0x3d, + "(GP analog input)\t", + 2444, + }, + { + 4, + 0x3f, + "(GP analog input)\t", + 2444, + }, + { + 5, + 0x41, + "(GP analog input)\t", + 2444, + }, + { + 6, + 0x43, + "(GP analog input)\t", + 2444, + }, + { + 7, + 0x45, + "(GP analog input)\t", + 2444, + }, + { + 8, + 0x47, + "(VBUS voltage)\t", + 6843, + }, + { + 9, + 0x49, + "(Charger backup bat volt)", + 4399, + }, + { + 11, + 0x4d, + "(Battery charger voltage)", + 9775, + }, + { + 12, + 0x4f, + "(Main battery voltage)", + 5865, + }, + { + 15, + 0x55, + "(VRUSB supply/spkr pol)", + 3225, + }, +}; + +struct +{ + u8 val; + char *str; + u8 pr_info; +} charge_state[] = { + { + 0x00, + "No charging device", + 0, + }, + { + 0x01, + "Off mode", + 0, + }, + { + 0x02, + "Standby mode", + 0, + }, + { + 0x03, + "Open bat or USB not debounced", + 0, + }, + { + 0x21, + "Constant voltage AC", + 1, + }, + { + 0x22, + "Quick charge AC 1", + 1, + }, + { + 0x23, + "Quick charge AC 2", + 1, + }, + { + 0x24, + "Quick charge AC 3", + 1, + }, + { + 0x25, + "Quick charge AC 4", + 1, + }, + { + 0x26, + "Quick charge AC 5", + 1, + }, + { + 0x27, + "Quick charge AC 6", + 1, + }, + { + 0x28, + "Charge stop AC 1", + 1, + }, + { + 0x29, + "Charge stop AC 1", + 1, + }, + { + 0x2a, + "Charge stop AC 1", + 1, + }, + { + 0x2b, + "Charge AC comp 1", + 1, + }, + { + 0x2c, + "Charge AC comp 2", + 1, + }, + { + 0x2d, + "Charge AC comp 3", + 1, + }, + { + 0x2e, + "Charge AC comp 4", + 1, + }, + { + 0x2f, + "AC adapter overvoltage", + 0, + }, + { + 0x12, + "Quick charge USB 1", + 1, + }, + { + 0x13, + "Quick charge USB 2", + 1, + }, + { + 0x14, + "Quick charge USB 3", + 1, + }, + { + 0x15, + "Quick charge USB 4", + 1, + }, + { + 0x16, + "Quick charge USB 5", + 1, + }, + { + 0x17, + "Quick charge USB 6", + 1, + }, + { + 0x18, + "Charge stop USB 1", + 1, + }, + { + 0x19, + "Charge stop USB 2", + 1, + }, + { + 0x1a, + "Charge stop USB 3", + 1, + }, + { + 0x1b, + "Charge USB comp 1", + 1, + }, + { + 0x1c, + "Charge USB comp 2", + 1, + }, + { + 0x1d, + "Charge USB comp 3", + 1, + }, + { + 0x1e, + "Charge USB comp 4", + 1, + }, + { + 0x1f, + "USB adapter overvoltage", + 0, + }, +}; + +int read_madc_msblsb(u8 reg) +{ + u8 val; + int temp; + + twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, reg+1); + temp = ((int)(val & 0x3)) << 8; + twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, reg); + return temp | val; +} + +#define VOLT_STEP_SIZE 588 +#define VOLT_PSR_R 100 + +int pm_battery_voltage(void) +{ + int volt = read_madc_msblsb(0x78); + return (volt * VOLT_STEP_SIZE) / VOLT_PSR_R; +} + +#define CURR_SLOPE 1194 + +int pm_battery_current(void) +{ + int curr = read_madc_msblsb(0x7c); + u8 val; + + twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, 0x98); + if (val & 0x20) + return (curr * 1000) / (2 * CURR_SLOPE); + else + return (curr * 1000) / (1 * CURR_SLOPE); +} + +static int batt_table[] = { +/* 0 C*/ +30800, 29500, 28300, 27100, +26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900, +17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100, +11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310, +8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830, +5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170, +4040, 3910, 3790, 3670, 3550 +}; + +#define TEMP_STEP_SIZE 147 +#define TEMP_PSR_R 100 + +int pm_battery_temp(void) +{ + u8 val; + int temp, curr, volt, res, ret; + + ret = read_madc_msblsb(0x7a); + + volt = (ret * TEMP_STEP_SIZE) / TEMP_PSR_R; + + twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, 0x98); + curr = ((val & 0x07) + 1) * 10; + res = volt * 1000 / curr; + for (temp = 58; temp >= 0; temp--) { + int actual = batt_table[temp]; + if ((actual - res) >= 0) + break; + } + + if (temp < 3) { + if (temp == 2) + temp = -1; + else if (temp == 1) + temp = -2; + else + temp = -3; + } + return temp + 1; +} + +void print_charge_info(void) +{ + printf("\n"); + + printf("Charger main battery voltage\t\t %4u mV\n", pm_battery_voltage()); + + printf("Charger current\t\t\t\t %4u mA\n", pm_battery_current()); + + printf("\n"); + + printf("Battery temperature (if using Logic battery)\t%2u deg C\n", pm_battery_temp()); + +} + +int twl4030_info(void) +{ + u8 val; + int i; + + twl4030_i2c_write_u8(TWL4030_CHIP_INTBR, 0x90, TWL4030_INTBR_GPBR1); + + twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0x01, 0x00); + + twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0xff, 0x06); + + twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0xff, 0x07); + + twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0x02, 0x97); + + twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0x20, 0x12); + + udelay(200000); + + for (i=0; i<sizeof(adc_regs)/sizeof(adc_regs[0]); ++i) { + u8 lsb, msb; + u32 adc, v; + + twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &lsb, adc_regs[i].reg_base); + twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &msb, adc_regs[i].reg_base+1); + adc = lsb / 64 + msb * 4; + v = (adc * adc_regs[i].mul) / 1000; + printf("ADC%d %s\tvalue 0x%03x = %4u mV\n", adc_regs[i].idx, adc_regs[i].str, adc, v); + } + + twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, 0x76); + + for (i=0; i<sizeof(charge_state)/sizeof(charge_state[0]);++i) { + if (val == charge_state[i].val) { + printf("Charge state \t\t\tvalue 0x%02x = %s\n", val, charge_state[i].str); + if (charge_state[i].pr_info) { + print_charge_info(); + } + break; + } + } + if (i >= sizeof(charge_state)/sizeof(charge_state[0])) { + printf("Charge state \t\t\tvalue 0x%02x = %s\n", val, "Unknown charge state"); + } + return 0; +} + + +int adc_cmd(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + char *cmd; + + if (argc < 2) + goto usage; + + cmd = argv[1]; + if (strcmp(cmd, "enable") == 0) + return twl4030_enable_charging(); + if (strcmp(cmd, "info") == 0) + return twl4030_info(); +usage: + return cmd_usage(cmdtp); +} + +U_BOOT_CMD( + madc, 2, 1, adc_cmd, + "MADC subsytem", + "madc enable - enable charging\n" + "madc info - print information on ADC registers/charging state" +); +#endif |