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