Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: mp8859: Cleanups and enhancements

Merge series from Mark Brown <broonie@kernel.org>:

I had cause to look at the MP8859 driver together with the datasheet and
noticed a few small issues and missing features. This series deals with
many of these issues, the device also has support for interrupts which
are not implemented here.

+251 -1
+251 -1
drivers/regulator/mp8859.c
··· 35 35 36 36 #define MP8859_GO_BIT 0x01 37 37 38 + #define MP8859_IOUT_LIM_MASK 0x7f 39 + 40 + #define MP8859_ENABLE_MASK 0x80 41 + #define MP8859_DISCHG_EN_MASK 0x10 42 + #define MP8859_MODE_MASK 0x08 43 + 44 + #define MP8859_PG_MASK 0x80 45 + #define MP8859_OTP_MASK 0x40 46 + #define MP8859_OTW_MASK 0x20 47 + #define MP8859_CC_CV_MASK 0x10 38 48 39 49 static int mp8859_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) 40 50 { ··· 83 73 return val; 84 74 } 85 75 76 + static int mp8859_set_voltage_time_sel(struct regulator_dev *rdev, 77 + unsigned int from, unsigned int to) 78 + { 79 + int change; 80 + 81 + /* The voltage ramps at 1mV/uS, selectors are 10mV */ 82 + if (from > to) 83 + change = from - to; 84 + else 85 + change = to - from; 86 + 87 + return change * 10 * 1000; 88 + } 89 + 90 + static unsigned int mp8859_get_mode(struct regulator_dev *rdev) 91 + { 92 + unsigned int val; 93 + int ret; 94 + 95 + ret = regmap_read(rdev->regmap, MP8859_CTL1_REG, &val); 96 + if (ret != 0) { 97 + dev_err(&rdev->dev, "Failed to read mode: %d\n", ret); 98 + return 0; 99 + } 100 + 101 + if (val & MP8859_MODE_MASK) 102 + return REGULATOR_MODE_FAST; 103 + else 104 + return REGULATOR_MODE_NORMAL; 105 + } 106 + 107 + static int mp8859_set_mode(struct regulator_dev *rdev, unsigned int mode) 108 + { 109 + unsigned int val; 110 + 111 + switch (mode) { 112 + case REGULATOR_MODE_FAST: 113 + val = MP8859_MODE_MASK; 114 + break; 115 + case REGULATOR_MODE_NORMAL: 116 + val = 0; 117 + break; 118 + default: 119 + return -EINVAL; 120 + } 121 + 122 + return regmap_update_bits(rdev->regmap, MP8859_CTL1_REG, 123 + MP8859_MODE_MASK, val); 124 + } 125 + 126 + static int mp8859_set_current_limit(struct regulator_dev *rdev, 127 + int min_uA, int max_uA) 128 + { 129 + unsigned int cur_val, new_val; 130 + int ret, i; 131 + 132 + /* Steps of 50mA */ 133 + new_val = max_uA / 50000; 134 + if (new_val > MP8859_IOUT_LIM_MASK) 135 + return -EINVAL; 136 + if (new_val == 0) 137 + return -EINVAL; 138 + 139 + /* 140 + * If the regulator is limiting then ramp gradually as per 141 + * datasheet, otherwise just set the value directly. 142 + */ 143 + ret = regmap_read(rdev->regmap, MP8859_STATUS_REG, &cur_val); 144 + if (ret != 0) 145 + return ret; 146 + if (!(cur_val & MP8859_CC_CV_MASK)) { 147 + return regmap_update_bits(rdev->regmap, MP8859_IOUT_LIM_REG, 148 + MP8859_IOUT_LIM_MASK, new_val); 149 + } 150 + 151 + ret = regmap_read(rdev->regmap, MP8859_IOUT_LIM_REG, &cur_val); 152 + if (ret != 0) 153 + return ret; 154 + 155 + if (cur_val >= new_val) { 156 + for (i = cur_val; i >= new_val; i--) { 157 + ret = regmap_update_bits(rdev->regmap, 158 + MP8859_IOUT_LIM_REG, 159 + MP8859_IOUT_LIM_MASK, 160 + cur_val - i); 161 + if (ret != 0) 162 + return ret; 163 + } 164 + } else { 165 + for (i = cur_val; i <= new_val; i++) { 166 + ret = regmap_update_bits(rdev->regmap, 167 + MP8859_IOUT_LIM_REG, 168 + MP8859_IOUT_LIM_MASK, 169 + cur_val + i); 170 + if (ret != 0) 171 + return ret; 172 + } 173 + } 174 + 175 + return 0; 176 + } 177 + 178 + static int mp8859_get_status(struct regulator_dev *rdev) 179 + { 180 + unsigned int val; 181 + int ret; 182 + 183 + /* Output status is only meaingful when enabled */ 184 + ret = regmap_read(rdev->regmap, MP8859_CTL1_REG, &val); 185 + if (ret != 0) 186 + return ret; 187 + if (!(val & MP8859_ENABLE_MASK)) 188 + return REGULATOR_STATUS_UNDEFINED; 189 + 190 + ret = regmap_read(rdev->regmap, MP8859_STATUS_REG, &val); 191 + if (ret != 0) 192 + return ret; 193 + 194 + if (val & MP8859_PG_MASK) 195 + return REGULATOR_STATUS_ON; 196 + else 197 + return REGULATOR_STATUS_ERROR; 198 + } 199 + 200 + static int mp8859_get_error_flags(struct regulator_dev *rdev, 201 + unsigned int *flags) 202 + { 203 + unsigned int status, enabled; 204 + int ret; 205 + 206 + *flags = 0; 207 + 208 + /* Output status is only meaingful when enabled */ 209 + ret = regmap_read(rdev->regmap, MP8859_CTL1_REG, &enabled); 210 + if (ret != 0) 211 + return ret; 212 + enabled &= MP8859_ENABLE_MASK; 213 + 214 + ret = regmap_read(rdev->regmap, MP8859_STATUS_REG, &status); 215 + if (ret != 0) 216 + return ret; 217 + 218 + if (enabled && !(status & MP8859_PG_MASK)) 219 + status |= REGULATOR_ERROR_FAIL; 220 + if (status & MP8859_OTP_MASK) 221 + status |= REGULATOR_ERROR_OVER_TEMP; 222 + if (status & MP8859_OTW_MASK) 223 + status |= REGULATOR_ERROR_OVER_TEMP_WARN; 224 + if (status & MP8859_CC_CV_MASK) 225 + status |= REGULATOR_ERROR_OVER_CURRENT; 226 + 227 + return 0; 228 + } 229 + 86 230 static const struct linear_range mp8859_dcdc_ranges[] = { 87 231 REGULATOR_LINEAR_RANGE(0, VOL_MIN_IDX, VOL_MAX_IDX, 10000), 88 232 }; 233 + 234 + static bool mp8859_readable(struct device *dev, unsigned int reg) 235 + { 236 + switch (reg) { 237 + case MP8859_VOUT_L_REG: 238 + case MP8859_VOUT_H_REG: 239 + case MP8859_VOUT_GO_REG: 240 + case MP8859_IOUT_LIM_REG: 241 + case MP8859_CTL1_REG: 242 + case MP8859_CTL2_REG: 243 + case MP8859_STATUS_REG: 244 + case MP8859_INTERRUPT_REG: 245 + case MP8859_MASK_REG: 246 + case MP8859_ID1_REG: 247 + case MP8859_MFR_ID_REG: 248 + case MP8859_DEV_ID_REG: 249 + case MP8859_IC_REV_REG: 250 + return true; 251 + default: 252 + return false; 253 + } 254 + } 255 + 256 + static bool mp8859_volatile(struct device *dev, unsigned int reg) 257 + { 258 + switch (reg) { 259 + case MP8859_VOUT_GO_REG: 260 + case MP8859_STATUS_REG: 261 + case MP8859_INTERRUPT_REG: 262 + return true; 263 + default: 264 + return false; 265 + } 266 + } 89 267 90 268 static const struct regmap_config mp8859_regmap = { 91 269 .reg_bits = 8, 92 270 .val_bits = 8, 93 271 .max_register = MP8859_MAX_REG, 94 - .cache_type = REGCACHE_RBTREE, 272 + .cache_type = REGCACHE_MAPLE, 273 + .readable_reg = mp8859_readable, 274 + .volatile_reg = mp8859_volatile, 95 275 }; 96 276 97 277 static const struct regulator_ops mp8859_ops = { 98 278 .set_voltage_sel = mp8859_set_voltage_sel, 99 279 .get_voltage_sel = mp8859_get_voltage_sel, 100 280 .list_voltage = regulator_list_voltage_linear_range, 281 + .set_voltage_time_sel = mp8859_set_voltage_time_sel, 282 + .enable = regulator_enable_regmap, 283 + .disable = regulator_disable_regmap, 284 + .is_enabled = regulator_is_enabled_regmap, 285 + .set_mode = mp8859_set_mode, 286 + .get_mode = mp8859_get_mode, 287 + .set_active_discharge = regulator_set_active_discharge_regmap, 288 + .set_current_limit = mp8859_set_current_limit, 289 + .get_status = mp8859_get_status, 290 + .get_error_flags = mp8859_get_error_flags, 101 291 }; 102 292 103 293 static const struct regulator_desc mp8859_regulators[] = { ··· 310 100 .n_voltages = VOL_MAX_IDX + 1, 311 101 .linear_ranges = mp8859_dcdc_ranges, 312 102 .n_linear_ranges = 1, 103 + .enable_reg = MP8859_CTL1_REG, 104 + .enable_mask = MP8859_ENABLE_MASK, 105 + .enable_val = MP8859_ENABLE_MASK, 106 + .active_discharge_reg = MP8859_CTL1_REG, 107 + .active_discharge_on = MP8859_DISCHG_EN_MASK, 108 + .active_discharge_mask = MP8859_DISCHG_EN_MASK, 313 109 .ops = &mp8859_ops, 314 110 .owner = THIS_MODULE, 315 111 }, ··· 327 111 struct regulator_config config = {.dev = &i2c->dev}; 328 112 struct regmap *regmap = devm_regmap_init_i2c(i2c, &mp8859_regmap); 329 113 struct regulator_dev *rdev; 114 + unsigned int val, rev; 330 115 331 116 if (IS_ERR(regmap)) { 332 117 ret = PTR_ERR(regmap); 333 118 dev_err(&i2c->dev, "regmap init failed: %d\n", ret); 334 119 return ret; 335 120 } 121 + 122 + ret = regmap_read(regmap, MP8859_MFR_ID_REG, &val); 123 + if (ret != 0) { 124 + dev_err(&i2c->dev, "Failed to read manufacturer ID: %d\n", ret); 125 + return ret; 126 + } 127 + if (val != 0x9) { 128 + dev_err(&i2c->dev, "Manufacturer ID %x != 9\n", val); 129 + return -EINVAL; 130 + } 131 + 132 + ret = regmap_read(regmap, MP8859_DEV_ID_REG, &val); 133 + if (ret != 0) { 134 + dev_err(&i2c->dev, "Failed to read device ID: %d\n", ret); 135 + return ret; 136 + } 137 + if (val != 0x58) { 138 + dev_err(&i2c->dev, "Manufacturer ID %x != 0x58\n", val); 139 + return -EINVAL; 140 + } 141 + 142 + ret = regmap_read(regmap, MP8859_IC_REV_REG, &rev); 143 + if (ret != 0) { 144 + dev_err(&i2c->dev, "Failed to read device revision: %d\n", ret); 145 + return ret; 146 + } 147 + ret = regmap_read(regmap, MP8859_ID1_REG, &val); 148 + if (ret != 0) { 149 + dev_err(&i2c->dev, "Failed to read device ID1: %d\n", ret); 150 + return ret; 151 + } 152 + dev_info(&i2c->dev, "MP8859-%04d revision %d\n", val, rev); 153 + 336 154 rdev = devm_regulator_register(&i2c->dev, &mp8859_regulators[0], 337 155 &config); 338 156