提交 555f8160 编写于 作者: L Linus Torvalds

Merge tag 'regulator-v4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator

Pull regulator updates from Mark Brown:
 "This has been an extremely quiet release for the regulator API, aside
  from bugfixes and small enhancements the only thing that really stands
  out are the new drivers for Action Semiconductors ACT8945A, HiSilicon
  HI665x, and the Maxim MAX20024 and MAX77620"

* tag 'regulator-v4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (46 commits)
  regulator: pwm: Add support to have multiple instance of pwm regulator
  regulator: pwm: Fix calculation of voltage-to-duty cycle
  regulator: of: Use of_property_read_u32() for reading min/max
  regulator: pv88060: fix incorrect clear of event register
  regulator: pv88090: fix incorrect clear of event register
  regulator: max77620: Add support to configure active-discharge
  regulator: core: Add support for active-discharge configuration
  regulator: helper: Add helper to configure active-discharge using regmap
  regulator: core: Add support for active-discharge configuration
  regulator: DT: Add DT property for active-discharge configuration
  regulator: act8865: Specify fixed voltage of 3.3V for ACT8600's REG9
  regulator: act8865: Rename platform_data field to init_data
  regulator: act8865: Remove "static" from local variable
  ASoC: cs4271: add regulator consumer support
  regulator: max77620: Remove duplicate module alias
  regulator: max77620: Eliminate duplicate code
  regulator: max77620: Remove unused fields
  regulator: core: fix crash in error path of regulator_register
  regulator: core: Request GPIO before creating sysfs entries
  regulator: gpio: don't print error on EPROBE_DEFER
  ...
