/* * as3720-regulator.c - voltage regulator support for AS3720 * * Copyright (C) 2012 ams * * Author: Bernhard Breinbauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include struct as3720_register_mapping { u8 reg_id; u8 reg_vsel; u32 reg_enable; u8 enable_bit; }; struct as3720_register_mapping as3720_reg_lookup[] = { { .reg_id = AS3720_LDO0, .reg_vsel = AS3720_LDO0_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL0_REG, .enable_bit = AS3720_LDO0_ON, }, { .reg_id = AS3720_LDO1, .reg_vsel = AS3720_LDO1_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL0_REG, .enable_bit = AS3720_LDO1_ON, }, { .reg_id = AS3720_LDO2, .reg_vsel = AS3720_LDO2_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL0_REG, .enable_bit = AS3720_LDO2_ON, }, { .reg_id = AS3720_LDO3, .reg_vsel = AS3720_LDO3_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL0_REG, .enable_bit = AS3720_LDO3_ON, }, { .reg_id = AS3720_LDO4, .reg_vsel = AS3720_LDO4_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL0_REG, .enable_bit = AS3720_LDO4_ON, }, { .reg_id = AS3720_LDO5, .reg_vsel = AS3720_LDO5_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL0_REG, .enable_bit = AS3720_LDO5_ON, }, { .reg_id = AS3720_LDO6, .reg_vsel = AS3720_LDO6_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL0_REG, .enable_bit = AS3720_LDO6_ON, }, { .reg_id = AS3720_LDO7, .reg_vsel = AS3720_LDO7_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL0_REG, .enable_bit = AS3720_LDO7_ON, }, { .reg_id = AS3720_LDO8, .reg_vsel = AS3720_LDO8_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL1_REG, .enable_bit = AS3720_LDO8_ON, }, { .reg_id = AS3720_LDO9, .reg_vsel = AS3720_LDO9_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL1_REG, .enable_bit = AS3720_LDO9_ON, }, { .reg_id = AS3720_LDO10, .reg_vsel = AS3720_LDO10_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL1_REG, .enable_bit = AS3720_LDO10_ON, }, { .reg_id = AS3720_LDO11, .reg_vsel = AS3720_LDO11_VOLTAGE_REG, .reg_enable = AS3720_LDOCONTROL1_REG, .enable_bit = AS3720_LDO11_ON, }, { .reg_id = AS3720_SD0, .reg_vsel = AS3720_SD0_VOLTAGE_REG, .reg_enable = AS3720_SD_CONTROL_REG, .enable_bit = AS3720_SD0_ON, }, { .reg_id = AS3720_SD1, .reg_vsel = AS3720_SD1_VOLTAGE_REG, .reg_enable = AS3720_SD_CONTROL_REG, .enable_bit = AS3720_SD1_ON, }, { .reg_id = AS3720_SD2, .reg_vsel = AS3720_SD2_VOLTAGE_REG, .reg_enable = AS3720_SD_CONTROL_REG, .enable_bit = AS3720_SD2_ON, }, { .reg_id = AS3720_SD3, .reg_vsel = AS3720_SD3_VOLTAGE_REG, .reg_enable = AS3720_SD_CONTROL_REG, .enable_bit = AS3720_SD3_ON, }, { .reg_id = AS3720_SD4, .reg_vsel = AS3720_SD4_VOLTAGE_REG, .reg_enable = AS3720_SD_CONTROL_REG, .enable_bit = AS3720_SD4_ON, }, { .reg_id = AS3720_SD5, .reg_vsel = AS3720_SD5_VOLTAGE_REG, .reg_enable = AS3720_SD_CONTROL_REG, .enable_bit = AS3720_SD5_ON, }, { .reg_id = AS3720_SD6, .reg_vsel = AS3720_SD6_VOLTAGE_REG, .reg_enable = AS3720_SD_CONTROL_REG, .enable_bit = AS3720_SD6_ON, }, }; /* * as3720 ldo0 extended input range (0.825-1.25V) */ static int as3720_ldo0_is_enabled(struct regulator_dev *dev) { u32 val; struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, AS3720_LDOCONTROL0_REG, &val); return (val & AS3720_LDO0_CTRL_MASK) != 0; } static int as3720_ldo0_enable(struct regulator_dev *dev) { struct as3720 *as3720 = rdev_get_drvdata(dev); return as3720_set_bits(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_enable, AS3720_LDO0_CTRL_MASK, AS3720_LDO0_ON); } static int as3720_ldo0_disable(struct regulator_dev *dev) { struct as3720 *as3720 = rdev_get_drvdata(dev); return as3720_set_bits(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_enable, AS3720_LDO0_CTRL_MASK, 0); } static int as3720_ldo0_list_voltage(struct regulator_dev *dev, unsigned selector) { if (selector >= AS3720_LDO0_VSEL_MAX) return -EINVAL; return 800000 + (selector + 1) * 25000; } static int as3720_ldo0_get_voltage(struct regulator_dev *dev) { u32 val; struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_vsel, &val); val &= AS3720_LDO_VSEL_MASK; if (val > 0) val--; /* ldo vsel has min value of 1, selector starts at 0 */ return as3720_ldo0_list_voltage(dev, val); } static int as3720_ldo0_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV) { u8 reg_val; int val; struct as3720 *as3720 = rdev_get_drvdata(dev); if (min_uV > 1250000 || max_uV < 825000) return -EINVAL; /* 25mV steps from 0.825V-1.25V */ val = (min_uV - 800001) / 25000 + 1; if (val < 1) val = 1; reg_val = (u8) val; if (reg_val * 25000 + 800000 > max_uV) return -EINVAL; BUG_ON(reg_val * 25000 + 800000 < min_uV); BUG_ON(reg_val > AS3720_LDO0_VSEL_MAX); return as3720_set_bits(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_vsel, AS3720_LDO_VSEL_MASK, reg_val); } static int as3720_ldo0_get_current_limit(struct regulator_dev *dev) { u32 val; struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_vsel, &val); val &= AS3720_LDO_ILIMIT_MASK; /* return ldo specific values */ if (val) return 300000; return 150000; } static int as3720_ldo0_set_current_limit(struct regulator_dev *dev, int min_uA, int max_uA) { u8 val; struct as3720 *as3720 = rdev_get_drvdata(dev); /* we check the values in case the constraints are wrong */ if (min_uA <= 150000 && max_uA >= 150000) val = 0; else if (min_uA > 150000 && max_uA >= 300000) val = AS3720_LDO_ILIMIT_BIT; else return -EINVAL; return as3720_set_bits(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_vsel, AS3720_LDO_ILIMIT_MASK, val); } static struct regulator_ops as3720_ldo0_ops = { .is_enabled = as3720_ldo0_is_enabled, .enable = as3720_ldo0_enable, .disable = as3720_ldo0_disable, .list_voltage = as3720_ldo0_list_voltage, .get_voltage = as3720_ldo0_get_voltage, .set_voltage = as3720_ldo0_set_voltage, .get_current_limit = as3720_ldo0_get_current_limit, .set_current_limit = as3720_ldo0_set_current_limit, }; /* * as3720 ldo3 low output range (0.61V-1.5V) */ static int as3720_ldo3_is_enabled(struct regulator_dev *dev) { u32 val = 0; struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_enable, &val); return (val & AS3720_LDO3_CTRL_MASK) != 0; } static int as3720_ldo3_enable(struct regulator_dev *dev) { struct as3720 *as3720 = rdev_get_drvdata(dev); return as3720_set_bits(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_enable, AS3720_LDO3_CTRL_MASK, AS3720_LDO3_ON); } static int as3720_ldo3_disable(struct regulator_dev *dev) { struct as3720 *as3720 = rdev_get_drvdata(dev); return as3720_set_bits(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_enable, AS3720_LDO3_CTRL_MASK, 0); } static int as3720_ldo3_list_voltage(struct regulator_dev *dev, unsigned selector) { if (selector >= AS3720_LDO3_VSEL_MAX) return -EINVAL; return 600000 + (selector + 1) * 10000; } static int as3720_ldo3_get_voltage(struct regulator_dev *dev) { u32 val; struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_vsel, &val); val &= AS3720_LDO3_VSEL_MASK; if (val > 0) val--; /* ldo vsel has min value 1, selector starts at 0 */ return as3720_ldo3_list_voltage(dev, val); } static int as3720_ldo3_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV) { u8 reg_val; int val; struct as3720 *as3720 = rdev_get_drvdata(dev); if (min_uV > 1800000 || max_uV < 610000) return -EINVAL; /* 10mV steps from 0.61V to 1.8V */ val = (min_uV - 600001) / 10000 + 1; if (val < 1) val = 1; reg_val = (u8) val; if (reg_val * 10000 + 600000 > max_uV) return -EINVAL; BUG_ON(reg_val * 10000 + 600000 < min_uV); BUG_ON(reg_val > AS3720_LDO3_VSEL_MAX); return as3720_set_bits(as3720, as3720_reg_lookup[rdev_get_id(dev)].reg_vsel, AS3720_LDO3_VSEL_MASK, reg_val); } static int as3720_ldo3_get_current_limit(struct regulator_dev *dev) { return 150000; } static struct regulator_ops as3720_ldo3_ops = { .is_enabled = as3720_ldo3_is_enabled, .enable = as3720_ldo3_enable, .disable = as3720_ldo3_disable, .list_voltage = as3720_ldo3_list_voltage, .get_voltage = as3720_ldo3_get_voltage, .set_voltage = as3720_ldo3_set_voltage, .get_current_limit = as3720_ldo3_get_current_limit, }; /* * as3720 ldo 1-2 and 4-11 (0.8V-3.3V) */ static int as3720_ldo_is_enabled(struct regulator_dev *dev) { u32 val = 0; int id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, as3720_reg_lookup[id].reg_enable, &val); return (val & as3720_reg_lookup[id].enable_bit) != 0; } static int as3720_ldo_enable(struct regulator_dev *dev) { int id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); return as3720_set_bits(as3720, as3720_reg_lookup[id].reg_enable, as3720_reg_lookup[id].enable_bit, as3720_reg_lookup[id].enable_bit); } static int as3720_ldo_disable(struct regulator_dev *dev) { int id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); return as3720_set_bits(as3720, as3720_reg_lookup[id].reg_enable, as3720_reg_lookup[id].enable_bit, 0); } static int as3720_ldo_list_voltage(struct regulator_dev *dev, unsigned selector) { if (selector >= AS3720_LDO_NUM_VOLT) return -EINVAL; selector++; /* ldo vsel min value is 1, selector starts at 0. */ return 800000 + selector * 25000; } static int as3720_ldo_get_voltage(struct regulator_dev *dev) { u32 val; int id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, as3720_reg_lookup[id].reg_vsel, &val); val &= AS3720_LDO_VSEL_MASK; /* ldo vsel has a gap from 0x25 to 0x3F (27 values). */ if (val > AS3720_LDO_VSEL_DNU_MAX) val -= 27; /* ldo vsel min value is 1, selector starts at 0. */ if (val > 0) val--; return as3720_ldo_list_voltage(dev, val); } static int as3720_ldo_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV) { u8 reg_val; int val; int id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); if (min_uV > 3300000 || max_uV < 825000) return -EINVAL; if (min_uV <= 1700000) { /* 25mV steps from 0.825V to 1.7V */ val = (min_uV - 800001) / 25000 + 1; if (val < 1) val = 1; reg_val = (u8) val; if (reg_val * 25000 + 800000 > max_uV) return -EINVAL; BUG_ON(reg_val * 25000 + 800000 < min_uV); } else { /* 25mV steps from 1.725V to 3.3V */ reg_val = (min_uV - 1700001) / 25000 + 0x40; if ((reg_val - 0x40) * 25000 + 1725000 > max_uV) return -EINVAL; BUG_ON((reg_val - 0x40) * 25000 + 1725000 < min_uV); } BUG_ON(reg_val > AS3720_LDO_VSEL_MAX); return as3720_set_bits(as3720, as3720_reg_lookup[id].reg_vsel, AS3720_LDO_VSEL_MASK, reg_val); } static int as3720_ldo_get_current_limit(struct regulator_dev *dev) { u32 val; int id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, as3720_reg_lookup[id].reg_vsel, &val); val &= AS3720_LDO_ILIMIT_MASK; /* return ldo specific values */ if (val) return 300000; /* ldo2,4,5 have 150mA and ldo6-11 have 160mA current limit */ if (id > AS3720_LDO5) return 160000; return 150000; } static int as3720_ldo_set_current_limit(struct regulator_dev *dev, int min_uA, int max_uA) { u8 val; int loweruA = 150000; int id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); /* ldo6-11 have 160mA current limit */ if (id > AS3720_LDO5) loweruA = 160000; /* we check the values in case the constraints are wrong */ if (min_uA <= loweruA && max_uA >= loweruA) val = 0; else if (min_uA > loweruA && max_uA >= 300000) val = AS3720_LDO_ILIMIT_BIT; else return -EINVAL; return as3720_set_bits(as3720, as3720_reg_lookup[id].reg_vsel, AS3720_LDO_ILIMIT_MASK, val); } static struct regulator_ops as3720_ldo_ops = { .is_enabled = as3720_ldo_is_enabled, .enable = as3720_ldo_enable, .disable = as3720_ldo_disable, .list_voltage = as3720_ldo_list_voltage, .get_voltage = as3720_ldo_get_voltage, .set_voltage = as3720_ldo_set_voltage, .get_current_limit = as3720_ldo_get_current_limit, .set_current_limit = as3720_ldo_set_current_limit, }; /* * as3720 step down */ static int as3720_sd_is_enabled(struct regulator_dev *dev) { u32 val; u8 id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, as3720_reg_lookup[id].reg_enable, &val); return (val & as3720_reg_lookup[id].enable_bit) != 0; } static int as3720_sd_enable(struct regulator_dev *dev) { u8 id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); return as3720_set_bits(as3720, as3720_reg_lookup[id].reg_enable, as3720_reg_lookup[id].enable_bit, as3720_reg_lookup[id].enable_bit); } static int as3720_sd_disable(struct regulator_dev *dev) { u8 id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); return as3720_set_bits(as3720, as3720_reg_lookup[id].reg_enable, as3720_reg_lookup[id].enable_bit, 0); } static unsigned int as3720_sd_get_mode(struct regulator_dev *dev) { u32 val; u8 reg_id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, AS3720_SD_CONTROL_REG, &val); switch (rdev_get_id(dev)) { case AS3720_SD1: if ((val & AS3720_SD1_MODE_MASK) == AS3720_SD1_MODE_FAST) return REGULATOR_MODE_FAST; else return REGULATOR_MODE_NORMAL; case AS3720_SD2: if ((val & AS3720_SD2_MODE_MASK) == AS3720_SD2_MODE_FAST) return REGULATOR_MODE_FAST; else return REGULATOR_MODE_NORMAL; case AS3720_SD3: if ((val & AS3720_SD3_MODE_MASK) == AS3720_SD3_MODE_FAST) return REGULATOR_MODE_FAST; else return REGULATOR_MODE_NORMAL; default: printk(KERN_ERR "%s: regulator id %d invalid.\n", __func__, reg_id); } return -ERANGE; } static int as3720_sd_set_mode(struct regulator_dev *dev, unsigned int mode) { u8 val, mask, reg; u8 id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); if (mode != REGULATOR_MODE_FAST && mode != REGULATOR_MODE_NORMAL) return -EINVAL; switch (id) { case AS3720_SD0: if (mode == REGULATOR_MODE_FAST) val = AS3720_SD0_MODE_FAST; else val = AS3720_SD0_MODE_NORMAL; reg = AS3720_SD0_CONTROL_REG; mask = AS3720_SD0_MODE_MASK; break; case AS3720_SD1: if (mode == REGULATOR_MODE_FAST) val = AS3720_SD1_MODE_FAST; else val = AS3720_SD1_MODE_NORMAL; reg = AS3720_SD1_CONTROL_REG; mask = AS3720_SD1_MODE_MASK; break; case AS3720_SD2: if (mode == REGULATOR_MODE_FAST) val = AS3720_SD2_MODE_FAST; else val = AS3720_SD2_MODE_NORMAL; reg = AS3720_SD23_CONTROL_REG; mask = AS3720_SD2_MODE_MASK; break; case AS3720_SD3: if (mode == REGULATOR_MODE_FAST) val = AS3720_SD3_MODE_FAST; else val = AS3720_SD3_MODE_NORMAL; reg = AS3720_SD23_CONTROL_REG; mask = AS3720_SD3_MODE_MASK; break; case AS3720_SD4: if (mode == REGULATOR_MODE_FAST) val = AS3720_SD4_MODE_FAST; else val = AS3720_SD4_MODE_NORMAL; reg = AS3720_SD4_CONTROL_REG; mask = AS3720_SD4_MODE_MASK; break; case AS3720_SD5: if (mode == REGULATOR_MODE_FAST) val = AS3720_SD5_MODE_FAST; else val = AS3720_SD5_MODE_NORMAL; reg = AS3720_SD5_CONTROL_REG; mask = AS3720_SD5_MODE_MASK; break; case AS3720_SD6: if (mode == REGULATOR_MODE_FAST) val = AS3720_SD6_MODE_FAST; else val = AS3720_SD6_MODE_NORMAL; reg = AS3720_SD6_CONTROL_REG; mask = AS3720_SD6_MODE_MASK; break; default: printk(KERN_ERR "%s: regulator id %d invalid.\n", __func__, id); return -EINVAL; } return as3720_set_bits(as3720, reg, mask, val); } static int as3720_sd_list_voltage(struct regulator_dev *dev, unsigned selector) { u8 id = rdev_get_id(dev); if (id == AS3720_SD0 || id == AS3720_SD1 || id == AS3720_SD6) { if (selector >= AS3720_SD0_VSEL_MAX) return -EINVAL; return 600000 + (selector + 1) * 10000; } else { if (selector > AS3720_SD2_VSEL_MAX) return -EINVAL; /* ldo vsel min value is 1, selector starts at 0. */ selector++; if (selector <= 0x40) return 600000 + selector * 12500; if (selector <= 0x70) return 1400000 + (selector - 0x40) * 25000; if (selector <= 0x7F) return 2600000 + (selector - 0x70) * 50000; return -ERANGE; } return -EINVAL; } static int as3720_sd_get_voltage(struct regulator_dev *dev) { u32 val; u8 id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); as3720_reg_read(as3720, as3720_reg_lookup[id].reg_vsel, &val); val &= AS3720_SD_VSEL_MASK; if (val > 0) val--; /* ldo vsel min value is 1, selector starts at 0. */ return as3720_sd_list_voltage(dev, val); } static int as3720_sd_lowpower_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV) { u8 reg_val; int val; u8 id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); /* 0 ... 0 0x00 : not allowed as voltage setting * 610000 ... 1500000: 0x01 - 0x40, 10mV steps */ if (min_uV > 1500000 || max_uV < 610000) return -EINVAL; val = (min_uV - 600001) / 10000 + 1; if (val < 1) val = 1; reg_val = (u8) val; if (reg_val * 10000 + 600000 > max_uV) return -EINVAL; BUG_ON(reg_val * 10000 + 600000 < min_uV); return as3720_set_bits(as3720, as3720_reg_lookup[id].reg_vsel, AS3720_SD_VSEL_MASK, reg_val); } static int as3720_sd_nom_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV) { u8 reg_val; int val; u8 id = rdev_get_id(dev); struct as3720 *as3720 = rdev_get_drvdata(dev); /* 0 ... 0 0x00 : not allowed as voltage setting * 612500 ... 1400000: 0x01 - 0x40, 12.5mV steps * 1425000 ... 2600000: 0x41 - 0x70, 25mV steps * 2650000 ... 3350000: 0x41 - 0x70, 50mV steps */ if (min_uV > 3350000 || max_uV < 612500) return -EINVAL; if (min_uV <= 1400000) { val = (min_uV - 600001) / 12500 + 1; if (val < 1) val = 1; reg_val = (u8) val; if ((reg_val * 12500) + 600000 > max_uV) return -EINVAL; BUG_ON((reg_val * 12500) + 600000 < min_uV); } else if (min_uV <= 2600000) { reg_val = (min_uV - 1400001) / 25000 + 1; if ((reg_val * 25000) + 1400000 > max_uV) return -EINVAL; BUG_ON((reg_val * 25000) + 1400000 < min_uV); reg_val += 0x40; } else { reg_val = (min_uV - 2600001) / 50000 + 1; if ((reg_val * 50000) + 2600000 > max_uV) return -EINVAL; BUG_ON((reg_val * 50000) + 2600000 < min_uV); reg_val += 0x70; } return as3720_set_bits(as3720, as3720_reg_lookup[id].reg_vsel, AS3720_SD_VSEL_MASK, reg_val); } static int as3720_sd_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV) { u8 id = rdev_get_id(dev); if (id == AS3720_SD0 || id == AS3720_SD1 || id == AS3720_SD6) return as3720_sd_lowpower_set_voltage(dev, min_uV, max_uV); else return as3720_sd_nom_set_voltage(dev, min_uV, max_uV); } static struct regulator_ops as3720_sd_ops = { .is_enabled = as3720_sd_is_enabled, .enable = as3720_sd_enable, .disable = as3720_sd_disable, .list_voltage = as3720_sd_list_voltage, .get_voltage = as3720_sd_get_voltage, .set_voltage = as3720_sd_set_voltage, .get_mode = as3720_sd_get_mode, .set_mode = as3720_sd_set_mode, }; static struct regulator_desc regulators[] = { { .name = "as3720-ldo0", .id = AS3720_LDO0, .ops = &as3720_ldo0_ops, .n_voltages = AS3720_LDO0_VSEL_MAX, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo1", .id = AS3720_LDO1, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo2", .id = AS3720_LDO2, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo3", .id = AS3720_LDO3, .ops = &as3720_ldo3_ops, .n_voltages = AS3720_LDO3_VSEL_MAX, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo4", .id = AS3720_LDO4, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo5", .id = AS3720_LDO5, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo6", .id = AS3720_LDO6, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo7", .id = AS3720_LDO7, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo8", .id = AS3720_LDO8, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo9", .id = AS3720_LDO9, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo10", .id = AS3720_LDO10, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-ldo11", .id = AS3720_LDO11, .ops = &as3720_ldo_ops, .n_voltages = AS3720_LDO_NUM_VOLT, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-sd0", .id = AS3720_SD0, .ops = &as3720_sd_ops, .n_voltages = AS3720_SD0_VSEL_MAX, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-sd1", .id = AS3720_SD1, .ops = &as3720_sd_ops, .n_voltages = AS3720_SD0_VSEL_MAX, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-sd2", .id = AS3720_SD2, .ops = &as3720_sd_ops, .n_voltages = AS3720_SD2_VSEL_MAX, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-sd3", .id = AS3720_SD3, .ops = &as3720_sd_ops, .n_voltages = AS3720_SD2_VSEL_MAX, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-sd4", .id = AS3720_SD4, .ops = &as3720_sd_ops, .n_voltages = AS3720_SD2_VSEL_MAX, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-sd5", .id = AS3720_SD5, .ops = &as3720_sd_ops, .n_voltages = AS3720_SD2_VSEL_MAX, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { .name = "as3720-sd6", .id = AS3720_SD6, .ops = &as3720_sd_ops, .n_voltages = AS3720_SD0_VSEL_MAX, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, }; static int as3720_regulator_probe(struct platform_device *pdev) { int regulator; struct regulator_dev *rdev; struct as3720 *as3720 = dev_get_drvdata(pdev->dev.parent); struct as3720_platform_data *pdata; struct regulator_config config = { }; pdata = dev_get_platdata(pdev->dev.parent); for (regulator = 0; regulator < AS3720_NUM_REGULATORS; regulator++) { if (pdata->reg_init[regulator]) { config.dev = &pdev->dev; config.init_data = pdata->reg_init[regulator]; config.driver_data = as3720; rdev = regulator_register(®ulators[regulator], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "as3720 regulator err\n"); return PTR_ERR(rdev); } as3720->rdevs[regulator] = rdev; } } return 0; } static int as3720_regulator_remove(struct platform_device *pdev) { struct as3720 *as3720 = dev_get_drvdata(&pdev->dev); int regulator; for (regulator = 0; regulator < AS3720_NUM_REGULATORS; regulator++) regulator_unregister(as3720->rdevs[regulator]); return 0; } static struct platform_driver as3720_regulator_driver = { .driver = { .name = "as3720-regulator", .owner = THIS_MODULE, }, .probe = as3720_regulator_probe, .remove = as3720_regulator_remove, }; static int __init as3720_regulator_init(void) { return platform_driver_register(&as3720_regulator_driver); } subsys_initcall(as3720_regulator_init); static void __exit as3720_regulator_exit(void) { platform_driver_unregister(&as3720_regulator_driver); } module_exit(as3720_regulator_exit); MODULE_AUTHOR("Bernhard Breinbauer "); MODULE_DESCRIPTION("AS3720 regulator driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:as3720-regulator");