1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2020, The Linux Foundation. All rights reserved.
4 #include <linux/module.h>
5 #include <linux/of_irq.h>
7 #include <linux/of_device.h>
8 #include <linux/platform_device.h>
9 #include <linux/regmap.h>
10 #include <linux/regulator/driver.h>
11 #include <linux/regulator/of_regulator.h>
13 #define REG_PERPH_TYPE 0x04
15 #define QCOM_LAB_TYPE 0x24
16 #define QCOM_IBB_TYPE 0x20
18 #define PMI8998_LAB_REG_BASE 0xde00
19 #define PMI8998_IBB_REG_BASE 0xdc00
21 #define REG_LABIBB_STATUS1 0x08
22 #define REG_LABIBB_ENABLE_CTL 0x46
23 #define LABIBB_STATUS1_VREG_OK_BIT BIT(7)
24 #define LABIBB_CONTROL_ENABLE BIT(7)
26 #define LAB_ENABLE_CTL_MASK BIT(7)
27 #define IBB_ENABLE_CTL_MASK (BIT(7) | BIT(6))
29 #define LABIBB_OFF_ON_DELAY 1000
30 #define LAB_ENABLE_TIME (LABIBB_OFF_ON_DELAY * 2)
31 #define IBB_ENABLE_TIME (LABIBB_OFF_ON_DELAY * 10)
32 #define LABIBB_POLL_ENABLED_TIME 1000
34 struct labibb_regulator
{
35 struct regulator_desc desc
;
37 struct regmap
*regmap
;
38 struct regulator_dev
*rdev
;
43 struct labibb_regulator_data
{
47 const struct regulator_desc
*desc
;
50 static const struct regulator_ops qcom_labibb_ops
= {
51 .enable
= regulator_enable_regmap
,
52 .disable
= regulator_disable_regmap
,
53 .is_enabled
= regulator_is_enabled_regmap
,
56 static const struct regulator_desc pmi8998_lab_desc
= {
57 .enable_mask
= LAB_ENABLE_CTL_MASK
,
58 .enable_reg
= (PMI8998_LAB_REG_BASE
+ REG_LABIBB_ENABLE_CTL
),
59 .enable_val
= LABIBB_CONTROL_ENABLE
,
60 .enable_time
= LAB_ENABLE_TIME
,
61 .poll_enabled_time
= LABIBB_POLL_ENABLED_TIME
,
62 .off_on_delay
= LABIBB_OFF_ON_DELAY
,
64 .type
= REGULATOR_VOLTAGE
,
65 .ops
= &qcom_labibb_ops
,
68 static const struct regulator_desc pmi8998_ibb_desc
= {
69 .enable_mask
= IBB_ENABLE_CTL_MASK
,
70 .enable_reg
= (PMI8998_IBB_REG_BASE
+ REG_LABIBB_ENABLE_CTL
),
71 .enable_val
= LABIBB_CONTROL_ENABLE
,
72 .enable_time
= IBB_ENABLE_TIME
,
73 .poll_enabled_time
= LABIBB_POLL_ENABLED_TIME
,
74 .off_on_delay
= LABIBB_OFF_ON_DELAY
,
76 .type
= REGULATOR_VOLTAGE
,
77 .ops
= &qcom_labibb_ops
,
80 static const struct labibb_regulator_data pmi8998_labibb_data
[] = {
81 {"lab", QCOM_LAB_TYPE
, PMI8998_LAB_REG_BASE
, &pmi8998_lab_desc
},
82 {"ibb", QCOM_IBB_TYPE
, PMI8998_IBB_REG_BASE
, &pmi8998_ibb_desc
},
86 static const struct of_device_id qcom_labibb_match
[] = {
87 { .compatible
= "qcom,pmi8998-lab-ibb", .data
= &pmi8998_labibb_data
},
90 MODULE_DEVICE_TABLE(of
, qcom_labibb_match
);
92 static int qcom_labibb_regulator_probe(struct platform_device
*pdev
)
94 struct labibb_regulator
*vreg
;
95 struct device
*dev
= &pdev
->dev
;
96 struct regulator_config cfg
= {};
98 const struct of_device_id
*match
;
99 const struct labibb_regulator_data
*reg_data
;
100 struct regmap
*reg_regmap
;
104 reg_regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
106 dev_err(&pdev
->dev
, "Couldn't get parent's regmap\n");
110 match
= of_match_device(qcom_labibb_match
, &pdev
->dev
);
114 for (reg_data
= match
->data
; reg_data
->name
; reg_data
++) {
116 /* Validate if the type of regulator is indeed
117 * what's mentioned in DT.
119 ret
= regmap_read(reg_regmap
, reg_data
->base
+ REG_PERPH_TYPE
,
123 "Peripheral type read failed ret=%d\n",
128 if (WARN_ON((type
!= QCOM_LAB_TYPE
) && (type
!= QCOM_IBB_TYPE
)) ||
129 WARN_ON(type
!= reg_data
->type
))
132 vreg
= devm_kzalloc(&pdev
->dev
, sizeof(*vreg
),
137 vreg
->regmap
= reg_regmap
;
139 vreg
->base
= reg_data
->base
;
140 vreg
->type
= reg_data
->type
;
142 memcpy(&vreg
->desc
, reg_data
->desc
, sizeof(vreg
->desc
));
143 vreg
->desc
.of_match
= reg_data
->name
;
144 vreg
->desc
.name
= reg_data
->name
;
147 cfg
.driver_data
= vreg
;
148 cfg
.regmap
= vreg
->regmap
;
150 vreg
->rdev
= devm_regulator_register(vreg
->dev
, &vreg
->desc
,
153 if (IS_ERR(vreg
->rdev
)) {
154 dev_err(dev
, "qcom_labibb: error registering %s : %d\n",
155 reg_data
->name
, ret
);
156 return PTR_ERR(vreg
->rdev
);
163 static struct platform_driver qcom_labibb_regulator_driver
= {
165 .name
= "qcom-lab-ibb-regulator",
166 .of_match_table
= qcom_labibb_match
,
168 .probe
= qcom_labibb_regulator_probe
,
170 module_platform_driver(qcom_labibb_regulator_driver
);
172 MODULE_DESCRIPTION("Qualcomm labibb driver");
173 MODULE_AUTHOR("Nisha Kumari <nishakumari@codeaurora.org>");
174 MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
175 MODULE_LICENSE("GPL v2");