mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-23 08:35:19 -05:00
Merge branch 'ib-mfd-regulator-pm8008-6.11' into ibs-for-mfd-merged
This commit is contained in:
commit
04f3893327
7 changed files with 420 additions and 141 deletions
|
@ -19,110 +19,136 @@ properties:
|
|||
const: qcom,pm8008
|
||||
|
||||
reg:
|
||||
description:
|
||||
I2C slave address.
|
||||
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
description: Parent interrupt.
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
vdd-l1-l2-supply: true
|
||||
vdd-l3-l4-supply: true
|
||||
vdd-l5-supply: true
|
||||
vdd-l6-supply: true
|
||||
vdd-l7-supply: true
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-ranges:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
description: |
|
||||
The first cell is the IRQ number, the second cell is the IRQ trigger
|
||||
flag. All interrupts are listed in include/dt-bindings/mfd/qcom-pm8008.h.
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
"#thermal-sensor-cells":
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^gpio@[0-9a-f]+$":
|
||||
pinctrl:
|
||||
type: object
|
||||
|
||||
description: |
|
||||
The GPIO peripheral. This node may be specified twice, one for each GPIO.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: qcom,pm8008-gpio
|
||||
- const: qcom,spmi-gpio
|
||||
|
||||
reg:
|
||||
description: Peripheral address of one of the two GPIO peripherals.
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
gpio-ranges:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- gpio-controller
|
||||
- interrupt-controller
|
||||
- "#gpio-cells"
|
||||
- gpio-ranges
|
||||
- "#interrupt-cells"
|
||||
|
||||
additionalProperties: false
|
||||
patternProperties:
|
||||
"-state$":
|
||||
type: object
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/pinctrl/pinmux-node.yaml
|
||||
- $ref: /schemas/pinctrl/pincfg-node.yaml
|
||||
|
||||
properties:
|
||||
pins:
|
||||
items:
|
||||
pattern: "^gpio[12]$"
|
||||
|
||||
function:
|
||||
items:
|
||||
- enum:
|
||||
- normal
|
||||
|
||||
required:
|
||||
- pins
|
||||
- function
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
regulators:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
patternProperties:
|
||||
"^ldo[1-7]$":
|
||||
type: object
|
||||
$ref: /schemas/regulator/regulator.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- vdd-l1-l2-supply
|
||||
- vdd-l3-l4-supply
|
||||
- vdd-l5-supply
|
||||
- vdd-l6-supply
|
||||
- vdd-l7-supply
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
- gpio-ranges
|
||||
- interrupt-controller
|
||||
- "#interrupt-cells"
|
||||
- "#thermal-sensor-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/mfd/qcom-pm8008.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pmic@8 {
|
||||
pm8008: pmic@8 {
|
||||
compatible = "qcom,pm8008";
|
||||
reg = <0x8>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
|
||||
interrupt-parent = <&tlmm>;
|
||||
interrupts = <32 IRQ_TYPE_EDGE_RISING>;
|
||||
|
||||
pm8008_gpios: gpio@c000 {
|
||||
compatible = "qcom,pm8008-gpio", "qcom,spmi-gpio";
|
||||
reg = <0xc000>;
|
||||
gpio-controller;
|
||||
gpio-ranges = <&pm8008_gpios 0 0 2>;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
reset-gpios = <&tlmm 42 GPIO_ACTIVE_LOW>;
|
||||
|
||||
vdd-l1-l2-supply = <&vreg_s8b_1p2>;
|
||||
vdd-l3-l4-supply = <&vreg_s1b_1p8>;
|
||||
vdd-l5-supply = <&vreg_bob>;
|
||||
vdd-l6-supply = <&vreg_bob>;
|
||||
vdd-l7-supply = <&vreg_bob>;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pm8008 0 0 2>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
|
||||
#thermal-sensor-cells = <0>;
|
||||
|
||||
pinctrl {
|
||||
gpio-keys-state {
|
||||
pins = "gpio1";
|
||||
function = "normal";
|
||||
};
|
||||
};
|
||||
|
||||
regulators {
|
||||
ldo1 {
|
||||
regulator-name = "vreg_l1";
|
||||
regulator-min-microvolt = <950000>;
|
||||
regulator-max-microvolt = <1300000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -2220,6 +2220,7 @@ config MFD_ACER_A500_EC
|
|||
config MFD_QCOM_PM8008
|
||||
tristate "QCOM PM8008 Power Management IC"
|
||||
depends on I2C && OF
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
help
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
@ -15,8 +18,6 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <dt-bindings/mfd/qcom-pm8008.h>
|
||||
|
||||
#define I2C_INTR_STATUS_BASE 0x0550
|
||||
#define INT_RT_STS_OFFSET 0x10
|
||||
#define INT_SET_TYPE_OFFSET 0x11
|
||||
|
@ -37,34 +38,54 @@ enum {
|
|||
|
||||
#define PM8008_PERIPH_0_BASE 0x900
|
||||
#define PM8008_PERIPH_1_BASE 0x2400
|
||||
#define PM8008_PERIPH_2_BASE 0xC000
|
||||
#define PM8008_PERIPH_3_BASE 0xC100
|
||||
#define PM8008_PERIPH_2_BASE 0xc000
|
||||
#define PM8008_PERIPH_3_BASE 0xc100
|
||||
|
||||
#define PM8008_TEMP_ALARM_ADDR PM8008_PERIPH_1_BASE
|
||||
#define PM8008_GPIO1_ADDR PM8008_PERIPH_2_BASE
|
||||
#define PM8008_GPIO2_ADDR PM8008_PERIPH_3_BASE
|
||||
|
||||
/* PM8008 IRQ numbers */
|
||||
#define PM8008_IRQ_MISC_UVLO 0
|
||||
#define PM8008_IRQ_MISC_OVLO 1
|
||||
#define PM8008_IRQ_MISC_OTST2 2
|
||||
#define PM8008_IRQ_MISC_OTST3 3
|
||||
#define PM8008_IRQ_MISC_LDO_OCP 4
|
||||
#define PM8008_IRQ_TEMP_ALARM 5
|
||||
#define PM8008_IRQ_GPIO1 6
|
||||
#define PM8008_IRQ_GPIO2 7
|
||||
|
||||
enum {
|
||||
SET_TYPE_INDEX,
|
||||
POLARITY_HI_INDEX,
|
||||
POLARITY_LO_INDEX,
|
||||
};
|
||||
|
||||
static unsigned int pm8008_config_regs[] = {
|
||||
static const unsigned int pm8008_config_regs[] = {
|
||||
INT_SET_TYPE_OFFSET,
|
||||
INT_POL_HIGH_OFFSET,
|
||||
INT_POL_LOW_OFFSET,
|
||||
};
|
||||
|
||||
static struct regmap_irq pm8008_irqs[] = {
|
||||
REGMAP_IRQ_REG(PM8008_IRQ_MISC_UVLO, PM8008_MISC, BIT(0)),
|
||||
REGMAP_IRQ_REG(PM8008_IRQ_MISC_OVLO, PM8008_MISC, BIT(1)),
|
||||
REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST2, PM8008_MISC, BIT(2)),
|
||||
REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST3, PM8008_MISC, BIT(3)),
|
||||
REGMAP_IRQ_REG(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC, BIT(4)),
|
||||
REGMAP_IRQ_REG(PM8008_IRQ_TEMP_ALARM, PM8008_TEMP_ALARM, BIT(0)),
|
||||
REGMAP_IRQ_REG(PM8008_IRQ_GPIO1, PM8008_GPIO1, BIT(0)),
|
||||
REGMAP_IRQ_REG(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0)),
|
||||
#define _IRQ(_irq, _off, _mask, _types) \
|
||||
[_irq] = { \
|
||||
.reg_offset = (_off), \
|
||||
.mask = (_mask), \
|
||||
.type = { \
|
||||
.type_reg_offset = (_off), \
|
||||
.types_supported = (_types), \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct regmap_irq pm8008_irqs[] = {
|
||||
_IRQ(PM8008_IRQ_MISC_UVLO, PM8008_MISC, BIT(0), IRQ_TYPE_EDGE_RISING),
|
||||
_IRQ(PM8008_IRQ_MISC_OVLO, PM8008_MISC, BIT(1), IRQ_TYPE_EDGE_RISING),
|
||||
_IRQ(PM8008_IRQ_MISC_OTST2, PM8008_MISC, BIT(2), IRQ_TYPE_EDGE_RISING),
|
||||
_IRQ(PM8008_IRQ_MISC_OTST3, PM8008_MISC, BIT(3), IRQ_TYPE_EDGE_RISING),
|
||||
_IRQ(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC, BIT(4), IRQ_TYPE_EDGE_RISING),
|
||||
_IRQ(PM8008_IRQ_TEMP_ALARM, PM8008_TEMP_ALARM,BIT(0), IRQ_TYPE_SENSE_MASK),
|
||||
_IRQ(PM8008_IRQ_GPIO1, PM8008_GPIO1, BIT(0), IRQ_TYPE_SENSE_MASK),
|
||||
_IRQ(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0), IRQ_TYPE_SENSE_MASK),
|
||||
};
|
||||
|
||||
static const unsigned int pm8008_periph_base[] = {
|
||||
|
@ -118,8 +139,8 @@ static int pm8008_set_type_config(unsigned int **buf, unsigned int type,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap_irq_chip pm8008_irq_chip = {
|
||||
.name = "pm8008_irq",
|
||||
static const struct regmap_irq_chip pm8008_irq_chip = {
|
||||
.name = "pm8008",
|
||||
.main_status = I2C_INTR_STATUS_BASE,
|
||||
.num_main_regs = 1,
|
||||
.irqs = pm8008_irqs,
|
||||
|
@ -137,62 +158,106 @@ static struct regmap_irq_chip pm8008_irq_chip = {
|
|||
.get_irq_reg = pm8008_get_irq_reg,
|
||||
};
|
||||
|
||||
static struct regmap_config qcom_mfd_regmap_cfg = {
|
||||
static const struct regmap_config qcom_mfd_regmap_cfg = {
|
||||
.name = "primary",
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.max_register = 0xFFFF,
|
||||
.max_register = 0xffff,
|
||||
};
|
||||
|
||||
static int pm8008_probe_irq_peripherals(struct device *dev,
|
||||
struct regmap *regmap,
|
||||
int client_irq)
|
||||
static const struct regmap_config pm8008_regmap_cfg_2 = {
|
||||
.name = "secondary",
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.max_register = 0xffff,
|
||||
};
|
||||
|
||||
static const struct resource pm8008_temp_res[] = {
|
||||
DEFINE_RES_MEM(PM8008_TEMP_ALARM_ADDR, 0x100),
|
||||
DEFINE_RES_IRQ(PM8008_IRQ_TEMP_ALARM),
|
||||
};
|
||||
|
||||
static const struct mfd_cell pm8008_cells[] = {
|
||||
MFD_CELL_NAME("pm8008-regulator"),
|
||||
MFD_CELL_RES("qpnp-temp-alarm", pm8008_temp_res),
|
||||
MFD_CELL_NAME("pm8008-gpio"),
|
||||
};
|
||||
|
||||
static void devm_irq_domain_fwnode_release(void *data)
|
||||
{
|
||||
int rc, i;
|
||||
struct regmap_irq_type *type;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
struct fwnode_handle *fwnode = data;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pm8008_irqs); i++) {
|
||||
type = &pm8008_irqs[i].type;
|
||||
|
||||
type->type_reg_offset = pm8008_irqs[i].reg_offset;
|
||||
|
||||
if (type->type_reg_offset == PM8008_MISC)
|
||||
type->types_supported = IRQ_TYPE_EDGE_RISING;
|
||||
else
|
||||
type->types_supported = (IRQ_TYPE_EDGE_BOTH |
|
||||
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
|
||||
}
|
||||
|
||||
rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
|
||||
IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
|
||||
if (rc) {
|
||||
dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
irq_domain_free_fwnode(fwnode);
|
||||
}
|
||||
|
||||
static int pm8008_probe(struct i2c_client *client)
|
||||
{
|
||||
int rc;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
struct device *dev = &client->dev;
|
||||
struct regmap *regmap, *regmap2;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct i2c_client *dummy;
|
||||
struct gpio_desc *reset;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
dev = &client->dev;
|
||||
dummy = devm_i2c_new_dummy_device(dev, client->adapter, client->addr + 1);
|
||||
if (IS_ERR(dummy)) {
|
||||
ret = PTR_ERR(dummy);
|
||||
dev_err(dev, "failed to claim second address: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap2 = devm_regmap_init_i2c(dummy, &qcom_mfd_regmap_cfg);
|
||||
if (IS_ERR(regmap2))
|
||||
return PTR_ERR(regmap2);
|
||||
|
||||
ret = regmap_attach_dev(dev, regmap2, &pm8008_regmap_cfg_2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Default regmap must be attached last. */
|
||||
regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
i2c_set_clientdata(client, regmap);
|
||||
reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(reset))
|
||||
return PTR_ERR(reset);
|
||||
|
||||
if (of_property_read_bool(dev->of_node, "interrupt-controller")) {
|
||||
rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq);
|
||||
if (rc)
|
||||
dev_err(dev, "Failed to probe irq periphs: %d\n", rc);
|
||||
/*
|
||||
* The PMIC does not appear to require a post-reset delay, but wait
|
||||
* for a millisecond for now anyway.
|
||||
*/
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
name = devm_kasprintf(dev, GFP_KERNEL, "%pOF-internal", dev->of_node);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
name = strreplace(name, '/', ':');
|
||||
|
||||
fwnode = irq_domain_alloc_named_fwnode(name);
|
||||
if (!fwnode)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, devm_irq_domain_fwnode_release, fwnode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_regmap_add_irq_chip_fwnode(dev, fwnode, regmap, client->irq,
|
||||
IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add IRQ chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_of_platform_populate(dev);
|
||||
/* Needed by GPIO driver. */
|
||||
dev_set_drvdata(dev, regmap_irq_get_domain(irq_data));
|
||||
|
||||
return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, pm8008_cells,
|
||||
ARRAY_SIZE(pm8008_cells), NULL, 0,
|
||||
regmap_irq_get_domain(irq_data));
|
||||
}
|
||||
|
||||
static const struct of_device_id pm8008_match[] = {
|
||||
|
|
|
@ -1033,6 +1033,13 @@ config REGULATOR_PWM
|
|||
This driver supports PWM controlled voltage regulators. PWM
|
||||
duty cycle can increase or decrease the voltage.
|
||||
|
||||
config REGULATOR_QCOM_PM8008
|
||||
tristate "Qualcomm PM8008 PMIC regulators"
|
||||
depends on MFD_QCOM_PM8008
|
||||
help
|
||||
Select this option to enable support for the voltage regulators in
|
||||
Qualcomm PM8008 PMICs.
|
||||
|
||||
config REGULATOR_QCOM_REFGEN
|
||||
tristate "Qualcomm REFGEN regulator driver"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
|
|
|
@ -113,6 +113,7 @@ obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
|
|||
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_QCOM_PM8008) += qcom-pm8008-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_QCOM_REFGEN) += qcom-refgen-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
|
||||
|
|
198
drivers/regulator/qcom-pm8008-regulator.c
Normal file
198
drivers/regulator/qcom-pm8008-regulator.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2024 Linaro Limited
|
||||
*/
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#define DEFAULT_VOLTAGE_STEPPER_RATE 38400
|
||||
|
||||
#define LDO_STEPPER_CTL_REG 0x3b
|
||||
#define STEP_RATE_MASK GENMASK(1, 0)
|
||||
|
||||
#define LDO_VSET_LB_REG 0x40
|
||||
|
||||
#define LDO_ENABLE_REG 0x46
|
||||
#define ENABLE_BIT BIT(7)
|
||||
|
||||
struct pm8008_regulator {
|
||||
struct regmap *regmap;
|
||||
struct regulator_desc desc;
|
||||
unsigned int base;
|
||||
};
|
||||
|
||||
struct pm8008_regulator_data {
|
||||
const char *name;
|
||||
const char *supply_name;
|
||||
unsigned int base;
|
||||
int min_dropout_uV;
|
||||
const struct linear_range *voltage_range;
|
||||
};
|
||||
|
||||
static const struct linear_range nldo_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(528000, 0, 122, 8000),
|
||||
};
|
||||
|
||||
static const struct linear_range pldo_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(1504000, 0, 237, 8000),
|
||||
};
|
||||
|
||||
static const struct pm8008_regulator_data pm8008_reg_data[] = {
|
||||
{ "ldo1", "vdd-l1-l2", 0x4000, 225000, nldo_ranges, },
|
||||
{ "ldo2", "vdd-l1-l2", 0x4100, 225000, nldo_ranges, },
|
||||
{ "ldo3", "vdd-l3-l4", 0x4200, 300000, pldo_ranges, },
|
||||
{ "ldo4", "vdd-l3-l4", 0x4300, 300000, pldo_ranges, },
|
||||
{ "ldo5", "vdd-l5", 0x4400, 200000, pldo_ranges, },
|
||||
{ "ldo6", "vdd-l6", 0x4500, 200000, pldo_ranges, },
|
||||
{ "ldo7", "vdd-l7", 0x4600, 200000, pldo_ranges, },
|
||||
};
|
||||
|
||||
static int pm8008_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
|
||||
{
|
||||
struct pm8008_regulator *preg = rdev_get_drvdata(rdev);
|
||||
unsigned int mV;
|
||||
__le16 val;
|
||||
int ret;
|
||||
|
||||
ret = regulator_list_voltage_linear_range(rdev, sel);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mV = DIV_ROUND_UP(ret, 1000);
|
||||
|
||||
val = cpu_to_le16(mV);
|
||||
|
||||
ret = regmap_bulk_write(preg->regmap, preg->base + LDO_VSET_LB_REG,
|
||||
&val, sizeof(val));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8008_regulator_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pm8008_regulator *preg = rdev_get_drvdata(rdev);
|
||||
unsigned int uV;
|
||||
__le16 val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(preg->regmap, preg->base + LDO_VSET_LB_REG,
|
||||
&val, sizeof(val));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
uV = le16_to_cpu(val) * 1000;
|
||||
|
||||
return (uV - preg->desc.min_uV) / preg->desc.uV_step;
|
||||
}
|
||||
|
||||
static const struct regulator_ops pm8008_regulator_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.set_voltage_sel = pm8008_regulator_set_voltage_sel,
|
||||
.get_voltage_sel = pm8008_regulator_get_voltage_sel,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
};
|
||||
|
||||
static int pm8008_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct pm8008_regulator_data *data;
|
||||
struct regulator_config config = {};
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pm8008_regulator *preg;
|
||||
struct regulator_desc *desc;
|
||||
struct regulator_dev *rdev;
|
||||
struct regmap *regmap;
|
||||
unsigned int val;
|
||||
int ret, i;
|
||||
|
||||
regmap = dev_get_regmap(dev->parent, "secondary");
|
||||
if (!regmap)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pm8008_reg_data); i++) {
|
||||
data = &pm8008_reg_data[i];
|
||||
|
||||
preg = devm_kzalloc(dev, sizeof(*preg), GFP_KERNEL);
|
||||
if (!preg)
|
||||
return -ENOMEM;
|
||||
|
||||
preg->regmap = regmap;
|
||||
preg->base = data->base;
|
||||
|
||||
desc = &preg->desc;
|
||||
|
||||
desc->name = data->name;
|
||||
desc->supply_name = data->supply_name;
|
||||
desc->of_match = data->name;
|
||||
desc->regulators_node = of_match_ptr("regulators");
|
||||
desc->ops = &pm8008_regulator_ops;
|
||||
desc->type = REGULATOR_VOLTAGE;
|
||||
desc->owner = THIS_MODULE;
|
||||
|
||||
desc->linear_ranges = data->voltage_range;
|
||||
desc->n_linear_ranges = 1;
|
||||
desc->uV_step = desc->linear_ranges[0].step;
|
||||
desc->min_uV = desc->linear_ranges[0].min;
|
||||
desc->n_voltages = linear_range_values_in_range(&desc->linear_ranges[0]);
|
||||
|
||||
ret = regmap_read(regmap, preg->base + LDO_STEPPER_CTL_REG, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read step rate: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
val &= STEP_RATE_MASK;
|
||||
desc->ramp_delay = DEFAULT_VOLTAGE_STEPPER_RATE >> val;
|
||||
|
||||
desc->min_dropout_uV = data->min_dropout_uV;
|
||||
|
||||
desc->enable_reg = preg->base + LDO_ENABLE_REG;
|
||||
desc->enable_mask = ENABLE_BIT;
|
||||
|
||||
config.dev = dev->parent;
|
||||
config.driver_data = preg;
|
||||
config.regmap = regmap;
|
||||
|
||||
rdev = devm_regulator_register(dev, desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
ret = PTR_ERR(rdev);
|
||||
dev_err(dev, "failed to register regulator %s: %d\n",
|
||||
desc->name, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id pm8008_regulator_id_table[] = {
|
||||
{ "pm8008-regulator" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, pm8008_regulator_id_table);
|
||||
|
||||
static struct platform_driver pm8008_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "qcom-pm8008-regulator",
|
||||
},
|
||||
.probe = pm8008_regulator_probe,
|
||||
.id_table = pm8008_regulator_id_table,
|
||||
};
|
||||
module_platform_driver(pm8008_regulator_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm PM8008 PMIC regulator driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,19 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __DT_BINDINGS_MFD_QCOM_PM8008_H
|
||||
#define __DT_BINDINGS_MFD_QCOM_PM8008_H
|
||||
|
||||
/* PM8008 IRQ numbers */
|
||||
#define PM8008_IRQ_MISC_UVLO 0
|
||||
#define PM8008_IRQ_MISC_OVLO 1
|
||||
#define PM8008_IRQ_MISC_OTST2 2
|
||||
#define PM8008_IRQ_MISC_OTST3 3
|
||||
#define PM8008_IRQ_MISC_LDO_OCP 4
|
||||
#define PM8008_IRQ_TEMP_ALARM 5
|
||||
#define PM8008_IRQ_GPIO1 6
|
||||
#define PM8008_IRQ_GPIO2 7
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue