Commit 79f20778 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull regulator updates from Mark Brown:
 "This has been a very busy release for the core, some fixes, one large
  new feature and a big bit of refactoring to update the GPIO API:

   - Support for coupled regulators from Dmitry Osipenko based on a
     prior attempt by Maciej Purski, allowing us to handle situations
     where the voltages on two regulators can't be too far apart from
     each other.

   - Conversion of the GPIO support in both drivers and the core to use
     GPIO descriptors rather than numbers, part of the overall project
     to remove GPIO numbers.

   - Support for standby mode suspend states from Andrei Stefanescu.

   - New drivers for Allwinner AXP209, Cirrus Logic Lochnagar and
     Microchip MPC16502"

* tag 'regulator-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (90 commits)
  regulator: tps65910: fix a missing check of return value
  regulator: mcp16502: Select REGMAP_I2C to fix build error
  regulator: convert to DEFINE_SHOW_ATTRIBUTE
  regulator: mcp16502: Fix missing n_voltages setting
  regulator: mcp16502: Use #ifdef CONFIG_PM_SLEEP around mcp16502_suspend/resume_noirq
  regulator: mcp16502: code cleanup
  regulator: act8945a-regulator: make symbol act8945a_pm static
  drivers/regulator: fix a missing check of return value
  regulator: act8945a-regulator: fix 'defined but not used' compiler warning
  regulator: axp20x: fix set_ramp_delay for AXP209/dcdc2
  regulator: mcp16502: add support for suspend
  mfd: axp20x: use explicit bit defines
  mfd: axp20x: Clean up included headers
  regulator: dts: enable soft-start and ramp delay for the OLinuXino Lime2
  dt-bindings: mfd: axp20x: Add software based soft_start for AXP209 LDO3
  regulator: axp20x: add software based soft_start for AXP209 LDO3
  dt-bindings: mfd: axp20x: add support for regulator-ramp-delay for AXP209
  regulator: axp20x: add support for set_ramp_delay for AXP209
  mfd: axp20x: name voltage ramping define properly
  regulator: mcp16502: add regulator driver for MCP16502
  ...