Device-Tree bindings for regulators of Active-semi ACT8945A Multi-Function Device
Required properties:
- compatible: "active-semi,act8945a", please refer to ../mfd/act8945a.txt.
Optional properties:
- active-semi,vsel-high: Indicates if the VSEL pin is set to logic-high.
If this property is missing, assume the VSEL pin is set to logic-low.
Optional input supply properties:
- vp1-supply: The input supply for REG_DCDC1
- vp2-supply: The input supply for REG_DCDC2
- vp3-supply: The input supply for REG_DCDC3
- inl45-supply: The input supply for REG_LDO1 and REG_LDO2
- inl67-supply: The input supply for REG_LDO3 and REG_LDO4
Any standard regulator properties can be used to configure the single regulator.
The valid names for regulators are:
REG_DCDC1, REG_DCDC2, REG_DCDC3, REG_LDO1, REG_LDO2, REG_LDO3, REG_LDO4.
Example:
pmic@5b {
compatible = "active-semi,act8945a";
reg = <0x5b>;
status = "okay";
active-semi,vsel-high;
regulators {
vdd_1v35_reg: REG_DCDC1 {
regulator-name = "VDD_1V35";
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
};
vdd_1v2_reg: REG_DCDC2 {
regulator-name = "VDD_1V2";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1300000>;
regulator-always-on;
};
vdd_3v3_reg: REG_DCDC3 {
regulator-name = "VDD_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
vdd_fuse_reg: REG_LDO1 {
regulator-name = "VDD_FUSE";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <2500000>;
regulator-always-on;
};
vdd_3v3_lp_reg: REG_LDO2 {
regulator-name = "VDD_3V3_LP";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
vdd_led_reg: REG_LDO3 {
regulator-name = "VDD_LED";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
vdd_sdhc_1v8_reg: REG_LDO4 {
regulator-name = "VDD_SDHC_1V8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
};
};
Hisilicon Hi655x Voltage regulators
Note:
The Hi655x regulator control is managed by Hi655x PMIC.
So the node of this regulator must be child node of Hi655x
PMIC node.
The driver uses the regulator core framework, so please also
take the bindings of regulator.txt for reference.
The valid names for regulators are:
LDO2_2V8 LDO7_SDIO LDO10_2V85 LDO13_1V8 LDO14_2V8
LDO15_1V8 LDO17_2V5 LDO19_3V0 LDO21_1V8 LDO22_1V2
Example:
pmic: pmic@f8000000 {
compatible = "hisilicon,hi655x-pmic";
...
regulators {
ldo2: LDO2@a21 {
regulator-name = "LDO2_2V8";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <3200000>;
regulator-enable-ramp-delay = <120>;
};
...
}
}
......@@ -28,6 +28,7 @@ Optional properties:
- ti,dvs-gpio: GPIO specifier for external DVS pin control of LP872x devices.
- ti,dvs-vsel: DVS selector. 0 = SEL_V1, 1 = SEL_V2.
- ti,dvs-state: initial DVS pin state. 0 = DVS_LOW, 1 = DVS_HIGH.
- enable-gpios: GPIO specifier for EN pin control of LP872x devices.
Sub nodes for regulator_init_data
LP8720 has maximum 6 nodes. (child name: ldo1 ~ 5 and buck)
......
......@@ -60,7 +60,7 @@ The possible values for "regulator-initial-mode" and "regulator-mode" are:
1: Normal regulator voltage output mode.
3: Low Power which reduces the quiescent current down to only 1uA
The list of valid modes are defined in the dt-bindings/clock/maxim,max77802.h
The valid modes list is defined in the dt-bindings/regulator/maxim,max77802.h
header and can be included by device tree source files.
The standard "regulator-mode" property can only be used for regulators that
......
Regulator DT binding for MAX77620 Power management IC from Maxim Semiconductor.
Device has multiple DCDC(sd[0-3] and LDOs(ldo[0-8]). The input supply
of these regulators are defined under parent device node.
Details of regulator properties are defined as child node under
sub-node "regulators" which is child node of device node.
Please refer file <Documentation/devicetree/bindings/regulator/regulator.txt>
for common regulator bindings used by client.
Following are properties of parent node related to regulators.
Optional properties:
-------------------
The input supply of regulators are the optional properties on the
parent device node. The input supply of these regulators are provided
through following properties:
in-sd0-supply: Input supply for SD0, INA-SD0 or INB-SD0 pins.
in-sd1-supply: Input supply for SD1.
in-sd2-supply: Input supply for SD2.
in-sd3-supply: Input supply for SD3.
in-ldo0-1-supply: Input supply for LDO0 and LDO1.
in-ldo2-supply: Input supply for LDO2.
in-ldo3-5-supply: Input supply for LDO3 and LDO5
in-ldo4-6-supply: Input supply for LDO4 and LDO6.
in-ldo7-8-supply: Input supply for LDO7 and LDO8.
Optional sub nodes for regulators under "regulators" subnode:
------------------------------------------------------------
The subnodes name is the name of regulator and it must be one of:
sd[0-3], ldo[0-8]
Each sub-node should contain the constraints and initialization
information for that regulator. The definition for each of these
nodes is defined using the standard binding for regulators found at
<Documentation/devicetree/bindings/regulator/regulator.txt>.
Theres are also additional properties for SD/LDOs. These additional properties
are required to configure FPS configuration parameters for SDs and LDOs.
Please refer <devicetree/bindings/mfd/max77620.txt> for more detail of Flexible
Power Sequence (FPS).
Following are additional properties:
- maxim,active-fps-source: FPS source for the regulators to get
enabled/disabled when system is in
active state. Valid values are:
- MAX77620_FPS_SRC_0,
FPS source is FPS0.
- MAX77620_FPS_SRC_1,
FPS source is FPS1
- MAX77620_FPS_SRC_2 and
FPS source is FPS2
- MAX77620_FPS_SRC_NONE.
Regulator is not controlled
by FPS events and it gets
enabled/disabled by register
access.
Absence of this property will leave
the FPS configuration register for that
regulator to default configuration.
- maxim,active-fps-power-up-slot: Sequencing event slot number on which
the regulator get enabled when
master FPS input event set to HIGH.
Valid values are 0 to 7.
This is applicable if FPS source is
selected as FPS0, FPS1 or FPS2.
- maxim,active-fps-power-down-slot: Sequencing event slot number on which
the regulator get disabled when master
FPS input event set to LOW.
Valid values are 0 to 7.
This is applicable if FPS source is
selected as FPS0, FPS1 or FPS2.
- maxim,suspend-fps-source: This is same as property
"maxim,active-fps-source" but value
get configured when system enters in
to suspend state.
- maxim,suspend-fps-power-up-slot: This is same as property
"maxim,active-fps-power-up-slot" but
this value get configured into FPS
configuration register when system
enters into suspend.
This is applicable if suspend state
FPS source is selected as FPS0, FPS1 or
- maxim,suspend-fps-power-down-slot: This is same as property
"maxim,active-fps-power-down-slot" but
this value get configured into FPS
configuration register when system
enters into suspend.
This is applicable if suspend state
FPS source is selected as FPS0, FPS1 or
FPS2.
Example:
--------
#include <dt-bindings/mfd/max77620.h>
...
max77620@3c {
in-ldo0-1-supply = <&max77620_sd2>;
in-ldo7-8-supply = <&max77620_sd2>;
regulators {
sd0 {
regulator-name = "vdd-core";
regulator-min-microvolt = <600000>;
regulator-max-microvolt = <1400000>;
regulator-boot-on;
regulator-always-on;
maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
};
sd1 {
regulator-name = "vddio-ddr";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
regulator-boot-on;
maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
};
sd2 {
regulator-name = "vdd-pre-reg";
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
};
sd3 {
regulator-name = "vdd-1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
};
ldo0 {
regulator-name = "avdd-sys";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
regulator-boot-on;
};
ldo1 {
regulator-name = "vdd-pex";
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
};
ldo2 {
regulator-name = "vddio-sdmmc3";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
};
ldo3 {
regulator-name = "vdd-cam-hv";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
};
ldo4 {
regulator-name = "vdd-rtc";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <1250000>;
regulator-always-on;
regulator-boot-on;
};
ldo5 {
regulator-name = "avdd-ts-hv";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
ldo6 {
regulator-name = "vdd-ts";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
};
ldo7 {
regulator-name = "vdd-gen-pll-edp";
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
regulator-always-on;
regulator-boot-on;
};
ldo8 {
regulator-name = "vdd-hdmi-dp";
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
};
};
};
......@@ -44,6 +44,11 @@ Optional properties:
any consumer request.
- regulator-pull-down: Enable pull down resistor when the regulator is disabled.
- regulator-over-current-protection: Enable over current protection.
- regulator-active-discharge: tristate, enable/disable active discharge of
regulators. The values are:
0: Disable active discharge.
1: Enable active discharge.
Absence of this property will leave configuration to default.
Deprecated properties:
- regulator-compatible: If a regulator chip contains multiple
......
......@@ -33,12 +33,19 @@ Optional properties:
Note that this is not needed in case the clocks are stable
throughout the entire runtime of the codec.
- vd-supply: Digital power
- vl-supply: Logic power
- va-supply: Analog Power
Examples:
codec_i2c: cs4271@10 {
compatible = "cirrus,cs4271";
reg = <0x10>;
reset-gpio = <&gpio 23 0>;
vd-supply = <&vdd_3v3_reg>;
vl-supply = <&vdd_3v3_reg>;
va-supply = <&vdd_3v3_reg>;
};
codec_spi: cs4271@0 {
......
......@@ -6910,7 +6910,7 @@ MAXIM MAX77802 MULTIFUNCTION PMIC DEVICE DRIVERS
M: Javier Martinez Canillas <javier@osg.samsung.com>
L: linux-kernel@vger.kernel.org
S: Supported
F: drivers/*/*max77802.c
F: drivers/*/*max77802*.c
F: Documentation/devicetree/bindings/*/*max77802.txt
F: include/dt-bindings/*/*max77802.h
......@@ -6920,7 +6920,7 @@ M: Krzysztof Kozlowski <k.kozlowski@samsung.com>
L: linux-kernel@vger.kernel.org
S: Supported
F: drivers/*/max14577.c
F: drivers/*/max77686.c
F: drivers/*/max77686*.c
F: drivers/*/max77693.c
F: drivers/extcon/extcon-max14577.c
F: drivers/extcon/extcon-max77693.c
......
......@@ -78,6 +78,15 @@ config REGULATOR_ACT8865
This driver controls a active-semi act8865 voltage output
regulator via I2C bus.
config REGULATOR_ACT8945A
tristate "Active-semi ACT8945A voltage regulator"
depends on MFD_ACT8945A
help
This driver controls a active-semi ACT8945A voltage regulator
via I2C bus. The ACT8945A features three step-down DC/DC converters
and four low-dropout linear regulators, along with a ActivePath
battery charger.
config REGULATOR_AD5398
tristate "Analog Devices AD5398/AD5821 regulators"
depends on I2C
......@@ -261,6 +270,14 @@ config REGULATOR_HI6421
21 general purpose LDOs, 3 dedicated LDOs, and 5 BUCKs. All
of them come with support to either ECO (idle) or sleep mode.
config REGULATOR_HI655X
tristate "Hisilicon HI655X PMIC regulators support"
depends on ARCH_HISI || COMPILE_TEST
depends on MFD_HI655X_PMIC && OF
help
This driver provides support for the voltage regulators of the
Hisilicon Hi655x PMIC device.
config REGULATOR_ISL9305
tristate "Intersil ISL9305 regulator"
depends on I2C
......@@ -343,6 +360,15 @@ config REGULATOR_MAX1586
regulator via I2C bus. The provided regulator is suitable
for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
config REGULATOR_MAX77620
tristate "Maxim 77620/MAX20024 voltage regulator"
depends on MFD_MAX77620
help
This driver controls Maxim MAX77620 voltage output regulator
via I2C bus. The provided regulator is suitable for Tegra
chip to control Step-Down DC-DC and LDOs. Say Y here to
enable the regulator driver.
config REGULATOR_MAX8649
tristate "Maxim 8649 voltage regulator"
depends on I2C
......
......@@ -15,6 +15,7 @@ obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
obj-$(CONFIG_REGULATOR_AB8500) += ab8500-ext.o ab8500.o
obj-$(CONFIG_REGULATOR_ACT8865) += act8865-regulator.o
obj-$(CONFIG_REGULATOR_ACT8945A) += act8945a-regulator.o
obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
......@@ -34,6 +35,7 @@ obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
......@@ -46,6 +48,7 @@ obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
obj-$(CONFIG_REGULATOR_MAX14577) += max14577.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o
......@@ -54,9 +57,9 @@ obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
......@@ -98,7 +101,7 @@ obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o
obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
......
......@@ -218,7 +218,7 @@ static const struct regulator_desc act8600_regulators[] = {
.ops = &act8865_ldo_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = 1,
.fixed_uV = 1800000,
.fixed_uV = 3300000,
.enable_reg = ACT8600_LDO910_CTRL,
.enable_mask = ACT8865_ENA,
.owner = THIS_MODULE,
......@@ -369,7 +369,7 @@ static int act8865_pdata_from_dt(struct device *dev,
for (i = 0; i < num_matches; i++) {
regulator->id = i;
regulator->name = matches[i].name;
regulator->platform_data = matches[i].init_data;
regulator->init_data = matches[i].init_data;
of_node[i] = matches[i].of_node;
regulator++;
}
......@@ -396,7 +396,7 @@ static struct regulator_init_data
for (i = 0; i < pdata->num_regulators; i++) {
if (pdata->regulators[i].id == id)
return pdata->regulators[i].platform_data;
return pdata->regulators[i].init_data;
}
return NULL;
......@@ -415,7 +415,7 @@ static void act8865_power_off(void)
static int act8865_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
static const struct regulator_desc *regulators;
const struct regulator_desc *regulators;
struct act8865_platform_data pdata_of, *pdata;
struct device *dev = &client->dev;
struct device_node **of_node;
......
/*
* Voltage regulation driver for active-semi ACT8945A PMIC
*
* Copyright (C) 2015 Atmel Corporation
*
* Author: Wenyou Yang <wenyou.yang@atmel.com>
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
/**
* ACT8945A Global Register Map.
*/
#define ACT8945A_SYS_MODE 0x00
#define ACT8945A_SYS_CTRL 0x01
#define ACT8945A_DCDC1_VSET1 0x20
#define ACT8945A_DCDC1_VSET2 0x21
#define ACT8945A_DCDC1_CTRL 0x22
#define ACT8945A_DCDC2_VSET1 0x30
#define ACT8945A_DCDC2_VSET2 0x31
#define ACT8945A_DCDC2_CTRL 0x32
#define ACT8945A_DCDC3_VSET1 0x40
#define ACT8945A_DCDC3_VSET2 0x41
#define ACT8945A_DCDC3_CTRL 0x42
#define ACT8945A_LDO1_VSET 0x50
#define ACT8945A_LDO1_CTRL 0x51
#define ACT8945A_LDO2_VSET 0x54
#define ACT8945A_LDO2_CTRL 0x55
#define ACT8945A_LDO3_VSET 0x60
#define ACT8945A_LDO3_CTRL 0x61
#define ACT8945A_LDO4_VSET 0x64
#define ACT8945A_LDO4_CTRL 0x65
/**
* Field Definitions.
*/
#define ACT8945A_ENA 0x80 /* ON - [7] */
#define ACT8945A_VSEL_MASK 0x3F /* VSET - [5:0] */
/**
* ACT8945A Voltage Number
*/
#define ACT8945A_VOLTAGE_NUM 64
enum {
ACT8945A_ID_DCDC1,
ACT8945A_ID_DCDC2,
ACT8945A_ID_DCDC3,
ACT8945A_ID_LDO1,
ACT8945A_ID_LDO2,
ACT8945A_ID_LDO3,
ACT8945A_ID_LDO4,
ACT8945A_REG_NUM,
};
static const struct regulator_linear_range act8945a_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000),
REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000),
REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
};
static struct regulator_ops act8945a_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
#define ACT89xx_REG(_name, _family, _id, _vsel_reg, _supply) \
[_family##_ID_##_id] = { \
.name = _name, \
.supply_name = _supply, \
.of_match = of_match_ptr("REG_"#_id), \
.regulators_node = of_match_ptr("regulators"), \
.id = _family##_ID_##_id, \
.type = REGULATOR_VOLTAGE, \
.ops = &act8945a_ops, \
.n_voltages = ACT8945A_VOLTAGE_NUM, \
.linear_ranges = act8945a_voltage_ranges, \
.n_linear_ranges = ARRAY_SIZE(act8945a_voltage_ranges), \
.vsel_reg = _family##_##_id##_##_vsel_reg, \
.vsel_mask = ACT8945A_VSEL_MASK, \
.enable_reg = _family##_##_id##_CTRL, \
.enable_mask = ACT8945A_ENA, \
.owner = THIS_MODULE, \
}
static const struct regulator_desc act8945a_regulators[] = {
ACT89xx_REG("DCDC_REG1", ACT8945A, DCDC1, VSET1, "vp1"),
ACT89xx_REG("DCDC_REG2", ACT8945A, DCDC2, VSET1, "vp2"),
ACT89xx_REG("DCDC_REG3", ACT8945A, DCDC3, VSET1, "vp3"),
ACT89xx_REG("LDO_REG1", ACT8945A, LDO1, VSET, "inl45"),
ACT89xx_REG("LDO_REG2", ACT8945A, LDO2, VSET, "inl45"),
ACT89xx_REG("LDO_REG3", ACT8945A, LDO3, VSET, "inl67"),
ACT89xx_REG("LDO_REG4", ACT8945A, LDO4, VSET, "inl67"),
};
static const struct regulator_desc act8945a_alt_regulators[] = {
ACT89xx_REG("DCDC_REG1", ACT8945A, DCDC1, VSET2, "vp1"),
ACT89xx_REG("DCDC_REG2", ACT8945A, DCDC2, VSET2, "vp2"),
ACT89xx_REG("DCDC_REG3", ACT8945A, DCDC3, VSET2, "vp3"),
ACT89xx_REG("LDO_REG1", ACT8945A, LDO1, VSET, "inl45"),
ACT89xx_REG("LDO_REG2", ACT8945A, LDO2, VSET, "inl45"),
ACT89xx_REG("LDO_REG3", ACT8945A, LDO3, VSET, "inl67"),
ACT89xx_REG("LDO_REG4", ACT8945A, LDO4, VSET, "inl67"),
};
static int act8945a_pmic_probe(struct platform_device *pdev)
{
struct regulator_config config = { };
const struct regulator_desc *regulators;
struct regulator_dev *rdev;
int i, num_regulators;
bool voltage_select;
voltage_select = of_property_read_bool(pdev->dev.parent->of_node,
"active-semi,vsel-high");
if (voltage_select) {
regulators = act8945a_alt_regulators;
num_regulators = ARRAY_SIZE(act8945a_alt_regulators);
} else {
regulators = act8945a_regulators;
num_regulators = ARRAY_SIZE(act8945a_regulators);
}
config.dev = &pdev->dev;
config.dev->of_node = pdev->dev.parent->of_node;
for (i = 0; i < num_regulators; i++) {
rdev = devm_regulator_register(&pdev->dev, &regulators[i], &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev,
"failed to register %s regulator\n",
regulators[i].name);
return PTR_ERR(rdev);
}
}
return 0;
}
static struct platform_driver act8945a_pmic_driver = {
.driver = {
.name = "act8945a-regulator",
},
.probe = act8945a_pmic_probe,
};
module_platform_driver(act8945a_pmic_driver);
MODULE_DESCRIPTION("Active-semi ACT8945A voltage regulator driver");
MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
MODULE_LICENSE("GPL");
......@@ -58,10 +58,12 @@ static int ad5398_write_reg(struct i2c_client *client, const unsigned short data
val = cpu_to_be16(data);
ret = i2c_master_send(client, (char *)&val, 2);
if (ret < 0)
if (ret != 2) {
dev_err(&client->dev, "I2C write error\n");
return ret < 0 ? ret : -EIO;
}
return ret;
return 0;
}
static int ad5398_get_current_limit(struct regulator_dev *rdev)
......
......@@ -39,7 +39,7 @@
#define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
_vmask, _ereg, _emask, _enable_val, _disable_val) \
[_family##_##_id] = { \
.name = #_id, \
.name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
......@@ -61,7 +61,7 @@
#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
_vmask, _ereg, _emask) \
[_family##_##_id] = { \
.name = #_id, \
.name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
......@@ -78,21 +78,15 @@
.ops = &axp20x_ops, \
}
#define AXP_DESC_SW(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
_vmask, _ereg, _emask) \
#define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \
[_family##_##_id] = { \
.name = #_id, \
.name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = _family##_##_id, \
.n_voltages = (((_max) - (_min)) / (_step) + 1), \
.owner = THIS_MODULE, \
.min_uV = (_min) * 1000, \
.uV_step = (_step) * 1000, \
.vsel_reg = (_vreg), \
.vsel_mask = (_vmask), \
.enable_reg = (_ereg), \
.enable_mask = (_emask), \
.ops = &axp20x_ops_sw, \
......@@ -100,7 +94,7 @@
#define AXP_DESC_FIXED(_family, _id, _match, _supply, _volt) \
[_family##_##_id] = { \
.name = #_id, \
.name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
......@@ -112,39 +106,34 @@
.ops = &axp20x_ops_fixed \
}
#define AXP_DESC_TABLE(_family, _id, _match, _supply, _table, _vreg, _vmask, \
_ereg, _emask) \
#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \
_vreg, _vmask, _ereg, _emask) \
[_family##_##_id] = { \
.name = #_id, \
.name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = _family##_##_id, \
.n_voltages = ARRAY_SIZE(_table), \
.n_voltages = (_n_voltages), \
.owner = THIS_MODULE, \
.vsel_reg = (_vreg), \
.vsel_mask = (_vmask), \
.enable_reg = (_ereg), \
.enable_mask = (_emask), \
.volt_table = (_table), \
.ops = &axp20x_ops_table, \
.linear_ranges = (_ranges), \
.n_linear_ranges = ARRAY_SIZE(_ranges), \
.ops = &axp20x_ops_range, \
}
static const int axp20x_ldo4_data[] = { 1250000, 1300000, 1400000, 1500000, 1600000,
1700000, 1800000, 1900000, 2000000, 2500000,
2700000, 2800000, 3000000, 3100000, 3200000,
3300000 };
static struct regulator_ops axp20x_ops_fixed = {
.list_voltage = regulator_list_voltage_linear,
};
static struct regulator_ops axp20x_ops_table = {
static struct regulator_ops axp20x_ops_range = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.list_voltage = regulator_list_voltage_linear_range,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
......@@ -160,13 +149,17 @@ static struct regulator_ops axp20x_ops = {
};
static struct regulator_ops axp20x_ops_sw = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
static const struct regulator_linear_range axp20x_ldo4_ranges[] = {
REGULATOR_LINEAR_RANGE(1250000, 0x0, 0x0, 0),
REGULATOR_LINEAR_RANGE(1300000, 0x1, 0x8, 100000),
REGULATOR_LINEAR_RANGE(2500000, 0x9, 0xf, 100000),
};
static const struct regulator_desc axp20x_regulators[] = {
AXP_DESC(AXP20X, DCDC2, "dcdc2", "vin2", 700, 2275, 25,
AXP20X_DCDC2_V_OUT, 0x3f, AXP20X_PWR_OUT_CTRL, 0x10),
......@@ -177,8 +170,9 @@ static const struct regulator_desc axp20x_regulators[] = {
AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04),
AXP_DESC(AXP20X, LDO3, "ldo3", "ldo3in", 700, 3500, 25,
AXP20X_LDO3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x40),
AXP_DESC_TABLE(AXP20X, LDO4, "ldo4", "ldo24in", axp20x_ldo4_data,
AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08),
AXP_DESC_RANGES(AXP20X, LDO4, "ldo4", "ldo24in", axp20x_ldo4_ranges,
16, AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL,
0x08),
AXP_DESC_IO(AXP20X, LDO5, "ldo5", "ldo5in", 1800, 3300, 100,
AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07,
AXP20X_IO_ENABLED, AXP20X_IO_DISABLED),
......@@ -196,8 +190,8 @@ static const struct regulator_desc axp22x_regulators[] = {
AXP_DESC(AXP22X, DCDC5, "dcdc5", "vin5", 1000, 2550, 50,
AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)),
/* secondary switchable output of DCDC1 */
AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, 1600, 3400, 100,
AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(7)),
AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2,
BIT(7)),
/* LDO regulator internally chained to DCDC5 */
AXP_DESC(AXP22X, DC5LDO, "dc5ldo", NULL, 700, 1400, 100,
AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)),
......
......@@ -1057,18 +1057,18 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = machine_constraints_voltage(rdev, rdev->constraints);
if (ret != 0)
goto out;
return ret;
ret = machine_constraints_current(rdev, rdev->constraints);
if (ret != 0)
goto out;
return ret;
if (rdev->constraints->ilim_uA && ops->set_input_current_limit) {
ret = ops->set_input_current_limit(rdev,
rdev->constraints->ilim_uA);
if (ret < 0) {
rdev_err(rdev, "failed to set input limit\n");
goto out;
return ret;
}
}
......@@ -1077,21 +1077,20 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = suspend_prepare(rdev, rdev->constraints->initial_state);
if (ret < 0) {
rdev_err(rdev, "failed to set suspend state\n");
goto out;
return ret;
}
}
if (rdev->constraints->initial_mode) {
if (!ops->set_mode) {
rdev_err(rdev, "no set_mode operation\n");
ret = -EINVAL;
goto out;
return -EINVAL;
}
ret = ops->set_mode(rdev, rdev->constraints->initial_mode);
if (ret < 0) {
rdev_err(rdev, "failed to set initial mode: %d\n", ret);
goto out;
return ret;
}
}
......@@ -1102,7 +1101,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = _regulator_do_enable(rdev);
if (ret < 0 && ret != -EINVAL) {
rdev_err(rdev, "failed to enable\n");
goto out;
return ret;
}
}
......@@ -1111,7 +1110,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
if (ret < 0) {
rdev_err(rdev, "failed to set ramp_delay\n");
goto out;
return ret;
}
}
......@@ -1119,7 +1118,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = ops->set_pull_down(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to set pull down\n");
goto out;
return ret;
}
}
......@@ -1127,7 +1126,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = ops->set_soft_start(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to set soft start\n");
goto out;
return ret;
}
}
......@@ -1136,16 +1135,34 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = ops->set_over_current_protection(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to set over current protection\n");
goto out;
return ret;
}
}
if (rdev->constraints->active_discharge && ops->set_active_discharge) {
bool ad_state = (rdev->constraints->active_discharge ==
REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
ret = ops->set_active_discharge(rdev, ad_state);
if (ret < 0) {
rdev_err(rdev, "failed to set active discharge\n");
return ret;
}
}
if (rdev->constraints->active_discharge && ops->set_active_discharge) {
bool ad_state = (rdev->constraints->active_discharge ==
REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
ret = ops->set_active_discharge(rdev, ad_state);
if (ret < 0) {
rdev_err(rdev, "failed to set active discharge\n");
return ret;
}
}
print_constraints(rdev);
return 0;
out:
kfree(rdev->constraints);
rdev->constraints = NULL;
return ret;
}
/**
......@@ -3918,6 +3935,16 @@ regulator_register(const struct regulator_desc *regulator_desc,
goto clean;
}
if ((config->ena_gpio || config->ena_gpio_initialized) &&
gpio_is_valid(config->ena_gpio)) {
ret = regulator_ena_gpio_request(rdev, config);
if (ret != 0) {
rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
config->ena_gpio, ret);
goto clean;
}
}
/* register with sysfs */
rdev->dev.class = &regulator_class;
rdev->dev.parent = dev;
......@@ -3926,21 +3953,11 @@ regulator_register(const struct regulator_desc *regulator_desc,
ret = device_register(&rdev->dev);
if (ret != 0) {
put_device(&rdev->dev);
goto clean;
goto wash;
}
dev_set_drvdata(&rdev->dev, rdev);
if ((config->ena_gpio || config->ena_gpio_initialized) &&
gpio_is_valid(config->ena_gpio)) {
ret = regulator_ena_gpio_request(rdev, config);
if (ret != 0) {
rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
config->ena_gpio, ret);
goto wash;
}
}
/* set regulator constraints */
if (init_data)
constraints = &init_data->constraints;
......@@ -3979,13 +3996,13 @@ regulator_register(const struct regulator_desc *regulator_desc,
scrub:
regulator_ena_gpio_free(rdev);
kfree(rdev->constraints);
wash:
device_unregister(&rdev->dev);
/* device core frees rdev */
rdev = ERR_PTR(ret);
goto out;
wash:
regulator_ena_gpio_free(rdev);
clean:
kfree(rdev);
rdev = ERR_PTR(ret);
......
......@@ -132,6 +132,8 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
if (error < 0)
goto error_i2c;
mutex_lock(&chip->rdev->mutex);
if (val & DA9210_E_OVCURR) {
regulator_notifier_call_chain(chip->rdev,
REGULATOR_EVENT_OVER_CURRENT,
......@@ -155,6 +157,9 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
NULL);
handled |= DA9210_E_VMAX;
}
mutex_unlock(&chip->rdev->mutex);
if (handled) {
/* Clear handled events */
error = regmap_write(chip->regmap, DA9210_REG_EVENT_B, handled);
......
......@@ -114,6 +114,22 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
return 0;
}
static int fan53555_set_suspend_enable(struct regulator_dev *rdev)
{
struct fan53555_device_info *di = rdev_get_drvdata(rdev);
return regmap_update_bits(di->regmap, di->sleep_reg,
VSEL_BUCK_EN, VSEL_BUCK_EN);
}
static int fan53555_set_suspend_disable(struct regulator_dev *rdev)
{
struct fan53555_device_info *di = rdev_get_drvdata(rdev);
return regmap_update_bits(di->regmap, di->sleep_reg,
VSEL_BUCK_EN, 0);
}
static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct fan53555_device_info *di = rdev_get_drvdata(rdev);
......@@ -192,6 +208,8 @@ static struct regulator_ops fan53555_regulator_ops = {
.set_mode = fan53555_set_mode,
.get_mode = fan53555_get_mode,
.set_ramp_delay = fan53555_set_ramp,
.set_suspend_enable = fan53555_set_suspend_enable,
.set_suspend_disable = fan53555_set_suspend_disable,
};
static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
......
......@@ -283,8 +283,10 @@ static int gpio_regulator_probe(struct platform_device *pdev)
drvdata->nr_gpios = config->nr_gpios;
ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"Could not obtain regulator setting GPIOs: %d\n", ret);
"Could not obtain regulator setting GPIOs: %d\n",
ret);
goto err_memstate;
}
}
......
......@@ -465,3 +465,26 @@ int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
return 0;
}
EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
/**
* regulator_set_active_discharge_regmap - Default set_active_discharge()
* using regmap
*
* @rdev: device to operate on.
* @enable: state to set, 0 to disable and 1 to enable.
*/
int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
bool enable)
{
unsigned int val;
if (enable)
val = rdev->desc->active_discharge_on;
else
val = rdev->desc->active_discharge_off;
return regmap_update_bits(rdev->regmap,
rdev->desc->active_discharge_reg,
rdev->desc->active_discharge_mask, val);
}
EXPORT_SYMBOL_GPL(regulator_set_active_discharge_regmap);
/*
* Device driver for regulators in Hi655x IC
*
* Copyright (c) 2016 Hisilicon.
*
* Authors:
* Chen Feng <puck.chen@hisilicon.com>
* Fei Wang <w.f@huawei.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.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/hi655x-pmic.h>
struct hi655x_regulator {
unsigned int disable_reg;
unsigned int status_reg;
unsigned int ctrl_regs;
unsigned int ctrl_mask;
struct regulator_desc rdesc;
};
/* LDO7 & LDO10 */
static const unsigned int ldo7_voltages[] = {
1800000, 1850000, 2850000, 2900000,
3000000, 3100000, 3200000, 3300000,
};
static const unsigned int ldo19_voltages[] = {
1800000, 1850000, 1900000, 1750000,
2800000, 2850000, 2900000, 3000000,
};
static const unsigned int ldo22_voltages[] = {
900000, 1000000, 1050000, 1100000,
1150000, 1175000, 1185000, 1200000,
};
enum hi655x_regulator_id {
HI655X_LDO0,
HI655X_LDO1,
HI655X_LDO2,
HI655X_LDO3,
HI655X_LDO4,
HI655X_LDO5,
HI655X_LDO6,
HI655X_LDO7,
HI655X_LDO8,
HI655X_LDO9,
HI655X_LDO10,
HI655X_LDO11,
HI655X_LDO12,
HI655X_LDO13,
HI655X_LDO14,
HI655X_LDO15,
HI655X_LDO16,
HI655X_LDO17,
HI655X_LDO18,
HI655X_LDO19,
HI655X_LDO20,
HI655X_LDO21,
HI655X_LDO22,
};
static int hi655x_is_enabled(struct regulator_dev *rdev)
{
unsigned int value = 0;
struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
regmap_read(rdev->regmap, regulator->status_reg, &value);
return (value & BIT(regulator->ctrl_mask));
}
static int hi655x_disable(struct regulator_dev *rdev)
{
int ret = 0;
struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
ret = regmap_write(rdev->regmap, regulator->disable_reg,
BIT(regulator->ctrl_mask));
return ret;
}
static struct regulator_ops hi655x_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = hi655x_disable,
.is_enabled = hi655x_is_enabled,
.list_voltage = regulator_list_voltage_table,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
static struct regulator_ops hi655x_ldo_linear_ops = {
.enable = regulator_enable_regmap,
.disable = hi655x_disable,
.is_enabled = hi655x_is_enabled,
.list_voltage = regulator_list_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
#define HI655X_LDO(_ID, vreg, vmask, ereg, dreg, \
sreg, cmask, vtable) { \
.rdesc = { \
.name = #_ID, \
.of_match = of_match_ptr(#_ID), \
.ops = &hi655x_regulator_ops, \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = HI655X_##_ID, \
.owner = THIS_MODULE, \
.n_voltages = ARRAY_SIZE(vtable), \
.volt_table = vtable, \
.vsel_reg = HI655X_BUS_ADDR(vreg), \
.vsel_mask = vmask, \
.enable_reg = HI655X_BUS_ADDR(ereg), \
.enable_mask = BIT(cmask), \
}, \
.disable_reg = HI655X_BUS_ADDR(dreg), \
.status_reg = HI655X_BUS_ADDR(sreg), \
.ctrl_mask = cmask, \
}
#define HI655X_LDO_LINEAR(_ID, vreg, vmask, ereg, dreg, \
sreg, cmask, minv, nvolt, vstep) { \
.rdesc = { \
.name = #_ID, \
.of_match = of_match_ptr(#_ID), \
.ops = &hi655x_ldo_linear_ops, \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = HI655X_##_ID, \
.owner = THIS_MODULE, \
.min_uV = minv, \
.n_voltages = nvolt, \
.uV_step = vstep, \
.vsel_reg = HI655X_BUS_ADDR(vreg), \
.vsel_mask = vmask, \
.enable_reg = HI655X_BUS_ADDR(ereg), \
.enable_mask = BIT(cmask), \
}, \
.disable_reg = HI655X_BUS_ADDR(dreg), \
.status_reg = HI655X_BUS_ADDR(sreg), \
.ctrl_mask = cmask, \
}
static struct hi655x_regulator regulators[] = {
HI655X_LDO_LINEAR(LDO2, 0x72, 0x07, 0x29, 0x2a, 0x2b, 0x01,
2500000, 8, 100000),
HI655X_LDO(LDO7, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x06, ldo7_voltages),
HI655X_LDO(LDO10, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x01, ldo7_voltages),
HI655X_LDO_LINEAR(LDO13, 0x7e, 0x07, 0x2c, 0x2d, 0x2e, 0x04,
1600000, 8, 50000),
HI655X_LDO_LINEAR(LDO14, 0x7f, 0x07, 0x2c, 0x2d, 0x2e, 0x05,
2500000, 8, 100000),
HI655X_LDO_LINEAR(LDO15, 0x80, 0x07, 0x2c, 0x2d, 0x2e, 0x06,
1600000, 8, 50000),
HI655X_LDO_LINEAR(LDO17, 0x82, 0x07, 0x2f, 0x30, 0x31, 0x00,
2500000, 8, 100000),
HI655X_LDO(LDO19, 0x84, 0x07, 0x2f, 0x30, 0x31, 0x02, ldo19_voltages),
HI655X_LDO_LINEAR(LDO21, 0x86, 0x07, 0x2f, 0x30, 0x31, 0x04,
1650000, 8, 50000),
HI655X_LDO(LDO22, 0x87, 0x07, 0x2f, 0x30, 0x31, 0x05, ldo22_voltages),
};
static int hi655x_regulator_probe(struct platform_device *pdev)
{
unsigned int i;
struct hi655x_regulator *regulator;
struct hi655x_pmic *pmic;
struct regulator_config config = { };
struct regulator_dev *rdev;
pmic = dev_get_drvdata(pdev->dev.parent);
if (!pmic) {
dev_err(&pdev->dev, "no pmic in the regulator parent node\n");
return -ENODEV;
}
regulator = devm_kzalloc(&pdev->dev, sizeof(*regulator), GFP_KERNEL);
if (!regulator)
return -ENOMEM;
platform_set_drvdata(pdev, regulator);
config.dev = pdev->dev.parent;
config.regmap = pmic->regmap;
config.driver_data = regulator;
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
rdev = devm_regulator_register(&pdev->dev,
&regulators[i].rdesc,
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
regulator->rdesc.name);
return PTR_ERR(rdev);
}
}
return 0;
}
static struct platform_driver hi655x_regulator_driver = {
.driver = {
.name = "hi655x-regulator",
},
.probe = hi655x_regulator_probe,
};
module_platform_driver(hi655x_regulator_driver);
MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>");
MODULE_DESCRIPTION("Hisilicon Hi655x regulator driver");
MODULE_LICENSE("GPL v2");
......@@ -15,6 +15,7 @@
#include <linux/regmap.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/regulator/lp872x.h>
#include <linux/regulator/driver.h>
#include <linux/platform_device.h>
......@@ -738,10 +739,8 @@ static int lp872x_init_dvs(struct lp872x *lp)
goto set_default_dvs_mode;
gpio = dvs->gpio;
if (!gpio_is_valid(gpio)) {
dev_warn(lp->dev, "invalid gpio: %d\n", gpio);
if (!gpio_is_valid(gpio))
goto set_default_dvs_mode;
}
pinstate = dvs->init_state;
ret = devm_gpio_request_one(lp->dev, gpio, pinstate, "LP872X DVS");
......@@ -759,6 +758,33 @@ static int lp872x_init_dvs(struct lp872x *lp)
default_dvs_mode[lp->chipid]);
}
static int lp872x_hw_enable(struct lp872x *lp)
{
int ret, gpio;
if (!lp->pdata)
return -EINVAL;
gpio = lp->pdata->enable_gpio;
if (!gpio_is_valid(gpio))
return 0;
/* Always set enable GPIO high. */
ret = devm_gpio_request_one(lp->dev, gpio, GPIOF_OUT_INIT_HIGH, "LP872X EN");
if (ret) {
dev_err(lp->dev, "gpio request err: %d\n", ret);
return ret;
}
/* Each chip has a different enable delay. */
if (lp->chipid == LP8720)
usleep_range(LP8720_ENABLE_DELAY, 1.5 * LP8720_ENABLE_DELAY);
else
usleep_range(LP8725_ENABLE_DELAY, 1.5 * LP8725_ENABLE_DELAY);
return 0;
}
static int lp872x_config(struct lp872x *lp)
{
struct lp872x_platform_data *pdata = lp->pdata;
......@@ -877,6 +903,8 @@ static struct lp872x_platform_data
of_property_read_u8(np, "ti,dvs-state", &dvs_state);
pdata->dvs->init_state = dvs_state ? DVS_HIGH : DVS_LOW;
pdata->enable_gpio = of_get_named_gpio(np, "enable-gpios", 0);
if (of_get_child_count(np) == 0)
goto out;
......@@ -950,6 +978,10 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
lp->chipid = id->driver_data;
i2c_set_clientdata(cl, lp);
ret = lp872x_hw_enable(lp);
if (ret)
return ret;
ret = lp872x_config(lp);
if (ret)
return ret;
......
......@@ -520,13 +520,16 @@ static int ltc3589_probe(struct i2c_client *client,
}
}
ret = devm_request_threaded_irq(dev, client->irq, NULL, ltc3589_isr,
if (client->irq) {
ret = devm_request_threaded_irq(dev, client->irq, NULL,
ltc3589_isr,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
client->name, ltc3589);
if (ret) {
dev_err(dev, "Failed to request IRQ: %d\n", ret);
return ret;
}
}
return 0;
}
......
此差异已折叠。
......@@ -317,11 +317,25 @@ static int mt6397_regulator_probe(struct platform_device *pdev)
return 0;
}
static const struct platform_device_id mt6397_platform_ids[] = {
{"mt6397-regulator", 0},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(platform, mt6397_platform_ids);
static const struct of_device_id mt6397_of_match[] = {
{ .compatible = "mediatek,mt6397-regulator", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mt6397_of_match);
static struct platform_driver mt6397_regulator_driver = {
.driver = {
.name = "mt6397-regulator",
.of_match_table = of_match_ptr(mt6397_of_match),
},
.probe = mt6397_regulator_probe,
.id_table = mt6397_platform_ids,
};
module_platform_driver(mt6397_regulator_driver);
......@@ -329,4 +343,3 @@ module_platform_driver(mt6397_regulator_driver);
MODULE_AUTHOR("Flora Fu <flora.fu@mediatek.com>");
MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mt6397-regulator");
......@@ -28,7 +28,6 @@ static void of_get_regulation_constraints(struct device_node *np,
struct regulator_init_data **init_data,
const struct regulator_desc *desc)
{
const __be32 *min_uV, *max_uV;
struct regulation_constraints *constraints = &(*init_data)->constraints;
struct regulator_state *suspend_state;
struct device_node *suspend_np;
......@@ -37,18 +36,18 @@ static void of_get_regulation_constraints(struct device_node *np,
constraints->name = of_get_property(np, "regulator-name", NULL);
min_uV = of_get_property(np, "regulator-min-microvolt", NULL);
if (min_uV)
constraints->min_uV = be32_to_cpu(*min_uV);
max_uV = of_get_property(np, "regulator-max-microvolt", NULL);
if (max_uV)
constraints->max_uV = be32_to_cpu(*max_uV);
if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
constraints->min_uV = pval;
if (!of_property_read_u32(np, "regulator-max-microvolt", &pval))
constraints->max_uV = pval;
/* Voltage change possible? */
if (constraints->min_uV != constraints->max_uV)
constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
/* Only one voltage? Then make sure it's set. */
if (min_uV && max_uV && constraints->min_uV == constraints->max_uV)
if (constraints->min_uV && constraints->max_uV &&
constraints->min_uV == constraints->max_uV)
constraints->apply_uV = true;
if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
......@@ -93,6 +92,12 @@ static void of_get_regulation_constraints(struct device_node *np,
constraints->soft_start = of_property_read_bool(np,
"regulator-soft-start");
ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
if (!ret) {
constraints->active_discharge =
(pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE :
REGULATOR_ACTIVE_DISCHARGE_DISABLE;
}
if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) {
if (desc && desc->of_map_mode) {
......
......@@ -285,8 +285,8 @@ static irqreturn_t pv88060_irq_handler(int irq, void *data)
}
}
err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,
PV88060_E_VDD_FLT, PV88060_E_VDD_FLT);
err = regmap_write(chip->regmap, PV88060_REG_EVENT_A,
PV88060_E_VDD_FLT);
if (err < 0)
goto error_i2c;
......@@ -302,8 +302,8 @@ static irqreturn_t pv88060_irq_handler(int irq, void *data)
}
}
err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,
PV88060_E_OVER_TEMP, PV88060_E_OVER_TEMP);
err = regmap_write(chip->regmap, PV88060_REG_EVENT_A,
PV88060_E_OVER_TEMP);
if (err < 0)
goto error_i2c;
......
......@@ -283,8 +283,8 @@ static irqreturn_t pv88090_irq_handler(int irq, void *data)
}
}
err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
PV88090_E_VDD_FLT, PV88090_E_VDD_FLT);
err = regmap_write(chip->regmap, PV88090_REG_EVENT_A,
PV88090_E_VDD_FLT);
if (err < 0)
goto error_i2c;
......@@ -300,8 +300,8 @@ static irqreturn_t pv88090_irq_handler(int irq, void *data)
}
}
err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
PV88090_E_OVER_TEMP, PV88090_E_OVER_TEMP);
err = regmap_write(chip->regmap, PV88090_REG_EVENT_A,
PV88090_E_OVER_TEMP);
if (err < 0)
goto error_i2c;
......
......@@ -27,6 +27,13 @@ struct pwm_regulator_data {
/* Voltage table */
struct pwm_voltages *duty_cycle_table;
/* regulator descriptor */
struct regulator_desc desc;
/* Regulator ops */
struct regulator_ops ops;
int state;
/* Continuous voltage */
......@@ -115,7 +122,7 @@ static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int
int max_uV = rdev->constraints->max_uV;
int diff = max_uV - min_uV;
return 100 - (((req_uV * 100) - (min_uV * 100)) / diff);
return ((req_uV * 100) - (min_uV * 100)) / diff;
}
static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
......@@ -212,8 +219,10 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
}
drvdata->duty_cycle_table = duty_cycle_table;
pwm_regulator_desc.ops = &pwm_regulator_voltage_table_ops;
pwm_regulator_desc.n_voltages = length / sizeof(*duty_cycle_table);
memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops,
sizeof(drvdata->ops));
drvdata->desc.ops = &drvdata->ops;
drvdata->desc.n_voltages = length / sizeof(*duty_cycle_table);
return 0;
}
......@@ -221,8 +230,10 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
static int pwm_regulator_init_continuous(struct platform_device *pdev,
struct pwm_regulator_data *drvdata)
{
pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops;
pwm_regulator_desc.continuous_voltage_range = true;
memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops,
sizeof(drvdata->ops));
drvdata->desc.ops = &drvdata->ops;
drvdata->desc.continuous_voltage_range = true;
return 0;
}
......@@ -245,6 +256,8 @@ static int pwm_regulator_probe(struct platform_device *pdev)
if (!drvdata)
return -ENOMEM;
memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));
if (of_find_property(np, "voltage-table", NULL))
ret = pwm_regulator_init_table(pdev, drvdata);
else
......@@ -253,7 +266,7 @@ static int pwm_regulator_probe(struct platform_device *pdev)
return ret;
init_data = of_get_regulator_init_data(&pdev->dev, np,
&pwm_regulator_desc);
&drvdata->desc);
if (!init_data)
return -ENOMEM;
......@@ -269,10 +282,10 @@ static int pwm_regulator_probe(struct platform_device *pdev)
}
regulator = devm_regulator_register(&pdev->dev,
&pwm_regulator_desc, &config);
&drvdata->desc, &config);
if (IS_ERR(regulator)) {
dev_err(&pdev->dev, "Failed to register regulator %s\n",
pwm_regulator_desc.name);
drvdata->desc.name);
return PTR_ERR(regulator);
}
......
......@@ -38,7 +38,6 @@
/* The highest number of possible regulators for supported devices. */
#define S2MPS_REGULATOR_MAX S2MPS13_REGULATOR_MAX
struct s2mps11_info {
unsigned int rdev_num;
int ramp_delay2;
int ramp_delay34;
int ramp_delay5;
......@@ -54,7 +53,10 @@ struct s2mps11_info {
*/
DECLARE_BITMAP(suspend_state, S2MPS_REGULATOR_MAX);
/* Array of size rdev_num with GPIO-s for external sleep control */
/*
* Array (size: number of regulators) with GPIO-s for external
* sleep control.
*/
int *ext_control_gpio;
};
......@@ -819,7 +821,8 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
}
static int s2mps11_pmic_dt_parse(struct platform_device *pdev,
struct of_regulator_match *rdata, struct s2mps11_info *s2mps11)
struct of_regulator_match *rdata, struct s2mps11_info *s2mps11,
unsigned int rdev_num)
{
struct device_node *reg_np;
......@@ -829,7 +832,7 @@ static int s2mps11_pmic_dt_parse(struct platform_device *pdev,
return -EINVAL;
}
of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
of_regulator_match(&pdev->dev, reg_np, rdata, rdev_num);
if (s2mps11->dev_type == S2MPS14X)
s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11);
......@@ -1077,6 +1080,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
struct of_regulator_match *rdata = NULL;
struct regulator_config config = { };
struct s2mps11_info *s2mps11;
unsigned int rdev_num = 0;
int i, ret = 0;
const struct regulator_desc *regulators;
......@@ -1088,28 +1092,29 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
s2mps11->dev_type = platform_get_device_id(pdev)->driver_data;
switch (s2mps11->dev_type) {
case S2MPS11X:
s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators);
rdev_num = ARRAY_SIZE(s2mps11_regulators);
regulators = s2mps11_regulators;
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps11_regulators));
break;
case S2MPS13X:
s2mps11->rdev_num = ARRAY_SIZE(s2mps13_regulators);
rdev_num = ARRAY_SIZE(s2mps13_regulators);
regulators = s2mps13_regulators;
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps13_regulators));
break;
case S2MPS14X:
s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators);
rdev_num = ARRAY_SIZE(s2mps14_regulators);
regulators = s2mps14_regulators;
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps14_regulators));
break;
case S2MPS15X:
s2mps11->rdev_num = ARRAY_SIZE(s2mps15_regulators);
rdev_num = ARRAY_SIZE(s2mps15_regulators);
regulators = s2mps15_regulators;
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps15_regulators));
break;
case S2MPU02:
s2mps11->rdev_num = ARRAY_SIZE(s2mpu02_regulators);
rdev_num = ARRAY_SIZE(s2mpu02_regulators);
regulators = s2mpu02_regulators;
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mpu02_regulators));
break;
default:
dev_err(&pdev->dev, "Invalid device type: %u\n",
......@@ -1118,7 +1123,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
}
s2mps11->ext_control_gpio = devm_kmalloc(&pdev->dev,
sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num,
sizeof(*s2mps11->ext_control_gpio) * rdev_num,
GFP_KERNEL);
if (!s2mps11->ext_control_gpio)
return -ENOMEM;
......@@ -1126,7 +1131,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
* 0 is a valid GPIO so initialize all GPIO-s to negative value
* to indicate that external control won't be used for this regulator.
*/
for (i = 0; i < s2mps11->rdev_num; i++)
for (i = 0; i < rdev_num; i++)
s2mps11->ext_control_gpio[i] = -EINVAL;
if (!iodev->dev->of_node) {
......@@ -1140,14 +1145,14 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
}
}
rdata = kzalloc(sizeof(*rdata) * s2mps11->rdev_num, GFP_KERNEL);
rdata = kzalloc(sizeof(*rdata) * rdev_num, GFP_KERNEL);
if (!rdata)
return -ENOMEM;
for (i = 0; i < s2mps11->rdev_num; i++)
for (i = 0; i < rdev_num; i++)
rdata[i].name = regulators[i].name;
ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11);
ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, rdev_num);
if (ret)
goto out;
......@@ -1159,7 +1164,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
config.driver_data = s2mps11;
config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
config.ena_gpio_initialized = true;
for (i = 0; i < s2mps11->rdev_num; i++) {
for (i = 0; i < rdev_num; i++) {
struct regulator_dev *regulator;
if (pdata) {
......
......@@ -202,9 +202,10 @@ static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id,
}
}
if (i < s5m8767->num_regulators)
*enable_ctrl =
s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
if (i >= s5m8767->num_regulators)
return -EINVAL;
*enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
return 0;
}
......@@ -937,8 +938,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
else
regulators[id].vsel_mask = 0xff;
s5m8767_get_register(s5m8767, id, &enable_reg,
ret = s5m8767_get_register(s5m8767, id, &enable_reg,
&enable_val);
if (ret) {
dev_err(s5m8767->dev, "error reading registers\n");
return ret;
}
regulators[id].enable_reg = enable_reg;
regulators[id].enable_mask = S5M8767_ENCTRL_MASK;
regulators[id].enable_val = enable_val;
......
......@@ -68,12 +68,12 @@ enum {
* act8865_regulator_data - regulator data
* @id: regulator id
* @name: regulator name
* @platform_data: regulator init data
* @init_data: regulator init data
*/
struct act8865_regulator_data {
int id;
const char *name;
struct regulator_init_data *platform_data;
struct regulator_init_data *init_data;
};
/**
......
......@@ -93,6 +93,8 @@ struct regulator_linear_range {
* @get_current_limit: Get the configured limit for a current-limited regulator.
* @set_input_current_limit: Configure an input limit.
*
* @set_active_discharge: Set active discharge enable/disable of regulators.
*
* @set_mode: Set the configured operating mode for the regulator.
* @get_mode: Get the configured operating mode for the regulator.
* @get_status: Return actual (not as-configured) status of regulator, as a
......@@ -149,6 +151,7 @@ struct regulator_ops {
int (*set_input_current_limit) (struct regulator_dev *, int lim_uA);
int (*set_over_current_protection) (struct regulator_dev *);
int (*set_active_discharge) (struct regulator_dev *, bool enable);
/* enable/disable regulator */
int (*enable) (struct regulator_dev *);
......@@ -266,6 +269,14 @@ enum regulator_type {
* @bypass_mask: Mask for control when using regmap set_bypass
* @bypass_val_on: Enabling value for control when using regmap set_bypass
* @bypass_val_off: Disabling value for control when using regmap set_bypass
* @active_discharge_off: Enabling value for control when using regmap
* set_active_discharge
* @active_discharge_on: Disabling value for control when using regmap
* set_active_discharge
* @active_discharge_mask: Mask for control when using regmap
* set_active_discharge
* @active_discharge_reg: Register for control when using regmap
* set_active_discharge
*
* @enable_time: Time taken for initial enable of regulator (in uS).
* @off_on_delay: guard time (in uS), before re-enabling a regulator
......@@ -315,6 +326,10 @@ struct regulator_desc {
unsigned int bypass_mask;
unsigned int bypass_val_on;
unsigned int bypass_val_off;
unsigned int active_discharge_on;
unsigned int active_discharge_off;
unsigned int active_discharge_mask;
unsigned int active_discharge_reg;
unsigned int enable_time;
......@@ -447,6 +462,8 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable);
int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable);
int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
bool enable);
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
#endif
......@@ -18,6 +18,9 @@
#define LP872X_MAX_REGULATORS 9
#define LP8720_ENABLE_DELAY 200
#define LP8725_ENABLE_DELAY 30000
enum lp872x_regulator_id {
LP8720_ID_BASE,
LP8720_ID_LDO1 = LP8720_ID_BASE,
......@@ -79,12 +82,14 @@ struct lp872x_regulator_data {
* @update_config : if LP872X_GENERAL_CFG register is updated, set true
* @regulator_data : platform regulator id and init data
* @dvs : dvs data for buck voltage control
* @enable_gpio : gpio pin number for enable control
*/
struct lp872x_platform_data {
u8 general_config;
bool update_config;
struct lp872x_regulator_data regulator_data[LP872X_MAX_REGULATORS];
struct lp872x_dvs *dvs;
int enable_gpio;
};
#endif
......@@ -42,6 +42,13 @@ struct regulator;
#define REGULATOR_CHANGE_DRMS 0x10
#define REGULATOR_CHANGE_BYPASS 0x20
/* Regulator active discharge flags */
enum regulator_active_discharge {
REGULATOR_ACTIVE_DISCHARGE_DEFAULT,
REGULATOR_ACTIVE_DISCHARGE_DISABLE,
REGULATOR_ACTIVE_DISCHARGE_ENABLE,
};
/**
* struct regulator_state - regulator state during low power system states
*
......@@ -100,6 +107,9 @@ struct regulator_state {
* @initial_state: Suspend state to set by default.
* @initial_mode: Mode to set at startup.
* @ramp_delay: Time to settle down after voltage change (unit: uV/us)
* @active_discharge: Enable/disable active discharge. The enum
* regulator_active_discharge values are used for
* initialisation.
* @enable_time: Turn-on time of the rails (unit: microseconds)
*/
struct regulation_constraints {
......@@ -140,6 +150,8 @@ struct regulation_constraints {
unsigned int ramp_delay;
unsigned int enable_time;
unsigned int active_discharge;
/* constraint flags */
unsigned always_on:1; /* regulator never off when system is on */
unsigned boot_on:1; /* bootloader/firmware enabled regulator */
......
......@@ -26,6 +26,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/tlv.h>
......@@ -157,6 +158,10 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
return reg == CS4271_CHIPID;
}
static const char * const supply_names[] = {
"vd", "vl", "va"
};
struct cs4271_private {
unsigned int mclk;
bool master;
......@@ -170,6 +175,7 @@ struct cs4271_private {
int gpio_disable;
/* enable soft reset workaround */
bool enable_soft_reset;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
};
static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
......@@ -487,6 +493,20 @@ static struct snd_soc_dai_driver cs4271_dai = {
.symmetric_rates = 1,
};
static int cs4271_reset(struct snd_soc_codec *codec)
{
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
if (gpio_is_valid(cs4271->gpio_nreset)) {
gpio_set_value(cs4271->gpio_nreset, 0);
mdelay(1);
gpio_set_value(cs4271->gpio_nreset, 1);
mdelay(1);
}
return 0;
}
#ifdef CONFIG_PM
static int cs4271_soc_suspend(struct snd_soc_codec *codec)
{
......@@ -499,6 +519,9 @@ static int cs4271_soc_suspend(struct snd_soc_codec *codec)
if (ret < 0)
return ret;
regcache_mark_dirty(cs4271->regmap);
regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
return 0;
}
......@@ -507,6 +530,16 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
int ret;
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
cs4271->supplies);
if (ret < 0) {
dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
return ret;
}
/* Do a proper reset after power up */
cs4271_reset(codec);
/* Restore codec state */
ret = regcache_sync(cs4271->regmap);
if (ret < 0)
......@@ -553,19 +586,24 @@ static int cs4271_codec_probe(struct snd_soc_codec *codec)
}
#endif
ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
cs4271->supplies);
if (ret < 0) {
dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
return ret;
}
if (cs4271plat) {
amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
}
if (gpio_is_valid(cs4271->gpio_nreset)) {
/* Reset codec */
gpio_direction_output(cs4271->gpio_nreset, 0);
mdelay(1);
gpio_set_value(cs4271->gpio_nreset, 1);
/* Give the codec time to wake up */
mdelay(1);
}
cs4271_reset(codec);
ret = regcache_sync(cs4271->regmap);
if (ret < 0)
return ret;
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
......@@ -595,6 +633,9 @@ static int cs4271_codec_remove(struct snd_soc_codec *codec)
/* Set codec to the reset state */
gpio_set_value(cs4271->gpio_nreset, 0);
regcache_mark_dirty(cs4271->regmap);
regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
return 0;
};
......@@ -617,6 +658,7 @@ static int cs4271_common_probe(struct device *dev,
{
struct cs4271_platform_data *cs4271plat = dev->platform_data;
struct cs4271_private *cs4271;
int i, ret;
cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
if (!cs4271)
......@@ -638,6 +680,17 @@ static int cs4271_common_probe(struct device *dev,
return ret;
}
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
cs4271->supplies[i].supply = supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs4271->supplies),
cs4271->supplies);
if (ret < 0) {
dev_err(dev, "Failed to get regulators: %d\n", ret);
return ret;
}
*c = cs4271;
return 0;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册