rtc: pcf8523: don't return invalid date when battery is low
[linux-2.6-block.git] / drivers / regulator / hi6421v530-regulator.c
1 /*
2  * Device driver for regulators in Hi6421V530 IC
3  *
4  * Copyright (c) <2017> HiSilicon Technologies Co., Ltd.
5  *              http://www.hisilicon.com
6  * Copyright (c) <2017> Linaro Ltd.
7  *              http://www.linaro.org
8  *
9  * Author: Wang Xiaoyin <hw.wangxiaoyin@hisilicon.com>
10  *         Guodong Xu <guodong.xu@linaro.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2 as
14  * published by the Free Software Foundation.
15  */
16
17 #include <linux/mfd/hi6421-pmic.h>
18 #include <linux/module.h>
19 #include <linux/of.h>
20 #include <linux/platform_device.h>
21 #include <linux/regmap.h>
22 #include <linux/regulator/driver.h>
23
24 /*
25  * struct hi6421v530_regulator_info - hi6421v530 regulator information
26  * @desc: regulator description
27  * @mode_mask: ECO mode bitmask of LDOs; for BUCKs, this masks sleep
28  * @eco_microamp: eco mode load upper limit (in uA), valid for LDOs only
29  */
30 struct hi6421v530_regulator_info {
31         struct regulator_desc rdesc;
32         u8 mode_mask;
33         u32 eco_microamp;
34 };
35
36 /* HI6421v530 regulators */
37 enum hi6421v530_regulator_id {
38         HI6421V530_LDO3,
39         HI6421V530_LDO9,
40         HI6421V530_LDO11,
41         HI6421V530_LDO15,
42         HI6421V530_LDO16,
43 };
44
45 static const unsigned int ldo_3_voltages[] = {
46         1800000, 1825000, 1850000, 1875000,
47         1900000, 1925000, 1950000, 1975000,
48         2000000, 2025000, 2050000, 2075000,
49         2100000, 2125000, 2150000, 2200000,
50 };
51
52 static const unsigned int ldo_9_11_voltages[] = {
53         1750000, 1800000, 1825000, 2800000,
54         2850000, 2950000, 3000000, 3300000,
55 };
56
57 static const unsigned int ldo_15_16_voltages[] = {
58         1750000, 1800000, 2400000, 2600000,
59         2700000, 2850000, 2950000, 3000000,
60 };
61
62 static const struct regulator_ops hi6421v530_ldo_ops;
63
64 #define HI6421V530_LDO_ENABLE_TIME (350)
65
66 /*
67  * _id - LDO id name string
68  * v_table - voltage table
69  * vreg - voltage select register
70  * vmask - voltage select mask
71  * ereg - enable register
72  * emask - enable mask
73  * odelay - off/on delay time in uS
74  * ecomask - eco mode mask
75  * ecoamp - eco mode load uppler limit in uA
76  */
77 #define HI6421V530_LDO(_ID, v_table, vreg, vmask, ereg, emask,          \
78                    odelay, ecomask, ecoamp) {                           \
79         .rdesc = {                                                      \
80                 .name            = #_ID,                                \
81                 .of_match        = of_match_ptr(#_ID),                  \
82                 .regulators_node = of_match_ptr("regulators"),          \
83                 .ops             = &hi6421v530_ldo_ops,                 \
84                 .type            = REGULATOR_VOLTAGE,                   \
85                 .id              = HI6421V530_##_ID,                    \
86                 .owner           = THIS_MODULE,                         \
87                 .n_voltages      = ARRAY_SIZE(v_table),                 \
88                 .volt_table      = v_table,                             \
89                 .vsel_reg        = HI6421_REG_TO_BUS_ADDR(vreg),        \
90                 .vsel_mask       = vmask,                               \
91                 .enable_reg      = HI6421_REG_TO_BUS_ADDR(ereg),        \
92                 .enable_mask     = emask,                               \
93                 .enable_time     = HI6421V530_LDO_ENABLE_TIME,          \
94                 .off_on_delay    = odelay,                              \
95         },                                                              \
96         .mode_mask      = ecomask,                                      \
97         .eco_microamp   = ecoamp,                                       \
98 }
99
100 /* HI6421V530 regulator information */
101
102 static struct hi6421v530_regulator_info hi6421v530_regulator_info[] = {
103         HI6421V530_LDO(LDO3, ldo_3_voltages, 0x061, 0xf, 0x060, 0x2,
104                    20000, 0x6, 8000),
105         HI6421V530_LDO(LDO9, ldo_9_11_voltages, 0x06b, 0x7, 0x06a, 0x2,
106                    40000, 0x6, 8000),
107         HI6421V530_LDO(LDO11, ldo_9_11_voltages, 0x06f, 0x7, 0x06e, 0x2,
108                    40000, 0x6, 8000),
109         HI6421V530_LDO(LDO15, ldo_15_16_voltages, 0x077, 0x7, 0x076, 0x2,
110                    40000, 0x6, 8000),
111         HI6421V530_LDO(LDO16, ldo_15_16_voltages, 0x079, 0x7, 0x078, 0x2,
112                    40000, 0x6, 8000),
113 };
114
115 static unsigned int hi6421v530_regulator_ldo_get_mode(
116                                         struct regulator_dev *rdev)
117 {
118         struct hi6421v530_regulator_info *info;
119         unsigned int reg_val;
120
121         info = rdev_get_drvdata(rdev);
122         regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
123
124         if (reg_val & (info->mode_mask))
125                 return REGULATOR_MODE_IDLE;
126
127         return REGULATOR_MODE_NORMAL;
128 }
129
130 static int hi6421v530_regulator_ldo_set_mode(struct regulator_dev *rdev,
131                                                 unsigned int mode)
132 {
133         struct hi6421v530_regulator_info *info;
134         unsigned int new_mode;
135
136         info = rdev_get_drvdata(rdev);
137         switch (mode) {
138         case REGULATOR_MODE_NORMAL:
139                 new_mode = 0;
140                 break;
141         case REGULATOR_MODE_IDLE:
142                 new_mode = info->mode_mask;
143                 break;
144         default:
145                 return -EINVAL;
146         }
147
148         regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
149                            info->mode_mask, new_mode);
150
151         return 0;
152 }
153
154
155 static const struct regulator_ops hi6421v530_ldo_ops = {
156         .is_enabled = regulator_is_enabled_regmap,
157         .enable = regulator_enable_regmap,
158         .disable = regulator_disable_regmap,
159         .list_voltage = regulator_list_voltage_table,
160         .map_voltage = regulator_map_voltage_ascend,
161         .get_voltage_sel = regulator_get_voltage_sel_regmap,
162         .set_voltage_sel = regulator_set_voltage_sel_regmap,
163         .get_mode = hi6421v530_regulator_ldo_get_mode,
164         .set_mode = hi6421v530_regulator_ldo_set_mode,
165 };
166
167 static int hi6421v530_regulator_probe(struct platform_device *pdev)
168 {
169         struct hi6421_pmic *pmic;
170         struct regulator_dev *rdev;
171         struct regulator_config config = { };
172         unsigned int i;
173
174         pmic = dev_get_drvdata(pdev->dev.parent);
175         if (!pmic) {
176                 dev_err(&pdev->dev, "no pmic in the regulator parent node\n");
177                 return -ENODEV;
178         }
179
180         for (i = 0; i < ARRAY_SIZE(hi6421v530_regulator_info); i++) {
181                 config.dev = pdev->dev.parent;
182                 config.regmap = pmic->regmap;
183                 config.driver_data = &hi6421v530_regulator_info[i];
184
185                 rdev = devm_regulator_register(&pdev->dev,
186                                 &hi6421v530_regulator_info[i].rdesc,
187                                 &config);
188                 if (IS_ERR(rdev)) {
189                         dev_err(&pdev->dev, "failed to register regulator %s\n",
190                                 hi6421v530_regulator_info[i].rdesc.name);
191                         return PTR_ERR(rdev);
192                 }
193         }
194         return 0;
195 }
196
197 static const struct platform_device_id hi6421v530_regulator_table[] = {
198         { .name = "hi6421v530-regulator" },
199         {},
200 };
201 MODULE_DEVICE_TABLE(platform, hi6421v530_regulator_table);
202
203 static struct platform_driver hi6421v530_regulator_driver = {
204         .id_table = hi6421v530_regulator_table,
205         .driver = {
206                 .name   = "hi6421v530-regulator",
207         },
208         .probe  = hi6421v530_regulator_probe,
209 };
210 module_platform_driver(hi6421v530_regulator_driver);
211
212 MODULE_AUTHOR("Wang Xiaoyin <hw.wangxiaoyin@hisilicon.com>");
213 MODULE_DESCRIPTION("Hi6421v530 regulator driver");
214 MODULE_LICENSE("GPL v2");