Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ib-mfd-regulator-pm8008-6.11' into ibs-for-mfd-merged

+420 -141
+94 -68
Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml
··· 19 19 const: qcom,pm8008 20 20 21 21 reg: 22 - description: 23 - I2C slave address. 24 - 25 22 maxItems: 1 26 23 27 24 interrupts: 28 25 maxItems: 1 29 26 30 - description: Parent interrupt. 27 + reset-gpios: 28 + maxItems: 1 29 + 30 + vdd-l1-l2-supply: true 31 + vdd-l3-l4-supply: true 32 + vdd-l5-supply: true 33 + vdd-l6-supply: true 34 + vdd-l7-supply: true 35 + 36 + gpio-controller: true 37 + 38 + "#gpio-cells": 39 + const: 2 40 + 41 + gpio-ranges: 42 + maxItems: 1 43 + 44 + interrupt-controller: true 31 45 32 46 "#interrupt-cells": 33 47 const: 2 34 48 35 - description: | 36 - The first cell is the IRQ number, the second cell is the IRQ trigger 37 - flag. All interrupts are listed in include/dt-bindings/mfd/qcom-pm8008.h. 38 - 39 - interrupt-controller: true 40 - 41 - "#address-cells": 42 - const: 1 43 - 44 - "#size-cells": 49 + "#thermal-sensor-cells": 45 50 const: 0 46 51 47 - patternProperties: 48 - "^gpio@[0-9a-f]+$": 52 + pinctrl: 49 53 type: object 50 - 51 - description: | 52 - The GPIO peripheral. This node may be specified twice, one for each GPIO. 53 - 54 - properties: 55 - compatible: 56 - items: 57 - - const: qcom,pm8008-gpio 58 - - const: qcom,spmi-gpio 59 - 60 - reg: 61 - description: Peripheral address of one of the two GPIO peripherals. 62 - maxItems: 1 63 - 64 - gpio-controller: true 65 - 66 - gpio-ranges: 67 - maxItems: 1 68 - 69 - interrupt-controller: true 70 - 71 - "#interrupt-cells": 72 - const: 2 73 - 74 - "#gpio-cells": 75 - const: 2 76 - 77 - required: 78 - - compatible 79 - - reg 80 - - gpio-controller 81 - - interrupt-controller 82 - - "#gpio-cells" 83 - - gpio-ranges 84 - - "#interrupt-cells" 85 - 86 54 additionalProperties: false 55 + patternProperties: 56 + "-state$": 57 + type: object 58 + 59 + allOf: 60 + - $ref: /schemas/pinctrl/pinmux-node.yaml 61 + - $ref: /schemas/pinctrl/pincfg-node.yaml 62 + 63 + properties: 64 + pins: 65 + items: 66 + pattern: "^gpio[12]$" 67 + 68 + function: 69 + items: 70 + - enum: 71 + - normal 72 + 73 + required: 74 + - pins 75 + - function 76 + 77 + additionalProperties: false 78 + 79 + regulators: 80 + type: object 81 + additionalProperties: false 82 + patternProperties: 83 + "^ldo[1-7]$": 84 + type: object 85 + $ref: /schemas/regulator/regulator.yaml# 86 + unevaluatedProperties: false 87 87 88 88 required: 89 89 - compatible 90 90 - reg 91 91 - interrupts 92 - - "#address-cells" 93 - - "#size-cells" 92 + - vdd-l1-l2-supply 93 + - vdd-l3-l4-supply 94 + - vdd-l5-supply 95 + - vdd-l6-supply 96 + - vdd-l7-supply 97 + - gpio-controller 98 + - "#gpio-cells" 99 + - gpio-ranges 100 + - interrupt-controller 94 101 - "#interrupt-cells" 102 + - "#thermal-sensor-cells" 95 103 96 104 additionalProperties: false 97 105 98 106 examples: 99 107 - | 100 - #include <dt-bindings/mfd/qcom-pm8008.h> 108 + #include <dt-bindings/gpio/gpio.h> 101 109 #include <dt-bindings/interrupt-controller/irq.h> 102 110 103 111 i2c { 104 112 #address-cells = <1>; 105 113 #size-cells = <0>; 106 114 107 - pmic@8 { 115 + pm8008: pmic@8 { 108 116 compatible = "qcom,pm8008"; 109 117 reg = <0x8>; 110 - #address-cells = <1>; 111 - #size-cells = <0>; 112 - interrupt-controller; 113 - #interrupt-cells = <2>; 114 118 115 119 interrupt-parent = <&tlmm>; 116 120 interrupts = <32 IRQ_TYPE_EDGE_RISING>; 117 121 118 - pm8008_gpios: gpio@c000 { 119 - compatible = "qcom,pm8008-gpio", "qcom,spmi-gpio"; 120 - reg = <0xc000>; 121 - gpio-controller; 122 - gpio-ranges = <&pm8008_gpios 0 0 2>; 123 - #gpio-cells = <2>; 124 - interrupt-controller; 125 - #interrupt-cells = <2>; 122 + reset-gpios = <&tlmm 42 GPIO_ACTIVE_LOW>; 123 + 124 + vdd-l1-l2-supply = <&vreg_s8b_1p2>; 125 + vdd-l3-l4-supply = <&vreg_s1b_1p8>; 126 + vdd-l5-supply = <&vreg_bob>; 127 + vdd-l6-supply = <&vreg_bob>; 128 + vdd-l7-supply = <&vreg_bob>; 129 + 130 + gpio-controller; 131 + #gpio-cells = <2>; 132 + gpio-ranges = <&pm8008 0 0 2>; 133 + 134 + interrupt-controller; 135 + #interrupt-cells = <2>; 136 + 137 + #thermal-sensor-cells = <0>; 138 + 139 + pinctrl { 140 + gpio-keys-state { 141 + pins = "gpio1"; 142 + function = "normal"; 143 + }; 144 + }; 145 + 146 + regulators { 147 + ldo1 { 148 + regulator-name = "vreg_l1"; 149 + regulator-min-microvolt = <950000>; 150 + regulator-max-microvolt = <1300000>; 151 + }; 126 152 }; 127 153 }; 128 154 };
+1
drivers/mfd/Kconfig
··· 2220 2220 config MFD_QCOM_PM8008 2221 2221 tristate "QCOM PM8008 Power Management IC" 2222 2222 depends on I2C && OF 2223 + select MFD_CORE 2223 2224 select REGMAP_I2C 2224 2225 select REGMAP_IRQ 2225 2226 help
+119 -54
drivers/mfd/qcom-pm8008.c
··· 4 4 */ 5 5 6 6 #include <linux/bitops.h> 7 + #include <linux/gpio/consumer.h> 7 8 #include <linux/i2c.h> 8 9 #include <linux/interrupt.h> 10 + #include <linux/ioport.h> 9 11 #include <linux/irq.h> 10 12 #include <linux/irqdomain.h> 13 + #include <linux/mfd/core.h> 11 14 #include <linux/module.h> 12 15 #include <linux/of.h> 13 16 #include <linux/of_platform.h> 14 17 #include <linux/pinctrl/consumer.h> 15 18 #include <linux/regmap.h> 16 19 #include <linux/slab.h> 17 - 18 - #include <dt-bindings/mfd/qcom-pm8008.h> 19 20 20 21 #define I2C_INTR_STATUS_BASE 0x0550 21 22 #define INT_RT_STS_OFFSET 0x10 ··· 38 37 39 38 #define PM8008_PERIPH_0_BASE 0x900 40 39 #define PM8008_PERIPH_1_BASE 0x2400 41 - #define PM8008_PERIPH_2_BASE 0xC000 42 - #define PM8008_PERIPH_3_BASE 0xC100 40 + #define PM8008_PERIPH_2_BASE 0xc000 41 + #define PM8008_PERIPH_3_BASE 0xc100 43 42 44 43 #define PM8008_TEMP_ALARM_ADDR PM8008_PERIPH_1_BASE 45 44 #define PM8008_GPIO1_ADDR PM8008_PERIPH_2_BASE 46 45 #define PM8008_GPIO2_ADDR PM8008_PERIPH_3_BASE 46 + 47 + /* PM8008 IRQ numbers */ 48 + #define PM8008_IRQ_MISC_UVLO 0 49 + #define PM8008_IRQ_MISC_OVLO 1 50 + #define PM8008_IRQ_MISC_OTST2 2 51 + #define PM8008_IRQ_MISC_OTST3 3 52 + #define PM8008_IRQ_MISC_LDO_OCP 4 53 + #define PM8008_IRQ_TEMP_ALARM 5 54 + #define PM8008_IRQ_GPIO1 6 55 + #define PM8008_IRQ_GPIO2 7 47 56 48 57 enum { 49 58 SET_TYPE_INDEX, ··· 61 50 POLARITY_LO_INDEX, 62 51 }; 63 52 64 - static unsigned int pm8008_config_regs[] = { 53 + static const unsigned int pm8008_config_regs[] = { 65 54 INT_SET_TYPE_OFFSET, 66 55 INT_POL_HIGH_OFFSET, 67 56 INT_POL_LOW_OFFSET, 68 57 }; 69 58 70 - static struct regmap_irq pm8008_irqs[] = { 71 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_UVLO, PM8008_MISC, BIT(0)), 72 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_OVLO, PM8008_MISC, BIT(1)), 73 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST2, PM8008_MISC, BIT(2)), 74 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST3, PM8008_MISC, BIT(3)), 75 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC, BIT(4)), 76 - REGMAP_IRQ_REG(PM8008_IRQ_TEMP_ALARM, PM8008_TEMP_ALARM, BIT(0)), 77 - REGMAP_IRQ_REG(PM8008_IRQ_GPIO1, PM8008_GPIO1, BIT(0)), 78 - REGMAP_IRQ_REG(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0)), 59 + #define _IRQ(_irq, _off, _mask, _types) \ 60 + [_irq] = { \ 61 + .reg_offset = (_off), \ 62 + .mask = (_mask), \ 63 + .type = { \ 64 + .type_reg_offset = (_off), \ 65 + .types_supported = (_types), \ 66 + }, \ 67 + } 68 + 69 + static const struct regmap_irq pm8008_irqs[] = { 70 + _IRQ(PM8008_IRQ_MISC_UVLO, PM8008_MISC, BIT(0), IRQ_TYPE_EDGE_RISING), 71 + _IRQ(PM8008_IRQ_MISC_OVLO, PM8008_MISC, BIT(1), IRQ_TYPE_EDGE_RISING), 72 + _IRQ(PM8008_IRQ_MISC_OTST2, PM8008_MISC, BIT(2), IRQ_TYPE_EDGE_RISING), 73 + _IRQ(PM8008_IRQ_MISC_OTST3, PM8008_MISC, BIT(3), IRQ_TYPE_EDGE_RISING), 74 + _IRQ(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC, BIT(4), IRQ_TYPE_EDGE_RISING), 75 + _IRQ(PM8008_IRQ_TEMP_ALARM, PM8008_TEMP_ALARM,BIT(0), IRQ_TYPE_SENSE_MASK), 76 + _IRQ(PM8008_IRQ_GPIO1, PM8008_GPIO1, BIT(0), IRQ_TYPE_SENSE_MASK), 77 + _IRQ(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0), IRQ_TYPE_SENSE_MASK), 79 78 }; 80 79 81 80 static const unsigned int pm8008_periph_base[] = { ··· 139 118 return 0; 140 119 } 141 120 142 - static struct regmap_irq_chip pm8008_irq_chip = { 143 - .name = "pm8008_irq", 121 + static const struct regmap_irq_chip pm8008_irq_chip = { 122 + .name = "pm8008", 144 123 .main_status = I2C_INTR_STATUS_BASE, 145 124 .num_main_regs = 1, 146 125 .irqs = pm8008_irqs, ··· 158 137 .get_irq_reg = pm8008_get_irq_reg, 159 138 }; 160 139 161 - static struct regmap_config qcom_mfd_regmap_cfg = { 140 + static const struct regmap_config qcom_mfd_regmap_cfg = { 141 + .name = "primary", 162 142 .reg_bits = 16, 163 143 .val_bits = 8, 164 - .max_register = 0xFFFF, 144 + .max_register = 0xffff, 165 145 }; 166 146 167 - static int pm8008_probe_irq_peripherals(struct device *dev, 168 - struct regmap *regmap, 169 - int client_irq) 147 + static const struct regmap_config pm8008_regmap_cfg_2 = { 148 + .name = "secondary", 149 + .reg_bits = 16, 150 + .val_bits = 8, 151 + .max_register = 0xffff, 152 + }; 153 + 154 + static const struct resource pm8008_temp_res[] = { 155 + DEFINE_RES_MEM(PM8008_TEMP_ALARM_ADDR, 0x100), 156 + DEFINE_RES_IRQ(PM8008_IRQ_TEMP_ALARM), 157 + }; 158 + 159 + static const struct mfd_cell pm8008_cells[] = { 160 + MFD_CELL_NAME("pm8008-regulator"), 161 + MFD_CELL_RES("qpnp-temp-alarm", pm8008_temp_res), 162 + MFD_CELL_NAME("pm8008-gpio"), 163 + }; 164 + 165 + static void devm_irq_domain_fwnode_release(void *data) 170 166 { 171 - int rc, i; 172 - struct regmap_irq_type *type; 173 - struct regmap_irq_chip_data *irq_data; 167 + struct fwnode_handle *fwnode = data; 174 168 175 - for (i = 0; i < ARRAY_SIZE(pm8008_irqs); i++) { 176 - type = &pm8008_irqs[i].type; 177 - 178 - type->type_reg_offset = pm8008_irqs[i].reg_offset; 179 - 180 - if (type->type_reg_offset == PM8008_MISC) 181 - type->types_supported = IRQ_TYPE_EDGE_RISING; 182 - else 183 - type->types_supported = (IRQ_TYPE_EDGE_BOTH | 184 - IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW); 185 - } 186 - 187 - rc = devm_regmap_add_irq_chip(dev, regmap, client_irq, 188 - IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data); 189 - if (rc) { 190 - dev_err(dev, "Failed to add IRQ chip: %d\n", rc); 191 - return rc; 192 - } 193 - 194 - return 0; 169 + irq_domain_free_fwnode(fwnode); 195 170 } 196 171 197 172 static int pm8008_probe(struct i2c_client *client) 198 173 { 199 - int rc; 200 - struct device *dev; 201 - struct regmap *regmap; 174 + struct regmap_irq_chip_data *irq_data; 175 + struct device *dev = &client->dev; 176 + struct regmap *regmap, *regmap2; 177 + struct fwnode_handle *fwnode; 178 + struct i2c_client *dummy; 179 + struct gpio_desc *reset; 180 + char *name; 181 + int ret; 202 182 203 - dev = &client->dev; 183 + dummy = devm_i2c_new_dummy_device(dev, client->adapter, client->addr + 1); 184 + if (IS_ERR(dummy)) { 185 + ret = PTR_ERR(dummy); 186 + dev_err(dev, "failed to claim second address: %d\n", ret); 187 + return ret; 188 + } 189 + 190 + regmap2 = devm_regmap_init_i2c(dummy, &qcom_mfd_regmap_cfg); 191 + if (IS_ERR(regmap2)) 192 + return PTR_ERR(regmap2); 193 + 194 + ret = regmap_attach_dev(dev, regmap2, &pm8008_regmap_cfg_2); 195 + if (ret) 196 + return ret; 197 + 198 + /* Default regmap must be attached last. */ 204 199 regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg); 205 200 if (IS_ERR(regmap)) 206 201 return PTR_ERR(regmap); 207 202 208 - i2c_set_clientdata(client, regmap); 203 + reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 204 + if (IS_ERR(reset)) 205 + return PTR_ERR(reset); 209 206 210 - if (of_property_read_bool(dev->of_node, "interrupt-controller")) { 211 - rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq); 212 - if (rc) 213 - dev_err(dev, "Failed to probe irq periphs: %d\n", rc); 207 + /* 208 + * The PMIC does not appear to require a post-reset delay, but wait 209 + * for a millisecond for now anyway. 210 + */ 211 + usleep_range(1000, 2000); 212 + 213 + name = devm_kasprintf(dev, GFP_KERNEL, "%pOF-internal", dev->of_node); 214 + if (!name) 215 + return -ENOMEM; 216 + 217 + name = strreplace(name, '/', ':'); 218 + 219 + fwnode = irq_domain_alloc_named_fwnode(name); 220 + if (!fwnode) 221 + return -ENOMEM; 222 + 223 + ret = devm_add_action_or_reset(dev, devm_irq_domain_fwnode_release, fwnode); 224 + if (ret) 225 + return ret; 226 + 227 + ret = devm_regmap_add_irq_chip_fwnode(dev, fwnode, regmap, client->irq, 228 + IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data); 229 + if (ret) { 230 + dev_err(dev, "failed to add IRQ chip: %d\n", ret); 231 + return ret; 214 232 } 215 233 216 - return devm_of_platform_populate(dev); 234 + /* Needed by GPIO driver. */ 235 + dev_set_drvdata(dev, regmap_irq_get_domain(irq_data)); 236 + 237 + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, pm8008_cells, 238 + ARRAY_SIZE(pm8008_cells), NULL, 0, 239 + regmap_irq_get_domain(irq_data)); 217 240 } 218 241 219 242 static const struct of_device_id pm8008_match[] = {
+7
drivers/regulator/Kconfig
··· 1033 1033 This driver supports PWM controlled voltage regulators. PWM 1034 1034 duty cycle can increase or decrease the voltage. 1035 1035 1036 + config REGULATOR_QCOM_PM8008 1037 + tristate "Qualcomm PM8008 PMIC regulators" 1038 + depends on MFD_QCOM_PM8008 1039 + help 1040 + Select this option to enable support for the voltage regulators in 1041 + Qualcomm PM8008 PMICs. 1042 + 1036 1043 config REGULATOR_QCOM_REFGEN 1037 1044 tristate "Qualcomm REFGEN regulator driver" 1038 1045 depends on ARCH_QCOM || COMPILE_TEST
+1
drivers/regulator/Makefile
··· 113 113 obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o 114 114 obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o 115 115 obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o 116 + obj-$(CONFIG_REGULATOR_QCOM_PM8008) += qcom-pm8008-regulator.o 116 117 obj-$(CONFIG_REGULATOR_QCOM_REFGEN) += qcom-refgen-regulator.o 117 118 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o 118 119 obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
+198
drivers/regulator/qcom-pm8008-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. 4 + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 5 + * Copyright (c) 2024 Linaro Limited 6 + */ 7 + 8 + #include <linux/array_size.h> 9 + #include <linux/bits.h> 10 + #include <linux/device.h> 11 + #include <linux/math.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/regmap.h> 16 + #include <linux/regulator/driver.h> 17 + 18 + #include <asm/byteorder.h> 19 + 20 + #define DEFAULT_VOLTAGE_STEPPER_RATE 38400 21 + 22 + #define LDO_STEPPER_CTL_REG 0x3b 23 + #define STEP_RATE_MASK GENMASK(1, 0) 24 + 25 + #define LDO_VSET_LB_REG 0x40 26 + 27 + #define LDO_ENABLE_REG 0x46 28 + #define ENABLE_BIT BIT(7) 29 + 30 + struct pm8008_regulator { 31 + struct regmap *regmap; 32 + struct regulator_desc desc; 33 + unsigned int base; 34 + }; 35 + 36 + struct pm8008_regulator_data { 37 + const char *name; 38 + const char *supply_name; 39 + unsigned int base; 40 + int min_dropout_uV; 41 + const struct linear_range *voltage_range; 42 + }; 43 + 44 + static const struct linear_range nldo_ranges[] = { 45 + REGULATOR_LINEAR_RANGE(528000, 0, 122, 8000), 46 + }; 47 + 48 + static const struct linear_range pldo_ranges[] = { 49 + REGULATOR_LINEAR_RANGE(1504000, 0, 237, 8000), 50 + }; 51 + 52 + static const struct pm8008_regulator_data pm8008_reg_data[] = { 53 + { "ldo1", "vdd-l1-l2", 0x4000, 225000, nldo_ranges, }, 54 + { "ldo2", "vdd-l1-l2", 0x4100, 225000, nldo_ranges, }, 55 + { "ldo3", "vdd-l3-l4", 0x4200, 300000, pldo_ranges, }, 56 + { "ldo4", "vdd-l3-l4", 0x4300, 300000, pldo_ranges, }, 57 + { "ldo5", "vdd-l5", 0x4400, 200000, pldo_ranges, }, 58 + { "ldo6", "vdd-l6", 0x4500, 200000, pldo_ranges, }, 59 + { "ldo7", "vdd-l7", 0x4600, 200000, pldo_ranges, }, 60 + }; 61 + 62 + static int pm8008_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) 63 + { 64 + struct pm8008_regulator *preg = rdev_get_drvdata(rdev); 65 + unsigned int mV; 66 + __le16 val; 67 + int ret; 68 + 69 + ret = regulator_list_voltage_linear_range(rdev, sel); 70 + if (ret < 0) 71 + return ret; 72 + 73 + mV = DIV_ROUND_UP(ret, 1000); 74 + 75 + val = cpu_to_le16(mV); 76 + 77 + ret = regmap_bulk_write(preg->regmap, preg->base + LDO_VSET_LB_REG, 78 + &val, sizeof(val)); 79 + if (ret < 0) 80 + return ret; 81 + 82 + return 0; 83 + } 84 + 85 + static int pm8008_regulator_get_voltage_sel(struct regulator_dev *rdev) 86 + { 87 + struct pm8008_regulator *preg = rdev_get_drvdata(rdev); 88 + unsigned int uV; 89 + __le16 val; 90 + int ret; 91 + 92 + ret = regmap_bulk_read(preg->regmap, preg->base + LDO_VSET_LB_REG, 93 + &val, sizeof(val)); 94 + if (ret < 0) 95 + return ret; 96 + 97 + uV = le16_to_cpu(val) * 1000; 98 + 99 + return (uV - preg->desc.min_uV) / preg->desc.uV_step; 100 + } 101 + 102 + static const struct regulator_ops pm8008_regulator_ops = { 103 + .list_voltage = regulator_list_voltage_linear, 104 + .set_voltage_sel = pm8008_regulator_set_voltage_sel, 105 + .get_voltage_sel = pm8008_regulator_get_voltage_sel, 106 + .enable = regulator_enable_regmap, 107 + .disable = regulator_disable_regmap, 108 + .is_enabled = regulator_is_enabled_regmap, 109 + }; 110 + 111 + static int pm8008_regulator_probe(struct platform_device *pdev) 112 + { 113 + const struct pm8008_regulator_data *data; 114 + struct regulator_config config = {}; 115 + struct device *dev = &pdev->dev; 116 + struct pm8008_regulator *preg; 117 + struct regulator_desc *desc; 118 + struct regulator_dev *rdev; 119 + struct regmap *regmap; 120 + unsigned int val; 121 + int ret, i; 122 + 123 + regmap = dev_get_regmap(dev->parent, "secondary"); 124 + if (!regmap) 125 + return -EINVAL; 126 + 127 + for (i = 0; i < ARRAY_SIZE(pm8008_reg_data); i++) { 128 + data = &pm8008_reg_data[i]; 129 + 130 + preg = devm_kzalloc(dev, sizeof(*preg), GFP_KERNEL); 131 + if (!preg) 132 + return -ENOMEM; 133 + 134 + preg->regmap = regmap; 135 + preg->base = data->base; 136 + 137 + desc = &preg->desc; 138 + 139 + desc->name = data->name; 140 + desc->supply_name = data->supply_name; 141 + desc->of_match = data->name; 142 + desc->regulators_node = of_match_ptr("regulators"); 143 + desc->ops = &pm8008_regulator_ops; 144 + desc->type = REGULATOR_VOLTAGE; 145 + desc->owner = THIS_MODULE; 146 + 147 + desc->linear_ranges = data->voltage_range; 148 + desc->n_linear_ranges = 1; 149 + desc->uV_step = desc->linear_ranges[0].step; 150 + desc->min_uV = desc->linear_ranges[0].min; 151 + desc->n_voltages = linear_range_values_in_range(&desc->linear_ranges[0]); 152 + 153 + ret = regmap_read(regmap, preg->base + LDO_STEPPER_CTL_REG, &val); 154 + if (ret < 0) { 155 + dev_err(dev, "failed to read step rate: %d\n", ret); 156 + return ret; 157 + } 158 + val &= STEP_RATE_MASK; 159 + desc->ramp_delay = DEFAULT_VOLTAGE_STEPPER_RATE >> val; 160 + 161 + desc->min_dropout_uV = data->min_dropout_uV; 162 + 163 + desc->enable_reg = preg->base + LDO_ENABLE_REG; 164 + desc->enable_mask = ENABLE_BIT; 165 + 166 + config.dev = dev->parent; 167 + config.driver_data = preg; 168 + config.regmap = regmap; 169 + 170 + rdev = devm_regulator_register(dev, desc, &config); 171 + if (IS_ERR(rdev)) { 172 + ret = PTR_ERR(rdev); 173 + dev_err(dev, "failed to register regulator %s: %d\n", 174 + desc->name, ret); 175 + return ret; 176 + } 177 + } 178 + 179 + return 0; 180 + } 181 + 182 + static const struct platform_device_id pm8008_regulator_id_table[] = { 183 + { "pm8008-regulator" }, 184 + { } 185 + }; 186 + MODULE_DEVICE_TABLE(platform, pm8008_regulator_id_table); 187 + 188 + static struct platform_driver pm8008_regulator_driver = { 189 + .driver = { 190 + .name = "qcom-pm8008-regulator", 191 + }, 192 + .probe = pm8008_regulator_probe, 193 + .id_table = pm8008_regulator_id_table, 194 + }; 195 + module_platform_driver(pm8008_regulator_driver); 196 + 197 + MODULE_DESCRIPTION("Qualcomm PM8008 PMIC regulator driver"); 198 + MODULE_LICENSE("GPL");
-19
include/dt-bindings/mfd/qcom-pm8008.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-only */ 2 - /* 3 - * Copyright (c) 2021 The Linux Foundation. All rights reserved. 4 - */ 5 - 6 - #ifndef __DT_BINDINGS_MFD_QCOM_PM8008_H 7 - #define __DT_BINDINGS_MFD_QCOM_PM8008_H 8 - 9 - /* PM8008 IRQ numbers */ 10 - #define PM8008_IRQ_MISC_UVLO 0 11 - #define PM8008_IRQ_MISC_OVLO 1 12 - #define PM8008_IRQ_MISC_OTST2 2 13 - #define PM8008_IRQ_MISC_OTST3 3 14 - #define PM8008_IRQ_MISC_LDO_OCP 4 15 - #define PM8008_IRQ_TEMP_ALARM 5 16 - #define PM8008_IRQ_GPIO1 6 17 - #define PM8008_IRQ_GPIO2 7 18 - 19 - #endif