Commit | Line | Data |
---|---|---|
38c09961 WY |
1 | /* |
2 | * Voltage regulation driver for active-semi ACT8945A PMIC | |
3 | * | |
4 | * Copyright (C) 2015 Atmel Corporation | |
5 | * | |
6 | * Author: Wenyou Yang <wenyou.yang@atmel.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of the | |
11 | * License, or (at your option) any later version. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <linux/module.h> | |
16 | #include <linux/of_device.h> | |
17 | #include <linux/platform_device.h> | |
18 | #include <linux/regulator/driver.h> | |
19 | #include <linux/regulator/machine.h> | |
20 | ||
21 | /** | |
22 | * ACT8945A Global Register Map. | |
23 | */ | |
24 | #define ACT8945A_SYS_MODE 0x00 | |
25 | #define ACT8945A_SYS_CTRL 0x01 | |
26 | #define ACT8945A_DCDC1_VSET1 0x20 | |
27 | #define ACT8945A_DCDC1_VSET2 0x21 | |
28 | #define ACT8945A_DCDC1_CTRL 0x22 | |
29 | #define ACT8945A_DCDC2_VSET1 0x30 | |
30 | #define ACT8945A_DCDC2_VSET2 0x31 | |
31 | #define ACT8945A_DCDC2_CTRL 0x32 | |
32 | #define ACT8945A_DCDC3_VSET1 0x40 | |
33 | #define ACT8945A_DCDC3_VSET2 0x41 | |
34 | #define ACT8945A_DCDC3_CTRL 0x42 | |
35 | #define ACT8945A_LDO1_VSET 0x50 | |
36 | #define ACT8945A_LDO1_CTRL 0x51 | |
37 | #define ACT8945A_LDO2_VSET 0x54 | |
38 | #define ACT8945A_LDO2_CTRL 0x55 | |
39 | #define ACT8945A_LDO3_VSET 0x60 | |
40 | #define ACT8945A_LDO3_CTRL 0x61 | |
41 | #define ACT8945A_LDO4_VSET 0x64 | |
42 | #define ACT8945A_LDO4_CTRL 0x65 | |
43 | ||
44 | /** | |
45 | * Field Definitions. | |
46 | */ | |
47 | #define ACT8945A_ENA 0x80 /* ON - [7] */ | |
48 | #define ACT8945A_VSEL_MASK 0x3F /* VSET - [5:0] */ | |
49 | ||
50 | /** | |
51 | * ACT8945A Voltage Number | |
52 | */ | |
53 | #define ACT8945A_VOLTAGE_NUM 64 | |
54 | ||
55 | enum { | |
56 | ACT8945A_ID_DCDC1, | |
57 | ACT8945A_ID_DCDC2, | |
58 | ACT8945A_ID_DCDC3, | |
59 | ACT8945A_ID_LDO1, | |
60 | ACT8945A_ID_LDO2, | |
61 | ACT8945A_ID_LDO3, | |
62 | ACT8945A_ID_LDO4, | |
63 | ACT8945A_REG_NUM, | |
64 | }; | |
65 | ||
66 | static const struct regulator_linear_range act8945a_voltage_ranges[] = { | |
67 | REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000), | |
68 | REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000), | |
69 | REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), | |
70 | }; | |
71 | ||
1ed1da3c | 72 | static const struct regulator_ops act8945a_ops = { |
38c09961 WY |
73 | .list_voltage = regulator_list_voltage_linear_range, |
74 | .map_voltage = regulator_map_voltage_linear_range, | |
75 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
76 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | |
77 | .enable = regulator_enable_regmap, | |
78 | .disable = regulator_disable_regmap, | |
79 | .is_enabled = regulator_is_enabled_regmap, | |
80 | }; | |
81 | ||
82 | #define ACT89xx_REG(_name, _family, _id, _vsel_reg, _supply) \ | |
83 | [_family##_ID_##_id] = { \ | |
84 | .name = _name, \ | |
85 | .supply_name = _supply, \ | |
86 | .of_match = of_match_ptr("REG_"#_id), \ | |
87 | .regulators_node = of_match_ptr("regulators"), \ | |
88 | .id = _family##_ID_##_id, \ | |
89 | .type = REGULATOR_VOLTAGE, \ | |
90 | .ops = &act8945a_ops, \ | |
91 | .n_voltages = ACT8945A_VOLTAGE_NUM, \ | |
92 | .linear_ranges = act8945a_voltage_ranges, \ | |
93 | .n_linear_ranges = ARRAY_SIZE(act8945a_voltage_ranges), \ | |
94 | .vsel_reg = _family##_##_id##_##_vsel_reg, \ | |
95 | .vsel_mask = ACT8945A_VSEL_MASK, \ | |
96 | .enable_reg = _family##_##_id##_CTRL, \ | |
97 | .enable_mask = ACT8945A_ENA, \ | |
98 | .owner = THIS_MODULE, \ | |
99 | } | |
100 | ||
101 | static const struct regulator_desc act8945a_regulators[] = { | |
102 | ACT89xx_REG("DCDC_REG1", ACT8945A, DCDC1, VSET1, "vp1"), | |
103 | ACT89xx_REG("DCDC_REG2", ACT8945A, DCDC2, VSET1, "vp2"), | |
104 | ACT89xx_REG("DCDC_REG3", ACT8945A, DCDC3, VSET1, "vp3"), | |
105 | ACT89xx_REG("LDO_REG1", ACT8945A, LDO1, VSET, "inl45"), | |
106 | ACT89xx_REG("LDO_REG2", ACT8945A, LDO2, VSET, "inl45"), | |
107 | ACT89xx_REG("LDO_REG3", ACT8945A, LDO3, VSET, "inl67"), | |
108 | ACT89xx_REG("LDO_REG4", ACT8945A, LDO4, VSET, "inl67"), | |
109 | }; | |
110 | ||
111 | static const struct regulator_desc act8945a_alt_regulators[] = { | |
112 | ACT89xx_REG("DCDC_REG1", ACT8945A, DCDC1, VSET2, "vp1"), | |
113 | ACT89xx_REG("DCDC_REG2", ACT8945A, DCDC2, VSET2, "vp2"), | |
114 | ACT89xx_REG("DCDC_REG3", ACT8945A, DCDC3, VSET2, "vp3"), | |
115 | ACT89xx_REG("LDO_REG1", ACT8945A, LDO1, VSET, "inl45"), | |
116 | ACT89xx_REG("LDO_REG2", ACT8945A, LDO2, VSET, "inl45"), | |
117 | ACT89xx_REG("LDO_REG3", ACT8945A, LDO3, VSET, "inl67"), | |
118 | ACT89xx_REG("LDO_REG4", ACT8945A, LDO4, VSET, "inl67"), | |
119 | }; | |
120 | ||
121 | static int act8945a_pmic_probe(struct platform_device *pdev) | |
122 | { | |
123 | struct regulator_config config = { }; | |
124 | const struct regulator_desc *regulators; | |
125 | struct regulator_dev *rdev; | |
126 | int i, num_regulators; | |
127 | bool voltage_select; | |
128 | ||
129 | voltage_select = of_property_read_bool(pdev->dev.parent->of_node, | |
130 | "active-semi,vsel-high"); | |
131 | ||
132 | if (voltage_select) { | |
133 | regulators = act8945a_alt_regulators; | |
134 | num_regulators = ARRAY_SIZE(act8945a_alt_regulators); | |
135 | } else { | |
136 | regulators = act8945a_regulators; | |
137 | num_regulators = ARRAY_SIZE(act8945a_regulators); | |
138 | } | |
139 | ||
140 | config.dev = &pdev->dev; | |
141 | config.dev->of_node = pdev->dev.parent->of_node; | |
142 | for (i = 0; i < num_regulators; i++) { | |
143 | rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); | |
144 | if (IS_ERR(rdev)) { | |
145 | dev_err(&pdev->dev, | |
146 | "failed to register %s regulator\n", | |
147 | regulators[i].name); | |
148 | return PTR_ERR(rdev); | |
149 | } | |
150 | } | |
151 | ||
152 | return 0; | |
153 | } | |
154 | ||
155 | static struct platform_driver act8945a_pmic_driver = { | |
156 | .driver = { | |
157 | .name = "act8945a-regulator", | |
158 | }, | |
159 | .probe = act8945a_pmic_probe, | |
160 | }; | |
161 | module_platform_driver(act8945a_pmic_driver); | |
162 | ||
163 | MODULE_DESCRIPTION("Active-semi ACT8945A voltage regulator driver"); | |
164 | MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>"); | |
165 | MODULE_LICENSE("GPL"); |