1ade7515fSKim, Milo /* 2ade7515fSKim, Milo * TI LP8788 MFD - buck regulator driver 3ade7515fSKim, Milo * 4ade7515fSKim, Milo * Copyright 2012 Texas Instruments 5ade7515fSKim, Milo * 6ade7515fSKim, Milo * Author: Milo(Woogyom) Kim <milo.kim@ti.com> 7ade7515fSKim, Milo * 8ade7515fSKim, Milo * This program is free software; you can redistribute it and/or modify 9ade7515fSKim, Milo * it under the terms of the GNU General Public License version 2 as 10ade7515fSKim, Milo * published by the Free Software Foundation. 11ade7515fSKim, Milo * 12ade7515fSKim, Milo */ 13ade7515fSKim, Milo 14ade7515fSKim, Milo #include <linux/module.h> 15ade7515fSKim, Milo #include <linux/slab.h> 16ade7515fSKim, Milo #include <linux/err.h> 17ade7515fSKim, Milo #include <linux/platform_device.h> 18ade7515fSKim, Milo #include <linux/regulator/driver.h> 19ade7515fSKim, Milo #include <linux/mfd/lp8788.h> 20ade7515fSKim, Milo #include <linux/gpio.h> 21ade7515fSKim, Milo 22ade7515fSKim, Milo /* register address */ 23ade7515fSKim, Milo #define LP8788_EN_BUCK 0x0C 24ade7515fSKim, Milo #define LP8788_BUCK_DVS_SEL 0x1D 25ade7515fSKim, Milo #define LP8788_BUCK1_VOUT0 0x1E 26ade7515fSKim, Milo #define LP8788_BUCK1_VOUT1 0x1F 27ade7515fSKim, Milo #define LP8788_BUCK1_VOUT2 0x20 28ade7515fSKim, Milo #define LP8788_BUCK1_VOUT3 0x21 29ade7515fSKim, Milo #define LP8788_BUCK2_VOUT0 0x22 30ade7515fSKim, Milo #define LP8788_BUCK2_VOUT1 0x23 31ade7515fSKim, Milo #define LP8788_BUCK2_VOUT2 0x24 32ade7515fSKim, Milo #define LP8788_BUCK2_VOUT3 0x25 33ade7515fSKim, Milo #define LP8788_BUCK3_VOUT 0x26 34ade7515fSKim, Milo #define LP8788_BUCK4_VOUT 0x27 35ade7515fSKim, Milo #define LP8788_BUCK1_TIMESTEP 0x28 36ade7515fSKim, Milo #define LP8788_BUCK_PWM 0x2D 37ade7515fSKim, Milo 38ade7515fSKim, Milo /* mask/shift bits */ 39ade7515fSKim, Milo #define LP8788_EN_BUCK1_M BIT(0) /* Addr 0Ch */ 40ade7515fSKim, Milo #define LP8788_EN_BUCK2_M BIT(1) 41ade7515fSKim, Milo #define LP8788_EN_BUCK3_M BIT(2) 42ade7515fSKim, Milo #define LP8788_EN_BUCK4_M BIT(3) 43ade7515fSKim, Milo #define LP8788_BUCK1_DVS_SEL_M 0x04 /* Addr 1Dh */ 44ade7515fSKim, Milo #define LP8788_BUCK1_DVS_M 0x03 45ade7515fSKim, Milo #define LP8788_BUCK1_DVS_S 0 46ade7515fSKim, Milo #define LP8788_BUCK2_DVS_SEL_M 0x40 47ade7515fSKim, Milo #define LP8788_BUCK2_DVS_M 0x30 48ade7515fSKim, Milo #define LP8788_BUCK2_DVS_S 4 49ade7515fSKim, Milo #define LP8788_BUCK1_DVS_I2C BIT(2) 50ade7515fSKim, Milo #define LP8788_BUCK2_DVS_I2C BIT(6) 51ade7515fSKim, Milo #define LP8788_BUCK1_DVS_PIN (0 << 2) 52ade7515fSKim, Milo #define LP8788_BUCK2_DVS_PIN (0 << 6) 53ade7515fSKim, Milo #define LP8788_VOUT_M 0x1F /* Addr 1Eh ~ 27h */ 54ade7515fSKim, Milo #define LP8788_STARTUP_TIME_M 0xF8 /* Addr 28h ~ 2Bh */ 55ade7515fSKim, Milo #define LP8788_STARTUP_TIME_S 3 56ade7515fSKim, Milo #define LP8788_FPWM_BUCK1_M BIT(0) /* Addr 2Dh */ 57ade7515fSKim, Milo #define LP8788_FPWM_BUCK1_S 0 58ade7515fSKim, Milo #define LP8788_FPWM_BUCK2_M BIT(1) 59ade7515fSKim, Milo #define LP8788_FPWM_BUCK2_S 1 60ade7515fSKim, Milo #define LP8788_FPWM_BUCK3_M BIT(2) 61ade7515fSKim, Milo #define LP8788_FPWM_BUCK3_S 2 62ade7515fSKim, Milo #define LP8788_FPWM_BUCK4_M BIT(3) 63ade7515fSKim, Milo #define LP8788_FPWM_BUCK4_S 3 64ade7515fSKim, Milo 65ade7515fSKim, Milo #define INVALID_ADDR 0xFF 66ade7515fSKim, Milo #define LP8788_FORCE_PWM 1 67ade7515fSKim, Milo #define LP8788_AUTO_PWM 0 68ade7515fSKim, Milo #define PIN_LOW 0 69ade7515fSKim, Milo #define PIN_HIGH 1 70ade7515fSKim, Milo #define ENABLE_TIME_USEC 32 71ade7515fSKim, Milo 720f4c46d2SAxel Lin #define BUCK_FPWM_MASK(x) (1 << (x)) 730f4c46d2SAxel Lin #define BUCK_FPWM_SHIFT(x) (x) 740f4c46d2SAxel Lin 75ade7515fSKim, Milo enum lp8788_dvs_state { 76ade7515fSKim, Milo DVS_LOW = GPIOF_OUT_INIT_LOW, 77ade7515fSKim, Milo DVS_HIGH = GPIOF_OUT_INIT_HIGH, 78ade7515fSKim, Milo }; 79ade7515fSKim, Milo 80ade7515fSKim, Milo enum lp8788_dvs_mode { 81ade7515fSKim, Milo REGISTER, 82ade7515fSKim, Milo EXTPIN, 83ade7515fSKim, Milo }; 84ade7515fSKim, Milo 85ade7515fSKim, Milo enum lp8788_buck_id { 86ade7515fSKim, Milo BUCK1, 87ade7515fSKim, Milo BUCK2, 88ade7515fSKim, Milo BUCK3, 89ade7515fSKim, Milo BUCK4, 90ade7515fSKim, Milo }; 91ade7515fSKim, Milo 92ade7515fSKim, Milo struct lp8788_buck { 93ade7515fSKim, Milo struct lp8788 *lp; 94ade7515fSKim, Milo struct regulator_dev *regulator; 95ade7515fSKim, Milo void *dvs; 96ade7515fSKim, Milo }; 97ade7515fSKim, Milo 98ade7515fSKim, Milo /* BUCK 1 ~ 4 voltage table */ 99ade7515fSKim, Milo static const int lp8788_buck_vtbl[] = { 100ade7515fSKim, Milo 500000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 101ade7515fSKim, Milo 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 102ade7515fSKim, Milo 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 103ade7515fSKim, Milo 1950000, 2000000, 104ade7515fSKim, Milo }; 105ade7515fSKim, Milo 106ade7515fSKim, Milo static const u8 buck1_vout_addr[] = { 107ade7515fSKim, Milo LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1, 108ade7515fSKim, Milo LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3, 109ade7515fSKim, Milo }; 110ade7515fSKim, Milo 111ade7515fSKim, Milo static const u8 buck2_vout_addr[] = { 112ade7515fSKim, Milo LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1, 113ade7515fSKim, Milo LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3, 114ade7515fSKim, Milo }; 115ade7515fSKim, Milo 116ade7515fSKim, Milo static void lp8788_buck1_set_dvs(struct lp8788_buck *buck) 117ade7515fSKim, Milo { 118ade7515fSKim, Milo struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs; 119ade7515fSKim, Milo enum lp8788_dvs_state pinstate; 120ade7515fSKim, Milo 121ade7515fSKim, Milo if (!dvs) 122ade7515fSKim, Milo return; 123ade7515fSKim, Milo 124ade7515fSKim, Milo pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH; 125ade7515fSKim, Milo if (gpio_is_valid(dvs->gpio)) 126ade7515fSKim, Milo gpio_set_value(dvs->gpio, pinstate); 127ade7515fSKim, Milo } 128ade7515fSKim, Milo 129ade7515fSKim, Milo static void lp8788_buck2_set_dvs(struct lp8788_buck *buck) 130ade7515fSKim, Milo { 131ade7515fSKim, Milo struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs; 132ade7515fSKim, Milo enum lp8788_dvs_state pin1, pin2; 133ade7515fSKim, Milo 134ade7515fSKim, Milo if (!dvs) 135ade7515fSKim, Milo return; 136ade7515fSKim, Milo 137ade7515fSKim, Milo switch (dvs->vsel) { 138ade7515fSKim, Milo case DVS_SEL_V0: 139ade7515fSKim, Milo pin1 = DVS_LOW; 140ade7515fSKim, Milo pin2 = DVS_LOW; 141ade7515fSKim, Milo break; 142ade7515fSKim, Milo case DVS_SEL_V1: 143ade7515fSKim, Milo pin1 = DVS_HIGH; 144ade7515fSKim, Milo pin2 = DVS_LOW; 145ade7515fSKim, Milo break; 146ade7515fSKim, Milo case DVS_SEL_V2: 147ade7515fSKim, Milo pin1 = DVS_LOW; 148ade7515fSKim, Milo pin2 = DVS_HIGH; 149ade7515fSKim, Milo break; 150ade7515fSKim, Milo case DVS_SEL_V3: 151ade7515fSKim, Milo pin1 = DVS_HIGH; 152ade7515fSKim, Milo pin2 = DVS_HIGH; 153ade7515fSKim, Milo break; 154ade7515fSKim, Milo default: 155ade7515fSKim, Milo return; 156ade7515fSKim, Milo } 157ade7515fSKim, Milo 158ade7515fSKim, Milo if (gpio_is_valid(dvs->gpio[0])) 159ade7515fSKim, Milo gpio_set_value(dvs->gpio[0], pin1); 160ade7515fSKim, Milo 161ade7515fSKim, Milo if (gpio_is_valid(dvs->gpio[1])) 162ade7515fSKim, Milo gpio_set_value(dvs->gpio[1], pin2); 163ade7515fSKim, Milo } 164ade7515fSKim, Milo 165ade7515fSKim, Milo static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) 166ade7515fSKim, Milo { 167ade7515fSKim, Milo switch (id) { 168ade7515fSKim, Milo case BUCK1: 169ade7515fSKim, Milo lp8788_buck1_set_dvs(buck); 170ade7515fSKim, Milo break; 171ade7515fSKim, Milo case BUCK2: 172ade7515fSKim, Milo lp8788_buck2_set_dvs(buck); 173ade7515fSKim, Milo break; 174ade7515fSKim, Milo default: 175ade7515fSKim, Milo break; 176ade7515fSKim, Milo } 177ade7515fSKim, Milo } 178ade7515fSKim, Milo 179ade7515fSKim, Milo static enum lp8788_dvs_mode 180ade7515fSKim, Milo lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id) 181ade7515fSKim, Milo { 182ade7515fSKim, Milo u8 val, mask; 183ade7515fSKim, Milo 184ade7515fSKim, Milo switch (id) { 185ade7515fSKim, Milo case BUCK1: 186ade7515fSKim, Milo mask = LP8788_BUCK1_DVS_SEL_M; 187ade7515fSKim, Milo break; 188ade7515fSKim, Milo case BUCK2: 189ade7515fSKim, Milo mask = LP8788_BUCK2_DVS_SEL_M; 190ade7515fSKim, Milo break; 191ade7515fSKim, Milo default: 192ade7515fSKim, Milo return REGISTER; 193ade7515fSKim, Milo } 194ade7515fSKim, Milo 195ade7515fSKim, Milo lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); 196ade7515fSKim, Milo 197ade7515fSKim, Milo return val & mask ? REGISTER : EXTPIN; 198ade7515fSKim, Milo } 199ade7515fSKim, Milo 200ade7515fSKim, Milo static bool lp8788_is_valid_buck_addr(u8 addr) 201ade7515fSKim, Milo { 202ade7515fSKim, Milo switch (addr) { 203ade7515fSKim, Milo case LP8788_BUCK1_VOUT0: 204ade7515fSKim, Milo case LP8788_BUCK1_VOUT1: 205ade7515fSKim, Milo case LP8788_BUCK1_VOUT2: 206ade7515fSKim, Milo case LP8788_BUCK1_VOUT3: 207ade7515fSKim, Milo case LP8788_BUCK2_VOUT0: 208ade7515fSKim, Milo case LP8788_BUCK2_VOUT1: 209ade7515fSKim, Milo case LP8788_BUCK2_VOUT2: 210ade7515fSKim, Milo case LP8788_BUCK2_VOUT3: 211ade7515fSKim, Milo return true; 212ade7515fSKim, Milo default: 213ade7515fSKim, Milo return false; 214ade7515fSKim, Milo } 215ade7515fSKim, Milo } 216ade7515fSKim, Milo 217ade7515fSKim, Milo static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck, 218ade7515fSKim, Milo enum lp8788_buck_id id) 219ade7515fSKim, Milo { 220ade7515fSKim, Milo enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id); 221ade7515fSKim, Milo struct lp8788_buck1_dvs *b1_dvs; 222ade7515fSKim, Milo struct lp8788_buck2_dvs *b2_dvs; 223ade7515fSKim, Milo u8 val, idx, addr; 224ade7515fSKim, Milo int pin1, pin2; 225ade7515fSKim, Milo 226ade7515fSKim, Milo switch (id) { 227ade7515fSKim, Milo case BUCK1: 228ade7515fSKim, Milo if (mode == EXTPIN) { 229ade7515fSKim, Milo b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs; 230ade7515fSKim, Milo if (!b1_dvs) 231ade7515fSKim, Milo goto err; 232ade7515fSKim, Milo 233ade7515fSKim, Milo idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0; 234ade7515fSKim, Milo } else { 235ade7515fSKim, Milo lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); 236ade7515fSKim, Milo idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S; 237ade7515fSKim, Milo } 238ade7515fSKim, Milo addr = buck1_vout_addr[idx]; 239ade7515fSKim, Milo break; 240ade7515fSKim, Milo case BUCK2: 241ade7515fSKim, Milo if (mode == EXTPIN) { 242ade7515fSKim, Milo b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs; 243ade7515fSKim, Milo if (!b2_dvs) 244ade7515fSKim, Milo goto err; 245ade7515fSKim, Milo 246ade7515fSKim, Milo pin1 = gpio_get_value(b2_dvs->gpio[0]); 247ade7515fSKim, Milo pin2 = gpio_get_value(b2_dvs->gpio[1]); 248ade7515fSKim, Milo 249ade7515fSKim, Milo if (pin1 == PIN_LOW && pin2 == PIN_LOW) 250ade7515fSKim, Milo idx = 0; 251ade7515fSKim, Milo else if (pin1 == PIN_LOW && pin2 == PIN_HIGH) 252ade7515fSKim, Milo idx = 2; 253ade7515fSKim, Milo else if (pin1 == PIN_HIGH && pin2 == PIN_LOW) 254ade7515fSKim, Milo idx = 1; 255ade7515fSKim, Milo else 256ade7515fSKim, Milo idx = 3; 257ade7515fSKim, Milo } else { 258ade7515fSKim, Milo lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); 259ade7515fSKim, Milo idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S; 260ade7515fSKim, Milo } 261ade7515fSKim, Milo addr = buck2_vout_addr[idx]; 262ade7515fSKim, Milo break; 263ade7515fSKim, Milo default: 264ade7515fSKim, Milo goto err; 265ade7515fSKim, Milo } 266ade7515fSKim, Milo 267ade7515fSKim, Milo return addr; 268ade7515fSKim, Milo err: 269ade7515fSKim, Milo return INVALID_ADDR; 270ade7515fSKim, Milo } 271ade7515fSKim, Milo 272ade7515fSKim, Milo static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev, 273ade7515fSKim, Milo unsigned selector) 274ade7515fSKim, Milo { 275ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 276ade7515fSKim, Milo enum lp8788_buck_id id = rdev_get_id(rdev); 277ade7515fSKim, Milo u8 addr; 278ade7515fSKim, Milo 279ade7515fSKim, Milo if (buck->dvs) 280ade7515fSKim, Milo lp8788_set_dvs(buck, id); 281ade7515fSKim, Milo 282ade7515fSKim, Milo addr = lp8788_select_buck_vout_addr(buck, id); 283ade7515fSKim, Milo if (!lp8788_is_valid_buck_addr(addr)) 284ade7515fSKim, Milo return -EINVAL; 285ade7515fSKim, Milo 286ade7515fSKim, Milo return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector); 287ade7515fSKim, Milo } 288ade7515fSKim, Milo 289ade7515fSKim, Milo static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev) 290ade7515fSKim, Milo { 291ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 292ade7515fSKim, Milo enum lp8788_buck_id id = rdev_get_id(rdev); 293ade7515fSKim, Milo int ret; 294ade7515fSKim, Milo u8 val, addr; 295ade7515fSKim, Milo 296ade7515fSKim, Milo addr = lp8788_select_buck_vout_addr(buck, id); 297ade7515fSKim, Milo if (!lp8788_is_valid_buck_addr(addr)) 298ade7515fSKim, Milo return -EINVAL; 299ade7515fSKim, Milo 300ade7515fSKim, Milo ret = lp8788_read_byte(buck->lp, addr, &val); 301ade7515fSKim, Milo if (ret) 302ade7515fSKim, Milo return ret; 303ade7515fSKim, Milo 304ade7515fSKim, Milo return val & LP8788_VOUT_M; 305ade7515fSKim, Milo } 306ade7515fSKim, Milo 307ade7515fSKim, Milo static int lp8788_buck_enable_time(struct regulator_dev *rdev) 308ade7515fSKim, Milo { 309ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 310ade7515fSKim, Milo enum lp8788_buck_id id = rdev_get_id(rdev); 311ade7515fSKim, Milo u8 val, addr = LP8788_BUCK1_TIMESTEP + id; 312ade7515fSKim, Milo 313ade7515fSKim, Milo if (lp8788_read_byte(buck->lp, addr, &val)) 314ade7515fSKim, Milo return -EINVAL; 315ade7515fSKim, Milo 316ade7515fSKim, Milo val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S; 317ade7515fSKim, Milo 318ade7515fSKim, Milo return ENABLE_TIME_USEC * val; 319ade7515fSKim, Milo } 320ade7515fSKim, Milo 321ade7515fSKim, Milo static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) 322ade7515fSKim, Milo { 323ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 3240f4c46d2SAxel Lin enum lp8788_buck_id id = rdev_get_id(rdev); 3250f4c46d2SAxel Lin u8 mask, val; 326ade7515fSKim, Milo 3270f4c46d2SAxel Lin mask = BUCK_FPWM_MASK(id); 328ade7515fSKim, Milo switch (mode) { 329ade7515fSKim, Milo case REGULATOR_MODE_FAST: 3300f4c46d2SAxel Lin val = LP8788_FORCE_PWM << BUCK_FPWM_SHIFT(id); 331ade7515fSKim, Milo break; 332ade7515fSKim, Milo case REGULATOR_MODE_NORMAL: 3330f4c46d2SAxel Lin val = LP8788_AUTO_PWM << BUCK_FPWM_SHIFT(id); 334ade7515fSKim, Milo break; 335ade7515fSKim, Milo default: 336ade7515fSKim, Milo return -EINVAL; 337ade7515fSKim, Milo } 338ade7515fSKim, Milo 3390f4c46d2SAxel Lin return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, mask, val); 340ade7515fSKim, Milo } 341ade7515fSKim, Milo 342ade7515fSKim, Milo static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev) 343ade7515fSKim, Milo { 344ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 3450f4c46d2SAxel Lin enum lp8788_buck_id id = rdev_get_id(rdev); 346ade7515fSKim, Milo u8 val; 347ade7515fSKim, Milo int ret; 348ade7515fSKim, Milo 349ade7515fSKim, Milo ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val); 350ade7515fSKim, Milo if (ret) 351ade7515fSKim, Milo return ret; 352ade7515fSKim, Milo 3530f4c46d2SAxel Lin return val & BUCK_FPWM_MASK(id) ? 3540f4c46d2SAxel Lin REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; 355ade7515fSKim, Milo } 356ade7515fSKim, Milo 357ade7515fSKim, Milo static struct regulator_ops lp8788_buck12_ops = { 358ade7515fSKim, Milo .list_voltage = regulator_list_voltage_table, 359ade7515fSKim, Milo .set_voltage_sel = lp8788_buck12_set_voltage_sel, 360ade7515fSKim, Milo .get_voltage_sel = lp8788_buck12_get_voltage_sel, 361ade7515fSKim, Milo .enable = regulator_enable_regmap, 362ade7515fSKim, Milo .disable = regulator_disable_regmap, 363ade7515fSKim, Milo .is_enabled = regulator_is_enabled_regmap, 364ade7515fSKim, Milo .enable_time = lp8788_buck_enable_time, 365ade7515fSKim, Milo .set_mode = lp8788_buck_set_mode, 366ade7515fSKim, Milo .get_mode = lp8788_buck_get_mode, 367ade7515fSKim, Milo }; 368ade7515fSKim, Milo 369ade7515fSKim, Milo static struct regulator_ops lp8788_buck34_ops = { 370ade7515fSKim, Milo .list_voltage = regulator_list_voltage_table, 371ade7515fSKim, Milo .set_voltage_sel = regulator_set_voltage_sel_regmap, 372ade7515fSKim, Milo .get_voltage_sel = regulator_get_voltage_sel_regmap, 373ade7515fSKim, Milo .enable = regulator_enable_regmap, 374ade7515fSKim, Milo .disable = regulator_disable_regmap, 375ade7515fSKim, Milo .is_enabled = regulator_is_enabled_regmap, 376ade7515fSKim, Milo .enable_time = lp8788_buck_enable_time, 377ade7515fSKim, Milo .set_mode = lp8788_buck_set_mode, 378ade7515fSKim, Milo .get_mode = lp8788_buck_get_mode, 379ade7515fSKim, Milo }; 380ade7515fSKim, Milo 381ade7515fSKim, Milo static struct regulator_desc lp8788_buck_desc[] = { 382ade7515fSKim, Milo { 383ade7515fSKim, Milo .name = "buck1", 384ade7515fSKim, Milo .id = BUCK1, 385ade7515fSKim, Milo .ops = &lp8788_buck12_ops, 386ade7515fSKim, Milo .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), 387ade7515fSKim, Milo .volt_table = lp8788_buck_vtbl, 388ade7515fSKim, Milo .type = REGULATOR_VOLTAGE, 389ade7515fSKim, Milo .owner = THIS_MODULE, 390ade7515fSKim, Milo .enable_reg = LP8788_EN_BUCK, 391ade7515fSKim, Milo .enable_mask = LP8788_EN_BUCK1_M, 392ade7515fSKim, Milo }, 393ade7515fSKim, Milo { 394ade7515fSKim, Milo .name = "buck2", 395ade7515fSKim, Milo .id = BUCK2, 396ade7515fSKim, Milo .ops = &lp8788_buck12_ops, 397ade7515fSKim, Milo .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), 398ade7515fSKim, Milo .volt_table = lp8788_buck_vtbl, 399ade7515fSKim, Milo .type = REGULATOR_VOLTAGE, 400ade7515fSKim, Milo .owner = THIS_MODULE, 401ade7515fSKim, Milo .enable_reg = LP8788_EN_BUCK, 402ade7515fSKim, Milo .enable_mask = LP8788_EN_BUCK2_M, 403ade7515fSKim, Milo }, 404ade7515fSKim, Milo { 405ade7515fSKim, Milo .name = "buck3", 406ade7515fSKim, Milo .id = BUCK3, 407ade7515fSKim, Milo .ops = &lp8788_buck34_ops, 408ade7515fSKim, Milo .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), 409ade7515fSKim, Milo .volt_table = lp8788_buck_vtbl, 410ade7515fSKim, Milo .type = REGULATOR_VOLTAGE, 411ade7515fSKim, Milo .owner = THIS_MODULE, 412ade7515fSKim, Milo .vsel_reg = LP8788_BUCK3_VOUT, 413ade7515fSKim, Milo .vsel_mask = LP8788_VOUT_M, 414ade7515fSKim, Milo .enable_reg = LP8788_EN_BUCK, 415ade7515fSKim, Milo .enable_mask = LP8788_EN_BUCK3_M, 416ade7515fSKim, Milo }, 417ade7515fSKim, Milo { 418ade7515fSKim, Milo .name = "buck4", 419ade7515fSKim, Milo .id = BUCK4, 420ade7515fSKim, Milo .ops = &lp8788_buck34_ops, 421ade7515fSKim, Milo .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), 422ade7515fSKim, Milo .volt_table = lp8788_buck_vtbl, 423ade7515fSKim, Milo .type = REGULATOR_VOLTAGE, 424ade7515fSKim, Milo .owner = THIS_MODULE, 425ade7515fSKim, Milo .vsel_reg = LP8788_BUCK4_VOUT, 426ade7515fSKim, Milo .vsel_mask = LP8788_VOUT_M, 427ade7515fSKim, Milo .enable_reg = LP8788_EN_BUCK, 428ade7515fSKim, Milo .enable_mask = LP8788_EN_BUCK4_M, 429ade7515fSKim, Milo }, 430ade7515fSKim, Milo }; 431ade7515fSKim, Milo 432*38d8f67cSKim, Milo static int lp8788_dvs_gpio_request(struct platform_device *pdev, 433*38d8f67cSKim, Milo struct lp8788_buck *buck, 434ade7515fSKim, Milo enum lp8788_buck_id id) 435ade7515fSKim, Milo { 436ade7515fSKim, Milo struct lp8788_platform_data *pdata = buck->lp->pdata; 437ade7515fSKim, Milo char *b1_name = "LP8788_B1_DVS"; 438ade7515fSKim, Milo char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" }; 439ade7515fSKim, Milo int i, gpio, ret; 440ade7515fSKim, Milo 441ade7515fSKim, Milo switch (id) { 442ade7515fSKim, Milo case BUCK1: 443ade7515fSKim, Milo gpio = pdata->buck1_dvs->gpio; 444*38d8f67cSKim, Milo ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW, 445131a5b9dSAxel Lin b1_name); 446ade7515fSKim, Milo if (ret) 447ade7515fSKim, Milo return ret; 448ade7515fSKim, Milo 449ade7515fSKim, Milo buck->dvs = pdata->buck1_dvs; 450ade7515fSKim, Milo break; 451ade7515fSKim, Milo case BUCK2: 452ade7515fSKim, Milo for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) { 453ade7515fSKim, Milo gpio = pdata->buck2_dvs->gpio[i]; 454*38d8f67cSKim, Milo ret = devm_gpio_request_one(&pdev->dev, gpio, 455131a5b9dSAxel Lin DVS_LOW, b2_name[i]); 456ade7515fSKim, Milo if (ret) 457ade7515fSKim, Milo return ret; 458ade7515fSKim, Milo } 459ade7515fSKim, Milo buck->dvs = pdata->buck2_dvs; 460ade7515fSKim, Milo break; 461ade7515fSKim, Milo default: 462ade7515fSKim, Milo break; 463ade7515fSKim, Milo } 464ade7515fSKim, Milo 465ade7515fSKim, Milo return 0; 466ade7515fSKim, Milo } 467ade7515fSKim, Milo 468*38d8f67cSKim, Milo static int lp8788_init_dvs(struct platform_device *pdev, 469*38d8f67cSKim, Milo struct lp8788_buck *buck, enum lp8788_buck_id id) 470ade7515fSKim, Milo { 471ade7515fSKim, Milo struct lp8788_platform_data *pdata = buck->lp->pdata; 472ade7515fSKim, Milo u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M }; 473ade7515fSKim, Milo u8 val[] = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN }; 474c42ea5cdSAxel Lin u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C }; 475ade7515fSKim, Milo 476ade7515fSKim, Milo /* no dvs for buck3, 4 */ 477ade7515fSKim, Milo if (id == BUCK3 || id == BUCK4) 478ade7515fSKim, Milo return 0; 479ade7515fSKim, Milo 480ade7515fSKim, Milo /* no dvs platform data, then dvs will be selected by I2C registers */ 481ade7515fSKim, Milo if (!pdata) 482ade7515fSKim, Milo goto set_default_dvs_mode; 483ade7515fSKim, Milo 484ade7515fSKim, Milo if ((id == BUCK1 && !pdata->buck1_dvs) || 485ade7515fSKim, Milo (id == BUCK2 && !pdata->buck2_dvs)) 486ade7515fSKim, Milo goto set_default_dvs_mode; 487ade7515fSKim, Milo 488*38d8f67cSKim, Milo if (lp8788_dvs_gpio_request(pdev, buck, id)) 489ade7515fSKim, Milo goto set_default_dvs_mode; 490ade7515fSKim, Milo 491ade7515fSKim, Milo return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id], 492ade7515fSKim, Milo val[id]); 493ade7515fSKim, Milo 494ade7515fSKim, Milo set_default_dvs_mode: 495c42ea5cdSAxel Lin return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id], 496c42ea5cdSAxel Lin default_dvs_mode[id]); 497ade7515fSKim, Milo } 498ade7515fSKim, Milo 499a5023574SBill Pemberton static int lp8788_buck_probe(struct platform_device *pdev) 500ade7515fSKim, Milo { 501ade7515fSKim, Milo struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); 502ade7515fSKim, Milo int id = pdev->id; 503ade7515fSKim, Milo struct lp8788_buck *buck; 504ade7515fSKim, Milo struct regulator_config cfg = { }; 505ade7515fSKim, Milo struct regulator_dev *rdev; 506ade7515fSKim, Milo int ret; 507ade7515fSKim, Milo 5083b0e8f12SKim, Milo buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL); 509ade7515fSKim, Milo if (!buck) 510ade7515fSKim, Milo return -ENOMEM; 511ade7515fSKim, Milo 512ade7515fSKim, Milo buck->lp = lp; 513ade7515fSKim, Milo 514*38d8f67cSKim, Milo ret = lp8788_init_dvs(pdev, buck, id); 515ade7515fSKim, Milo if (ret) 516ade7515fSKim, Milo return ret; 517ade7515fSKim, Milo 5183b0e8f12SKim, Milo cfg.dev = pdev->dev.parent; 519ade7515fSKim, Milo cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL; 520ade7515fSKim, Milo cfg.driver_data = buck; 521ade7515fSKim, Milo cfg.regmap = lp->regmap; 522ade7515fSKim, Milo 523ade7515fSKim, Milo rdev = regulator_register(&lp8788_buck_desc[id], &cfg); 524ade7515fSKim, Milo if (IS_ERR(rdev)) { 525ade7515fSKim, Milo ret = PTR_ERR(rdev); 5263b0e8f12SKim, Milo dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n", 527ade7515fSKim, Milo id + 1, ret); 528ade7515fSKim, Milo return ret; 529ade7515fSKim, Milo } 530ade7515fSKim, Milo 531ade7515fSKim, Milo buck->regulator = rdev; 532ade7515fSKim, Milo platform_set_drvdata(pdev, buck); 533ade7515fSKim, Milo 534ade7515fSKim, Milo return 0; 535ade7515fSKim, Milo } 536ade7515fSKim, Milo 5378dc995f5SBill Pemberton static int lp8788_buck_remove(struct platform_device *pdev) 538ade7515fSKim, Milo { 539ade7515fSKim, Milo struct lp8788_buck *buck = platform_get_drvdata(pdev); 540ade7515fSKim, Milo 541ade7515fSKim, Milo platform_set_drvdata(pdev, NULL); 542ade7515fSKim, Milo regulator_unregister(buck->regulator); 543ade7515fSKim, Milo 544ade7515fSKim, Milo return 0; 545ade7515fSKim, Milo } 546ade7515fSKim, Milo 547ade7515fSKim, Milo static struct platform_driver lp8788_buck_driver = { 548ade7515fSKim, Milo .probe = lp8788_buck_probe, 5495eb9f2b9SBill Pemberton .remove = lp8788_buck_remove, 550ade7515fSKim, Milo .driver = { 551ade7515fSKim, Milo .name = LP8788_DEV_BUCK, 552ade7515fSKim, Milo .owner = THIS_MODULE, 553ade7515fSKim, Milo }, 554ade7515fSKim, Milo }; 555ade7515fSKim, Milo 556ade7515fSKim, Milo static int __init lp8788_buck_init(void) 557ade7515fSKim, Milo { 558ade7515fSKim, Milo return platform_driver_register(&lp8788_buck_driver); 559ade7515fSKim, Milo } 560ade7515fSKim, Milo subsys_initcall(lp8788_buck_init); 561ade7515fSKim, Milo 562ade7515fSKim, Milo static void __exit lp8788_buck_exit(void) 563ade7515fSKim, Milo { 564ade7515fSKim, Milo platform_driver_unregister(&lp8788_buck_driver); 565ade7515fSKim, Milo } 566ade7515fSKim, Milo module_exit(lp8788_buck_exit); 567ade7515fSKim, Milo 568ade7515fSKim, Milo MODULE_DESCRIPTION("TI LP8788 BUCK Driver"); 569ade7515fSKim, Milo MODULE_AUTHOR("Milo Kim"); 570ade7515fSKim, Milo MODULE_LICENSE("GPL"); 571ade7515fSKim, Milo MODULE_ALIAS("platform:lp8788-buck"); 572