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 72ade7515fSKim, Milo enum lp8788_dvs_state { 73ade7515fSKim, Milo DVS_LOW = GPIOF_OUT_INIT_LOW, 74ade7515fSKim, Milo DVS_HIGH = GPIOF_OUT_INIT_HIGH, 75ade7515fSKim, Milo }; 76ade7515fSKim, Milo 77ade7515fSKim, Milo enum lp8788_dvs_mode { 78ade7515fSKim, Milo REGISTER, 79ade7515fSKim, Milo EXTPIN, 80ade7515fSKim, Milo }; 81ade7515fSKim, Milo 82ade7515fSKim, Milo enum lp8788_buck_id { 83ade7515fSKim, Milo BUCK1, 84ade7515fSKim, Milo BUCK2, 85ade7515fSKim, Milo BUCK3, 86ade7515fSKim, Milo BUCK4, 87ade7515fSKim, Milo }; 88ade7515fSKim, Milo 89ade7515fSKim, Milo struct lp8788_pwm_map { 90ade7515fSKim, Milo u8 mask; 91ade7515fSKim, Milo u8 shift; 92ade7515fSKim, Milo }; 93ade7515fSKim, Milo 94ade7515fSKim, Milo struct lp8788_buck { 95ade7515fSKim, Milo struct lp8788 *lp; 96ade7515fSKim, Milo struct regulator_dev *regulator; 97ade7515fSKim, Milo struct lp8788_pwm_map *pmap; 98ade7515fSKim, Milo void *dvs; 99ade7515fSKim, Milo }; 100ade7515fSKim, Milo 101ade7515fSKim, Milo /* BUCK 1 ~ 4 voltage table */ 102ade7515fSKim, Milo static const int lp8788_buck_vtbl[] = { 103ade7515fSKim, Milo 500000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 104ade7515fSKim, Milo 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 105ade7515fSKim, Milo 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 106ade7515fSKim, Milo 1950000, 2000000, 107ade7515fSKim, Milo }; 108ade7515fSKim, Milo 109ade7515fSKim, Milo /* buck pwm mode selection : used for set/get_mode in regulator ops 110ade7515fSKim, Milo * @forced pwm : fast mode 111ade7515fSKim, Milo * @auto pwm : normal mode 112ade7515fSKim, Milo */ 113ade7515fSKim, Milo static struct lp8788_pwm_map buck_pmap[] = { 114ade7515fSKim, Milo [BUCK1] = { 115ade7515fSKim, Milo .mask = LP8788_FPWM_BUCK1_M, 116ade7515fSKim, Milo .shift = LP8788_FPWM_BUCK1_S, 117ade7515fSKim, Milo }, 118ade7515fSKim, Milo [BUCK2] = { 119ade7515fSKim, Milo .mask = LP8788_FPWM_BUCK2_M, 120ade7515fSKim, Milo .shift = LP8788_FPWM_BUCK2_S, 121ade7515fSKim, Milo }, 122ade7515fSKim, Milo [BUCK3] = { 123ade7515fSKim, Milo .mask = LP8788_FPWM_BUCK3_M, 124ade7515fSKim, Milo .shift = LP8788_FPWM_BUCK3_S, 125ade7515fSKim, Milo }, 126ade7515fSKim, Milo [BUCK4] = { 127ade7515fSKim, Milo .mask = LP8788_FPWM_BUCK4_M, 128ade7515fSKim, Milo .shift = LP8788_FPWM_BUCK4_S, 129ade7515fSKim, Milo }, 130ade7515fSKim, Milo }; 131ade7515fSKim, Milo 132ade7515fSKim, Milo static const u8 buck1_vout_addr[] = { 133ade7515fSKim, Milo LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1, 134ade7515fSKim, Milo LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3, 135ade7515fSKim, Milo }; 136ade7515fSKim, Milo 137ade7515fSKim, Milo static const u8 buck2_vout_addr[] = { 138ade7515fSKim, Milo LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1, 139ade7515fSKim, Milo LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3, 140ade7515fSKim, Milo }; 141ade7515fSKim, Milo 142ade7515fSKim, Milo static void lp8788_buck1_set_dvs(struct lp8788_buck *buck) 143ade7515fSKim, Milo { 144ade7515fSKim, Milo struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs; 145ade7515fSKim, Milo enum lp8788_dvs_state pinstate; 146ade7515fSKim, Milo 147ade7515fSKim, Milo if (!dvs) 148ade7515fSKim, Milo return; 149ade7515fSKim, Milo 150ade7515fSKim, Milo pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH; 151ade7515fSKim, Milo if (gpio_is_valid(dvs->gpio)) 152ade7515fSKim, Milo gpio_set_value(dvs->gpio, pinstate); 153ade7515fSKim, Milo } 154ade7515fSKim, Milo 155ade7515fSKim, Milo static void lp8788_buck2_set_dvs(struct lp8788_buck *buck) 156ade7515fSKim, Milo { 157ade7515fSKim, Milo struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs; 158ade7515fSKim, Milo enum lp8788_dvs_state pin1, pin2; 159ade7515fSKim, Milo 160ade7515fSKim, Milo if (!dvs) 161ade7515fSKim, Milo return; 162ade7515fSKim, Milo 163ade7515fSKim, Milo switch (dvs->vsel) { 164ade7515fSKim, Milo case DVS_SEL_V0: 165ade7515fSKim, Milo pin1 = DVS_LOW; 166ade7515fSKim, Milo pin2 = DVS_LOW; 167ade7515fSKim, Milo break; 168ade7515fSKim, Milo case DVS_SEL_V1: 169ade7515fSKim, Milo pin1 = DVS_HIGH; 170ade7515fSKim, Milo pin2 = DVS_LOW; 171ade7515fSKim, Milo break; 172ade7515fSKim, Milo case DVS_SEL_V2: 173ade7515fSKim, Milo pin1 = DVS_LOW; 174ade7515fSKim, Milo pin2 = DVS_HIGH; 175ade7515fSKim, Milo break; 176ade7515fSKim, Milo case DVS_SEL_V3: 177ade7515fSKim, Milo pin1 = DVS_HIGH; 178ade7515fSKim, Milo pin2 = DVS_HIGH; 179ade7515fSKim, Milo break; 180ade7515fSKim, Milo default: 181ade7515fSKim, Milo return; 182ade7515fSKim, Milo } 183ade7515fSKim, Milo 184ade7515fSKim, Milo if (gpio_is_valid(dvs->gpio[0])) 185ade7515fSKim, Milo gpio_set_value(dvs->gpio[0], pin1); 186ade7515fSKim, Milo 187ade7515fSKim, Milo if (gpio_is_valid(dvs->gpio[1])) 188ade7515fSKim, Milo gpio_set_value(dvs->gpio[1], pin2); 189ade7515fSKim, Milo } 190ade7515fSKim, Milo 191ade7515fSKim, Milo static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) 192ade7515fSKim, Milo { 193ade7515fSKim, Milo switch (id) { 194ade7515fSKim, Milo case BUCK1: 195ade7515fSKim, Milo lp8788_buck1_set_dvs(buck); 196ade7515fSKim, Milo break; 197ade7515fSKim, Milo case BUCK2: 198ade7515fSKim, Milo lp8788_buck2_set_dvs(buck); 199ade7515fSKim, Milo break; 200ade7515fSKim, Milo default: 201ade7515fSKim, Milo break; 202ade7515fSKim, Milo } 203ade7515fSKim, Milo } 204ade7515fSKim, Milo 205ade7515fSKim, Milo static enum lp8788_dvs_mode 206ade7515fSKim, Milo lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id) 207ade7515fSKim, Milo { 208ade7515fSKim, Milo u8 val, mask; 209ade7515fSKim, Milo 210ade7515fSKim, Milo switch (id) { 211ade7515fSKim, Milo case BUCK1: 212ade7515fSKim, Milo mask = LP8788_BUCK1_DVS_SEL_M; 213ade7515fSKim, Milo break; 214ade7515fSKim, Milo case BUCK2: 215ade7515fSKim, Milo mask = LP8788_BUCK2_DVS_SEL_M; 216ade7515fSKim, Milo break; 217ade7515fSKim, Milo default: 218ade7515fSKim, Milo return REGISTER; 219ade7515fSKim, Milo } 220ade7515fSKim, Milo 221ade7515fSKim, Milo lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); 222ade7515fSKim, Milo 223ade7515fSKim, Milo return val & mask ? REGISTER : EXTPIN; 224ade7515fSKim, Milo } 225ade7515fSKim, Milo 226ade7515fSKim, Milo static bool lp8788_is_valid_buck_addr(u8 addr) 227ade7515fSKim, Milo { 228ade7515fSKim, Milo switch (addr) { 229ade7515fSKim, Milo case LP8788_BUCK1_VOUT0: 230ade7515fSKim, Milo case LP8788_BUCK1_VOUT1: 231ade7515fSKim, Milo case LP8788_BUCK1_VOUT2: 232ade7515fSKim, Milo case LP8788_BUCK1_VOUT3: 233ade7515fSKim, Milo case LP8788_BUCK2_VOUT0: 234ade7515fSKim, Milo case LP8788_BUCK2_VOUT1: 235ade7515fSKim, Milo case LP8788_BUCK2_VOUT2: 236ade7515fSKim, Milo case LP8788_BUCK2_VOUT3: 237ade7515fSKim, Milo return true; 238ade7515fSKim, Milo default: 239ade7515fSKim, Milo return false; 240ade7515fSKim, Milo } 241ade7515fSKim, Milo } 242ade7515fSKim, Milo 243ade7515fSKim, Milo static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck, 244ade7515fSKim, Milo enum lp8788_buck_id id) 245ade7515fSKim, Milo { 246ade7515fSKim, Milo enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id); 247ade7515fSKim, Milo struct lp8788_buck1_dvs *b1_dvs; 248ade7515fSKim, Milo struct lp8788_buck2_dvs *b2_dvs; 249ade7515fSKim, Milo u8 val, idx, addr; 250ade7515fSKim, Milo int pin1, pin2; 251ade7515fSKim, Milo 252ade7515fSKim, Milo switch (id) { 253ade7515fSKim, Milo case BUCK1: 254ade7515fSKim, Milo if (mode == EXTPIN) { 255ade7515fSKim, Milo b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs; 256ade7515fSKim, Milo if (!b1_dvs) 257ade7515fSKim, Milo goto err; 258ade7515fSKim, Milo 259ade7515fSKim, Milo idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0; 260ade7515fSKim, Milo } else { 261ade7515fSKim, Milo lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); 262ade7515fSKim, Milo idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S; 263ade7515fSKim, Milo } 264ade7515fSKim, Milo addr = buck1_vout_addr[idx]; 265ade7515fSKim, Milo break; 266ade7515fSKim, Milo case BUCK2: 267ade7515fSKim, Milo if (mode == EXTPIN) { 268ade7515fSKim, Milo b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs; 269ade7515fSKim, Milo if (!b2_dvs) 270ade7515fSKim, Milo goto err; 271ade7515fSKim, Milo 272ade7515fSKim, Milo pin1 = gpio_get_value(b2_dvs->gpio[0]); 273ade7515fSKim, Milo pin2 = gpio_get_value(b2_dvs->gpio[1]); 274ade7515fSKim, Milo 275ade7515fSKim, Milo if (pin1 == PIN_LOW && pin2 == PIN_LOW) 276ade7515fSKim, Milo idx = 0; 277ade7515fSKim, Milo else if (pin1 == PIN_LOW && pin2 == PIN_HIGH) 278ade7515fSKim, Milo idx = 2; 279ade7515fSKim, Milo else if (pin1 == PIN_HIGH && pin2 == PIN_LOW) 280ade7515fSKim, Milo idx = 1; 281ade7515fSKim, Milo else 282ade7515fSKim, Milo idx = 3; 283ade7515fSKim, Milo } else { 284ade7515fSKim, Milo lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); 285ade7515fSKim, Milo idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S; 286ade7515fSKim, Milo } 287ade7515fSKim, Milo addr = buck2_vout_addr[idx]; 288ade7515fSKim, Milo break; 289ade7515fSKim, Milo default: 290ade7515fSKim, Milo goto err; 291ade7515fSKim, Milo } 292ade7515fSKim, Milo 293ade7515fSKim, Milo return addr; 294ade7515fSKim, Milo err: 295ade7515fSKim, Milo return INVALID_ADDR; 296ade7515fSKim, Milo } 297ade7515fSKim, Milo 298ade7515fSKim, Milo static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev, 299ade7515fSKim, Milo unsigned selector) 300ade7515fSKim, Milo { 301ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 302ade7515fSKim, Milo enum lp8788_buck_id id = rdev_get_id(rdev); 303ade7515fSKim, Milo u8 addr; 304ade7515fSKim, Milo 305ade7515fSKim, Milo if (buck->dvs) 306ade7515fSKim, Milo lp8788_set_dvs(buck, id); 307ade7515fSKim, Milo 308ade7515fSKim, Milo addr = lp8788_select_buck_vout_addr(buck, id); 309ade7515fSKim, Milo if (!lp8788_is_valid_buck_addr(addr)) 310ade7515fSKim, Milo return -EINVAL; 311ade7515fSKim, Milo 312ade7515fSKim, Milo return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector); 313ade7515fSKim, Milo } 314ade7515fSKim, Milo 315ade7515fSKim, Milo static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev) 316ade7515fSKim, Milo { 317ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 318ade7515fSKim, Milo enum lp8788_buck_id id = rdev_get_id(rdev); 319ade7515fSKim, Milo int ret; 320ade7515fSKim, Milo u8 val, addr; 321ade7515fSKim, Milo 322ade7515fSKim, Milo addr = lp8788_select_buck_vout_addr(buck, id); 323ade7515fSKim, Milo if (!lp8788_is_valid_buck_addr(addr)) 324ade7515fSKim, Milo return -EINVAL; 325ade7515fSKim, Milo 326ade7515fSKim, Milo ret = lp8788_read_byte(buck->lp, addr, &val); 327ade7515fSKim, Milo if (ret) 328ade7515fSKim, Milo return ret; 329ade7515fSKim, Milo 330ade7515fSKim, Milo return val & LP8788_VOUT_M; 331ade7515fSKim, Milo } 332ade7515fSKim, Milo 333ade7515fSKim, Milo static int lp8788_buck_enable_time(struct regulator_dev *rdev) 334ade7515fSKim, Milo { 335ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 336ade7515fSKim, Milo enum lp8788_buck_id id = rdev_get_id(rdev); 337ade7515fSKim, Milo u8 val, addr = LP8788_BUCK1_TIMESTEP + id; 338ade7515fSKim, Milo 339ade7515fSKim, Milo if (lp8788_read_byte(buck->lp, addr, &val)) 340ade7515fSKim, Milo return -EINVAL; 341ade7515fSKim, Milo 342ade7515fSKim, Milo val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S; 343ade7515fSKim, Milo 344ade7515fSKim, Milo return ENABLE_TIME_USEC * val; 345ade7515fSKim, Milo } 346ade7515fSKim, Milo 347ade7515fSKim, Milo static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) 348ade7515fSKim, Milo { 349ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 350ade7515fSKim, Milo struct lp8788_pwm_map *pmap = buck->pmap; 351ade7515fSKim, Milo u8 val; 352ade7515fSKim, Milo 353ade7515fSKim, Milo if (!pmap) 354ade7515fSKim, Milo return -EINVAL; 355ade7515fSKim, Milo 356ade7515fSKim, Milo switch (mode) { 357ade7515fSKim, Milo case REGULATOR_MODE_FAST: 358ade7515fSKim, Milo val = LP8788_FORCE_PWM << pmap->shift; 359ade7515fSKim, Milo break; 360ade7515fSKim, Milo case REGULATOR_MODE_NORMAL: 361ade7515fSKim, Milo val = LP8788_AUTO_PWM << pmap->shift; 362ade7515fSKim, Milo break; 363ade7515fSKim, Milo default: 364ade7515fSKim, Milo return -EINVAL; 365ade7515fSKim, Milo } 366ade7515fSKim, Milo 367ade7515fSKim, Milo return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, pmap->mask, val); 368ade7515fSKim, Milo } 369ade7515fSKim, Milo 370ade7515fSKim, Milo static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev) 371ade7515fSKim, Milo { 372ade7515fSKim, Milo struct lp8788_buck *buck = rdev_get_drvdata(rdev); 373ade7515fSKim, Milo struct lp8788_pwm_map *pmap = buck->pmap; 374ade7515fSKim, Milo u8 val; 375ade7515fSKim, Milo int ret; 376ade7515fSKim, Milo 377ade7515fSKim, Milo if (!pmap) 378ade7515fSKim, Milo return -EINVAL; 379ade7515fSKim, Milo 380ade7515fSKim, Milo ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val); 381ade7515fSKim, Milo if (ret) 382ade7515fSKim, Milo return ret; 383ade7515fSKim, Milo 384ade7515fSKim, Milo return val & pmap->mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; 385ade7515fSKim, Milo } 386ade7515fSKim, Milo 387ade7515fSKim, Milo static struct regulator_ops lp8788_buck12_ops = { 388ade7515fSKim, Milo .list_voltage = regulator_list_voltage_table, 389ade7515fSKim, Milo .set_voltage_sel = lp8788_buck12_set_voltage_sel, 390ade7515fSKim, Milo .get_voltage_sel = lp8788_buck12_get_voltage_sel, 391ade7515fSKim, Milo .enable = regulator_enable_regmap, 392ade7515fSKim, Milo .disable = regulator_disable_regmap, 393ade7515fSKim, Milo .is_enabled = regulator_is_enabled_regmap, 394ade7515fSKim, Milo .enable_time = lp8788_buck_enable_time, 395ade7515fSKim, Milo .set_mode = lp8788_buck_set_mode, 396ade7515fSKim, Milo .get_mode = lp8788_buck_get_mode, 397ade7515fSKim, Milo }; 398ade7515fSKim, Milo 399ade7515fSKim, Milo static struct regulator_ops lp8788_buck34_ops = { 400ade7515fSKim, Milo .list_voltage = regulator_list_voltage_table, 401ade7515fSKim, Milo .set_voltage_sel = regulator_set_voltage_sel_regmap, 402ade7515fSKim, Milo .get_voltage_sel = regulator_get_voltage_sel_regmap, 403ade7515fSKim, Milo .enable = regulator_enable_regmap, 404ade7515fSKim, Milo .disable = regulator_disable_regmap, 405ade7515fSKim, Milo .is_enabled = regulator_is_enabled_regmap, 406ade7515fSKim, Milo .enable_time = lp8788_buck_enable_time, 407ade7515fSKim, Milo .set_mode = lp8788_buck_set_mode, 408ade7515fSKim, Milo .get_mode = lp8788_buck_get_mode, 409ade7515fSKim, Milo }; 410ade7515fSKim, Milo 411ade7515fSKim, Milo static struct regulator_desc lp8788_buck_desc[] = { 412ade7515fSKim, Milo { 413ade7515fSKim, Milo .name = "buck1", 414ade7515fSKim, Milo .id = BUCK1, 415ade7515fSKim, Milo .ops = &lp8788_buck12_ops, 416ade7515fSKim, Milo .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), 417ade7515fSKim, Milo .volt_table = lp8788_buck_vtbl, 418ade7515fSKim, Milo .type = REGULATOR_VOLTAGE, 419ade7515fSKim, Milo .owner = THIS_MODULE, 420ade7515fSKim, Milo .enable_reg = LP8788_EN_BUCK, 421ade7515fSKim, Milo .enable_mask = LP8788_EN_BUCK1_M, 422ade7515fSKim, Milo }, 423ade7515fSKim, Milo { 424ade7515fSKim, Milo .name = "buck2", 425ade7515fSKim, Milo .id = BUCK2, 426ade7515fSKim, Milo .ops = &lp8788_buck12_ops, 427ade7515fSKim, Milo .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), 428ade7515fSKim, Milo .volt_table = lp8788_buck_vtbl, 429ade7515fSKim, Milo .type = REGULATOR_VOLTAGE, 430ade7515fSKim, Milo .owner = THIS_MODULE, 431ade7515fSKim, Milo .enable_reg = LP8788_EN_BUCK, 432ade7515fSKim, Milo .enable_mask = LP8788_EN_BUCK2_M, 433ade7515fSKim, Milo }, 434ade7515fSKim, Milo { 435ade7515fSKim, Milo .name = "buck3", 436ade7515fSKim, Milo .id = BUCK3, 437ade7515fSKim, Milo .ops = &lp8788_buck34_ops, 438ade7515fSKim, Milo .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), 439ade7515fSKim, Milo .volt_table = lp8788_buck_vtbl, 440ade7515fSKim, Milo .type = REGULATOR_VOLTAGE, 441ade7515fSKim, Milo .owner = THIS_MODULE, 442ade7515fSKim, Milo .vsel_reg = LP8788_BUCK3_VOUT, 443ade7515fSKim, Milo .vsel_mask = LP8788_VOUT_M, 444ade7515fSKim, Milo .enable_reg = LP8788_EN_BUCK, 445ade7515fSKim, Milo .enable_mask = LP8788_EN_BUCK3_M, 446ade7515fSKim, Milo }, 447ade7515fSKim, Milo { 448ade7515fSKim, Milo .name = "buck4", 449ade7515fSKim, Milo .id = BUCK4, 450ade7515fSKim, Milo .ops = &lp8788_buck34_ops, 451ade7515fSKim, Milo .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), 452ade7515fSKim, Milo .volt_table = lp8788_buck_vtbl, 453ade7515fSKim, Milo .type = REGULATOR_VOLTAGE, 454ade7515fSKim, Milo .owner = THIS_MODULE, 455ade7515fSKim, Milo .vsel_reg = LP8788_BUCK4_VOUT, 456ade7515fSKim, Milo .vsel_mask = LP8788_VOUT_M, 457ade7515fSKim, Milo .enable_reg = LP8788_EN_BUCK, 458ade7515fSKim, Milo .enable_mask = LP8788_EN_BUCK4_M, 459ade7515fSKim, Milo }, 460ade7515fSKim, Milo }; 461ade7515fSKim, Milo 462ade7515fSKim, Milo static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name) 463ade7515fSKim, Milo { 464ade7515fSKim, Milo struct device *dev = buck->lp->dev; 465ade7515fSKim, Milo 466ade7515fSKim, Milo if (!gpio_is_valid(gpio)) { 467ade7515fSKim, Milo dev_err(dev, "invalid gpio: %d\n", gpio); 468ade7515fSKim, Milo return -EINVAL; 469ade7515fSKim, Milo } 470ade7515fSKim, Milo 471ade7515fSKim, Milo return devm_gpio_request_one(dev, gpio, DVS_LOW, name); 472ade7515fSKim, Milo } 473ade7515fSKim, Milo 474ade7515fSKim, Milo static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, 475ade7515fSKim, Milo enum lp8788_buck_id id) 476ade7515fSKim, Milo { 477ade7515fSKim, Milo struct lp8788_platform_data *pdata = buck->lp->pdata; 478ade7515fSKim, Milo char *b1_name = "LP8788_B1_DVS"; 479ade7515fSKim, Milo char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" }; 480ade7515fSKim, Milo int i, gpio, ret; 481ade7515fSKim, Milo 482ade7515fSKim, Milo switch (id) { 483ade7515fSKim, Milo case BUCK1: 484ade7515fSKim, Milo gpio = pdata->buck1_dvs->gpio; 485ade7515fSKim, Milo ret = _gpio_request(buck, gpio, b1_name); 486ade7515fSKim, Milo if (ret) 487ade7515fSKim, Milo return ret; 488ade7515fSKim, Milo 489ade7515fSKim, Milo buck->dvs = pdata->buck1_dvs; 490ade7515fSKim, Milo break; 491ade7515fSKim, Milo case BUCK2: 492ade7515fSKim, Milo for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) { 493ade7515fSKim, Milo gpio = pdata->buck2_dvs->gpio[i]; 494ade7515fSKim, Milo ret = _gpio_request(buck, gpio, b2_name[i]); 495ade7515fSKim, Milo if (ret) 496ade7515fSKim, Milo return ret; 497ade7515fSKim, Milo } 498ade7515fSKim, Milo buck->dvs = pdata->buck2_dvs; 499ade7515fSKim, Milo break; 500ade7515fSKim, Milo default: 501ade7515fSKim, Milo break; 502ade7515fSKim, Milo } 503ade7515fSKim, Milo 504ade7515fSKim, Milo return 0; 505ade7515fSKim, Milo } 506ade7515fSKim, Milo 507ade7515fSKim, Milo static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) 508ade7515fSKim, Milo { 509ade7515fSKim, Milo struct lp8788_platform_data *pdata = buck->lp->pdata; 510ade7515fSKim, Milo u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M }; 511ade7515fSKim, Milo u8 val[] = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN }; 512*c42ea5cdSAxel Lin u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C }; 513ade7515fSKim, Milo 514ade7515fSKim, Milo /* no dvs for buck3, 4 */ 515ade7515fSKim, Milo if (id == BUCK3 || id == BUCK4) 516ade7515fSKim, Milo return 0; 517ade7515fSKim, Milo 518ade7515fSKim, Milo /* no dvs platform data, then dvs will be selected by I2C registers */ 519ade7515fSKim, Milo if (!pdata) 520ade7515fSKim, Milo goto set_default_dvs_mode; 521ade7515fSKim, Milo 522ade7515fSKim, Milo if ((id == BUCK1 && !pdata->buck1_dvs) || 523ade7515fSKim, Milo (id == BUCK2 && !pdata->buck2_dvs)) 524ade7515fSKim, Milo goto set_default_dvs_mode; 525ade7515fSKim, Milo 526ade7515fSKim, Milo if (lp8788_dvs_gpio_request(buck, id)) 527ade7515fSKim, Milo goto set_default_dvs_mode; 528ade7515fSKim, Milo 529ade7515fSKim, Milo return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id], 530ade7515fSKim, Milo val[id]); 531ade7515fSKim, Milo 532ade7515fSKim, Milo set_default_dvs_mode: 533*c42ea5cdSAxel Lin return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id], 534*c42ea5cdSAxel Lin default_dvs_mode[id]); 535ade7515fSKim, Milo } 536ade7515fSKim, Milo 537ade7515fSKim, Milo static __devinit int lp8788_buck_probe(struct platform_device *pdev) 538ade7515fSKim, Milo { 539ade7515fSKim, Milo struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); 540ade7515fSKim, Milo int id = pdev->id; 541ade7515fSKim, Milo struct lp8788_buck *buck; 542ade7515fSKim, Milo struct regulator_config cfg = { }; 543ade7515fSKim, Milo struct regulator_dev *rdev; 544ade7515fSKim, Milo int ret; 545ade7515fSKim, Milo 546ade7515fSKim, Milo buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL); 547ade7515fSKim, Milo if (!buck) 548ade7515fSKim, Milo return -ENOMEM; 549ade7515fSKim, Milo 550ade7515fSKim, Milo buck->lp = lp; 551ade7515fSKim, Milo buck->pmap = &buck_pmap[id]; 552ade7515fSKim, Milo 553ade7515fSKim, Milo ret = lp8788_init_dvs(buck, id); 554ade7515fSKim, Milo if (ret) 555ade7515fSKim, Milo return ret; 556ade7515fSKim, Milo 557ade7515fSKim, Milo cfg.dev = lp->dev; 558ade7515fSKim, Milo cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL; 559ade7515fSKim, Milo cfg.driver_data = buck; 560ade7515fSKim, Milo cfg.regmap = lp->regmap; 561ade7515fSKim, Milo 562ade7515fSKim, Milo rdev = regulator_register(&lp8788_buck_desc[id], &cfg); 563ade7515fSKim, Milo if (IS_ERR(rdev)) { 564ade7515fSKim, Milo ret = PTR_ERR(rdev); 565ade7515fSKim, Milo dev_err(lp->dev, "BUCK%d regulator register err = %d\n", 566ade7515fSKim, Milo id + 1, ret); 567ade7515fSKim, Milo return ret; 568ade7515fSKim, Milo } 569ade7515fSKim, Milo 570ade7515fSKim, Milo buck->regulator = rdev; 571ade7515fSKim, Milo platform_set_drvdata(pdev, buck); 572ade7515fSKim, Milo 573ade7515fSKim, Milo return 0; 574ade7515fSKim, Milo } 575ade7515fSKim, Milo 576ade7515fSKim, Milo static int __devexit lp8788_buck_remove(struct platform_device *pdev) 577ade7515fSKim, Milo { 578ade7515fSKim, Milo struct lp8788_buck *buck = platform_get_drvdata(pdev); 579ade7515fSKim, Milo 580ade7515fSKim, Milo platform_set_drvdata(pdev, NULL); 581ade7515fSKim, Milo regulator_unregister(buck->regulator); 582ade7515fSKim, Milo 583ade7515fSKim, Milo return 0; 584ade7515fSKim, Milo } 585ade7515fSKim, Milo 586ade7515fSKim, Milo static struct platform_driver lp8788_buck_driver = { 587ade7515fSKim, Milo .probe = lp8788_buck_probe, 588ade7515fSKim, Milo .remove = __devexit_p(lp8788_buck_remove), 589ade7515fSKim, Milo .driver = { 590ade7515fSKim, Milo .name = LP8788_DEV_BUCK, 591ade7515fSKim, Milo .owner = THIS_MODULE, 592ade7515fSKim, Milo }, 593ade7515fSKim, Milo }; 594ade7515fSKim, Milo 595ade7515fSKim, Milo static int __init lp8788_buck_init(void) 596ade7515fSKim, Milo { 597ade7515fSKim, Milo return platform_driver_register(&lp8788_buck_driver); 598ade7515fSKim, Milo } 599ade7515fSKim, Milo subsys_initcall(lp8788_buck_init); 600ade7515fSKim, Milo 601ade7515fSKim, Milo static void __exit lp8788_buck_exit(void) 602ade7515fSKim, Milo { 603ade7515fSKim, Milo platform_driver_unregister(&lp8788_buck_driver); 604ade7515fSKim, Milo } 605ade7515fSKim, Milo module_exit(lp8788_buck_exit); 606ade7515fSKim, Milo 607ade7515fSKim, Milo MODULE_DESCRIPTION("TI LP8788 BUCK Driver"); 608ade7515fSKim, Milo MODULE_AUTHOR("Milo Kim"); 609ade7515fSKim, Milo MODULE_LICENSE("GPL"); 610ade7515fSKim, Milo MODULE_ALIAS("platform:lp8788-buck"); 611