···514514 Say y here to support the regulators found on the Freescale515515 PFUZE100/PFUZE200 PMIC.516516517517+config REGULATOR_PV88060518518+ tristate "Powerventure Semiconductor PV88060 regulator"519519+ depends on I2C520520+ select REGMAP_I2C521521+ help522522+ Say y here to support the voltage regulators and convertors523523+ PV88060524524+517525config REGULATOR_PWM518526 tristate "PWM voltage regulator"519527 depends on PWM
···612612 .map_voltage = regulator_map_voltage_linear,613613};614614615615+static struct regulator_ops palmas_ops_ldo9 = {616616+ .is_enabled = palmas_is_enabled_ldo,617617+ .enable = regulator_enable_regmap,618618+ .disable = regulator_disable_regmap,619619+ .get_voltage_sel = regulator_get_voltage_sel_regmap,620620+ .set_voltage_sel = regulator_set_voltage_sel_regmap,621621+ .list_voltage = regulator_list_voltage_linear,622622+ .map_voltage = regulator_map_voltage_linear,623623+ .set_bypass = regulator_set_bypass_regmap,624624+ .get_bypass = regulator_get_bypass_regmap,625625+};626626+615627static struct regulator_ops palmas_ops_ext_control_ldo = {616628 .get_voltage_sel = regulator_get_voltage_sel_regmap,617629 .set_voltage_sel = regulator_set_voltage_sel_regmap,···649637 .list_voltage = regulator_list_voltage_linear,650638 .map_voltage = regulator_map_voltage_linear,651639 .set_voltage_time_sel = regulator_set_voltage_time_sel,640640+};641641+642642+static struct regulator_ops tps65917_ops_ldo_1_2 = {643643+ .is_enabled = palmas_is_enabled_ldo,644644+ .enable = regulator_enable_regmap,645645+ .disable = regulator_disable_regmap,646646+ .get_voltage_sel = regulator_get_voltage_sel_regmap,647647+ .set_voltage_sel = regulator_set_voltage_sel_regmap,648648+ .list_voltage = regulator_list_voltage_linear,649649+ .map_voltage = regulator_map_voltage_linear,650650+ .set_voltage_time_sel = regulator_set_voltage_time_sel,651651+ .set_bypass = regulator_set_bypass_regmap,652652+ .get_bypass = regulator_get_bypass_regmap,652653};653654654655static int palmas_regulator_config_external(struct palmas *palmas, int id,···940915 if (pdata && pdata->ldo6_vibrator &&941916 (id == PALMAS_REG_LDO6))942917 desc->enable_time = 2000;918918+919919+ if (id == PALMAS_REG_LDO9) {920920+ desc->ops = &palmas_ops_ldo9;921921+ desc->bypass_reg = desc->enable_reg;922922+ desc->bypass_mask =923923+ PALMAS_LDO9_CTRL_LDO_BYPASS_EN;924924+ }943925 } else {944926 if (!ddata->has_regen3 && id == PALMAS_REG_REGEN3)945927 continue;···10511019 * It is of the order of ~60mV/uS.10521020 */10531021 desc->ramp_delay = 2500;10221022+ if (id == TPS65917_REG_LDO1 ||10231023+ id == TPS65917_REG_LDO2) {10241024+ desc->ops = &tps65917_ops_ldo_1_2;10251025+ desc->bypass_reg = desc->enable_reg;10261026+ desc->bypass_mask =10271027+ TPS65917_LDO1_CTRL_BYPASS_EN;10281028+ }10541029 } else {10551030 desc->n_voltages = 1;10561031 if (reg_init && reg_init->roof_floor)
+437
drivers/regulator/pv88060-regulator.c
···11+/*22+ * pv88060-regulator.c - Regulator device driver for PV8806033+ * Copyright (C) 2015 Powerventure Semiconductor Ltd.44+ *55+ * This program is free software; you can redistribute it and/or66+ * modify it under the terms of the GNU General Public License77+ * as published by the Free Software Foundation; either version 288+ * of the License, or (at your option) any later version.99+ *1010+ * This program is distributed in the hope that it will be useful,1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1313+ * GNU General Public License for more details.1414+ */1515+1616+#include <linux/err.h>1717+#include <linux/gpio.h>1818+#include <linux/i2c.h>1919+#include <linux/module.h>2020+#include <linux/init.h>2121+#include <linux/slab.h>2222+#include <linux/regulator/driver.h>2323+#include <linux/regulator/machine.h>2424+#include <linux/regmap.h>2525+#include <linux/irq.h>2626+#include <linux/interrupt.h>2727+#include <linux/regulator/of_regulator.h>2828+#include <linux/proc_fs.h>2929+#include <linux/uaccess.h>3030+#include "pv88060-regulator.h"3131+3232+#define PV88060_MAX_REGULATORS 143333+3434+/* PV88060 REGULATOR IDs */3535+enum {3636+ /* BUCKs */3737+ PV88060_ID_BUCK1,3838+3939+ /* LDOs */4040+ PV88060_ID_LDO1,4141+ PV88060_ID_LDO2,4242+ PV88060_ID_LDO3,4343+ PV88060_ID_LDO4,4444+ PV88060_ID_LDO5,4545+ PV88060_ID_LDO6,4646+ PV88060_ID_LDO7,4747+4848+ /* SWTs */4949+ PV88060_ID_SW1,5050+ PV88060_ID_SW2,5151+ PV88060_ID_SW3,5252+ PV88060_ID_SW4,5353+ PV88060_ID_SW5,5454+ PV88060_ID_SW6,5555+};5656+5757+struct pv88060_regulator {5858+ struct regulator_desc desc;5959+ /* Current limiting */6060+ unsigned n_current_limits;6161+ const int *current_limits;6262+ unsigned int limit_mask;6363+ unsigned int conf; /* buck configuration register */6464+};6565+6666+struct pv88060 {6767+ struct device *dev;6868+ struct regmap *regmap;6969+ struct regulator_dev *rdev[PV88060_MAX_REGULATORS];7070+};7171+7272+static const struct regmap_config pv88060_regmap_config = {7373+ .reg_bits = 8,7474+ .val_bits = 8,7575+};7676+7777+/* Current limits array (in uA) for BUCK17878+ * Entry indexes corresponds to register values.7979+ */8080+8181+static const int pv88060_buck1_limits[] = {8282+ 1496000, 2393000, 3291000, 41890008383+};8484+8585+static unsigned int pv88060_buck_get_mode(struct regulator_dev *rdev)8686+{8787+ struct pv88060_regulator *info = rdev_get_drvdata(rdev);8888+ unsigned int data;8989+ int ret, mode = 0;9090+9191+ ret = regmap_read(rdev->regmap, info->conf, &data);9292+ if (ret < 0)9393+ return ret;9494+9595+ switch (data & PV88060_BUCK_MODE_MASK) {9696+ case PV88060_BUCK_MODE_SYNC:9797+ mode = REGULATOR_MODE_FAST;9898+ break;9999+ case PV88060_BUCK_MODE_AUTO:100100+ mode = REGULATOR_MODE_NORMAL;101101+ break;102102+ case PV88060_BUCK_MODE_SLEEP:103103+ mode = REGULATOR_MODE_STANDBY;104104+ break;105105+ }106106+107107+ return mode;108108+}109109+110110+static int pv88060_buck_set_mode(struct regulator_dev *rdev,111111+ unsigned int mode)112112+{113113+ struct pv88060_regulator *info = rdev_get_drvdata(rdev);114114+ int val = 0;115115+116116+ switch (mode) {117117+ case REGULATOR_MODE_FAST:118118+ val = PV88060_BUCK_MODE_SYNC;119119+ break;120120+ case REGULATOR_MODE_NORMAL:121121+ val = PV88060_BUCK_MODE_AUTO;122122+ break;123123+ case REGULATOR_MODE_STANDBY:124124+ val = PV88060_BUCK_MODE_SLEEP;125125+ break;126126+ default:127127+ return -EINVAL;128128+ }129129+130130+ return regmap_update_bits(rdev->regmap, info->conf,131131+ PV88060_BUCK_MODE_MASK, val);132132+}133133+134134+static int pv88060_set_current_limit(struct regulator_dev *rdev, int min,135135+ int max)136136+{137137+ struct pv88060_regulator *info = rdev_get_drvdata(rdev);138138+ int i;139139+140140+ /* search for closest to maximum */141141+ for (i = info->n_current_limits; i >= 0; i--) {142142+ if (min <= info->current_limits[i]143143+ && max >= info->current_limits[i]) {144144+ return regmap_update_bits(rdev->regmap,145145+ info->conf,146146+ info->limit_mask,147147+ i << PV88060_BUCK_ILIM_SHIFT);148148+ }149149+ }150150+151151+ return -EINVAL;152152+}153153+154154+static int pv88060_get_current_limit(struct regulator_dev *rdev)155155+{156156+ struct pv88060_regulator *info = rdev_get_drvdata(rdev);157157+ unsigned int data;158158+ int ret;159159+160160+ ret = regmap_read(rdev->regmap, info->conf, &data);161161+ if (ret < 0)162162+ return ret;163163+164164+ data = (data & info->limit_mask) >> PV88060_BUCK_ILIM_SHIFT;165165+ return info->current_limits[data];166166+}167167+168168+static struct regulator_ops pv88060_buck_ops = {169169+ .get_mode = pv88060_buck_get_mode,170170+ .set_mode = pv88060_buck_set_mode,171171+ .enable = regulator_enable_regmap,172172+ .disable = regulator_disable_regmap,173173+ .is_enabled = regulator_is_enabled_regmap,174174+ .set_voltage_sel = regulator_set_voltage_sel_regmap,175175+ .get_voltage_sel = regulator_get_voltage_sel_regmap,176176+ .list_voltage = regulator_list_voltage_linear,177177+ .set_current_limit = pv88060_set_current_limit,178178+ .get_current_limit = pv88060_get_current_limit,179179+};180180+181181+static struct regulator_ops pv88060_ldo_ops = {182182+ .enable = regulator_enable_regmap,183183+ .disable = regulator_disable_regmap,184184+ .is_enabled = regulator_is_enabled_regmap,185185+ .set_voltage_sel = regulator_set_voltage_sel_regmap,186186+ .get_voltage_sel = regulator_get_voltage_sel_regmap,187187+ .list_voltage = regulator_list_voltage_linear,188188+};189189+190190+#define PV88060_BUCK(chip, regl_name, min, step, max, limits_array) \191191+{\192192+ .desc = {\193193+ .id = chip##_ID_##regl_name,\194194+ .name = __stringify(chip##_##regl_name),\195195+ .of_match = of_match_ptr(#regl_name),\196196+ .regulators_node = of_match_ptr("regulators"),\197197+ .type = REGULATOR_VOLTAGE,\198198+ .owner = THIS_MODULE,\199199+ .ops = &pv88060_buck_ops,\200200+ .min_uV = min,\201201+ .uV_step = step,\202202+ .n_voltages = ((max) - (min))/(step) + 1,\203203+ .enable_reg = PV88060_REG_##regl_name##_CONF0,\204204+ .enable_mask = PV88060_BUCK_EN, \205205+ .vsel_reg = PV88060_REG_##regl_name##_CONF0,\206206+ .vsel_mask = PV88060_VBUCK_MASK,\207207+ },\208208+ .current_limits = limits_array,\209209+ .n_current_limits = ARRAY_SIZE(limits_array),\210210+ .limit_mask = PV88060_BUCK_ILIM_MASK, \211211+ .conf = PV88060_REG_##regl_name##_CONF1,\212212+}213213+214214+#define PV88060_LDO(chip, regl_name, min, step, max) \215215+{\216216+ .desc = {\217217+ .id = chip##_ID_##regl_name,\218218+ .name = __stringify(chip##_##regl_name),\219219+ .of_match = of_match_ptr(#regl_name),\220220+ .regulators_node = of_match_ptr("regulators"),\221221+ .type = REGULATOR_VOLTAGE,\222222+ .owner = THIS_MODULE,\223223+ .ops = &pv88060_ldo_ops,\224224+ .min_uV = min, \225225+ .uV_step = step, \226226+ .n_voltages = (step) ? ((max - min) / step + 1) : 1, \227227+ .enable_reg = PV88060_REG_##regl_name##_CONF, \228228+ .enable_mask = PV88060_LDO_EN, \229229+ .vsel_reg = PV88060_REG_##regl_name##_CONF, \230230+ .vsel_mask = PV88060_VLDO_MASK, \231231+ },\232232+}233233+234234+#define PV88060_SW(chip, regl_name, max) \235235+{\236236+ .desc = {\237237+ .id = chip##_ID_##regl_name,\238238+ .name = __stringify(chip##_##regl_name),\239239+ .of_match = of_match_ptr(#regl_name),\240240+ .regulators_node = of_match_ptr("regulators"),\241241+ .type = REGULATOR_VOLTAGE,\242242+ .owner = THIS_MODULE,\243243+ .ops = &pv88060_ldo_ops,\244244+ .min_uV = max,\245245+ .uV_step = 0,\246246+ .n_voltages = 1,\247247+ .enable_reg = PV88060_REG_##regl_name##_CONF,\248248+ .enable_mask = PV88060_SW_EN,\249249+ },\250250+}251251+252252+static const struct pv88060_regulator pv88060_regulator_info[] = {253253+ PV88060_BUCK(PV88060, BUCK1, 2800000, 12500, 4387500,254254+ pv88060_buck1_limits),255255+ PV88060_LDO(PV88060, LDO1, 1200000, 50000, 3350000),256256+ PV88060_LDO(PV88060, LDO2, 1200000, 50000, 3350000),257257+ PV88060_LDO(PV88060, LDO3, 1200000, 50000, 3350000),258258+ PV88060_LDO(PV88060, LDO4, 1200000, 50000, 3350000),259259+ PV88060_LDO(PV88060, LDO5, 1200000, 50000, 3350000),260260+ PV88060_LDO(PV88060, LDO6, 1200000, 50000, 3350000),261261+ PV88060_LDO(PV88060, LDO7, 1200000, 50000, 3350000),262262+ PV88060_SW(PV88060, SW1, 5000000),263263+ PV88060_SW(PV88060, SW2, 5000000),264264+ PV88060_SW(PV88060, SW3, 5000000),265265+ PV88060_SW(PV88060, SW4, 5000000),266266+ PV88060_SW(PV88060, SW5, 5000000),267267+ PV88060_SW(PV88060, SW6, 5000000),268268+};269269+270270+static irqreturn_t pv88060_irq_handler(int irq, void *data)271271+{272272+ struct pv88060 *chip = data;273273+ int i, reg_val, err, ret = IRQ_NONE;274274+275275+ err = regmap_read(chip->regmap, PV88060_REG_EVENT_A, ®_val);276276+ if (err < 0)277277+ goto error_i2c;278278+279279+ if (reg_val & PV88060_E_VDD_FLT) {280280+ for (i = 0; i < PV88060_MAX_REGULATORS; i++) {281281+ if (chip->rdev[i] != NULL) {282282+ regulator_notifier_call_chain(chip->rdev[i],283283+ REGULATOR_EVENT_UNDER_VOLTAGE,284284+ NULL);285285+ }286286+ }287287+288288+ err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,289289+ PV88060_E_VDD_FLT, PV88060_E_VDD_FLT);290290+ if (err < 0)291291+ goto error_i2c;292292+293293+ ret = IRQ_HANDLED;294294+ }295295+296296+ if (reg_val & PV88060_E_OVER_TEMP) {297297+ for (i = 0; i < PV88060_MAX_REGULATORS; i++) {298298+ if (chip->rdev[i] != NULL) {299299+ regulator_notifier_call_chain(chip->rdev[i],300300+ REGULATOR_EVENT_OVER_TEMP,301301+ NULL);302302+ }303303+ }304304+305305+ err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,306306+ PV88060_E_OVER_TEMP, PV88060_E_OVER_TEMP);307307+ if (err < 0)308308+ goto error_i2c;309309+310310+ ret = IRQ_HANDLED;311311+ }312312+313313+ return ret;314314+315315+error_i2c:316316+ dev_err(chip->dev, "I2C error : %d\n", err);317317+ return IRQ_NONE;318318+}319319+320320+/*321321+ * I2C driver interface functions322322+ */323323+static int pv88060_i2c_probe(struct i2c_client *i2c,324324+ const struct i2c_device_id *id)325325+{326326+ struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);327327+ struct pv88060 *chip;328328+ struct regulator_config config = { };329329+ int error, i, ret = 0;330330+331331+ chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88060), GFP_KERNEL);332332+ if (!chip)333333+ return -ENOMEM;334334+335335+ chip->dev = &i2c->dev;336336+ chip->regmap = devm_regmap_init_i2c(i2c, &pv88060_regmap_config);337337+ if (IS_ERR(chip->regmap)) {338338+ error = PTR_ERR(chip->regmap);339339+ dev_err(chip->dev, "Failed to allocate register map: %d\n",340340+ error);341341+ return error;342342+ }343343+344344+ i2c_set_clientdata(i2c, chip);345345+346346+ if (i2c->irq != 0) {347347+ ret = regmap_write(chip->regmap, PV88060_REG_MASK_A, 0xFF);348348+ if (ret < 0) {349349+ dev_err(chip->dev,350350+ "Failed to mask A reg: %d\n", ret);351351+ return ret;352352+ }353353+354354+ ret = regmap_write(chip->regmap, PV88060_REG_MASK_B, 0xFF);355355+ if (ret < 0) {356356+ dev_err(chip->dev,357357+ "Failed to mask B reg: %d\n", ret);358358+ return ret;359359+ }360360+361361+ ret = regmap_write(chip->regmap, PV88060_REG_MASK_C, 0xFF);362362+ if (ret < 0) {363363+ dev_err(chip->dev,364364+ "Failed to mask C reg: %d\n", ret);365365+ return ret;366366+ }367367+368368+ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,369369+ pv88060_irq_handler,370370+ IRQF_TRIGGER_LOW|IRQF_ONESHOT,371371+ "pv88060", chip);372372+ if (ret != 0) {373373+ dev_err(chip->dev, "Failed to request IRQ: %d\n",374374+ i2c->irq);375375+ return ret;376376+ }377377+378378+ ret = regmap_update_bits(chip->regmap, PV88060_REG_MASK_A,379379+ PV88060_M_VDD_FLT | PV88060_M_OVER_TEMP, 0);380380+ if (ret < 0) {381381+ dev_err(chip->dev,382382+ "Failed to update mask reg: %d\n", ret);383383+ return ret;384384+ }385385+386386+ } else {387387+ dev_warn(chip->dev, "No IRQ configured\n");388388+ }389389+390390+ config.dev = chip->dev;391391+ config.regmap = chip->regmap;392392+393393+ for (i = 0; i < PV88060_MAX_REGULATORS; i++) {394394+ if (init_data)395395+ config.init_data = &init_data[i];396396+397397+ config.driver_data = (void *)&pv88060_regulator_info[i];398398+ chip->rdev[i] = devm_regulator_register(chip->dev,399399+ &pv88060_regulator_info[i].desc, &config);400400+ if (IS_ERR(chip->rdev[i])) {401401+ dev_err(chip->dev,402402+ "Failed to register PV88060 regulator\n");403403+ return PTR_ERR(chip->rdev[i]);404404+ }405405+ }406406+407407+ return 0;408408+}409409+410410+static const struct i2c_device_id pv88060_i2c_id[] = {411411+ {"pv88060", 0},412412+ {},413413+};414414+MODULE_DEVICE_TABLE(i2c, pv88060_i2c_id);415415+416416+#ifdef CONFIG_OF417417+static const struct of_device_id pv88060_dt_ids[] = {418418+ { .compatible = "pvs,pv88060", .data = &pv88060_i2c_id[0] },419419+ {},420420+};421421+MODULE_DEVICE_TABLE(of, pv88060_dt_ids);422422+#endif423423+424424+static struct i2c_driver pv88060_regulator_driver = {425425+ .driver = {426426+ .name = "pv88060",427427+ .of_match_table = of_match_ptr(pv88060_dt_ids),428428+ },429429+ .probe = pv88060_i2c_probe,430430+ .id_table = pv88060_i2c_id,431431+};432432+433433+module_i2c_driver(pv88060_regulator_driver);434434+435435+MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");436436+MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88060");437437+MODULE_LICENSE("GPL");
+69
drivers/regulator/pv88060-regulator.h
···11+/*22+ * pv88060-regulator.h - Regulator definitions for PV8806033+ * Copyright (C) 2015 Powerventure Semiconductor Ltd.44+ *55+ * This program is free software; you can redistribute it and/or66+ * modify it under the terms of the GNU General Public License77+ * as published by the Free Software Foundation; either version 288+ * of the License, or (at your option) any later version.99+ *1010+ * This program is distributed in the hope that it will be useful,1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1313+ * GNU General Public License for more details.1414+ */1515+1616+#ifndef __PV88060_REGISTERS_H__1717+#define __PV88060_REGISTERS_H__1818+1919+/* System Control and Event Registers */2020+#define PV88060_REG_EVENT_A 0x042121+#define PV88060_REG_MASK_A 0x082222+#define PV88060_REG_MASK_B 0x092323+#define PV88060_REG_MASK_C 0x0A2424+2525+/* Regulator Registers */2626+#define PV88060_REG_BUCK1_CONF0 0x1B2727+#define PV88060_REG_BUCK1_CONF1 0x1C2828+#define PV88060_REG_LDO1_CONF 0x1D2929+#define PV88060_REG_LDO2_CONF 0x1E3030+#define PV88060_REG_LDO3_CONF 0x1F3131+#define PV88060_REG_LDO4_CONF 0x203232+#define PV88060_REG_LDO5_CONF 0x213333+#define PV88060_REG_LDO6_CONF 0x223434+#define PV88060_REG_LDO7_CONF 0x233535+3636+#define PV88060_REG_SW1_CONF 0x3B3737+#define PV88060_REG_SW2_CONF 0x3C3838+#define PV88060_REG_SW3_CONF 0x3D3939+#define PV88060_REG_SW4_CONF 0x3E4040+#define PV88060_REG_SW5_CONF 0x3F4141+#define PV88060_REG_SW6_CONF 0x404242+4343+/* PV88060_REG_EVENT_A (addr=0x04) */4444+#define PV88060_E_VDD_FLT 0x014545+#define PV88060_E_OVER_TEMP 0x024646+4747+/* PV88060_REG_MASK_A (addr=0x08) */4848+#define PV88060_M_VDD_FLT 0x014949+#define PV88060_M_OVER_TEMP 0x025050+5151+/* PV88060_REG_BUCK1_CONF0 (addr=0x1B) */5252+#define PV88060_BUCK_EN 0x805353+#define PV88060_VBUCK_MASK 0x7F5454+/* PV88060_REG_LDO1/2/3/4/5/6/7_CONT */5555+#define PV88060_LDO_EN 0x405656+#define PV88060_VLDO_MASK 0x3F5757+/* PV88060_REG_SW1/2/3/4/5_CONF */5858+#define PV88060_SW_EN 0x805959+6060+/* PV88060_REG_BUCK1_CONF1 (addr=0x1C) */6161+#define PV88060_BUCK_ILIM_SHIFT 26262+#define PV88060_BUCK_ILIM_MASK 0x0C6363+#define PV88060_BUCK_MODE_SHIFT 06464+#define PV88060_BUCK_MODE_MASK 0x036565+#define PV88060_BUCK_MODE_SLEEP 0x006666+#define PV88060_BUCK_MODE_AUTO 0x016767+#define PV88060_BUCK_MODE_SYNC 0x026868+6969+#endif /* __PV88060_REGISTERS_H__ */
+3
include/linux/regulator/consumer.h
···140140 *141141 * @supply: The name of the supply. Initialised by the user before142142 * using the bulk regulator APIs.143143+ * @optional: The supply should be considered optional. Initialised by the user144144+ * before using the bulk regulator APIs.143145 * @consumer: The regulator consumer for the supply. This will be managed144146 * by the bulk API.145147 *···151149 */152150struct regulator_bulk_data {153151 const char *supply;152152+ bool optional;154153 struct regulator *consumer;155154156155 /* private: Internal use */