1857765e9SRajeshwari Shinde /* 2857765e9SRajeshwari Shinde * Copyright (C) 2012 Samsung Electronics 3857765e9SRajeshwari Shinde * Rajeshwari Shinde <rajeshwari.s@samsung.com> 4857765e9SRajeshwari Shinde * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 6857765e9SRajeshwari Shinde */ 7857765e9SRajeshwari Shinde 8857765e9SRajeshwari Shinde #include <common.h> 94050f070SRajeshwari Shinde #include <fdtdec.h> 104050f070SRajeshwari Shinde #include <i2c.h> 11857765e9SRajeshwari Shinde #include <power/pmic.h> 12857765e9SRajeshwari Shinde #include <power/max77686_pmic.h> 13857765e9SRajeshwari Shinde #include <errno.h> 14857765e9SRajeshwari Shinde 154050f070SRajeshwari Shinde DECLARE_GLOBAL_DATA_PTR; 164050f070SRajeshwari Shinde 17812d7576SPiotr Wilczek static const char max77686_buck_addr[] = { 18812d7576SPiotr Wilczek 0xff, 0x10, 0x12, 0x1c, 0x26, 0x30, 0x32, 0x34, 0x36, 0x38 19812d7576SPiotr Wilczek }; 20812d7576SPiotr Wilczek 21812d7576SPiotr Wilczek static unsigned int max77686_ldo_volt2hex(int ldo, ulong uV) 22812d7576SPiotr Wilczek { 23812d7576SPiotr Wilczek unsigned int hex = 0; 24812d7576SPiotr Wilczek 25812d7576SPiotr Wilczek switch (ldo) { 26812d7576SPiotr Wilczek case 1: 27812d7576SPiotr Wilczek case 2: 28812d7576SPiotr Wilczek case 6: 29812d7576SPiotr Wilczek case 7: 30812d7576SPiotr Wilczek case 8: 31812d7576SPiotr Wilczek case 15: 32812d7576SPiotr Wilczek hex = (uV - 800000) / 25000; 33812d7576SPiotr Wilczek break; 34812d7576SPiotr Wilczek default: 35812d7576SPiotr Wilczek hex = (uV - 800000) / 50000; 36812d7576SPiotr Wilczek } 37812d7576SPiotr Wilczek 38812d7576SPiotr Wilczek if (hex >= 0 && hex <= MAX77686_LDO_VOLT_MAX_HEX) 39812d7576SPiotr Wilczek return hex; 40812d7576SPiotr Wilczek 41812d7576SPiotr Wilczek debug("%s: %ld is wrong voltage value for LDO%d\n", __func__, uV, ldo); 42812d7576SPiotr Wilczek return 0; 43812d7576SPiotr Wilczek } 44812d7576SPiotr Wilczek 45*7e46be8aSSuriyan Ramasami static int max77686_buck_volt2hex(int buck, ulong uV) 46*7e46be8aSSuriyan Ramasami { 47*7e46be8aSSuriyan Ramasami int hex = 0; 48*7e46be8aSSuriyan Ramasami 49*7e46be8aSSuriyan Ramasami if (buck < 5 || buck > 9) { 50*7e46be8aSSuriyan Ramasami debug("%s: buck %d is not supported\n", __func__, buck); 51*7e46be8aSSuriyan Ramasami return -EINVAL; 52*7e46be8aSSuriyan Ramasami } 53*7e46be8aSSuriyan Ramasami 54*7e46be8aSSuriyan Ramasami hex = (uV - 750000) / 50000; 55*7e46be8aSSuriyan Ramasami 56*7e46be8aSSuriyan Ramasami if (hex >= 0 && hex <= MAX77686_BUCK_VOLT_MAX_HEX) 57*7e46be8aSSuriyan Ramasami return hex; 58*7e46be8aSSuriyan Ramasami 59*7e46be8aSSuriyan Ramasami debug("%s: %ld is wrong voltage value for BUCK%d\n", 60*7e46be8aSSuriyan Ramasami __func__, uV, buck); 61*7e46be8aSSuriyan Ramasami return -EINVAL; 62*7e46be8aSSuriyan Ramasami } 63*7e46be8aSSuriyan Ramasami 64812d7576SPiotr Wilczek int max77686_set_ldo_voltage(struct pmic *p, int ldo, ulong uV) 65812d7576SPiotr Wilczek { 66812d7576SPiotr Wilczek unsigned int val, ret, hex, adr; 67812d7576SPiotr Wilczek 68*7e46be8aSSuriyan Ramasami if (ldo < 1 || ldo > 26) { 69812d7576SPiotr Wilczek printf("%s: %d is wrong ldo number\n", __func__, ldo); 70812d7576SPiotr Wilczek return -1; 71812d7576SPiotr Wilczek } 72812d7576SPiotr Wilczek 73812d7576SPiotr Wilczek adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1; 74812d7576SPiotr Wilczek hex = max77686_ldo_volt2hex(ldo, uV); 75812d7576SPiotr Wilczek 76812d7576SPiotr Wilczek if (!hex) 77812d7576SPiotr Wilczek return -1; 78812d7576SPiotr Wilczek 79812d7576SPiotr Wilczek ret = pmic_reg_read(p, adr, &val); 80812d7576SPiotr Wilczek if (ret) 81812d7576SPiotr Wilczek return ret; 82812d7576SPiotr Wilczek 83812d7576SPiotr Wilczek val &= ~MAX77686_LDO_VOLT_MASK; 84812d7576SPiotr Wilczek val |= hex; 85812d7576SPiotr Wilczek ret |= pmic_reg_write(p, adr, val); 86812d7576SPiotr Wilczek 87812d7576SPiotr Wilczek return ret; 88812d7576SPiotr Wilczek } 89812d7576SPiotr Wilczek 90*7e46be8aSSuriyan Ramasami int max77686_set_buck_voltage(struct pmic *p, int buck, ulong uV) 91*7e46be8aSSuriyan Ramasami { 92*7e46be8aSSuriyan Ramasami unsigned int val, adr; 93*7e46be8aSSuriyan Ramasami int hex, ret; 94*7e46be8aSSuriyan Ramasami 95*7e46be8aSSuriyan Ramasami if (buck < 5 || buck > 9) { 96*7e46be8aSSuriyan Ramasami printf("%s: %d is an unsupported bucket number\n", 97*7e46be8aSSuriyan Ramasami __func__, buck); 98*7e46be8aSSuriyan Ramasami return -EINVAL; 99*7e46be8aSSuriyan Ramasami } 100*7e46be8aSSuriyan Ramasami 101*7e46be8aSSuriyan Ramasami adr = max77686_buck_addr[buck] + 1; 102*7e46be8aSSuriyan Ramasami hex = max77686_buck_volt2hex(buck, uV); 103*7e46be8aSSuriyan Ramasami 104*7e46be8aSSuriyan Ramasami if (hex < 0) 105*7e46be8aSSuriyan Ramasami return hex; 106*7e46be8aSSuriyan Ramasami 107*7e46be8aSSuriyan Ramasami ret = pmic_reg_read(p, adr, &val); 108*7e46be8aSSuriyan Ramasami if (ret) 109*7e46be8aSSuriyan Ramasami return ret; 110*7e46be8aSSuriyan Ramasami 111*7e46be8aSSuriyan Ramasami val &= ~MAX77686_BUCK_VOLT_MASK; 112*7e46be8aSSuriyan Ramasami ret |= pmic_reg_write(p, adr, val | hex); 113*7e46be8aSSuriyan Ramasami 114*7e46be8aSSuriyan Ramasami return ret; 115*7e46be8aSSuriyan Ramasami } 116*7e46be8aSSuriyan Ramasami 117812d7576SPiotr Wilczek int max77686_set_ldo_mode(struct pmic *p, int ldo, char opmode) 118812d7576SPiotr Wilczek { 119812d7576SPiotr Wilczek unsigned int val, ret, adr, mode; 120812d7576SPiotr Wilczek 121*7e46be8aSSuriyan Ramasami if (ldo < 1 || 26 < ldo) { 122812d7576SPiotr Wilczek printf("%s: %d is wrong ldo number\n", __func__, ldo); 123812d7576SPiotr Wilczek return -1; 124812d7576SPiotr Wilczek } 125812d7576SPiotr Wilczek 126812d7576SPiotr Wilczek adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1; 127812d7576SPiotr Wilczek 128812d7576SPiotr Wilczek /* mode */ 129812d7576SPiotr Wilczek switch (opmode) { 130812d7576SPiotr Wilczek case OPMODE_OFF: 131812d7576SPiotr Wilczek mode = MAX77686_LDO_MODE_OFF; 132812d7576SPiotr Wilczek break; 133812d7576SPiotr Wilczek case OPMODE_STANDBY: 134812d7576SPiotr Wilczek switch (ldo) { 135812d7576SPiotr Wilczek case 2: 136812d7576SPiotr Wilczek case 6: 137812d7576SPiotr Wilczek case 7: 138812d7576SPiotr Wilczek case 8: 139812d7576SPiotr Wilczek case 10: 140812d7576SPiotr Wilczek case 11: 141812d7576SPiotr Wilczek case 12: 142812d7576SPiotr Wilczek case 14: 143812d7576SPiotr Wilczek case 15: 144812d7576SPiotr Wilczek case 16: 145812d7576SPiotr Wilczek mode = MAX77686_LDO_MODE_STANDBY; 146812d7576SPiotr Wilczek break; 147812d7576SPiotr Wilczek default: 148812d7576SPiotr Wilczek mode = 0xff; 149812d7576SPiotr Wilczek } 150812d7576SPiotr Wilczek break; 151812d7576SPiotr Wilczek case OPMODE_LPM: 152812d7576SPiotr Wilczek mode = MAX77686_LDO_MODE_LPM; 153812d7576SPiotr Wilczek break; 154812d7576SPiotr Wilczek case OPMODE_ON: 155812d7576SPiotr Wilczek mode = MAX77686_LDO_MODE_ON; 156812d7576SPiotr Wilczek break; 157812d7576SPiotr Wilczek default: 158812d7576SPiotr Wilczek mode = 0xff; 159812d7576SPiotr Wilczek } 160812d7576SPiotr Wilczek 161812d7576SPiotr Wilczek if (mode == 0xff) { 162812d7576SPiotr Wilczek printf("%s: %d is not supported on LDO%d\n", 163812d7576SPiotr Wilczek __func__, opmode, ldo); 164812d7576SPiotr Wilczek return -1; 165812d7576SPiotr Wilczek } 166812d7576SPiotr Wilczek 167812d7576SPiotr Wilczek ret = pmic_reg_read(p, adr, &val); 168812d7576SPiotr Wilczek if (ret) 169812d7576SPiotr Wilczek return ret; 170812d7576SPiotr Wilczek 171812d7576SPiotr Wilczek val &= ~MAX77686_LDO_MODE_MASK; 172812d7576SPiotr Wilczek val |= mode; 173812d7576SPiotr Wilczek ret |= pmic_reg_write(p, adr, val); 174812d7576SPiotr Wilczek 175812d7576SPiotr Wilczek return ret; 176812d7576SPiotr Wilczek } 177812d7576SPiotr Wilczek 178812d7576SPiotr Wilczek int max77686_set_buck_mode(struct pmic *p, int buck, char opmode) 179812d7576SPiotr Wilczek { 180812d7576SPiotr Wilczek unsigned int val, ret, mask, adr, size, mode, mode_shift; 181812d7576SPiotr Wilczek 182812d7576SPiotr Wilczek size = ARRAY_SIZE(max77686_buck_addr); 183812d7576SPiotr Wilczek if (buck >= size) { 184812d7576SPiotr Wilczek printf("%s: %d is wrong buck number\n", __func__, buck); 185812d7576SPiotr Wilczek return -1; 186812d7576SPiotr Wilczek } 187812d7576SPiotr Wilczek 188812d7576SPiotr Wilczek adr = max77686_buck_addr[buck]; 189812d7576SPiotr Wilczek 190812d7576SPiotr Wilczek /* mask */ 191812d7576SPiotr Wilczek switch (buck) { 192812d7576SPiotr Wilczek case 2: 193812d7576SPiotr Wilczek case 3: 194812d7576SPiotr Wilczek case 4: 195812d7576SPiotr Wilczek mode_shift = MAX77686_BUCK_MODE_SHIFT_2; 196812d7576SPiotr Wilczek break; 197812d7576SPiotr Wilczek default: 198812d7576SPiotr Wilczek mode_shift = MAX77686_BUCK_MODE_SHIFT_1; 199812d7576SPiotr Wilczek } 200812d7576SPiotr Wilczek 201812d7576SPiotr Wilczek mask = MAX77686_BUCK_MODE_MASK << mode_shift; 202812d7576SPiotr Wilczek 203812d7576SPiotr Wilczek /* mode */ 204812d7576SPiotr Wilczek switch (opmode) { 205812d7576SPiotr Wilczek case OPMODE_OFF: 206*7e46be8aSSuriyan Ramasami mode = MAX77686_BUCK_MODE_OFF << mode_shift; 207812d7576SPiotr Wilczek break; 208812d7576SPiotr Wilczek case OPMODE_STANDBY: 209812d7576SPiotr Wilczek switch (buck) { 210812d7576SPiotr Wilczek case 1: 211812d7576SPiotr Wilczek case 2: 212812d7576SPiotr Wilczek case 3: 213812d7576SPiotr Wilczek case 4: 214812d7576SPiotr Wilczek mode = MAX77686_BUCK_MODE_STANDBY << mode_shift; 215812d7576SPiotr Wilczek break; 216812d7576SPiotr Wilczek default: 217812d7576SPiotr Wilczek mode = 0xff; 218812d7576SPiotr Wilczek } 219812d7576SPiotr Wilczek break; 220812d7576SPiotr Wilczek case OPMODE_LPM: 221812d7576SPiotr Wilczek switch (buck) { 222812d7576SPiotr Wilczek case 2: 223812d7576SPiotr Wilczek case 3: 224812d7576SPiotr Wilczek case 4: 225812d7576SPiotr Wilczek mode = MAX77686_BUCK_MODE_LPM << mode_shift; 226812d7576SPiotr Wilczek break; 227812d7576SPiotr Wilczek default: 228812d7576SPiotr Wilczek mode = 0xff; 229812d7576SPiotr Wilczek } 230812d7576SPiotr Wilczek break; 231812d7576SPiotr Wilczek case OPMODE_ON: 232812d7576SPiotr Wilczek mode = MAX77686_BUCK_MODE_ON << mode_shift; 233812d7576SPiotr Wilczek break; 234812d7576SPiotr Wilczek default: 235812d7576SPiotr Wilczek mode = 0xff; 236812d7576SPiotr Wilczek } 237812d7576SPiotr Wilczek 238812d7576SPiotr Wilczek if (mode == 0xff) { 239812d7576SPiotr Wilczek printf("%s: %d is not supported on BUCK%d\n", 240812d7576SPiotr Wilczek __func__, opmode, buck); 241812d7576SPiotr Wilczek return -1; 242812d7576SPiotr Wilczek } 243812d7576SPiotr Wilczek 244812d7576SPiotr Wilczek ret = pmic_reg_read(p, adr, &val); 245812d7576SPiotr Wilczek if (ret) 246812d7576SPiotr Wilczek return ret; 247812d7576SPiotr Wilczek 248812d7576SPiotr Wilczek val &= ~mask; 249812d7576SPiotr Wilczek val |= mode; 250812d7576SPiotr Wilczek ret |= pmic_reg_write(p, adr, val); 251812d7576SPiotr Wilczek 252812d7576SPiotr Wilczek return ret; 253812d7576SPiotr Wilczek } 254812d7576SPiotr Wilczek 255857765e9SRajeshwari Shinde int pmic_init(unsigned char bus) 256857765e9SRajeshwari Shinde { 257857765e9SRajeshwari Shinde static const char name[] = "MAX77686_PMIC"; 258857765e9SRajeshwari Shinde struct pmic *p = pmic_alloc(); 25900d4796cSJeroen Hofstee #ifdef CONFIG_OF_CONTROL 26000d4796cSJeroen Hofstee const void *blob = gd->fdt_blob; 26100d4796cSJeroen Hofstee int node, parent, tmp; 26200d4796cSJeroen Hofstee #endif 263857765e9SRajeshwari Shinde 264857765e9SRajeshwari Shinde if (!p) { 265857765e9SRajeshwari Shinde printf("%s: POWER allocation error!\n", __func__); 266857765e9SRajeshwari Shinde return -ENOMEM; 267857765e9SRajeshwari Shinde } 268857765e9SRajeshwari Shinde 2694050f070SRajeshwari Shinde #ifdef CONFIG_OF_CONTROL 2704050f070SRajeshwari Shinde node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_MAX77686_PMIC); 2714050f070SRajeshwari Shinde if (node < 0) { 2724050f070SRajeshwari Shinde debug("PMIC: No node for PMIC Chip in device tree\n"); 2734050f070SRajeshwari Shinde debug("node = %d\n", node); 2744050f070SRajeshwari Shinde return -1; 2754050f070SRajeshwari Shinde } 2764050f070SRajeshwari Shinde 2774050f070SRajeshwari Shinde parent = fdt_parent_offset(blob, node); 2784050f070SRajeshwari Shinde if (parent < 0) { 2794050f070SRajeshwari Shinde debug("%s: Cannot find node parent\n", __func__); 2804050f070SRajeshwari Shinde return -1; 2814050f070SRajeshwari Shinde } 2824050f070SRajeshwari Shinde 28300d4796cSJeroen Hofstee /* tmp since p->bus is unsigned */ 28400d4796cSJeroen Hofstee tmp = i2c_get_bus_num_fdt(parent); 28500d4796cSJeroen Hofstee if (tmp < 0) { 2864050f070SRajeshwari Shinde debug("%s: Cannot find I2C bus\n", __func__); 2874050f070SRajeshwari Shinde return -1; 2884050f070SRajeshwari Shinde } 28900d4796cSJeroen Hofstee p->bus = tmp; 2904050f070SRajeshwari Shinde p->hw.i2c.addr = fdtdec_get_int(blob, node, "reg", 9); 2914050f070SRajeshwari Shinde #else 2924050f070SRajeshwari Shinde p->bus = bus; 2934050f070SRajeshwari Shinde p->hw.i2c.addr = MAX77686_I2C_ADDR; 2944050f070SRajeshwari Shinde #endif 2954050f070SRajeshwari Shinde 296857765e9SRajeshwari Shinde p->name = name; 297857765e9SRajeshwari Shinde p->interface = PMIC_I2C; 298857765e9SRajeshwari Shinde p->number_of_regs = PMIC_NUM_OF_REGS; 299857765e9SRajeshwari Shinde p->hw.i2c.tx_num = 1; 3004050f070SRajeshwari Shinde 3014050f070SRajeshwari Shinde puts("Board PMIC init\n"); 302857765e9SRajeshwari Shinde 303857765e9SRajeshwari Shinde return 0; 304857765e9SRajeshwari Shinde } 305