Merge remote-tracking branches 'regulator/topic/pv88090', 'regulator/topic/qcom-smd', 'regulator/topic/tps6105x', 'regulator/topic/tps65086' and 'regulator/topic/tps65218' into regulator-next
This commit is contained in:
commit
78ae902552
|
@ -0,0 +1,65 @@
|
|||
* Powerventure Semiconductor PV88090 Voltage Regulator
|
||||
|
||||
Required properties:
|
||||
- compatible: "pvs,pv88090".
|
||||
- reg: I2C slave address, usually 0x48.
|
||||
- interrupts: the interrupt outputs of the controller
|
||||
- regulators: A node that houses a sub-node for each regulator within the
|
||||
device. Each sub-node is identified using the node's name, with valid
|
||||
values listed below. The content of each sub-node is defined by the
|
||||
standard binding for regulators; see regulator.txt.
|
||||
BUCK1, BUCK2, BUCK3, LDO1, and LDO2.
|
||||
|
||||
Optional properties:
|
||||
- Any optional property defined in regulator.txt
|
||||
|
||||
Example
|
||||
|
||||
pmic: pv88090@48 {
|
||||
compatible = "pvs,pv88090";
|
||||
reg = <0x48>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <24 24>;
|
||||
|
||||
regulators {
|
||||
BUCK1 {
|
||||
regulator-name = "buck1";
|
||||
regulator-min-microvolt = < 600000>;
|
||||
regulator-max-microvolt = <1393750>;
|
||||
regulator-min-microamp = < 220000>;
|
||||
regulator-max-microamp = <7040000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
BUCK2 {
|
||||
regulator-name = "buck2";
|
||||
regulator-min-microvolt = < 600000>;
|
||||
regulator-max-microvolt = <1393750>;
|
||||
regulator-min-microamp = <1496000>;
|
||||
regulator-max-microamp = <4189000>;
|
||||
};
|
||||
|
||||
BUCK3 {
|
||||
regulator-name = "buck3";
|
||||
regulator-min-microvolt = <600000>;
|
||||
regulator-max-microvolt = <1393750>;
|
||||
regulator-min-microamp = <1496000>;
|
||||
regulator-max-microamp = <4189000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
LDO1 {
|
||||
regulator-name = "ldo1";
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <4350000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
LDO2 {
|
||||
regulator-name = "ldo2";
|
||||
regulator-min-microvolt = < 650000>;
|
||||
regulator-max-microvolt = <2225000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,27 +1,17 @@
|
|||
Qualcomm Resource Power Manager (RPM) over SMD
|
||||
QCOM SMD RPM REGULATOR
|
||||
|
||||
This driver is used to interface with the Resource Power Manager (RPM) found in
|
||||
various Qualcomm platforms. The RPM allows each component in the system to vote
|
||||
for state of the system resources, such as clocks, regulators and bus
|
||||
frequencies.
|
||||
The Qualcomm RPM over SMD regulator is modelled as a subdevice of the RPM.
|
||||
Because SMD is used as the communication transport mechanism, the RPM resides as
|
||||
a subnode of the SMD. As such, the SMD-RPM regulator requires that the SMD and
|
||||
RPM nodes be present.
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be one of:
|
||||
"qcom,rpm-msm8974"
|
||||
Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt for
|
||||
information pertaining to the SMD node.
|
||||
|
||||
- qcom,smd-channels:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: Shared Memory channel used for communication with the RPM
|
||||
Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt for
|
||||
information regarding the RPM node.
|
||||
|
||||
= SUBDEVICES
|
||||
|
||||
The RPM exposes resources to its subnodes. The below bindings specify the set
|
||||
of valid subnodes that can operate on these resources.
|
||||
|
||||
== Regulators
|
||||
== Regulator
|
||||
|
||||
Regulator nodes are identified by their compatible:
|
||||
|
||||
|
@ -30,7 +20,9 @@ Regulator nodes are identified by their compatible:
|
|||
Value type: <string>
|
||||
Definition: must be one of:
|
||||
"qcom,rpm-pm8841-regulators"
|
||||
"qcom,rpm-pm8916-regulators"
|
||||
"qcom,rpm-pm8941-regulators"
|
||||
"qcom,rpm-pma8084-regulators"
|
||||
|
||||
- vdd_s1-supply:
|
||||
- vdd_s2-supply:
|
||||
|
@ -45,6 +37,19 @@ Regulator nodes are identified by their compatible:
|
|||
Definition: reference to regulator supplying the input pin, as
|
||||
described in the data sheet
|
||||
|
||||
- vdd_s1-supply:
|
||||
- vdd_s2-supply:
|
||||
- vdd_s3-supply:
|
||||
- vdd_s4-supply:
|
||||
- vdd_l1_l2_l3-supply:
|
||||
- vdd_l4_l5_l6-supply:
|
||||
- vdd_l7-supply:
|
||||
- vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18-supply:
|
||||
Usage: optional (pm8916 only)
|
||||
Value type: <phandle>
|
||||
Definition: reference to regulator supplying the input pin, as
|
||||
described in the data sheet
|
||||
|
||||
- vdd_s1-supply:
|
||||
- vdd_s2-supply:
|
||||
- vdd_s3-supply:
|
||||
|
@ -63,6 +68,35 @@ Regulator nodes are identified by their compatible:
|
|||
Definition: reference to regulator supplying the input pin, as
|
||||
described in the data sheet
|
||||
|
||||
- vdd_s1-supply:
|
||||
- vdd_s2-supply:
|
||||
- vdd_s3-supply:
|
||||
- vdd_s4-supply:
|
||||
- vdd_s5-supply:
|
||||
- vdd_s6-supply:
|
||||
- vdd_s7-supply:
|
||||
- vdd_s8-supply:
|
||||
- vdd_s9-supply:
|
||||
- vdd_s10-supply:
|
||||
- vdd_s11-supply:
|
||||
- vdd_s12-supply:
|
||||
- vdd_l1_l11-supply:
|
||||
- vdd_l2_l3_l4_l27-supply:
|
||||
- vdd_l5_l7-supply:
|
||||
- vdd_l6_l12_l14_l15_l26-supply:
|
||||
- vdd_l8-supply:
|
||||
- vdd_l9_l10_l13_l20_l23_l24-supply:
|
||||
- vdd_l16_l25-supply:
|
||||
- vdd_l17-supply:
|
||||
- vdd_l18-supply:
|
||||
- vdd_l19-supply:
|
||||
- vdd_l21-supply:
|
||||
- vdd_l22-supply:
|
||||
Usage: optional (pma8084 only)
|
||||
Value type: <phandle>
|
||||
Definition: reference to regulator supplying the input pin, as
|
||||
described in the data sheet
|
||||
|
||||
The regulator node houses sub-nodes for each regulator within the device. Each
|
||||
sub-node is identified using the node's name, with valid values listed for each
|
||||
of the pmics below.
|
||||
|
@ -70,11 +104,20 @@ of the pmics below.
|
|||
pm8841:
|
||||
s1, s2, s3, s4, s5, s6, s7, s8
|
||||
|
||||
pm8916:
|
||||
s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
|
||||
l14, l15, l16, l17, l18
|
||||
|
||||
pm8941:
|
||||
s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
|
||||
l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2,
|
||||
lvs3, 5vs1, 5vs2
|
||||
|
||||
pma8084:
|
||||
s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5,
|
||||
l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
|
||||
l21, l22, l23, l24, l25, l26, l27, lvs1, lvs2, lvs3, lvs4, 5vs1
|
||||
|
||||
The content of each sub-node is defined by the standard binding for regulators -
|
||||
see regulator.txt.
|
||||
|
||||
|
@ -114,4 +157,3 @@ see regulator.txt.
|
|||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
Qualcomm Resource Power Manager (RPM) over SMD
|
||||
|
||||
This driver is used to interface with the Resource Power Manager (RPM) found in
|
||||
various Qualcomm platforms. The RPM allows each component in the system to vote
|
||||
for state of the system resources, such as clocks, regulators and bus
|
||||
frequencies.
|
||||
|
||||
The SMD information for the RPM edge should be filled out. See qcom,smd.txt for
|
||||
the required edge properties. All SMD related properties will reside within the
|
||||
RPM node itself.
|
||||
|
||||
= SUBDEVICES
|
||||
|
||||
The RPM exposes resources to its subnodes. The rpm_requests node must be
|
||||
present and this subnode may contain children that designate regulator
|
||||
resources.
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be one of:
|
||||
"qcom,rpm-apq8084"
|
||||
"qcom,rpm-msm8916"
|
||||
"qcom,rpm-msm8974"
|
||||
|
||||
- qcom,smd-channels:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be "rpm_requests"
|
||||
|
||||
Refer to Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
|
||||
for information on the regulator subnodes that can exist under the rpm_requests.
|
||||
|
||||
Example:
|
||||
|
||||
soc {
|
||||
apcs: syscon@f9011000 {
|
||||
compatible = "syscon";
|
||||
reg = <0xf9011000 0x1000>;
|
||||
};
|
||||
};
|
||||
|
||||
smd {
|
||||
compatible = "qcom,smd";
|
||||
|
||||
rpm {
|
||||
interrupts = <0 168 1>;
|
||||
qcom,ipc = <&apcs 8 0>;
|
||||
qcom,smd-edge = <15>;
|
||||
|
||||
rpm_requests {
|
||||
compatible = "qcom,rpm-msm8974";
|
||||
qcom,smd-channels = "rpm_requests";
|
||||
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
|
@ -522,6 +522,14 @@ config REGULATOR_PV88060
|
|||
Say y here to support the voltage regulators and convertors
|
||||
PV88060
|
||||
|
||||
config REGULATOR_PV88090
|
||||
tristate "Powerventure Semiconductor PV88090 regulator"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say y here to support the voltage regulators and convertors
|
||||
on PV88090
|
||||
|
||||
config REGULATOR_PWM
|
||||
tristate "PWM voltage regulator"
|
||||
depends on PWM
|
||||
|
@ -698,6 +706,13 @@ config REGULATOR_TPS6507X
|
|||
three step-down converters and two general-purpose LDO voltage regulators.
|
||||
It supports TI's software based Class-2 SmartReflex implementation.
|
||||
|
||||
config REGULATOR_TPS65086
|
||||
tristate "TI TPS65086 Power regulators"
|
||||
depends on MFD_TPS65086
|
||||
help
|
||||
This driver provides support for the voltage regulators on
|
||||
TI TPS65086 PMICs.
|
||||
|
||||
config REGULATOR_TPS65090
|
||||
tristate "TI TPS65090 Power regulator"
|
||||
depends on MFD_TPS65090
|
||||
|
|
|
@ -68,6 +68,7 @@ obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
|
|||
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PV88090) += pv88090-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
|
||||
|
@ -87,6 +88,7 @@ obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
|
|||
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS65086) += tps65086-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS65218) += tps65218-regulator.o
|
||||
|
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
* pv88090-regulator.c - Regulator device driver for PV88090
|
||||
* Copyright (C) 2015 Powerventure Semiconductor Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "pv88090-regulator.h"
|
||||
|
||||
#define PV88090_MAX_REGULATORS 5
|
||||
|
||||
/* PV88090 REGULATOR IDs */
|
||||
enum {
|
||||
/* BUCKs */
|
||||
PV88090_ID_BUCK1,
|
||||
PV88090_ID_BUCK2,
|
||||
PV88090_ID_BUCK3,
|
||||
|
||||
/* LDOs */
|
||||
PV88090_ID_LDO1,
|
||||
PV88090_ID_LDO2,
|
||||
};
|
||||
|
||||
struct pv88090_regulator {
|
||||
struct regulator_desc desc;
|
||||
/* Current limiting */
|
||||
unsigned n_current_limits;
|
||||
const int *current_limits;
|
||||
unsigned int limit_mask;
|
||||
unsigned int conf;
|
||||
unsigned int conf2;
|
||||
};
|
||||
|
||||
struct pv88090 {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regulator_dev *rdev[PV88090_MAX_REGULATORS];
|
||||
};
|
||||
|
||||
struct pv88090_buck_voltage {
|
||||
int min_uV;
|
||||
int max_uV;
|
||||
int uV_step;
|
||||
};
|
||||
|
||||
static const struct regmap_config pv88090_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.
|
||||
* Entry indexes corresponds to register values.
|
||||
*/
|
||||
|
||||
static const int pv88090_buck1_limits[] = {
|
||||
220000, 440000, 660000, 880000, 1100000, 1320000, 1540000, 1760000,
|
||||
1980000, 2200000, 2420000, 2640000, 2860000, 3080000, 3300000, 3520000,
|
||||
3740000, 3960000, 4180000, 4400000, 4620000, 4840000, 5060000, 5280000,
|
||||
5500000, 5720000, 5940000, 6160000, 6380000, 6600000, 6820000, 7040000
|
||||
};
|
||||
|
||||
static const int pv88090_buck23_limits[] = {
|
||||
1496000, 2393000, 3291000, 4189000
|
||||
};
|
||||
|
||||
static const struct pv88090_buck_voltage pv88090_buck_vol[3] = {
|
||||
{
|
||||
.min_uV = 600000,
|
||||
.max_uV = 1393750,
|
||||
.uV_step = 6250,
|
||||
},
|
||||
|
||||
{
|
||||
.min_uV = 1400000,
|
||||
.max_uV = 2193750,
|
||||
.uV_step = 6250,
|
||||
},
|
||||
{
|
||||
.min_uV = 1250000,
|
||||
.max_uV = 2837500,
|
||||
.uV_step = 12500,
|
||||
},
|
||||
};
|
||||
|
||||
static unsigned int pv88090_buck_get_mode(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pv88090_regulator *info = rdev_get_drvdata(rdev);
|
||||
unsigned int data;
|
||||
int ret, mode = 0;
|
||||
|
||||
ret = regmap_read(rdev->regmap, info->conf, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (data & PV88090_BUCK1_MODE_MASK) {
|
||||
case PV88090_BUCK_MODE_SYNC:
|
||||
mode = REGULATOR_MODE_FAST;
|
||||
break;
|
||||
case PV88090_BUCK_MODE_AUTO:
|
||||
mode = REGULATOR_MODE_NORMAL;
|
||||
break;
|
||||
case PV88090_BUCK_MODE_SLEEP:
|
||||
mode = REGULATOR_MODE_STANDBY;
|
||||
break;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int pv88090_buck_set_mode(struct regulator_dev *rdev,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct pv88090_regulator *info = rdev_get_drvdata(rdev);
|
||||
int val = 0;
|
||||
|
||||
switch (mode) {
|
||||
case REGULATOR_MODE_FAST:
|
||||
val = PV88090_BUCK_MODE_SYNC;
|
||||
break;
|
||||
case REGULATOR_MODE_NORMAL:
|
||||
val = PV88090_BUCK_MODE_AUTO;
|
||||
break;
|
||||
case REGULATOR_MODE_STANDBY:
|
||||
val = PV88090_BUCK_MODE_SLEEP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_update_bits(rdev->regmap, info->conf,
|
||||
PV88090_BUCK1_MODE_MASK, val);
|
||||
}
|
||||
|
||||
static int pv88090_set_current_limit(struct regulator_dev *rdev, int min,
|
||||
int max)
|
||||
{
|
||||
struct pv88090_regulator *info = rdev_get_drvdata(rdev);
|
||||
int i;
|
||||
|
||||
/* search for closest to maximum */
|
||||
for (i = info->n_current_limits; i >= 0; i--) {
|
||||
if (min <= info->current_limits[i]
|
||||
&& max >= info->current_limits[i]) {
|
||||
return regmap_update_bits(rdev->regmap,
|
||||
info->conf,
|
||||
info->limit_mask,
|
||||
i << PV88090_BUCK1_ILIM_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int pv88090_get_current_limit(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pv88090_regulator *info = rdev_get_drvdata(rdev);
|
||||
unsigned int data;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(rdev->regmap, info->conf, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data = (data & info->limit_mask) >> PV88090_BUCK1_ILIM_SHIFT;
|
||||
return info->current_limits[data];
|
||||
}
|
||||
|
||||
static struct regulator_ops pv88090_buck_ops = {
|
||||
.get_mode = pv88090_buck_get_mode,
|
||||
.set_mode = pv88090_buck_set_mode,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.set_current_limit = pv88090_set_current_limit,
|
||||
.get_current_limit = pv88090_get_current_limit,
|
||||
};
|
||||
|
||||
static struct regulator_ops pv88090_ldo_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
};
|
||||
|
||||
#define PV88090_BUCK(chip, regl_name, min, step, max, limits_array) \
|
||||
{\
|
||||
.desc = {\
|
||||
.id = chip##_ID_##regl_name,\
|
||||
.name = __stringify(chip##_##regl_name),\
|
||||
.of_match = of_match_ptr(#regl_name),\
|
||||
.regulators_node = of_match_ptr("regulators"),\
|
||||
.type = REGULATOR_VOLTAGE,\
|
||||
.owner = THIS_MODULE,\
|
||||
.ops = &pv88090_buck_ops,\
|
||||
.min_uV = min, \
|
||||
.uV_step = step, \
|
||||
.n_voltages = ((max) - (min))/(step) + 1, \
|
||||
.enable_reg = PV88090_REG_##regl_name##_CONF0, \
|
||||
.enable_mask = PV88090_##regl_name##_EN, \
|
||||
.vsel_reg = PV88090_REG_##regl_name##_CONF0, \
|
||||
.vsel_mask = PV88090_V##regl_name##_MASK, \
|
||||
},\
|
||||
.current_limits = limits_array, \
|
||||
.n_current_limits = ARRAY_SIZE(limits_array), \
|
||||
.limit_mask = PV88090_##regl_name##_ILIM_MASK, \
|
||||
.conf = PV88090_REG_##regl_name##_CONF1, \
|
||||
.conf2 = PV88090_REG_##regl_name##_CONF2, \
|
||||
}
|
||||
|
||||
#define PV88090_LDO(chip, regl_name, min, step, max) \
|
||||
{\
|
||||
.desc = {\
|
||||
.id = chip##_ID_##regl_name,\
|
||||
.name = __stringify(chip##_##regl_name),\
|
||||
.of_match = of_match_ptr(#regl_name),\
|
||||
.regulators_node = of_match_ptr("regulators"),\
|
||||
.type = REGULATOR_VOLTAGE,\
|
||||
.owner = THIS_MODULE,\
|
||||
.ops = &pv88090_ldo_ops,\
|
||||
.min_uV = min, \
|
||||
.uV_step = step, \
|
||||
.n_voltages = ((max) - (min))/(step) + 1, \
|
||||
.enable_reg = PV88090_REG_##regl_name##_CONT, \
|
||||
.enable_mask = PV88090_##regl_name##_EN, \
|
||||
.vsel_reg = PV88090_REG_##regl_name##_CONT, \
|
||||
.vsel_mask = PV88090_V##regl_name##_MASK, \
|
||||
},\
|
||||
}
|
||||
|
||||
static struct pv88090_regulator pv88090_regulator_info[] = {
|
||||
PV88090_BUCK(PV88090, BUCK1, 600000, 6250, 1393750,
|
||||
pv88090_buck1_limits),
|
||||
PV88090_BUCK(PV88090, BUCK2, 600000, 6250, 1393750,
|
||||
pv88090_buck23_limits),
|
||||
PV88090_BUCK(PV88090, BUCK3, 600000, 6250, 1393750,
|
||||
pv88090_buck23_limits),
|
||||
PV88090_LDO(PV88090, LDO1, 1200000, 50000, 4350000),
|
||||
PV88090_LDO(PV88090, LDO2, 650000, 25000, 2225000),
|
||||
};
|
||||
|
||||
static irqreturn_t pv88090_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct pv88090 *chip = data;
|
||||
int i, reg_val, err, ret = IRQ_NONE;
|
||||
|
||||
err = regmap_read(chip->regmap, PV88090_REG_EVENT_A, ®_val);
|
||||
if (err < 0)
|
||||
goto error_i2c;
|
||||
|
||||
if (reg_val & PV88090_E_VDD_FLT) {
|
||||
for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
|
||||
if (chip->rdev[i] != NULL) {
|
||||
regulator_notifier_call_chain(chip->rdev[i],
|
||||
REGULATOR_EVENT_UNDER_VOLTAGE,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
|
||||
PV88090_E_VDD_FLT, PV88090_E_VDD_FLT);
|
||||
if (err < 0)
|
||||
goto error_i2c;
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (reg_val & PV88090_E_OVER_TEMP) {
|
||||
for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
|
||||
if (chip->rdev[i] != NULL) {
|
||||
regulator_notifier_call_chain(chip->rdev[i],
|
||||
REGULATOR_EVENT_OVER_TEMP,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
|
||||
PV88090_E_OVER_TEMP, PV88090_E_OVER_TEMP);
|
||||
if (err < 0)
|
||||
goto error_i2c;
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error_i2c:
|
||||
dev_err(chip->dev, "I2C error : %d\n", err);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C driver interface functions
|
||||
*/
|
||||
static int pv88090_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
|
||||
struct pv88090 *chip;
|
||||
struct regulator_config config = { };
|
||||
int error, i, ret = 0;
|
||||
unsigned int conf2, range, index;
|
||||
|
||||
chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88090), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->dev = &i2c->dev;
|
||||
chip->regmap = devm_regmap_init_i2c(i2c, &pv88090_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
error = PTR_ERR(chip->regmap);
|
||||
dev_err(chip->dev, "Failed to allocate register map: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, chip);
|
||||
|
||||
if (i2c->irq != 0) {
|
||||
ret = regmap_write(chip->regmap, PV88090_REG_MASK_A, 0xFF);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to mask A reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(chip->regmap, PV88090_REG_MASK_B, 0xFF);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to mask B reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
|
||||
pv88090_irq_handler,
|
||||
IRQF_TRIGGER_LOW|IRQF_ONESHOT,
|
||||
"pv88090", chip);
|
||||
if (ret != 0) {
|
||||
dev_err(chip->dev, "Failed to request IRQ: %d\n",
|
||||
i2c->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(chip->regmap, PV88090_REG_MASK_A,
|
||||
PV88090_M_VDD_FLT | PV88090_M_OVER_TEMP, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to update mask reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} else {
|
||||
dev_warn(chip->dev, "No IRQ configured\n");
|
||||
}
|
||||
|
||||
config.dev = chip->dev;
|
||||
config.regmap = chip->regmap;
|
||||
|
||||
for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
|
||||
if (init_data)
|
||||
config.init_data = &init_data[i];
|
||||
|
||||
if (i == PV88090_ID_BUCK2 || i == PV88090_ID_BUCK3) {
|
||||
ret = regmap_read(chip->regmap,
|
||||
pv88090_regulator_info[i].conf2, &conf2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
conf2 = (conf2 >> PV88090_BUCK_VDAC_RANGE_SHIFT) &
|
||||
PV88090_BUCK_VDAC_RANGE_MASK;
|
||||
|
||||
ret = regmap_read(chip->regmap,
|
||||
PV88090_REG_BUCK_FOLD_RANGE, &range);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
range = (range >>
|
||||
(PV88080_BUCK_VRANGE_GAIN_SHIFT + i - 1)) &
|
||||
PV88080_BUCK_VRANGE_GAIN_MASK;
|
||||
index = ((range << 1) | conf2);
|
||||
|
||||
pv88090_regulator_info[i].desc.min_uV
|
||||
= pv88090_buck_vol[index].min_uV;
|
||||
pv88090_regulator_info[i].desc.uV_step
|
||||
= pv88090_buck_vol[index].uV_step;
|
||||
pv88090_regulator_info[i].desc.n_voltages
|
||||
= ((pv88090_buck_vol[index].max_uV)
|
||||
- (pv88090_buck_vol[index].min_uV))
|
||||
/(pv88090_buck_vol[index].uV_step) + 1;
|
||||
}
|
||||
|
||||
config.driver_data = (void *)&pv88090_regulator_info[i];
|
||||
chip->rdev[i] = devm_regulator_register(chip->dev,
|
||||
&pv88090_regulator_info[i].desc, &config);
|
||||
if (IS_ERR(chip->rdev[i])) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to register PV88090 regulator\n");
|
||||
return PTR_ERR(chip->rdev[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id pv88090_i2c_id[] = {
|
||||
{"pv88090", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pv88090_i2c_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pv88090_dt_ids[] = {
|
||||
{ .compatible = "pvs,pv88090", .data = &pv88090_i2c_id[0] },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pv88090_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver pv88090_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "pv88090",
|
||||
.of_match_table = of_match_ptr(pv88090_dt_ids),
|
||||
},
|
||||
.probe = pv88090_i2c_probe,
|
||||
.id_table = pv88090_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(pv88090_regulator_driver);
|
||||
|
||||
MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
|
||||
MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88090");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* pv88090-regulator.h - Regulator definitions for PV88090
|
||||
* Copyright (C) 2015 Powerventure Semiconductor Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __PV88090_REGISTERS_H__
|
||||
#define __PV88090_REGISTERS_H__
|
||||
|
||||
/* System Control and Event Registers */
|
||||
#define PV88090_REG_EVENT_A 0x03
|
||||
#define PV88090_REG_MASK_A 0x06
|
||||
#define PV88090_REG_MASK_B 0x07
|
||||
|
||||
/* Regulator Registers */
|
||||
#define PV88090_REG_BUCK1_CONF0 0x18
|
||||
#define PV88090_REG_BUCK1_CONF1 0x19
|
||||
#define PV88090_REG_BUCK1_CONF2 0x1a
|
||||
#define PV88090_REG_BUCK2_CONF0 0x1b
|
||||
#define PV88090_REG_BUCK2_CONF1 0x1c
|
||||
#define PV88090_REG_BUCK2_CONF2 0x58
|
||||
#define PV88090_REG_BUCK3_CONF0 0x1d
|
||||
#define PV88090_REG_BUCK3_CONF1 0x1e
|
||||
#define PV88090_REG_BUCK3_CONF2 0x5c
|
||||
|
||||
#define PV88090_REG_LDO1_CONT 0x1f
|
||||
#define PV88090_REG_LDO2_CONT 0x20
|
||||
#define PV88090_REG_LDO3_CONT 0x21
|
||||
#define PV88090_REG_BUCK_FOLD_RANGE 0x61
|
||||
|
||||
/* PV88090_REG_EVENT_A (addr=0x03) */
|
||||
#define PV88090_E_VDD_FLT 0x01
|
||||
#define PV88090_E_OVER_TEMP 0x02
|
||||
|
||||
/* PV88090_REG_MASK_A (addr=0x06) */
|
||||
#define PV88090_M_VDD_FLT 0x01
|
||||
#define PV88090_M_OVER_TEMP 0x02
|
||||
|
||||
/* PV88090_REG_BUCK1_CONF0 (addr=0x18) */
|
||||
#define PV88090_BUCK1_EN 0x80
|
||||
#define PV88090_VBUCK1_MASK 0x7F
|
||||
/* PV88090_REG_BUCK2_CONF0 (addr=0x1b) */
|
||||
#define PV88090_BUCK2_EN 0x80
|
||||
#define PV88090_VBUCK2_MASK 0x7F
|
||||
/* PV88090_REG_BUCK3_CONF0 (addr=0x1d) */
|
||||
#define PV88090_BUCK3_EN 0x80
|
||||
#define PV88090_VBUCK3_MASK 0x7F
|
||||
/* PV88090_REG_LDO1_CONT (addr=0x1f) */
|
||||
#define PV88090_LDO1_EN 0x40
|
||||
#define PV88090_VLDO1_MASK 0x3F
|
||||
/* PV88090_REG_LDO2_CONT (addr=0x20) */
|
||||
#define PV88090_LDO2_EN 0x40
|
||||
#define PV88090_VLDO2_MASK 0x3F
|
||||
|
||||
/* PV88090_REG_BUCK1_CONF1 (addr=0x19) */
|
||||
#define PV88090_BUCK1_ILIM_SHIFT 2
|
||||
#define PV88090_BUCK1_ILIM_MASK 0x7C
|
||||
#define PV88090_BUCK1_MODE_MASK 0x03
|
||||
|
||||
/* PV88090_REG_BUCK2_CONF1 (addr=0x1c) */
|
||||
#define PV88090_BUCK2_ILIM_SHIFT 2
|
||||
#define PV88090_BUCK2_ILIM_MASK 0x0C
|
||||
#define PV88090_BUCK2_MODE_MASK 0x03
|
||||
|
||||
/* PV88090_REG_BUCK3_CONF1 (addr=0x1e) */
|
||||
#define PV88090_BUCK3_ILIM_SHIFT 2
|
||||
#define PV88090_BUCK3_ILIM_MASK 0x0C
|
||||
#define PV88090_BUCK3_MODE_MASK 0x03
|
||||
|
||||
#define PV88090_BUCK_MODE_SLEEP 0x00
|
||||
#define PV88090_BUCK_MODE_AUTO 0x01
|
||||
#define PV88090_BUCK_MODE_SYNC 0x02
|
||||
|
||||
/* PV88090_REG_BUCK2_CONF2 (addr=0x58) */
|
||||
/* PV88090_REG_BUCK3_CONF2 (addr=0x5c) */
|
||||
#define PV88090_BUCK_VDAC_RANGE_SHIFT 7
|
||||
#define PV88090_BUCK_VDAC_RANGE_MASK 0x01
|
||||
|
||||
#define PV88090_BUCK_VDAC_RANGE_1 0x00
|
||||
#define PV88090_BUCK_VDAC_RANGE_2 0x01
|
||||
|
||||
/* PV88090_REG_BUCK_FOLD_RANGE (addr=0x61) */
|
||||
#define PV88080_BUCK_VRANGE_GAIN_SHIFT 3
|
||||
#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01
|
||||
|
||||
#define PV88080_BUCK_VRANGE_GAIN_1 0x00
|
||||
#define PV88080_BUCK_VRANGE_GAIN_2 0x01
|
||||
|
||||
#endif /* __PV88090_REGISTERS_H__ */
|
|
@ -153,6 +153,49 @@ static const struct regulator_ops rpm_switch_ops = {
|
|||
.is_enabled = rpm_reg_is_enabled,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pma8084_hfsmps = {
|
||||
.linear_ranges = (struct regulator_linear_range[]) {
|
||||
REGULATOR_LINEAR_RANGE(375000, 0, 95, 12500),
|
||||
REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000),
|
||||
},
|
||||
.n_linear_ranges = 2,
|
||||
.n_voltages = 159,
|
||||
.ops = &rpm_smps_ldo_ops,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pma8084_ftsmps = {
|
||||
.linear_ranges = (struct regulator_linear_range[]) {
|
||||
REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000),
|
||||
REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000),
|
||||
},
|
||||
.n_linear_ranges = 2,
|
||||
.n_voltages = 340,
|
||||
.ops = &rpm_smps_ldo_ops,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pma8084_pldo = {
|
||||
.linear_ranges = (struct regulator_linear_range[]) {
|
||||
REGULATOR_LINEAR_RANGE(750000, 0, 30, 25000),
|
||||
REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000),
|
||||
},
|
||||
.n_linear_ranges = 2,
|
||||
.n_voltages = 100,
|
||||
.ops = &rpm_smps_ldo_ops,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pma8084_nldo = {
|
||||
.linear_ranges = (struct regulator_linear_range[]) {
|
||||
REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500),
|
||||
},
|
||||
.n_linear_ranges = 1,
|
||||
.n_voltages = 64,
|
||||
.ops = &rpm_smps_ldo_ops,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pma8084_switch = {
|
||||
.ops = &rpm_switch_ops,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pm8x41_hfsmps = {
|
||||
.linear_ranges = (struct regulator_linear_range[]) {
|
||||
REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500),
|
||||
|
@ -211,6 +254,43 @@ static const struct regulator_desc pm8941_switch = {
|
|||
.ops = &rpm_switch_ops,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pm8916_pldo = {
|
||||
.linear_ranges = (struct regulator_linear_range[]) {
|
||||
REGULATOR_LINEAR_RANGE(750000, 0, 208, 12500),
|
||||
},
|
||||
.n_linear_ranges = 1,
|
||||
.n_voltages = 209,
|
||||
.ops = &rpm_smps_ldo_ops,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pm8916_nldo = {
|
||||
.linear_ranges = (struct regulator_linear_range[]) {
|
||||
REGULATOR_LINEAR_RANGE(375000, 0, 93, 12500),
|
||||
},
|
||||
.n_linear_ranges = 1,
|
||||
.n_voltages = 94,
|
||||
.ops = &rpm_smps_ldo_ops,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pm8916_buck_lvo_smps = {
|
||||
.linear_ranges = (struct regulator_linear_range[]) {
|
||||
REGULATOR_LINEAR_RANGE(375000, 0, 95, 12500),
|
||||
REGULATOR_LINEAR_RANGE(750000, 96, 127, 25000),
|
||||
},
|
||||
.n_linear_ranges = 2,
|
||||
.n_voltages = 128,
|
||||
.ops = &rpm_smps_ldo_ops,
|
||||
};
|
||||
|
||||
static const struct regulator_desc pm8916_buck_hvo_smps = {
|
||||
.linear_ranges = (struct regulator_linear_range[]) {
|
||||
REGULATOR_LINEAR_RANGE(1550000, 0, 31, 25000),
|
||||
},
|
||||
.n_linear_ranges = 1,
|
||||
.n_voltages = 32,
|
||||
.ops = &rpm_smps_ldo_ops,
|
||||
};
|
||||
|
||||
struct rpm_regulator_data {
|
||||
const char *name;
|
||||
u32 type;
|
||||
|
@ -231,6 +311,32 @@ static const struct rpm_regulator_data rpm_pm8841_regulators[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static const struct rpm_regulator_data rpm_pm8916_regulators[] = {
|
||||
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pm8916_buck_lvo_smps, "vdd_s1" },
|
||||
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pm8916_buck_lvo_smps, "vdd_s2" },
|
||||
{ "s3", QCOM_SMD_RPM_SMPA, 3, &pm8916_buck_lvo_smps, "vdd_s3" },
|
||||
{ "s4", QCOM_SMD_RPM_SMPA, 4, &pm8916_buck_hvo_smps, "vdd_s4" },
|
||||
{ "l1", QCOM_SMD_RPM_LDOA, 1, &pm8916_nldo, "vdd_l1_l2_l3" },
|
||||
{ "l2", QCOM_SMD_RPM_LDOA, 2, &pm8916_nldo, "vdd_l1_l2_l3" },
|
||||
{ "l3", QCOM_SMD_RPM_LDOA, 3, &pm8916_nldo, "vdd_l1_l2_l3" },
|
||||
{ "l4", QCOM_SMD_RPM_LDOA, 4, &pm8916_pldo, "vdd_l4_l5_l6" },
|
||||
{ "l5", QCOM_SMD_RPM_LDOA, 5, &pm8916_pldo, "vdd_l4_l5_l6" },
|
||||
{ "l6", QCOM_SMD_RPM_LDOA, 6, &pm8916_pldo, "vdd_l4_l5_l6" },
|
||||
{ "l7", QCOM_SMD_RPM_LDOA, 7, &pm8916_pldo, "vdd_l7" },
|
||||
{ "l8", QCOM_SMD_RPM_LDOA, 8, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18" },
|
||||
{ "l9", QCOM_SMD_RPM_LDOA, 9, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18" },
|
||||
{ "l10", QCOM_SMD_RPM_LDOA, 10, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
|
||||
{ "l11", QCOM_SMD_RPM_LDOA, 11, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
|
||||
{ "l12", QCOM_SMD_RPM_LDOA, 12, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
|
||||
{ "l13", QCOM_SMD_RPM_LDOA, 13, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
|
||||
{ "l14", QCOM_SMD_RPM_LDOA, 14, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
|
||||
{ "l15", QCOM_SMD_RPM_LDOA, 15, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
|
||||
{ "l16", QCOM_SMD_RPM_LDOA, 16, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
|
||||
{ "l17", QCOM_SMD_RPM_LDOA, 17, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
|
||||
{ "l18", QCOM_SMD_RPM_LDOA, 18, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
|
||||
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" },
|
||||
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" },
|
||||
|
@ -272,9 +378,62 @@ static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static const struct rpm_regulator_data rpm_pma8084_regulators[] = {
|
||||
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pma8084_ftsmps, "vdd_s1" },
|
||||
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pma8084_ftsmps, "vdd_s2" },
|
||||
{ "s3", QCOM_SMD_RPM_SMPA, 3, &pma8084_hfsmps, "vdd_s3" },
|
||||
{ "s4", QCOM_SMD_RPM_SMPA, 4, &pma8084_hfsmps, "vdd_s4" },
|
||||
{ "s5", QCOM_SMD_RPM_SMPA, 5, &pma8084_hfsmps, "vdd_s5" },
|
||||
{ "s6", QCOM_SMD_RPM_SMPA, 6, &pma8084_ftsmps, "vdd_s6" },
|
||||
{ "s7", QCOM_SMD_RPM_SMPA, 7, &pma8084_ftsmps, "vdd_s7" },
|
||||
{ "s8", QCOM_SMD_RPM_SMPA, 8, &pma8084_ftsmps, "vdd_s8" },
|
||||
{ "s9", QCOM_SMD_RPM_SMPA, 9, &pma8084_ftsmps, "vdd_s9" },
|
||||
{ "s10", QCOM_SMD_RPM_SMPA, 10, &pma8084_ftsmps, "vdd_s10" },
|
||||
{ "s11", QCOM_SMD_RPM_SMPA, 11, &pma8084_ftsmps, "vdd_s11" },
|
||||
{ "s12", QCOM_SMD_RPM_SMPA, 12, &pma8084_ftsmps, "vdd_s12" },
|
||||
|
||||
{ "l1", QCOM_SMD_RPM_LDOA, 1, &pma8084_nldo, "vdd_l1_l11" },
|
||||
{ "l2", QCOM_SMD_RPM_LDOA, 2, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
|
||||
{ "l3", QCOM_SMD_RPM_LDOA, 3, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
|
||||
{ "l4", QCOM_SMD_RPM_LDOA, 4, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
|
||||
{ "l5", QCOM_SMD_RPM_LDOA, 5, &pma8084_pldo, "vdd_l5_l7" },
|
||||
{ "l6", QCOM_SMD_RPM_LDOA, 6, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
|
||||
{ "l7", QCOM_SMD_RPM_LDOA, 7, &pma8084_pldo, "vdd_l5_l7" },
|
||||
{ "l8", QCOM_SMD_RPM_LDOA, 8, &pma8084_pldo, "vdd_l8" },
|
||||
{ "l9", QCOM_SMD_RPM_LDOA, 9, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
|
||||
{ "l10", QCOM_SMD_RPM_LDOA, 10, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
|
||||
{ "l11", QCOM_SMD_RPM_LDOA, 11, &pma8084_nldo, "vdd_l1_l11" },
|
||||
{ "l12", QCOM_SMD_RPM_LDOA, 12, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
|
||||
{ "l13", QCOM_SMD_RPM_LDOA, 13, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
|
||||
{ "l14", QCOM_SMD_RPM_LDOA, 14, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
|
||||
{ "l15", QCOM_SMD_RPM_LDOA, 15, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
|
||||
{ "l16", QCOM_SMD_RPM_LDOA, 16, &pma8084_pldo, "vdd_l16_l25" },
|
||||
{ "l17", QCOM_SMD_RPM_LDOA, 17, &pma8084_pldo, "vdd_l17" },
|
||||
{ "l18", QCOM_SMD_RPM_LDOA, 18, &pma8084_pldo, "vdd_l18" },
|
||||
{ "l19", QCOM_SMD_RPM_LDOA, 19, &pma8084_pldo, "vdd_l19" },
|
||||
{ "l20", QCOM_SMD_RPM_LDOA, 20, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
|
||||
{ "l21", QCOM_SMD_RPM_LDOA, 21, &pma8084_pldo, "vdd_l21" },
|
||||
{ "l22", QCOM_SMD_RPM_LDOA, 22, &pma8084_pldo, "vdd_l22" },
|
||||
{ "l23", QCOM_SMD_RPM_LDOA, 23, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
|
||||
{ "l24", QCOM_SMD_RPM_LDOA, 24, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
|
||||
{ "l25", QCOM_SMD_RPM_LDOA, 25, &pma8084_pldo, "vdd_l16_l25" },
|
||||
{ "l26", QCOM_SMD_RPM_LDOA, 26, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
|
||||
{ "l27", QCOM_SMD_RPM_LDOA, 27, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
|
||||
|
||||
{ "lvs1", QCOM_SMD_RPM_VSA, 1, &pma8084_switch },
|
||||
{ "lvs2", QCOM_SMD_RPM_VSA, 2, &pma8084_switch },
|
||||
{ "lvs3", QCOM_SMD_RPM_VSA, 3, &pma8084_switch },
|
||||
{ "lvs4", QCOM_SMD_RPM_VSA, 4, &pma8084_switch },
|
||||
{ "5vs1", QCOM_SMD_RPM_VSA, 5, &pma8084_switch },
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct of_device_id rpm_of_match[] = {
|
||||
{ .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
|
||||
{ .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
|
||||
{ .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
|
||||
{ .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rpm_of_match);
|
||||
|
|
|
@ -27,90 +27,12 @@ static const unsigned int tps6105x_voltages[] = {
|
|||
5000000, /* There is an additional 5V */
|
||||
};
|
||||
|
||||
static int tps6105x_regulator_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
/* Activate voltage mode */
|
||||
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_MODE_MASK,
|
||||
TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps6105x_regulator_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
/* Set into shutdown mode */
|
||||
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_MODE_MASK,
|
||||
TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
regval &= TPS6105X_REG0_MODE_MASK;
|
||||
regval >>= TPS6105X_REG0_MODE_SHIFT;
|
||||
|
||||
if (regval == TPS6105X_REG0_MODE_VOLTAGE)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regval &= TPS6105X_REG0_VOLTAGE_MASK;
|
||||
regval >>= TPS6105X_REG0_VOLTAGE_SHIFT;
|
||||
return (int) regval;
|
||||
}
|
||||
|
||||
static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_VOLTAGE_MASK,
|
||||
selector << TPS6105X_REG0_VOLTAGE_SHIFT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regulator_ops tps6105x_regulator_ops = {
|
||||
.enable = tps6105x_regulator_enable,
|
||||
.disable = tps6105x_regulator_disable,
|
||||
.is_enabled = tps6105x_regulator_is_enabled,
|
||||
.get_voltage_sel = tps6105x_regulator_get_voltage_sel,
|
||||
.set_voltage_sel = tps6105x_regulator_set_voltage_sel,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_table,
|
||||
};
|
||||
|
||||
|
@ -122,6 +44,12 @@ static const struct regulator_desc tps6105x_regulator_desc = {
|
|||
.owner = THIS_MODULE,
|
||||
.n_voltages = ARRAY_SIZE(tps6105x_voltages),
|
||||
.volt_table = tps6105x_voltages,
|
||||
.vsel_reg = TPS6105X_REG_0,
|
||||
.vsel_mask = TPS6105X_REG0_VOLTAGE_MASK,
|
||||
.enable_reg = TPS6105X_REG_0,
|
||||
.enable_mask = TPS6105X_REG0_MODE_MASK,
|
||||
.enable_val = TPS6105X_REG0_MODE_VOLTAGE <<
|
||||
TPS6105X_REG0_MODE_SHIFT,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -144,6 +72,7 @@ static int tps6105x_regulator_probe(struct platform_device *pdev)
|
|||
config.dev = &tps6105x->client->dev;
|
||||
config.init_data = pdata->regulator_data;
|
||||
config.driver_data = tps6105x;
|
||||
config.regmap = tps6105x->regmap;
|
||||
|
||||
/* Register regulator with framework */
|
||||
tps6105x->regulator = devm_regulator_register(&pdev->dev,
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* Author: Andrew F. Davis <afd@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether expressed or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License version 2 for more details.
|
||||
*
|
||||
* Based on the TPS65912 driver
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
|
||||
#include <linux/mfd/tps65086.h>
|
||||
|
||||
enum tps65086_regulators { BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, LDOA1,
|
||||
LDOA2, LDOA3, SWA1, SWB1, SWB2, VTT };
|
||||
|
||||
#define TPS65086_REGULATOR(_name, _of, _id, _nv, _vr, _vm, _er, _em, _lr, _dr, _dm) \
|
||||
[_id] = { \
|
||||
.desc = { \
|
||||
.name = _name, \
|
||||
.of_match = of_match_ptr(_of), \
|
||||
.regulators_node = "regulators", \
|
||||
.of_parse_cb = tps65086_of_parse_cb, \
|
||||
.id = _id, \
|
||||
.ops = ®_ops, \
|
||||
.n_voltages = _nv, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.vsel_reg = _vr, \
|
||||
.vsel_mask = _vm, \
|
||||
.enable_reg = _er, \
|
||||
.enable_mask = _em, \
|
||||
.volt_table = NULL, \
|
||||
.linear_ranges = _lr, \
|
||||
.n_linear_ranges = ARRAY_SIZE(_lr), \
|
||||
}, \
|
||||
.decay_reg = _dr, \
|
||||
.decay_mask = _dm, \
|
||||
}
|
||||
|
||||
#define TPS65086_SWITCH(_name, _of, _id, _er, _em) \
|
||||
[_id] = { \
|
||||
.desc = { \
|
||||
.name = _name, \
|
||||
.of_match = of_match_ptr(_of), \
|
||||
.regulators_node = "regulators", \
|
||||
.of_parse_cb = tps65086_of_parse_cb, \
|
||||
.id = _id, \
|
||||
.ops = &switch_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.enable_reg = _er, \
|
||||
.enable_mask = _em, \
|
||||
}, \
|
||||
}
|
||||
|
||||
struct tps65086_regulator {
|
||||
struct regulator_desc desc;
|
||||
unsigned int decay_reg;
|
||||
unsigned int decay_mask;
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range tps65086_buck126_10mv_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
|
||||
REGULATOR_LINEAR_RANGE(410000, 0x1, 0x7F, 10000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range tps65086_buck126_25mv_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
|
||||
REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x18, 0),
|
||||
REGULATOR_LINEAR_RANGE(1025000, 0x19, 0x7F, 25000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range tps65086_buck345_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
|
||||
REGULATOR_LINEAR_RANGE(425000, 0x1, 0x7F, 25000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range tps65086_ldoa1_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(1350000, 0x0, 0x0, 0),
|
||||
REGULATOR_LINEAR_RANGE(1500000, 0x1, 0x7, 100000),
|
||||
REGULATOR_LINEAR_RANGE(2300000, 0x8, 0xA, 100000),
|
||||
REGULATOR_LINEAR_RANGE(2700000, 0xB, 0xD, 150000),
|
||||
REGULATOR_LINEAR_RANGE(3300000, 0xE, 0xE, 0),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range tps65086_ldoa23_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(700000, 0x0, 0xD, 50000),
|
||||
REGULATOR_LINEAR_RANGE(1400000, 0xE, 0xF, 100000),
|
||||
};
|
||||
|
||||
/* Operations permitted on regulators */
|
||||
static struct regulator_ops reg_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
};
|
||||
|
||||
/* Operations permitted on load switches */
|
||||
static struct regulator_ops switch_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
};
|
||||
|
||||
static int tps65086_of_parse_cb(struct device_node *dev,
|
||||
const struct regulator_desc *desc,
|
||||
struct regulator_config *config);
|
||||
|
||||
static struct tps65086_regulator regulators[] = {
|
||||
TPS65086_REGULATOR("BUCK1", "buck1", BUCK1, 0x80, TPS65086_BUCK1CTRL,
|
||||
BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(0),
|
||||
tps65086_buck126_10mv_ranges, TPS65086_BUCK1CTRL,
|
||||
BIT(0)),
|
||||
TPS65086_REGULATOR("BUCK2", "buck2", BUCK2, 0x80, TPS65086_BUCK2CTRL,
|
||||
BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(1),
|
||||
tps65086_buck126_10mv_ranges, TPS65086_BUCK2CTRL,
|
||||
BIT(0)),
|
||||
TPS65086_REGULATOR("BUCK3", "buck3", BUCK3, 0x80, TPS65086_BUCK3VID,
|
||||
BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(2),
|
||||
tps65086_buck345_ranges, TPS65086_BUCK3DECAY,
|
||||
BIT(0)),
|
||||
TPS65086_REGULATOR("BUCK4", "buck4", BUCK4, 0x80, TPS65086_BUCK4VID,
|
||||
BUCK_VID_MASK, TPS65086_BUCK4CTRL, BIT(0),
|
||||
tps65086_buck345_ranges, TPS65086_BUCK4VID,
|
||||
BIT(0)),
|
||||
TPS65086_REGULATOR("BUCK5", "buck5", BUCK5, 0x80, TPS65086_BUCK5VID,
|
||||
BUCK_VID_MASK, TPS65086_BUCK5CTRL, BIT(0),
|
||||
tps65086_buck345_ranges, TPS65086_BUCK5CTRL,
|
||||
BIT(0)),
|
||||
TPS65086_REGULATOR("BUCK6", "buck6", BUCK6, 0x80, TPS65086_BUCK6VID,
|
||||
BUCK_VID_MASK, TPS65086_BUCK6CTRL, BIT(0),
|
||||
tps65086_buck126_10mv_ranges, TPS65086_BUCK6CTRL,
|
||||
BIT(0)),
|
||||
TPS65086_REGULATOR("LDOA1", "ldoa1", LDOA1, 0xF, TPS65086_LDOA1CTRL,
|
||||
VDOA1_VID_MASK, TPS65086_LDOA1CTRL, BIT(0),
|
||||
tps65086_ldoa1_ranges, 0, 0),
|
||||
TPS65086_REGULATOR("LDOA2", "ldoa2", LDOA2, 0x10, TPS65086_LDOA2VID,
|
||||
VDOA23_VID_MASK, TPS65086_LDOA2CTRL, BIT(0),
|
||||
tps65086_ldoa23_ranges, 0, 0),
|
||||
TPS65086_REGULATOR("LDOA3", "ldoa3", LDOA3, 0x10, TPS65086_LDOA3VID,
|
||||
VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
|
||||
tps65086_ldoa23_ranges, 0, 0),
|
||||
TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
|
||||
TPS65086_SWITCH("SWB1", "swa2", SWB1, TPS65086_SWVTT_EN, BIT(6)),
|
||||
TPS65086_SWITCH("SWB2", "swa3", SWB2, TPS65086_SWVTT_EN, BIT(7)),
|
||||
TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
|
||||
};
|
||||
|
||||
static inline bool has_25mv_mode(int id)
|
||||
{
|
||||
switch (id) {
|
||||
case BUCK1:
|
||||
case BUCK2:
|
||||
case BUCK6:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int tps65086_of_parse_cb(struct device_node *dev,
|
||||
const struct regulator_desc *desc,
|
||||
struct regulator_config *config)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check for 25mV step mode */
|
||||
if (has_25mv_mode(desc->id) &&
|
||||
of_property_read_bool(config->of_node, "ti,regulator-step-size-25mv")) {
|
||||
regulators[desc->id].desc.linear_ranges =
|
||||
tps65086_buck126_25mv_ranges;
|
||||
regulators[desc->id].desc.n_linear_ranges =
|
||||
ARRAY_SIZE(tps65086_buck126_25mv_ranges);
|
||||
}
|
||||
|
||||
/* Check for decay mode */
|
||||
if (desc->id <= BUCK6 && of_property_read_bool(config->of_node, "ti,regulator-decay")) {
|
||||
ret = regmap_write_bits(config->regmap,
|
||||
regulators[desc->id].decay_reg,
|
||||
regulators[desc->id].decay_mask,
|
||||
regulators[desc->id].decay_mask);
|
||||
if (ret) {
|
||||
dev_err(config->dev, "Error setting decay\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65086_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps65086 *tps = dev_get_drvdata(pdev->dev.parent);
|
||||
struct regulator_config config = { };
|
||||
struct regulator_dev *rdev;
|
||||
int i;
|
||||
|
||||
platform_set_drvdata(pdev, tps);
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.dev->of_node = tps->dev->of_node;
|
||||
config.driver_data = tps;
|
||||
config.regmap = tps->regmap;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
|
||||
rdev = devm_regulator_register(&pdev->dev, ®ulators[i].desc,
|
||||
&config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(tps->dev, "failed to register %s regulator\n",
|
||||
pdev->name);
|
||||
return PTR_ERR(rdev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id tps65086_regulator_id_table[] = {
|
||||
{ "tps65086-regulator", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, tps65086_regulator_id_table);
|
||||
|
||||
static struct platform_driver tps65086_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "tps65086-regulator",
|
||||
},
|
||||
.probe = tps65086_regulator_probe,
|
||||
.id_table = tps65086_regulator_id_table,
|
||||
};
|
||||
module_platform_driver(tps65086_regulator_driver);
|
||||
|
||||
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
|
||||
MODULE_DESCRIPTION("TPS65086 Regulator driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -27,19 +27,22 @@
|
|||
#include <linux/regulator/machine.h>
|
||||
#include <linux/mfd/tps65218.h>
|
||||
|
||||
enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 };
|
||||
enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
|
||||
DCDC5, DCDC6, LDO1, LS3 };
|
||||
|
||||
#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, \
|
||||
_lr, _nlr, _delay, _fuv) \
|
||||
#define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \
|
||||
_cr, _cm, _lr, _nlr, _delay, _fuv) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.id = _id, \
|
||||
.ops = &_ops, \
|
||||
.n_voltages = _n, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.type = _type, \
|
||||
.owner = THIS_MODULE, \
|
||||
.vsel_reg = _vr, \
|
||||
.vsel_mask = _vm, \
|
||||
.csel_reg = _cr, \
|
||||
.csel_mask = _cm, \
|
||||
.enable_reg = _er, \
|
||||
.enable_mask = _em, \
|
||||
.volt_table = NULL, \
|
||||
|
@ -80,6 +83,7 @@ static struct tps_info tps65218_pmic_regs[] = {
|
|||
TPS65218_INFO(DCDC5, "DCDC5", 1000000, 1000000),
|
||||
TPS65218_INFO(DCDC6, "DCDC6", 1800000, 1800000),
|
||||
TPS65218_INFO(LDO1, "LDO1", 900000, 3400000),
|
||||
TPS65218_INFO(LS3, "LS3", -1, -1),
|
||||
};
|
||||
|
||||
#define TPS65218_OF_MATCH(comp, label) \
|
||||
|
@ -96,6 +100,7 @@ static const struct of_device_id tps65218_of_match[] = {
|
|||
TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]),
|
||||
TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]),
|
||||
TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]),
|
||||
TPS65218_OF_MATCH("ti,tps65218-ls3", tps65218_pmic_regs[LS3]),
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tps65218_of_match);
|
||||
|
@ -175,6 +180,68 @@ static struct regulator_ops tps65218_ldo1_dcdc34_ops = {
|
|||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
};
|
||||
|
||||
static const int ls3_currents[] = { 100, 200, 500, 1000 };
|
||||
|
||||
static int tps65218_pmic_set_input_current_lim(struct regulator_dev *dev,
|
||||
int lim_uA)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
unsigned int num_currents = ARRAY_SIZE(ls3_currents);
|
||||
struct tps65218 *tps = rdev_get_drvdata(dev);
|
||||
|
||||
while (index < num_currents && ls3_currents[index] != lim_uA)
|
||||
index++;
|
||||
|
||||
if (index == num_currents)
|
||||
return -EINVAL;
|
||||
|
||||
return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask,
|
||||
index << 2, TPS65218_PROTECT_L1);
|
||||
}
|
||||
|
||||
static int tps65218_pmic_set_current_limit(struct regulator_dev *dev,
|
||||
int min_uA, int max_uA)
|
||||
{
|
||||
int index = 0;
|
||||
unsigned int num_currents = ARRAY_SIZE(ls3_currents);
|
||||
struct tps65218 *tps = rdev_get_drvdata(dev);
|
||||
|
||||
while (index < num_currents && ls3_currents[index] < max_uA)
|
||||
index++;
|
||||
|
||||
index--;
|
||||
|
||||
if (index < 0 || ls3_currents[index] < min_uA)
|
||||
return -EINVAL;
|
||||
|
||||
return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask,
|
||||
index << 2, TPS65218_PROTECT_L1);
|
||||
}
|
||||
|
||||
static int tps65218_pmic_get_current_limit(struct regulator_dev *dev)
|
||||
{
|
||||
int retval;
|
||||
unsigned int index;
|
||||
struct tps65218 *tps = rdev_get_drvdata(dev);
|
||||
|
||||
retval = tps65218_reg_read(tps, dev->desc->csel_reg, &index);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
index = (index & dev->desc->csel_mask) >> 2;
|
||||
|
||||
return ls3_currents[index];
|
||||
}
|
||||
|
||||
static struct regulator_ops tps65218_ls3_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = tps65218_pmic_enable,
|
||||
.disable = tps65218_pmic_disable,
|
||||
.set_input_current_limit = tps65218_pmic_set_input_current_lim,
|
||||
.set_current_limit = tps65218_pmic_set_current_limit,
|
||||
.get_current_limit = tps65218_pmic_get_current_limit,
|
||||
};
|
||||
|
||||
/* Operations permitted on DCDC5, DCDC6 */
|
||||
static struct regulator_ops tps65218_dcdc56_pmic_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
|
@ -183,36 +250,46 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = {
|
|||
};
|
||||
|
||||
static const struct regulator_desc regulators[] = {
|
||||
TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, tps65218_dcdc12_ops, 64,
|
||||
TPS65218_REG_CONTROL_DCDC1,
|
||||
TPS65218_CONTROL_DCDC1_MASK,
|
||||
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN,
|
||||
dcdc1_dcdc2_ranges, 2, 4000, 0),
|
||||
TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, tps65218_dcdc12_ops, 64,
|
||||
TPS65218_REG_CONTROL_DCDC2,
|
||||
TPS65218_CONTROL_DCDC2_MASK,
|
||||
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN,
|
||||
dcdc1_dcdc2_ranges, 2, 4000, 0),
|
||||
TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops,
|
||||
64, TPS65218_REG_CONTROL_DCDC3,
|
||||
TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, REGULATOR_VOLTAGE,
|
||||
tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1,
|
||||
TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1,
|
||||
TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges,
|
||||
2, 4000, 0),
|
||||
TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE,
|
||||
tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2,
|
||||
TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1,
|
||||
TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges,
|
||||
2, 4000, 0),
|
||||
TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE,
|
||||
tps65218_ldo1_dcdc34_ops, 64,
|
||||
TPS65218_REG_CONTROL_DCDC3,
|
||||
TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
|
||||
TPS65218_ENABLE1_DC3_EN, ldo1_dcdc3_ranges, 2, 0, 0),
|
||||
TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, tps65218_ldo1_dcdc34_ops,
|
||||
53, TPS65218_REG_CONTROL_DCDC4,
|
||||
TPS65218_CONTROL_DCDC4_MASK,
|
||||
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN,
|
||||
dcdc4_ranges, 2, 0, 0),
|
||||
TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops,
|
||||
1, -1, -1, TPS65218_REG_ENABLE1,
|
||||
TPS65218_ENABLE1_DC5_EN, NULL, 0, 0, 1000000),
|
||||
TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops,
|
||||
1, -1, -1, TPS65218_REG_ENABLE1,
|
||||
TPS65218_ENABLE1_DC6_EN, NULL, 0, 0, 1800000),
|
||||
TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64,
|
||||
TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2,
|
||||
0, 0),
|
||||
TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE,
|
||||
tps65218_ldo1_dcdc34_ops, 53,
|
||||
TPS65218_REG_CONTROL_DCDC4,
|
||||
TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1,
|
||||
TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2,
|
||||
0, 0),
|
||||
TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE,
|
||||
tps65218_dcdc56_pmic_ops, 1, -1, -1,
|
||||
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0,
|
||||
NULL, 0, 0, 1000000),
|
||||
TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE,
|
||||
tps65218_dcdc56_pmic_ops, 1, -1, -1,
|
||||
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0,
|
||||
NULL, 0, 0, 1800000),
|
||||
TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE,
|
||||
tps65218_ldo1_dcdc34_ops, 64,
|
||||
TPS65218_REG_CONTROL_LDO1,
|
||||
TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
|
||||
TPS65218_ENABLE2_LDO1_EN, ldo1_dcdc3_ranges,
|
||||
TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges,
|
||||
2, 0, 0),
|
||||
TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT,
|
||||
tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2,
|
||||
TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2,
|
||||
TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0),
|
||||
};
|
||||
|
||||
static int tps65218_regulator_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -200,6 +200,8 @@ enum tps65218_regulator_id {
|
|||
TPS65218_DCDC_4,
|
||||
TPS65218_DCDC_5,
|
||||
TPS65218_DCDC_6,
|
||||
/* LS's */
|
||||
TPS65218_LS_3,
|
||||
/* LDOs */
|
||||
TPS65218_LDO_1,
|
||||
};
|
||||
|
@ -210,8 +212,11 @@ enum tps65218_regulator_id {
|
|||
#define TPS65218_NUM_DCDC 6
|
||||
/* Number of LDO voltage regulators available */
|
||||
#define TPS65218_NUM_LDO 1
|
||||
/* Number of total LS current regulators available */
|
||||
#define TPS65218_NUM_LS 1
|
||||
/* Number of total regulators available */
|
||||
#define TPS65218_NUM_REGULATOR (TPS65218_NUM_DCDC + TPS65218_NUM_LDO)
|
||||
#define TPS65218_NUM_REGULATOR (TPS65218_NUM_DCDC + TPS65218_NUM_LDO \
|
||||
+ TPS65218_NUM_LS)
|
||||
|
||||
/* Define the TPS65218 IRQ numbers */
|
||||
enum tps65218_irqs {
|
||||
|
|
|
@ -302,6 +302,8 @@ struct regulator_desc {
|
|||
|
||||
unsigned int vsel_reg;
|
||||
unsigned int vsel_mask;
|
||||
unsigned int csel_reg;
|
||||
unsigned int csel_mask;
|
||||
unsigned int apply_reg;
|
||||
unsigned int apply_bit;
|
||||
unsigned int enable_reg;
|
||||
|
|
Loading…
Reference in New Issue