parents d923fd6d c3b57259
......@@ -32,6 +32,15 @@ Required properties:
- interrupt-controller: The PMIC has its own internal IRQs
- #interrupt-cells: Should be set to 1
Supported common regulator properties, see ../regulator/regulator.txt for
more information:
- regulator-ramp-delay: sets the ramp up delay in uV/us
AXP20x/DCDC2: 1600, 800
AXP20x/LDO3: 1600, 800
- regulator-soft-start: enable the output at the lowest possible voltage and
only then set the desired voltage
AXP20x/LDO3: software-based implementation
Optional properties:
- x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz
AXP152/20X: range: 750-1875, Default: 1.5 MHz
......
......@@ -15,11 +15,17 @@ Optional input supply properties:
- inl67-supply: The input supply for REG_LDO3 and REG_LDO4
Any standard regulator properties can be used to configure the single regulator.
regulator-initial-mode, regulator-allowed-modes and regulator-mode could be
specified using mode values from dt-bindings/regulator/active-semi,8945a-regulator.h
file.
The valid names for regulators are:
REG_DCDC1, REG_DCDC2, REG_DCDC3, REG_LDO1, REG_LDO2, REG_LDO3, REG_LDO4.
Example:
#include <dt-bindings/regulator/active-semi,8945a-regulator.h>
pmic@5b {
compatible = "active-semi,act8945a";
reg = <0x5b>;
......@@ -32,6 +38,18 @@ Example:
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_FIXED>,
<ACT8945A_REGULATOR_MODE_LOWPOWER>;
regulator-initial-mode = <ACT8945A_REGULATOR_MODE_FIXED>;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-min-microvolt=<1400000>;
regulator-suspend-max-microvolt=<1400000>;
regulator-changeable-in-suspend;
regulator-mode=<ACT8945A_REGULATOR_MODE_LOWPOWER>;
};
};
vdd_1v2_reg: REG_DCDC2 {
......@@ -39,6 +57,14 @@ Example:
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1300000>;
regulator-always-on;
regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_FIXED>,
<ACT8945A_REGULATOR_MODE_LOWPOWER>;
regulator-initial-mode = <ACT8945A_REGULATOR_MODE_FIXED>;
regulator-state-mem {
regulator-off-in-suspend;
};
};
vdd_3v3_reg: REG_DCDC3 {
......@@ -53,6 +79,14 @@ Example:
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <2500000>;
regulator-always-on;
regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_NORMAL>,
<ACT8945A_REGULATOR_MODE_LOWPOWER>;
regulator-initial-mode = <ACT8945A_REGULATOR_MODE_NORMAL>;
regulator-state-mem {
regulator-off-in-suspend;
};
};
vdd_3v3_lp_reg: REG_LDO2 {
......
Cirrus Logic Lochnagar Audio Development Board
Lochnagar is an evaluation and development board for Cirrus Logic
Smart CODEC and Amp devices. It allows the connection of most Cirrus
Logic devices on mini-cards, as well as allowing connection of
various application processor systems to provide a full evaluation
platform. Audio system topology, clocking and power can all be
controlled through the Lochnagar, allowing the device under test
to be used in a variety of possible use cases.
This binding document describes the binding for the regulator portion
of the driver.
Also see these documents for generic binding information:
[1] Regulator: ../regulator/regulator.txt
This binding must be part of the Lochnagar MFD binding:
[2] ../mfd/cirrus,lochnagar.txt
Optional sub-nodes:
- VDDCORE : Initialisation data for the VDDCORE regulator, which
supplies the CODECs digital core if it has no build regulator for that
purpose.
Required Properties:
- compatible : One of the following strings:
"cirrus,lochnagar2-vddcore"
- SYSVDD-supply: Primary power supply for the Lochnagar.
- MICVDD : Initialisation data for the MICVDD regulator, which
supplies the CODECs MICVDD.
Required Properties:
- compatible : One of the following strings:
"cirrus,lochnagar2-micvdd"
- SYSVDD-supply: Primary power supply for the Lochnagar.
- MIC1VDD, MIC2VDD : Initialisation data for the MICxVDD supplies.
Required Properties:
- compatible : One of the following strings:
"cirrus,lochnagar2-mic1vdd", "cirrus,lochnagar2-mic2vdd"
Optional Properties:
- cirrus,micbias-input : A property selecting which of the CODEC
minicard micbias outputs should be used, valid values are 1 - 4.
- MICBIAS1-supply, MICBIAS2-supply: Regulator supplies for the
MICxVDD outputs, supplying the digital microphones, normally
supplied from the attached CODEC.
- VDD1V8 : Recommended fixed regulator for the VDD1V8 regulator, which supplies the
CODECs analog and 1.8V digital supplies.
Required Properties:
- compatible : Should be set to "regulator-fixed"
- regulator-min-microvolt : Should be set to 1.8V
- regulator-max-microvolt : Should be set to 1.8V
- regulator-boot-on
- regulator-always-on
- vin-supply : Should be set to same supply as SYSVDD
Example:
lochnagar {
lochnagar-micvdd: MICVDD {
compatible = "cirrus,lochnagar2-micvdd";
SYSVDD-supply = <&wallvdd>;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
lochnagar-vdd1v8: VDD1V8 {
compatible = "regulator-fixed";
regulator-name = "VDD1V8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-boot-on;
regulator-always-on;
vin-supply = <&wallvdd>;
};
};
MCP16502 PMIC
Required properties:
- compatible: "microchip,mcp16502"
- reg: I2C slave address
- lpm-gpios: GPIO for LPM pin. Note that this GPIO *must* remain high during
suspend-to-ram, keeping the PMIC into HIBERNATE mode.
- regulators: A node that houses a sub-node for each regulator within
the device. Each sub-node is identified using the node's
name. The content of each sub-node is defined by the
standard binding for regulators; see regulator.txt.
Regualtors of MCP16502 PMIC:
1) VDD_IO - Buck (1.2 - 3.7 V)
2) VDD_DDR - Buck (0.6 - 1.85 V)
3) VDD_CORE - Buck (0.6 - 1.85 V)
4) VDD_OTHER - BUCK (0.6 - 1.85 V)
5) LDO1 - LDO (1.2 - 3.7 V)
6) LDO2 - LDO (1.2 - 3.7 V)
Regulator modes:
2 - FPWM: higher precision, higher consumption
4 - AutoPFM: lower precision, lower consumption
Each regulator is defined using the standard binding for regulators.
Example:
mcp16502@5b {
compatible = "microchip,mcp16502";
reg = <0x5b>;
status = "okay";
lpm-gpios = <&pioBU 7 GPIO_ACTIVE_HIGH>;
regulators {
VDD_IO {
regulator-name = "VDD_IO";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3700000>;
regulator-initial-mode = <2>;
regulator-allowed-modes = <2>, <4>;
regulator-always-on;
regulator-state-standby {
regulator-on-in-suspend;
regulator-mode = <4>;
};
regulator-state-mem {
regulator-off-in-suspend;
regulator-mode = <4>;
};
};
VDD_DDR {
regulator-name = "VDD_DDR";
regulator-min-microvolt = <600000>;
regulator-max-microvolt = <1850000>;
regulator-initial-mode = <2>;
regulator-allowed-modes = <2>, <4>;
regulator-always-on;
regulator-state-standby {
regulator-on-in-suspend;
regulator-mode = <4>;
};
regulator-state-mem {
regulator-on-in-suspend;
regulator-mode = <4>;
};
};
VDD_CORE {
regulator-name = "VDD_CORE";
regulator-min-microvolt = <600000>;
regulator-max-microvolt = <1850000>;
regulator-initial-mode = <2>;
regulator-allowed-modes = <2>, <4>;
regulator-always-on;
regulator-state-standby {
regulator-on-in-suspend;
regulator-mode = <4>;
};
regulator-state-mem {
regulator-off-in-suspend;
regulator-mode = <4>;
};
};
VDD_OTHER {
regulator-name = "VDD_OTHER";
regulator-min-microvolt = <600000>;
regulator-max-microvolt = <1850000>;
regulator-initial-mode = <2>;
regulator-allowed-modes = <2>, <4>;
regulator-always-on;
regulator-state-standby {
regulator-on-in-suspend;
regulator-mode = <4>;
};
regulator-state-mem {
regulator-off-in-suspend;
regulator-mode = <4>;
};
};
LDO1 {
regulator-name = "LDO1";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3700000>;
regulator-always-on;
regulator-state-standby {
regulator-on-in-suspend;
};
regulator-state-mem {
regulator-off-in-suspend;
};
};
LDO2 {
regulator-name = "LDO2";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3700000>;
regulator-always-on;
regulator-state-standby {
regulator-on-in-suspend;
};
regulator-state-mem {
regulator-off-in-suspend;
};
};
};
};
......@@ -33,13 +33,16 @@ Optional properties:
decreases of any level. This is useful for regulators with exponential
voltage changes.
- regulator-soft-start: Enable soft start so that voltage ramps slowly
- regulator-state-standby sub-root node for Standby mode
: equivalent with standby Linux sleep state, which provides energy savings
with a relatively quick transition back time.
- regulator-state-mem sub-root node for Suspend-to-RAM mode
: suspend to memory, the device goes to sleep, but all data stored in memory,
only some external interrupt can wake the device.
- regulator-state-disk sub-root node for Suspend-to-DISK mode
: suspend to disk, this state operates similarly to Suspend-to-RAM,
but includes a final step of writing memory contents to disk.
- regulator-state-[mem/disk] node has following common properties:
- regulator-state-[mem/disk/standby] node has following common properties:
- regulator-on-in-suspend: regulator should be on in suspend state.
- regulator-off-in-suspend: regulator should be off in suspend state.
- regulator-suspend-min-microvolt: minimum voltage may be set in
......@@ -76,8 +79,11 @@ Optional properties:
- regulator-coupled-with: Regulators with which the regulator
is coupled. The linkage is 2-way - all coupled regulators should be linked
with each other. A regulator should not be coupled with its supplier.
- regulator-coupled-max-spread: Max spread between voltages of coupled regulators
in microvolts.
- regulator-coupled-max-spread: Array of maximum spread between voltages of
coupled regulators in microvolts, each value in the array relates to the
corresponding couple specified by the regulator-coupled-with property.
- regulator-max-step-microvolt: Maximum difference between current and target
voltages that can be changed safely in a single step.
Deprecated properties:
- regulator-compatible: If a regulator chip contains multiple
......
......@@ -254,6 +254,7 @@ GPIO
devm_gpiod_get_index_optional()
devm_gpiod_get_optional()
devm_gpiod_put()
devm_gpiod_unhinge()
devm_gpiochip_add_data()
devm_gpiochip_remove()
devm_gpio_request()
......
......@@ -9891,6 +9891,13 @@ M: Ludovic Desroches <ludovic.desroches@microchip.com>
S: Maintained
F: drivers/mmc/host/atmel-mci.c
MICROCHIP MCP16502 PMIC DRIVER
M: Andrei Stefanescu <andrei.stefanescu@microchip.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
F: drivers/regulator/mcp16502.c
MICROCHIP MCP3911 ADC DRIVER
M: Marcus Folkesson <marcus.folkesson@gmail.com>
M: Kent Gustavsson <kent@minoris.se>
......
......@@ -245,6 +245,8 @@ &reg_ldo3 {
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
regulator-name = "vddio-csi0";
regulator-soft-start;
regulator-ramp-delay = <1600>;
};
&reg_ldo4 {
......
......@@ -194,8 +194,8 @@ static struct wm8994_pdata wm8994_pdata = {
0x3, /* IRQ out, active high, CMOS */
},
.ldo = {
{ .enable = S3C64XX_GPN(6), .init_data = &wm8994_ldo1, },
{ .enable = S3C64XX_GPN(4), .init_data = &wm8994_ldo2, },
{ .init_data = &wm8994_ldo1, },
{ .init_data = &wm8994_ldo2, },
},
};
......@@ -203,6 +203,18 @@ static const struct i2c_board_info wm1277_devs[] = {
{ I2C_BOARD_INFO("wm8958", 0x1a), /* WM8958 is the superset */
.platform_data = &wm8994_pdata,
.irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
.dev_name = "wm8958",
},
};
static struct gpiod_lookup_table wm8994_gpiod_table = {
.dev_id = "i2c-wm8958", /* I2C device name */
.table = {
GPIO_LOOKUP("GPION", 6,
"wlf,ldo1ena", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("GPION", 4,
"wlf,ldo2ena", GPIO_ACTIVE_HIGH),
{ },
},
};
......@@ -381,6 +393,7 @@ static int wlf_gf_module_probe(struct i2c_client *i2c,
gpiod_add_lookup_table(&wm5102_reva_gpiod_table);
gpiod_add_lookup_table(&wm5102_gpiod_table);
gpiod_add_lookup_table(&wm8994_gpiod_table);
if (i < ARRAY_SIZE(gf_mods)) {
dev_info(&i2c->dev, "%s revision %d\n",
......
......@@ -98,15 +98,28 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
struct gpio_desc **dr;
struct gpio_desc *desc;
desc = gpiod_get_index(dev, con_id, idx, flags);
if (IS_ERR(desc))
return desc;
/*
* For non-exclusive GPIO descriptors, check if this descriptor is
* already under resource management by this device.
*/
if (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
struct devres *dres;
dres = devres_find(dev, devm_gpiod_release,
devm_gpiod_match, &desc);
if (dres)
return desc;
}
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
GFP_KERNEL);
if (!dr)
if (!dr) {
gpiod_put(desc);
return ERR_PTR(-ENOMEM);
desc = gpiod_get_index(dev, con_id, idx, flags);
if (IS_ERR(desc)) {
devres_free(dr);
return desc;
}
*dr = desc;
......@@ -140,15 +153,28 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
struct gpio_desc **dr;
struct gpio_desc *desc;
desc = gpiod_get_from_of_node(node, propname, index, dflags, label);
if (IS_ERR(desc))
return desc;
/*
* For non-exclusive GPIO descriptors, check if this descriptor is
* already under resource management by this device.
*/
if (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
struct devres *dres;
dres = devres_find(dev, devm_gpiod_release,
devm_gpiod_match, &desc);
if (dres)
return desc;
}
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
GFP_KERNEL);
if (!dr)
if (!dr) {
gpiod_put(desc);
return ERR_PTR(-ENOMEM);
desc = gpiod_get_from_of_node(node, propname, index, dflags, label);
if (IS_ERR(desc)) {
devres_free(dr);
return desc;
}
*dr = desc;
......@@ -320,6 +346,36 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
}
EXPORT_SYMBOL(devm_gpiod_put);
/**
* devm_gpiod_unhinge - Remove resource management from a gpio descriptor
* @dev: GPIO consumer
* @desc: GPIO descriptor to remove resource management from
*
* Remove resource management from a GPIO descriptor. This is needed when
* you want to hand over lifecycle management of a descriptor to another
* mechanism.
*/
void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc)
{
int ret;
if (IS_ERR_OR_NULL(desc))
return;
ret = devres_destroy(dev, devm_gpiod_release,
devm_gpiod_match, &desc);
/*
* If the GPIO descriptor is requested as nonexclusive, we
* may call this function several times on the same descriptor
* so it is OK if devres_destroy() returns -ENOENT.
*/
if (ret == -ENOENT)
return;
/* Anything else we should warn about */
WARN_ON(ret);
}
EXPORT_SYMBOL(devm_gpiod_unhinge);
/**
* devm_gpiod_put_array - Resource-managed gpiod_put_array()
* @dev: GPIO consumer
......
......@@ -4205,6 +4205,8 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
transitory = flags & OF_GPIO_TRANSITORY;
ret = gpiod_request(desc, label);
if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
return desc;
if (ret)
return ERR_PTR(ret);
......
......@@ -201,12 +201,6 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
struct gpio_array *array_info,
unsigned long *value_bitmap);
/* This is just passed between gpiolib and devres */
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label);
extern struct spinlock gpio_lock;
extern struct list_head gpio_devices;
......
......@@ -16,20 +16,21 @@
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/axp20x.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/axp20x.h>
#include <linux/mfd/core.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#define AXP20X_OFF 0x80
#define AXP20X_OFF BIT(7)
#define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE 0
#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4)
......
......@@ -21,7 +21,6 @@
#include <linux/mfd/core.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
......@@ -306,14 +305,6 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994)
pdata->csnaddr_pd = of_property_read_bool(np, "wlf,csnaddr-pd");
pdata->ldo[0].enable = of_get_named_gpio(np, "wlf,ldo1ena", 0);
if (pdata->ldo[0].enable < 0)
pdata->ldo[0].enable = 0;
pdata->ldo[1].enable = of_get_named_gpio(np, "wlf,ldo2ena", 0);
if (pdata->ldo[1].enable < 0)
pdata->ldo[1].enable = 0;
return 0;
}
#else
......
......@@ -328,7 +328,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
return -ENODEV;
}
for_each_child_of_node(nproot, np) {
if (!of_node_cmp(np->name, info->desc.name)) {
if (of_node_name_eq(np, info->desc.name)) {
config->init_data =
of_get_regulator_init_data(&pdev->dev, np,
&info->desc);
......
......@@ -567,6 +567,16 @@ config REGULATOR_MC13892
Say y here to support the regulators found on the Freescale MC13892
PMIC.
config REGULATOR_MCP16502
tristate "Microchip MCP16502 PMIC"
depends on I2C && OF
select REGMAP_I2C
help
Say y here to support the MCP16502 PMIC. This driver supports
basic operations (get/set voltage, get/set operating mode)
through the regulator interface. In addition it enables
suspend-to-ram/standby transition.
config REGULATOR_MT6311
tristate "MediaTek MT6311 PMIC"
depends on I2C
......
......@@ -74,6 +74,7 @@ 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
obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
......
......@@ -15,31 +15,41 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <dt-bindings/regulator/active-semi,8945a-regulator.h>
/**
* ACT8945A Global Register Map.
*/
#define ACT8945A_SYS_MODE 0x00
#define ACT8945A_SYS_CTRL 0x01
#define ACT8945A_SYS_UNLK_REGS 0x0b
#define ACT8945A_DCDC1_VSET1 0x20
#define ACT8945A_DCDC1_VSET2 0x21
#define ACT8945A_DCDC1_CTRL 0x22
#define ACT8945A_DCDC1_SUS 0x24
#define ACT8945A_DCDC2_VSET1 0x30
#define ACT8945A_DCDC2_VSET2 0x31
#define ACT8945A_DCDC2_CTRL 0x32
#define ACT8945A_DCDC2_SUS 0x34
#define ACT8945A_DCDC3_VSET1 0x40
#define ACT8945A_DCDC3_VSET2 0x41
#define ACT8945A_DCDC3_CTRL 0x42
#define ACT8945A_DCDC3_SUS 0x44
#define ACT8945A_LDO1_VSET 0x50
#define ACT8945A_LDO1_CTRL 0x51
#define ACT8945A_LDO1_SUS 0x52
#define ACT8945A_LDO2_VSET 0x54
#define ACT8945A_LDO2_CTRL 0x55
#define ACT8945A_LDO2_SUS 0x56
#define ACT8945A_LDO3_VSET 0x60
#define ACT8945A_LDO3_CTRL 0x61
#define ACT8945A_LDO3_SUS 0x62
#define ACT8945A_LDO4_VSET 0x64
#define ACT8945A_LDO4_CTRL 0x65
#define ACT8945A_LDO4_SUS 0x66
/**
* Field Definitions.
......@@ -60,7 +70,12 @@ enum {
ACT8945A_ID_LDO2,
ACT8945A_ID_LDO3,
ACT8945A_ID_LDO4,
ACT8945A_REG_NUM,
ACT8945A_ID_MAX,
};
struct act8945a_pmic {
struct regmap *regmap;
u32 op_mode[ACT8945A_ID_MAX];
};
static const struct regulator_linear_range act8945a_voltage_ranges[] = {
......@@ -69,6 +84,143 @@ static const struct regulator_linear_range act8945a_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
};
static int act8945a_set_suspend_state(struct regulator_dev *rdev, bool enable)
{
struct regmap *regmap = rdev->regmap;
int id = rdev->desc->id, reg, val;
switch (id) {
case ACT8945A_ID_DCDC1:
reg = ACT8945A_DCDC1_SUS;
val = 0xa8;
break;
case ACT8945A_ID_DCDC2:
reg = ACT8945A_DCDC2_SUS;
val = 0xa8;
break;
case ACT8945A_ID_DCDC3:
reg = ACT8945A_DCDC3_SUS;
val = 0xa8;
break;
case ACT8945A_ID_LDO1:
reg = ACT8945A_LDO1_SUS;
val = 0xe8;
break;
case ACT8945A_ID_LDO2:
reg = ACT8945A_LDO2_SUS;
val = 0xe8;
break;
case ACT8945A_ID_LDO3:
reg = ACT8945A_LDO3_SUS;
val = 0xe8;
break;
case ACT8945A_ID_LDO4:
reg = ACT8945A_LDO4_SUS;
val = 0xe8;
break;
default:
return -EINVAL;
}
if (enable)
val |= BIT(4);
/*
* Ask the PMIC to enable/disable this output when entering hibernate
* mode.
*/
return regmap_write(regmap, reg, val);
}
static int act8945a_set_suspend_enable(struct regulator_dev *rdev)
{
return act8945a_set_suspend_state(rdev, true);
}
static int act8945a_set_suspend_disable(struct regulator_dev *rdev)
{
return act8945a_set_suspend_state(rdev, false);
}
static unsigned int act8945a_of_map_mode(unsigned int mode)
{
switch (mode) {
case ACT8945A_REGULATOR_MODE_FIXED:
case ACT8945A_REGULATOR_MODE_NORMAL:
return REGULATOR_MODE_NORMAL;
case ACT8945A_REGULATOR_MODE_LOWPOWER:
return REGULATOR_MODE_STANDBY;
default:
return REGULATOR_MODE_INVALID;
}
}
static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev);
struct regmap *regmap = rdev->regmap;
int id = rdev->desc->id;
int reg, ret, val = 0;
switch (id) {
case ACT8945A_ID_DCDC1:
reg = ACT8945A_DCDC1_CTRL;
break;
case ACT8945A_ID_DCDC2:
reg = ACT8945A_DCDC2_CTRL;
break;
case ACT8945A_ID_DCDC3:
reg = ACT8945A_DCDC3_CTRL;
break;
case ACT8945A_ID_LDO1:
reg = ACT8945A_LDO1_SUS;
break;
case ACT8945A_ID_LDO2:
reg = ACT8945A_LDO2_SUS;
break;
case ACT8945A_ID_LDO3:
reg = ACT8945A_LDO3_SUS;
break;
case ACT8945A_ID_LDO4:
reg = ACT8945A_LDO4_SUS;
break;
default:
return -EINVAL;
}
switch (mode) {
case REGULATOR_MODE_STANDBY:
if (rdev->desc->id > ACT8945A_ID_DCDC3)
val = BIT(5);
break;
case REGULATOR_MODE_NORMAL:
if (rdev->desc->id <= ACT8945A_ID_DCDC3)
val = BIT(5);
break;
default:
return -EINVAL;
}
ret = regmap_update_bits(regmap, reg, BIT(5), val);
if (ret)
return ret;
act8945a->op_mode[id] = mode;
return 0;
}
static unsigned int act8945a_get_mode(struct regulator_dev *rdev)
{
struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev);
int id = rdev->desc->id;
if (id < ACT8945A_ID_DCDC1 || id >= ACT8945A_ID_MAX)
return -EINVAL;
return act8945a->op_mode[id];
}
static const struct regulator_ops act8945a_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
......@@ -76,7 +228,11 @@ static const struct regulator_ops act8945a_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.set_mode = act8945a_set_mode,
.get_mode = act8945a_get_mode,
.is_enabled = regulator_is_enabled_regmap,
.set_suspend_enable = act8945a_set_suspend_enable,
.set_suspend_disable = act8945a_set_suspend_disable,
};
#define ACT89xx_REG(_name, _family, _id, _vsel_reg, _supply) \
......@@ -84,6 +240,7 @@ static const struct regulator_ops act8945a_ops = {
.name = _name, \
.supply_name = _supply, \
.of_match = of_match_ptr("REG_"#_id), \
.of_map_mode = act8945a_of_map_mode, \
.regulators_node = of_match_ptr("regulators"), \
.id = _family##_ID_##_id, \
.type = REGULATOR_VOLTAGE, \
......@@ -122,10 +279,22 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
{
struct regulator_config config = { };
const struct regulator_desc *regulators;
struct act8945a_pmic *act8945a;
struct regulator_dev *rdev;
int i, num_regulators;
bool voltage_select;
act8945a = devm_kzalloc(&pdev->dev, sizeof(*act8945a), GFP_KERNEL);
if (!act8945a)
return -ENOMEM;
act8945a->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!act8945a->regmap) {
dev_err(&pdev->dev,
"could not retrieve regmap from parent device\n");
return -EINVAL;
}
voltage_select = of_property_read_bool(pdev->dev.parent->of_node,
"active-semi,vsel-high");
......@@ -139,8 +308,10 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
config.dev = &pdev->dev;
config.dev->of_node = pdev->dev.parent->of_node;
config.driver_data = act8945a;
for (i = 0; i < num_regulators; i++) {
rdev = devm_regulator_register(&pdev->dev, &regulators[i], &config);
rdev = devm_regulator_register(&pdev->dev, &regulators[i],
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev,
"failed to register %s regulator\n",
......@@ -149,14 +320,42 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
}
}
return 0;
platform_set_drvdata(pdev, act8945a);
/* Unlock expert registers. */
return regmap_write(act8945a->regmap, ACT8945A_SYS_UNLK_REGS, 0xef);
}
static int __maybe_unused act8945a_suspend(struct device *pdev)
{
struct act8945a_pmic *act8945a = dev_get_drvdata(pdev);
/*
* Ask the PMIC to enter the suspend mode on the next PWRHLD
* transition.
*/
return regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x42);
}
static SIMPLE_DEV_PM_OPS(act8945a_pm, act8945a_suspend, NULL);
static void act8945a_pmic_shutdown(struct platform_device *pdev)
{
struct act8945a_pmic *act8945a = platform_get_drvdata(pdev);
/*
* Ask the PMIC to shutdown everything on the next PWRHLD transition.
*/
regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x0);
}
static struct platform_driver act8945a_pmic_driver = {
.driver = {
.name = "act8945a-regulator",
.pm = &act8945a_pm,
},
.probe = act8945a_pmic_probe,
.shutdown = act8945a_pmic_shutdown,
};
module_platform_driver(act8945a_pmic_driver);
......
......@@ -283,9 +283,6 @@ static int arizona_ldo1_common_init(struct platform_device *pdev,
of_node_put(config.of_node);
if (IS_ERR(ldo1->regulator)) {
if (config.ena_gpiod)
gpiod_put(config.ena_gpiod);
ret = PTR_ERR(ldo1->regulator);
dev_err(&pdev->dev, "Failed to register LDO1 supply: %d\n",
ret);
......
// SPDX-License-Identifier: GPL-2.0
/*
* AS3711 PMIC regulator driver, using DCDC Step Down and LDO supplies
*
* Copyright (C) 2012 Renesas Electronics Corporation
* Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the version 2 of the GNU General Public License as
* published by the Free Software Foundation
*/
#include <linux/err.h>
......
This diff is collapsed.
......@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd718x7.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
......@@ -130,6 +131,7 @@ static struct regulator_ops bd718xx_buck_regulator_nolinear_ops = {
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = bd718xx_set_voltage_sel_restricted,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
......@@ -1007,7 +1009,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
};
struct bd718xx_pmic_inits {
const struct bd718xx_regulator_data (*r_datas)[];
const struct bd718xx_regulator_data *r_datas;
unsigned int r_amount;
};
......@@ -1017,11 +1019,11 @@ static int bd718xx_probe(struct platform_device *pdev)
struct regulator_config config = { 0 };
struct bd718xx_pmic_inits pmic_regulators[] = {
[BD718XX_TYPE_BD71837] = {
.r_datas = &bd71837_regulators,
.r_datas = bd71837_regulators,
.r_amount = ARRAY_SIZE(bd71837_regulators),
},
[BD718XX_TYPE_BD71847] = {
.r_datas = &bd71847_regulators,
.r_datas = bd71847_regulators,
.r_amount = ARRAY_SIZE(bd71847_regulators),
},
};
......@@ -1053,13 +1055,36 @@ static int bd718xx_probe(struct platform_device *pdev)
BD718XX_REG_REGLOCK);
}
/* At poweroff transition PMIC HW disables EN bit for regulators but
* leaves SEL bit untouched. So if state transition from POWEROFF
* is done to SNVS - then all power rails controlled by SW (having
* SEL bit set) stay disabled as EN is cleared. This may result boot
* failure if any crucial systems are powered by these rails.
*
* Change the next stage from poweroff to be READY instead of SNVS
* for all reset types because OTP loading at READY will clear SEL
* bit allowing HW defaults for power rails to be used
*/
err = regmap_update_bits(mfd->regmap, BD718XX_REG_TRANS_COND1,
BD718XX_ON_REQ_POWEROFF_MASK |
BD718XX_SWRESET_POWEROFF_MASK |
BD718XX_WDOG_POWEROFF_MASK |
BD718XX_KEY_L_POWEROFF_MASK,
BD718XX_POWOFF_TO_RDY);
if (err) {
dev_err(&pdev->dev, "Failed to change reset target\n");
goto err;
} else {
dev_dbg(&pdev->dev, "Changed all resets from SVNS to READY\n");
}
for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) {
const struct regulator_desc *desc;
struct regulator_dev *rdev;
const struct bd718xx_regulator_data *r;
r = &(*pmic_regulators[mfd->chip_type].r_datas)[i];
r = &pmic_regulators[mfd->chip_type].r_datas[i];
desc = &r->desc;
config.dev = pdev->dev.parent;
......
// SPDX-License-Identifier: GPL-2.0
/*
* ROHM BD9571MWV-M regulator driver
*
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.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 TPS65086 driver
*
* NOTE: VD09 is missing
......
This diff is collapsed.
......@@ -435,7 +435,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
return -ENODEV;
for_each_child_of_node(nproot, np) {
if (!of_node_cmp(np->name,
if (of_node_name_eq(np,
regulator->info->reg_desc.name)) {
config.init_data = of_get_regulator_init_data(
&pdev->dev, np,
......
......@@ -131,7 +131,7 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
if (error < 0)
goto error_i2c;
mutex_lock(&chip->rdev->mutex);
regulator_lock(chip->rdev);
if (val & DA9210_E_OVCURR) {
regulator_notifier_call_chain(chip->rdev,
......@@ -157,7 +157,7 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
handled |= DA9210_E_VMAX;
}
mutex_unlock(&chip->rdev->mutex);
regulator_unlock(chip->rdev);
if (handled) {
/* Clear handled events */
......
......@@ -389,6 +389,12 @@ static int da9211_regulator_init(struct da9211 *chip)
else
config.ena_gpiod = NULL;
/*
* Hand the GPIO descriptor management over to the regulator
* core, remove it from GPIO devres management.
*/
if (config.ena_gpiod)
devm_gpiod_unhinge(chip->dev, config.ena_gpiod);
chip->rdev[i] = devm_regulator_register(chip->dev,
&da9211_regulators[i], &config);
if (IS_ERR(chip->rdev[i])) {
......
......@@ -75,7 +75,7 @@ static struct ux500_regulator_debug {
u8 *state_after_suspend;
} rdebug;
static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
static int ux500_regulator_power_state_cnt_show(struct seq_file *s, void *p)
{
/* print power state count */
seq_printf(s, "ux500-regulator power state count: %i\n",
......@@ -83,23 +83,9 @@ static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
return 0;
}
DEFINE_SHOW_ATTRIBUTE(ux500_regulator_power_state_cnt);
static int ux500_regulator_power_state_cnt_open(struct inode *inode,
struct file *file)
{
return single_open(file, ux500_regulator_power_state_cnt_print,
inode->i_private);
}
static const struct file_operations ux500_regulator_power_state_cnt_fops = {
.open = ux500_regulator_power_state_cnt_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static int ux500_regulator_status_print(struct seq_file *s, void *p)
static int ux500_regulator_status_show(struct seq_file *s, void *p)
{
int i;
......@@ -122,20 +108,7 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p)
return 0;
}
static int ux500_regulator_status_open(struct inode *inode, struct file *file)
{
return single_open(file, ux500_regulator_status_print,
inode->i_private);
}
static const struct file_operations ux500_regulator_status_fops = {
.open = ux500_regulator_status_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
DEFINE_SHOW_ATTRIBUTE(ux500_regulator_status);
int __attribute__((weak)) dbx500_regulator_testcase(
struct dbx500_regulator_info *regulator_info,
......
......@@ -183,7 +183,11 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
*/
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags);
/*
* Do not use devm* here: the regulator core takes over the
* lifecycle management of the GPIO descriptor.
*/
cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags);
if (IS_ERR(cfg.ena_gpiod))
return PTR_ERR(cfg.ena_gpiod);
......
......@@ -42,6 +42,8 @@ struct regulator {
unsigned int always_on:1;
unsigned int bypass:1;
int uA_load;
unsigned int enable_count;
unsigned int deferred_disables;
struct regulator_voltage voltage[REGULATOR_STATES_NUM];
const char *supply_name;
struct device_attribute dev_attr;
......
......@@ -224,13 +224,15 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev,
/*
* Check LCM_EN1/2_GPIO is configured.
* Those pins are used for enabling VPOS/VNEG LDOs.
* Do not use devm* here: the regulator core takes over the
* lifecycle management of the GPIO descriptor.
*/
switch (id) {
case LM3632_LDO_POS:
return devm_gpiod_get_index_optional(dev, "enable", 0,
return gpiod_get_index_optional(dev, "enable", 0,
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
case LM3632_LDO_NEG:
return devm_gpiod_get_index_optional(dev, "enable", 1,
return gpiod_get_index_optional(dev, "enable", 1,
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
default:
return NULL;
......@@ -263,6 +265,8 @@ static int lm363x_regulator_probe(struct platform_device *pdev)
LM3632_EXT_EN_MASK,
LM3632_EXT_EN_MASK);
if (ret) {
if (gpiod)
gpiod_put(gpiod);
dev_err(dev, "External pin err: %d\n", ret);
return ret;
}
......
......@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
......@@ -20,6 +21,8 @@
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/lochnagar.h>
#include <linux/mfd/lochnagar1_regs.h>
#include <linux/mfd/lochnagar2_regs.h>
static const struct regulator_ops lochnagar_micvdd_ops = {
.enable = regulator_enable_regmap,
......@@ -212,28 +215,52 @@ static const struct regulator_desc lochnagar_regulators[] = {
},
};
static const struct of_device_id lochnagar_of_match[] = {
{
.compatible = "cirrus,lochnagar2-micvdd",
.data = &lochnagar_regulators[LOCHNAGAR_MICVDD],
},
{
.compatible = "cirrus,lochnagar2-mic1vdd",
.data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD],
},
{
.compatible = "cirrus,lochnagar2-mic2vdd",
.data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD],
},
{
.compatible = "cirrus,lochnagar2-vddcore",
.data = &lochnagar_regulators[LOCHNAGAR_VDDCORE],
},
{},
};
static int lochnagar_regulator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
struct regulator_config config = { };
const struct of_device_id *of_id;
const struct regulator_desc *desc;
struct regulator_dev *rdev;
int ret, i;
int ret;
config.dev = lochnagar->dev;
config.dev = dev;
config.regmap = lochnagar->regmap;
config.driver_data = lochnagar;
for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) {
const struct regulator_desc *desc = &lochnagar_regulators[i];
of_id = of_match_device(lochnagar_of_match, dev);
if (!of_id)
return -EINVAL;
rdev = devm_regulator_register(dev, desc, &config);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
dev_err(dev, "Failed to register %s regulator: %d\n",
desc->name, ret);
return ret;
}
desc = of_id->data;
rdev = devm_regulator_register(dev, desc, &config);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
dev_err(dev, "Failed to register %s regulator: %d\n",
desc->name, ret);
return ret;
}
return 0;
......@@ -242,6 +269,7 @@ static int lochnagar_regulator_probe(struct platform_device *pdev)
static struct platform_driver lochnagar_regulator_driver = {
.driver = {
.name = "lochnagar-regulator",
.of_match_table = of_match_ptr(lochnagar_of_match),
},
.probe = lochnagar_regulator_probe,
......
......@@ -501,8 +501,12 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
return 0;
}
/* FIXME: check default mode for GPIO here: high or low? */
ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev,
/*
* Do not use devm* here: the regulator core takes over the
* lifecycle management of the GPIO descriptor.
* FIXME: check default mode for GPIO here: high or low?
*/
ldo->ena_gpiod = gpiod_get_index_optional(&pdev->dev,
"enable",
enable_id,
GPIOD_OUT_HIGH |
......
......@@ -11,8 +11,7 @@
#include <linux/kernel.h>
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
......@@ -76,6 +75,7 @@ enum max77686_ramp_rate {
};
struct max77686_data {
struct device *dev;
DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS);
/* Array indexed by regulator id */
......@@ -250,26 +250,34 @@ static int max77686_of_parse_cb(struct device_node *np,
struct regulator_config *config)
{
struct max77686_data *max77686 = config->driver_data;
int ret;
switch (desc->id) {
case MAX77686_BUCK8:
case MAX77686_BUCK9:
case MAX77686_LDO20 ... MAX77686_LDO22:
config->ena_gpio = of_get_named_gpio(np,
"maxim,ena-gpios", 0);
config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
config->ena_gpio_initialized = true;
config->ena_gpiod = gpiod_get_from_of_node(np,
"maxim,ena",
0,
GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
"max77686-regulator");
if (IS_ERR(config->ena_gpiod))
config->ena_gpiod = NULL;
break;
default:
return 0;
}
if (gpio_is_valid(config->ena_gpio)) {
if (config->ena_gpiod) {
set_bit(desc->id, max77686->gpio_enabled);
return regmap_update_bits(config->regmap, desc->enable_reg,
desc->enable_mask,
MAX77686_GPIO_CONTROL);
ret = regmap_update_bits(config->regmap, desc->enable_reg,
desc->enable_mask,
MAX77686_GPIO_CONTROL);
if (ret) {
gpiod_put(config->ena_gpiod);
config->ena_gpiod = NULL;
}
}
return 0;
......@@ -507,6 +515,7 @@ static int max77686_pmic_probe(struct platform_device *pdev)
if (!max77686)
return -ENOMEM;
max77686->dev = &pdev->dev;
config.dev = iodev->dev;
config.regmap = iodev->regmap;
config.driver_data = max77686;
......
......@@ -231,9 +231,13 @@ static int max8952_pmic_probe(struct i2c_client *client,
else
gflags = GPIOD_OUT_LOW;
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
gpiod = devm_gpiod_get_optional(&client->dev,
"max8952,en",
gflags);
/*
* Do not use devm* here: the regulator core takes over the
* lifecycle management of the GPIO descriptor.
*/
gpiod = gpiod_get_optional(&client->dev,
"max8952,en",
gflags);
if (IS_ERR(gpiod))
return PTR_ERR(gpiod);
if (gpiod)
......
......@@ -808,7 +808,13 @@ static int max8973_probe(struct i2c_client *client,
config.of_node = client->dev.of_node;
config.regmap = max->regmap;
/* Register the regulators */
/*
* Register the regulators
* Turn the GPIO descriptor over to the regulator core for
* lifecycle management if we pass an ena_gpiod.
*/
if (config.ena_gpiod)
devm_gpiod_unhinge(&client->dev, config.ena_gpiod);
rdev = devm_regulator_register(&client->dev, &max->desc, &config);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
......
......@@ -925,7 +925,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
pdata->regulators = rdata;
for_each_child_of_node(regulators_np, reg_np) {
for (i = 0; i < ARRAY_SIZE(regulators); i++)
if (!of_node_cmp(reg_np->name, regulators[i].name))
if (of_node_name_eq(reg_np, regulators[i].name))
break;
if (i == ARRAY_SIZE(regulators)) {
......
......@@ -186,7 +186,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
for (i = 0; i < num_regulators; i++) {
if (!regulators[i].desc.name)
continue;
if (!of_node_cmp(child->name,
if (of_node_name_eq(child,
regulators[i].desc.name)) {
p->id = i;
p->init_data = of_get_regulator_init_data(
......
This diff is collapsed.
......@@ -20,6 +20,7 @@
#include "internal.h"
static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
[PM_SUSPEND_STANDBY] = "regulator-state-standby",
[PM_SUSPEND_MEM] = "regulator-state-mem",
[PM_SUSPEND_MAX] = "regulator-state-disk",
};
......@@ -170,6 +171,10 @@ static void of_get_regulation_constraints(struct device_node *np,
&pval))
constraints->max_spread = pval;
if (!of_property_read_u32(np, "regulator-max-step-microvolt",
&pval))
constraints->max_uV_step = pval;
constraints->over_current_protection = of_property_read_bool(np,
"regulator-over-current-protection");
......@@ -181,9 +186,11 @@ static void of_get_regulation_constraints(struct device_node *np,
case PM_SUSPEND_MAX:
suspend_state = &constraints->state_disk;
break;
case PM_SUSPEND_STANDBY:
suspend_state = &constraints->state_standby;
break;
case PM_SUSPEND_ON:
case PM_SUSPEND_TO_IDLE:
case PM_SUSPEND_STANDBY:
default:
continue;
}
......@@ -364,24 +371,25 @@ int of_regulator_match(struct device *dev, struct device_node *node,
}
EXPORT_SYMBOL_GPL(of_regulator_match);
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
const struct regulator_desc *desc,
struct regulator_config *config,
struct device_node **node)
struct device_node *regulator_of_get_init_node(struct device *dev,
const struct regulator_desc *desc)
{
struct device_node *search, *child;
struct regulator_init_data *init_data = NULL;
const char *name;
if (!dev->of_node || !desc->of_match)
return NULL;
if (desc->regulators_node)
if (desc->regulators_node) {
search = of_get_child_by_name(dev->of_node,
desc->regulators_node);
else
} else {
search = of_node_get(dev->of_node);
if (!strcmp(desc->of_match, search->name))
return search;
}
if (!search) {
dev_dbg(dev, "Failed to find regulator container node '%s'\n",
desc->regulators_node);
......@@ -393,35 +401,48 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
if (!name)
name = child->name;
if (strcmp(desc->of_match, name))
continue;
if (!strcmp(desc->of_match, name))
return of_node_get(child);
}
init_data = of_get_regulator_init_data(dev, child, desc);
if (!init_data) {
dev_err(dev,
"failed to parse DT for regulator %pOFn\n",
child);
break;
}
of_node_put(search);
if (desc->of_parse_cb) {
if (desc->of_parse_cb(child, desc, config)) {
dev_err(dev,
"driver callback failed to parse DT for regulator %pOFn\n",
child);
init_data = NULL;
break;
}
}
return NULL;
}
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
const struct regulator_desc *desc,
struct regulator_config *config,
struct device_node **node)
{
struct device_node *child;
struct regulator_init_data *init_data = NULL;
of_node_get(child);
*node = child;
break;
child = regulator_of_get_init_node(dev, desc);
if (!child)
return NULL;
init_data = of_get_regulator_init_data(dev, child, desc);
if (!init_data) {
dev_err(dev, "failed to parse DT for regulator %pOFn\n", child);
goto error;
}
of_node_put(search);
if (desc->of_parse_cb && desc->of_parse_cb(child, desc, config)) {
dev_err(dev,
"driver callback failed to parse DT for regulator %pOFn\n",
child);
goto error;
}
*node = child;
return init_data;
error:
of_node_put(child);
return NULL;
}
static int of_node_match(struct device *dev, const void *data)
......
......@@ -443,13 +443,16 @@ static int palmas_ldo_write(struct palmas *palmas, unsigned int reg,
static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
{
int id = rdev_get_id(dev);
int ret;
struct palmas_pmic *pmic = rdev_get_drvdata(dev);
struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata;
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
unsigned int reg;
bool rail_enable = true;
palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, &reg);
ret = palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, &reg);
if (ret)
return ret;
reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
......
......@@ -370,6 +370,7 @@ static struct pfuze_regulator pfuze100_regulators[] = {
PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
PFUZE100_COIN_REG(PFUZE100, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin),
};
static struct pfuze_regulator pfuze200_regulators[] = {
......@@ -436,6 +437,7 @@ static struct of_regulator_match pfuze100_matches[] = {
{ .name = "vgen4", },
{ .name = "vgen5", },
{ .name = "vgen6", },
{ .name = "coin", },
};
/* PFUZE200 */
......
......@@ -410,7 +410,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
vreg->dev = dev;
for (rpmh_data = pmic_rpmh_data; rpmh_data->name; rpmh_data++)
if (!strcmp(rpmh_data->name, node->name))
if (of_node_name_eq(node, rpmh_data->name))
break;
if (!rpmh_data->name) {
......
......@@ -5,7 +5,7 @@
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
......@@ -14,7 +14,6 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/of_gpio.h>
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s2mps13.h>
......@@ -44,7 +43,7 @@ struct s2mps11_info {
* Array (size: number of regulators) with GPIO-s for external
* sleep control.
*/
int *ext_control_gpio;
struct gpio_desc **ext_control_gpiod;
};
static int get_ramp_delay(int ramp_delay)
......@@ -511,7 +510,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev)
case S2MPS14X:
if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
val = S2MPS14_ENABLE_SUSPEND;
else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)]))
else if (s2mps11->ext_control_gpiod[rdev_get_id(rdev)])
val = S2MPS14_ENABLE_EXT_CONTROL;
else
val = rdev->desc->enable_mask;
......@@ -805,7 +804,7 @@ static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11,
static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
struct of_regulator_match *rdata, struct s2mps11_info *s2mps11)
{
int *gpio = s2mps11->ext_control_gpio;
struct gpio_desc **gpio = s2mps11->ext_control_gpiod;
unsigned int i;
unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11,
S2MPS14_LDO12 };
......@@ -816,11 +815,20 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
if (!rdata[reg].init_data || !rdata[reg].of_node)
continue;
gpio[reg] = of_get_named_gpio(rdata[reg].of_node,
"samsung,ext-control-gpios", 0);
if (gpio_is_valid(gpio[reg]))
dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n",
gpio[reg], reg, rdata[reg].name);
gpio[reg] = devm_gpiod_get_from_of_node(&pdev->dev,
rdata[reg].of_node,
"samsung,ext-control-gpios",
0,
GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
"s2mps11-regulator");
if (IS_ERR(gpio[reg])) {
dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n",
reg, rdata[reg].name);
continue;
}
if (gpio[reg])
dev_dbg(&pdev->dev, "Using GPIO for ext-control over %d/%s\n",
reg, rdata[reg].name);
}
}
......@@ -1126,17 +1134,10 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
return -EINVAL;
}
s2mps11->ext_control_gpio = devm_kmalloc_array(&pdev->dev,
rdev_num, sizeof(*s2mps11->ext_control_gpio),
GFP_KERNEL);
if (!s2mps11->ext_control_gpio)
s2mps11->ext_control_gpiod = devm_kcalloc(&pdev->dev, rdev_num,
sizeof(*s2mps11->ext_control_gpiod), GFP_KERNEL);
if (!s2mps11->ext_control_gpiod)
return -ENOMEM;
/*
* 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 < rdev_num; i++)
s2mps11->ext_control_gpio[i] = -EINVAL;
if (!iodev->dev->of_node) {
if (iodev->pdata) {
......@@ -1166,8 +1167,6 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
config.dev = &pdev->dev;
config.regmap = iodev->regmap_pmic;
config.driver_data = s2mps11;
config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
config.ena_gpio_initialized = true;
for (i = 0; i < rdev_num; i++) {
struct regulator_dev *regulator;
......@@ -1178,8 +1177,13 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
config.init_data = rdata[i].init_data;
config.of_node = rdata[i].of_node;
}
config.ena_gpio = s2mps11->ext_control_gpio[i];
config.ena_gpiod = s2mps11->ext_control_gpiod[i];
/*
* Hand the GPIO descriptor management over to the regulator
* core, remove it from devres management.
*/
if (config.ena_gpiod)
devm_gpiod_unhinge(&pdev->dev, config.ena_gpiod);
regulator = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
if (IS_ERR(regulator)) {
......@@ -1189,7 +1193,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
goto out;
}
if (gpio_is_valid(s2mps11->ext_control_gpio[i])) {
if (s2mps11->ext_control_gpiod[i]) {
ret = s2mps14_pmic_enable_ext_control(s2mps11,
regulator);
if (ret < 0) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment