12708Swollman/* 22708Swollman * Copyright 2017, Data61 32708Swollman * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 42708Swollman * ABN 41 687 119 230. 5227753Stheraven * 6227753Stheraven * This software may be distributed and modified according to the terms of 7227753Stheraven * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8227753Stheraven * See "LICENSE_BSD2.txt" for details. 9227753Stheraven * 102708Swollman * @TAG(DATA61_BSD) 112708Swollman */ 122708Swollman 132708Swollman#include <utils/util.h> 142708Swollman#include <platsupport/mach/pmic.h> 15192625Sedwin#include <string.h> 162708Swollman 172708Swollman#define mV 182708Swollman 192708Swollman#define REG_CHIPID 0x00 202708Swollman#define REG_RESET_DELAY 0x0A 212708Swollman 222708Swollman#define MAX77686_CHIPID 0x02 239912Swollman#define MAX77802_CHIPID 0x06 249912Swollman#define MAXXXXXX_CHIPID 0x91 25192625Sedwin 269912Swollman#define NLDO (26 + 1 /* + reserved LDO0 */) 27267798Spfg#define LDO_VMIN 800 mV 28267798Spfg#define LDO_VSTEP 50 mV 29267798Spfg#define LDO_VMASK 0x3F 309912Swollman#define LDO_MV(mv) (( ((mv) + LDO_VSTEP / 2) - LDO_VMIN) / LDO_VSTEP) 319912Swollman#define LDO_GET_MV(reg) (((reg) & LDO_VMASK) * LDO_VSTEP + LDO_VMIN) 329912Swollman#define LDOMODE_OFF (0x0 << 6) 3371579Sdeischen#define LDOMODE_STANDBY (BIT(6)) 349912Swollman#define LDOMODE_LOWPWR (0x2 << 6) 359912Swollman#define LDOMODE_ON (0x3 << 6) 3692986Sobrien#define LDOMODE_MASK (0x3 << 6) 379912Swollman 3892986Sobrienstruct max77_config { 3992986Sobrien int ctrl1_start; 4092986Sobrien int ctrl2_start; 412708Swollman int nldo; 422708Swollman}; 439912Swollman 449912Swollmanstatic const struct max77_config max77802_cfg = { 4571579Sdeischen .ctrl1_start = 0x60, 4628021Sjoerg .ctrl2_start = 0x90, 472708Swollman .nldo = 35 4897423Salfred}; 4997423Salfred 50192625Sedwinstatic const struct max77_config max77686_cfg = { 51227753Stheraven .ctrl1_start = 0x40, 52192625Sedwin .ctrl2_start = 0x60, 532708Swollman .nldo = 26 549912Swollman}; 552708Swollman 56130461Sstefanfstatic inline const struct max77_config* 57130461Sstefanfpmic_get_priv(pmic_t* pmic) { 58130461Sstefanf return (const struct max77_config*)pmic->priv; 59130461Sstefanf} 60267798Spfg 61267798Spfgstatic int 62267798Spfgpmic_reg_read(pmic_t* pmic, uint8_t reg, void* data, int count) 63267798Spfg{ 64130461Sstefanf return !(i2c_kvslave_read(&pmic->kvslave, reg, data, count) == count); 65267798Spfg} 66267798Spfg 67267798Spfgstatic int 68267798Spfgpmic_reg_write(pmic_t* pmic, uint8_t reg, const void* data, int count) 69137190Sdelphij{ 70237211Sjilles return !(i2c_kvslave_write(&pmic->kvslave, reg, data, count) == count); 71137190Sdelphij} 72267798Spfg 73267798Spfgstatic int 74267798Spfgldo_valid(pmic_t* pmic, int ldo) 75267798Spfg{ 76267798Spfg int nldo = pmic_nldo(pmic); 77267798Spfg return !(nldo < 0 || ldo <= 0 || ldo > nldo); 78267798Spfg} 79137190Sdelphij 80267798Spfgint 81267798Spfgpmic_init(i2c_bus_t* i2c, int addr, pmic_t* pmic) 82137190Sdelphij{ 83137190Sdelphij uint16_t chip_id; 84137190Sdelphij int ret; 85267798Spfg ret = i2c_slave_init(i2c, addr, 86137190Sdelphij I2C_SLAVE_ADDR_7BIT, I2C_SLAVE_SPEED_FAST, 87137190Sdelphij 0, &pmic->i2c_slave); 88137190Sdelphij if (ret) { 892708Swollman ZF_LOGE("Failed to register I2C slave"); 90227753Stheraven return -1; 91227753Stheraven } 922708Swollman 93130461Sstefanf ret = i2c_kvslave_init(&pmic->i2c_slave, LITTLE8, LITTLE8, &pmic->kvslave); 94130461Sstefanf if (ret) { 95227753Stheraven ZF_LOGE("Failed to initialize I2C KV-slave lib instance."); 962708Swollman return -1; 979912Swollman } 98130461Sstefanf 99227753Stheraven /* Read the chip ID */ 100130461Sstefanf if (pmic_reg_read(pmic, REG_CHIPID, &chip_id, 2)) { 101130461Sstefanf ZF_LOGE("Bus error"); 102227753Stheraven return -1; 103130461Sstefanf } 104227753Stheraven /* Check the chip ID */ 105227753Stheraven switch (chip_id) { 106130461Sstefanf case MAX77686_CHIPID: 107227753Stheraven pmic->priv = (void*)&max77686_cfg; 108130461Sstefanf break; 109227753Stheraven case MAXXXXXX_CHIPID: 110130461Sstefanf case MAX77802_CHIPID: 111227753Stheraven pmic->priv = (void*)&max77802_cfg; 112227753Stheraven break; 113227753Stheraven default: 114130461Sstefanf ZF_LOGE("Unidentified chip 0x%02x", chip_id); 115130461Sstefanf return -1; 1162708Swollman } 117267798Spfg 1182708Swollman ZF_LOGE("found chip ID 0x%x", chip_id); 1192708Swollman return 0; 1202708Swollman} 1212708Swollman 122227753Stheravenint 123227753Stheravenpmic_nldo(pmic_t* pmic) 124227753Stheraven{ 125227753Stheraven const struct max77_config* cfg = pmic_get_priv(pmic); 126227753Stheraven assert(cfg); 127227753Stheraven return cfg->nldo; 128227753Stheraven} 1292708Swollman 130227753Stheravenint 131130461Sstefanfpmic_ldo_cfg(pmic_t* pmic, int ldo, enum ldo_mode ldo_mode, int milli_volt) 132130461Sstefanf{ 133130461Sstefanf if (!ldo_valid(pmic, ldo)) { 134130461Sstefanf return -1; 135130461Sstefanf } else { 136227753Stheraven const struct max77_config* cfg; 1372708Swollman uint8_t v; 138137190Sdelphij cfg = pmic_get_priv(pmic); 139227753Stheraven assert(cfg); 14053940Sache /* Generate the register data */ 1419912Swollman v = LDO_MV(milli_volt); 1422708Swollman switch (ldo_mode) { 14353940Sache case LDO_OFF: 14453940Sache v |= LDOMODE_OFF; 145137190Sdelphij break; 1462708Swollman case LDO_STANDBY: 1479912Swollman v |= LDOMODE_STANDBY; 1482708Swollman break; 1492708Swollman case LDO_LOWPWR: 1502708Swollman v |= LDOMODE_LOWPWR; 1512708Swollman break; 152130461Sstefanf case LDO_ON: 153130461Sstefanf v |= LDOMODE_ON; 15472168Sphantom break; 1559912Swollman default: 1562708Swollman /* Invalid mode */ 1572708Swollman return -1; 158130461Sstefanf } 159130461Sstefanf /* Write the register */ 16072168Sphantom if (pmic_reg_write(pmic, cfg->ctrl1_start + ldo - 1, &v, 1)) { 1619912Swollman return -1; 1622708Swollman } else { 1632708Swollman return LDO_GET_MV(v); 164130461Sstefanf } 165130461Sstefanf } 16672168Sphantom} 16772168Sphantom 1689912Swollmanint 1692708Swollmanpmic_ldo_get_cfg(pmic_t* pmic, int ldo, enum ldo_mode* ldo_mode) 1702708Swollman{ 1712708Swollman if (!ldo_valid(pmic, ldo)) { 172130461Sstefanf return -1; 173130461Sstefanf } else { 17472168Sphantom const struct max77_config* cfg; 1759912Swollman uint8_t v; 1762708Swollman cfg = pmic_get_priv(pmic); 1772708Swollman assert(cfg); 1782708Swollman /* Read in the register */ 179267798Spfg if (pmic_reg_read(pmic, cfg->ctrl1_start + ldo - 1, &v, 1)) { 180267798Spfg return -1; 181267798Spfg } 182267798Spfg /* Decode the mode */ 183267798Spfg if (ldo_mode != NULL) { 184267798Spfg switch (v & LDOMODE_MASK) { 185192625Sedwin case LDOMODE_OFF: 186192625Sedwin *ldo_mode = LDO_OFF; 1872708Swollman break; 1889912Swollman case LDOMODE_STANDBY: 189130461Sstefanf *ldo_mode = LDO_STANDBY; 190130461Sstefanf break; 191130461Sstefanf case LDOMODE_LOWPWR: 192227753Stheraven *ldo_mode = LDO_LOWPWR; 193130461Sstefanf break; 194130461Sstefanf case LDOMODE_ON: 195130461Sstefanf *ldo_mode = LDO_ON; 196130461Sstefanf break; 197130461Sstefanf default: 1989912Swollman /* Should never get here */ 1992708Swollman return -1; 200227753Stheraven } 2012708Swollman } 2022708Swollman return LDO_GET_MV(v); 203137190Sdelphij } 204137190Sdelphij} 2052708Swollman 2062708Swollmanint 20753960Sachepmic_get_reset_delay(pmic_t* pmic) 20853960Sache{ 20953940Sache uint8_t data; 21053940Sache if (pmic_reg_read(pmic, REG_RESET_DELAY, &data, 1)) { 2112708Swollman return -1; 2122708Swollman } else { 213267798Spfg return 1000 * (data >> 1); 214267798Spfg } 215267798Spfg} 216267798Spfg 217267798Spfgint 218267798Spfgpmic_set_reset_delay(pmic_t* pmic, int ms) 219267798Spfg{ 220267798Spfg uint8_t data; 221267798Spfg /* Clip ms value */ 222267798Spfg if (ms < 0) { 223267798Spfg ms = 0; 22453960Sache } else if (ms > 10000) { 22553960Sache ms = 10000; 22653940Sache } 2272708Swollman /* Write the data */ 2282708Swollman data = (ms / 1000) << 1; 229137190Sdelphij if (pmic_reg_write(pmic, REG_RESET_DELAY, &data, 1)) { 230137190Sdelphij return -1; 2312708Swollman } else { 23253960Sache return data; 233227753Stheraven } 23453960Sache} 2352708Swollman 236137190Sdelphijvoid 237137190Sdelphijpmic_print_status(pmic_t* pmic) 2382708Swollman{ 2392708Swollman uint8_t data; 2402708Swollman int nldo; 2412708Swollman int err; 242267798Spfg int i; 243267798Spfg printf("### PMIC ###\n"); 2442708Swollman err = pmic_reg_read(pmic, REG_CHIPID, &data, 1); 2452708Swollman assert(!err); 246137190Sdelphij if (err) { 247137190Sdelphij return; 2482708Swollman } 2492708Swollman switch (data) { 2502708Swollman case MAX77686_CHIPID: 251267798Spfg printf("MAX77686"); 252267798Spfg break; 253267798Spfg case MAX77802_CHIPID: 254267798Spfg printf("MAX77802"); 255267798Spfg break; 256267798Spfg case MAXXXXXX_CHIPID: 257267798Spfg printf("MAXXXXXx"); 258267798Spfg break; 259267798Spfg default: 260137190Sdelphij printf("Unknown CHIP"); 261137190Sdelphij } 2622708Swollman nldo = pmic_nldo(pmic); 2632708Swollman printf(": %d LDOs\n", nldo); 2642708Swollman for (i = 1; i < nldo; i++) { 2652708Swollman int mv, v; 2662708Swollman enum ldo_mode mode; 2672708Swollman mv = pmic_ldo_get_cfg(pmic, i, &mode); 2682708Swollman v = mv / 1000; 2692708Swollman mv -= v * 1000; 2702708Swollman printf("LDO%02d: %d.%03dV (", i, v, mv); 2712708Swollman switch (mode) { 2722708Swollman case LDO_OFF: 273267798Spfg printf("Off"); 274267798Spfg break; 275267798Spfg case LDO_STANDBY: 276267798Spfg printf("Standby"); 277267798Spfg break; 278267798Spfg case LDO_LOWPWR: 279267798Spfg printf("Low power"); 280267798Spfg break; 2812708Swollman case LDO_ON: 2822708Swollman printf("On"); 283267798Spfg break; 284267798Spfg default: 2852708Swollman printf("Unknown state"); 2862708Swollman } 287137190Sdelphij printf(")\n"); 288137190Sdelphij } 2892708Swollman printf("Reset delay: %d ms\n", pmic_get_reset_delay(pmic)); 2902708Swollman} 291137190Sdelphij