Commit | Line | Data |
---|---|---|
78cd96f0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
ac2c4936 HG |
2 | /* |
3 | * Intel CHT Whiskey Cove PMIC operation region driver | |
4 | * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> | |
5 | * | |
6 | * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: | |
7 | * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. | |
ac2c4936 HG |
8 | */ |
9 | ||
10 | #include <linux/acpi.h> | |
11 | #include <linux/init.h> | |
12 | #include <linux/mfd/intel_soc_pmic.h> | |
13 | #include <linux/platform_device.h> | |
14 | #include <linux/regmap.h> | |
15 | #include "intel_pmic.h" | |
16 | ||
17 | #define CHT_WC_V1P05A_CTRL 0x6e3b | |
18 | #define CHT_WC_V1P15_CTRL 0x6e3c | |
19 | #define CHT_WC_V1P05A_VSEL 0x6e3d | |
20 | #define CHT_WC_V1P15_VSEL 0x6e3e | |
21 | #define CHT_WC_V1P8A_CTRL 0x6e56 | |
22 | #define CHT_WC_V1P8SX_CTRL 0x6e57 | |
23 | #define CHT_WC_VDDQ_CTRL 0x6e58 | |
24 | #define CHT_WC_V1P2A_CTRL 0x6e59 | |
25 | #define CHT_WC_V1P2SX_CTRL 0x6e5a | |
26 | #define CHT_WC_V1P8A_VSEL 0x6e5b | |
27 | #define CHT_WC_VDDQ_VSEL 0x6e5c | |
28 | #define CHT_WC_V2P8SX_CTRL 0x6e5d | |
29 | #define CHT_WC_V3P3A_CTRL 0x6e5e | |
30 | #define CHT_WC_V3P3SD_CTRL 0x6e5f | |
31 | #define CHT_WC_VSDIO_CTRL 0x6e67 | |
32 | #define CHT_WC_V3P3A_VSEL 0x6e68 | |
33 | #define CHT_WC_VPROG1A_CTRL 0x6e90 | |
34 | #define CHT_WC_VPROG1B_CTRL 0x6e91 | |
35 | #define CHT_WC_VPROG1F_CTRL 0x6e95 | |
36 | #define CHT_WC_VPROG2D_CTRL 0x6e99 | |
37 | #define CHT_WC_VPROG3A_CTRL 0x6e9a | |
38 | #define CHT_WC_VPROG3B_CTRL 0x6e9b | |
39 | #define CHT_WC_VPROG4A_CTRL 0x6e9c | |
40 | #define CHT_WC_VPROG4B_CTRL 0x6e9d | |
41 | #define CHT_WC_VPROG4C_CTRL 0x6e9e | |
42 | #define CHT_WC_VPROG4D_CTRL 0x6e9f | |
43 | #define CHT_WC_VPROG5A_CTRL 0x6ea0 | |
44 | #define CHT_WC_VPROG5B_CTRL 0x6ea1 | |
45 | #define CHT_WC_VPROG6A_CTRL 0x6ea2 | |
46 | #define CHT_WC_VPROG6B_CTRL 0x6ea3 | |
47 | #define CHT_WC_VPROG1A_VSEL 0x6ec0 | |
48 | #define CHT_WC_VPROG1B_VSEL 0x6ec1 | |
49 | #define CHT_WC_V1P8SX_VSEL 0x6ec2 | |
50 | #define CHT_WC_V1P2SX_VSEL 0x6ec3 | |
51 | #define CHT_WC_V1P2A_VSEL 0x6ec4 | |
52 | #define CHT_WC_VPROG1F_VSEL 0x6ec5 | |
53 | #define CHT_WC_VSDIO_VSEL 0x6ec6 | |
54 | #define CHT_WC_V2P8SX_VSEL 0x6ec7 | |
55 | #define CHT_WC_V3P3SD_VSEL 0x6ec8 | |
56 | #define CHT_WC_VPROG2D_VSEL 0x6ec9 | |
57 | #define CHT_WC_VPROG3A_VSEL 0x6eca | |
58 | #define CHT_WC_VPROG3B_VSEL 0x6ecb | |
59 | #define CHT_WC_VPROG4A_VSEL 0x6ecc | |
60 | #define CHT_WC_VPROG4B_VSEL 0x6ecd | |
61 | #define CHT_WC_VPROG4C_VSEL 0x6ece | |
62 | #define CHT_WC_VPROG4D_VSEL 0x6ecf | |
63 | #define CHT_WC_VPROG5A_VSEL 0x6ed0 | |
64 | #define CHT_WC_VPROG5B_VSEL 0x6ed1 | |
65 | #define CHT_WC_VPROG6A_VSEL 0x6ed2 | |
66 | #define CHT_WC_VPROG6B_VSEL 0x6ed3 | |
67 | ||
68 | /* | |
69 | * Regulator support is based on the non upstream patch: | |
70 | * "regulator: whiskey_cove: implements Whiskey Cove pmic VRF support" | |
71 | * https://github.com/intel-aero/meta-intel-aero/blob/master/recipes-kernel/linux/linux-yocto/0019-regulator-whiskey_cove-implements-WhiskeyCove-pmic-V.patch | |
72 | */ | |
73 | static struct pmic_table power_table[] = { | |
74 | { | |
75 | .address = 0x0, | |
76 | .reg = CHT_WC_V1P8A_CTRL, | |
77 | .bit = 0x01, | |
78 | }, /* V18A */ | |
79 | { | |
80 | .address = 0x04, | |
81 | .reg = CHT_WC_V1P8SX_CTRL, | |
82 | .bit = 0x07, | |
83 | }, /* V18X */ | |
84 | { | |
85 | .address = 0x08, | |
86 | .reg = CHT_WC_VDDQ_CTRL, | |
87 | .bit = 0x01, | |
88 | }, /* VDDQ */ | |
89 | { | |
90 | .address = 0x0c, | |
91 | .reg = CHT_WC_V1P2A_CTRL, | |
92 | .bit = 0x07, | |
93 | }, /* V12A */ | |
94 | { | |
95 | .address = 0x10, | |
96 | .reg = CHT_WC_V1P2SX_CTRL, | |
97 | .bit = 0x07, | |
98 | }, /* V12X */ | |
99 | { | |
100 | .address = 0x14, | |
101 | .reg = CHT_WC_V2P8SX_CTRL, | |
102 | .bit = 0x07, | |
103 | }, /* V28X */ | |
104 | { | |
105 | .address = 0x18, | |
106 | .reg = CHT_WC_V3P3A_CTRL, | |
107 | .bit = 0x01, | |
108 | }, /* V33A */ | |
109 | { | |
110 | .address = 0x1c, | |
111 | .reg = CHT_WC_V3P3SD_CTRL, | |
112 | .bit = 0x07, | |
113 | }, /* V3SD */ | |
114 | { | |
115 | .address = 0x20, | |
116 | .reg = CHT_WC_VSDIO_CTRL, | |
117 | .bit = 0x07, | |
118 | }, /* VSD */ | |
119 | /* { | |
120 | .address = 0x24, | |
121 | .reg = ??, | |
122 | .bit = ??, | |
123 | }, ** VSW2 */ | |
124 | /* { | |
125 | .address = 0x28, | |
126 | .reg = ??, | |
127 | .bit = ??, | |
128 | }, ** VSW1 */ | |
129 | /* { | |
130 | .address = 0x2c, | |
131 | .reg = ??, | |
132 | .bit = ??, | |
133 | }, ** VUPY */ | |
134 | /* { | |
135 | .address = 0x30, | |
136 | .reg = ??, | |
137 | .bit = ??, | |
138 | }, ** VRSO */ | |
139 | { | |
140 | .address = 0x34, | |
141 | .reg = CHT_WC_VPROG1A_CTRL, | |
142 | .bit = 0x07, | |
143 | }, /* VP1A */ | |
144 | { | |
145 | .address = 0x38, | |
146 | .reg = CHT_WC_VPROG1B_CTRL, | |
147 | .bit = 0x07, | |
148 | }, /* VP1B */ | |
149 | { | |
150 | .address = 0x3c, | |
151 | .reg = CHT_WC_VPROG1F_CTRL, | |
152 | .bit = 0x07, | |
153 | }, /* VP1F */ | |
154 | { | |
155 | .address = 0x40, | |
156 | .reg = CHT_WC_VPROG2D_CTRL, | |
157 | .bit = 0x07, | |
158 | }, /* VP2D */ | |
159 | { | |
160 | .address = 0x44, | |
161 | .reg = CHT_WC_VPROG3A_CTRL, | |
162 | .bit = 0x07, | |
163 | }, /* VP3A */ | |
164 | { | |
165 | .address = 0x48, | |
166 | .reg = CHT_WC_VPROG3B_CTRL, | |
167 | .bit = 0x07, | |
168 | }, /* VP3B */ | |
169 | { | |
170 | .address = 0x4c, | |
171 | .reg = CHT_WC_VPROG4A_CTRL, | |
172 | .bit = 0x07, | |
173 | }, /* VP4A */ | |
174 | { | |
175 | .address = 0x50, | |
176 | .reg = CHT_WC_VPROG4B_CTRL, | |
177 | .bit = 0x07, | |
178 | }, /* VP4B */ | |
179 | { | |
180 | .address = 0x54, | |
181 | .reg = CHT_WC_VPROG4C_CTRL, | |
182 | .bit = 0x07, | |
183 | }, /* VP4C */ | |
184 | { | |
185 | .address = 0x58, | |
186 | .reg = CHT_WC_VPROG4D_CTRL, | |
187 | .bit = 0x07, | |
188 | }, /* VP4D */ | |
189 | { | |
190 | .address = 0x5c, | |
191 | .reg = CHT_WC_VPROG5A_CTRL, | |
192 | .bit = 0x07, | |
193 | }, /* VP5A */ | |
194 | { | |
195 | .address = 0x60, | |
196 | .reg = CHT_WC_VPROG5B_CTRL, | |
197 | .bit = 0x07, | |
198 | }, /* VP5B */ | |
199 | { | |
200 | .address = 0x64, | |
201 | .reg = CHT_WC_VPROG6A_CTRL, | |
202 | .bit = 0x07, | |
203 | }, /* VP6A */ | |
204 | { | |
205 | .address = 0x68, | |
206 | .reg = CHT_WC_VPROG6B_CTRL, | |
207 | .bit = 0x07, | |
208 | }, /* VP6B */ | |
209 | /* { | |
210 | .address = 0x6c, | |
211 | .reg = ??, | |
212 | .bit = ??, | |
213 | } ** VP7A */ | |
214 | }; | |
215 | ||
216 | static int intel_cht_wc_pmic_get_power(struct regmap *regmap, int reg, | |
217 | int bit, u64 *value) | |
218 | { | |
219 | int data; | |
220 | ||
221 | if (regmap_read(regmap, reg, &data)) | |
222 | return -EIO; | |
223 | ||
224 | *value = (data & bit) ? 1 : 0; | |
225 | return 0; | |
226 | } | |
227 | ||
228 | static int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg, | |
229 | int bitmask, bool on) | |
230 | { | |
231 | return regmap_update_bits(regmap, reg, bitmask, on ? 1 : 0); | |
232 | } | |
233 | ||
4f601682 HG |
234 | static int intel_cht_wc_exec_mipi_pmic_seq_element(struct regmap *regmap, |
235 | u16 i2c_client_address, | |
236 | u32 reg_address, | |
237 | u32 value, u32 mask) | |
238 | { | |
239 | u32 address; | |
240 | ||
241 | if (i2c_client_address > 0xff || reg_address > 0xff) { | |
242 | pr_warn("%s warning addresses too big client 0x%x reg 0x%x\n", | |
243 | __func__, i2c_client_address, reg_address); | |
244 | return -ERANGE; | |
245 | } | |
246 | ||
247 | address = (i2c_client_address << 8) | reg_address; | |
248 | ||
249 | return regmap_update_bits(regmap, address, mask, value); | |
250 | } | |
251 | ||
ac2c4936 HG |
252 | /* |
253 | * The thermal table and ops are empty, we do not support the Thermal opregion | |
254 | * (DPTF) due to lacking documentation. | |
255 | */ | |
256 | static struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = { | |
257 | .get_power = intel_cht_wc_pmic_get_power, | |
258 | .update_power = intel_cht_wc_pmic_update_power, | |
4f601682 | 259 | .exec_mipi_pmic_seq_element = intel_cht_wc_exec_mipi_pmic_seq_element, |
ac2c4936 HG |
260 | .power_table = power_table, |
261 | .power_table_count = ARRAY_SIZE(power_table), | |
262 | }; | |
263 | ||
264 | static int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev) | |
265 | { | |
266 | struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); | |
267 | ||
268 | return intel_pmic_install_opregion_handler(&pdev->dev, | |
269 | ACPI_HANDLE(pdev->dev.parent), | |
270 | pmic->regmap, | |
271 | &intel_cht_wc_pmic_opregion_data); | |
272 | } | |
273 | ||
e8894f55 | 274 | static const struct platform_device_id cht_wc_opregion_id_table[] = { |
ac2c4936 HG |
275 | { .name = "cht_wcove_region" }, |
276 | {}, | |
277 | }; | |
ac2c4936 HG |
278 | |
279 | static struct platform_driver intel_cht_wc_pmic_opregion_driver = { | |
280 | .probe = intel_cht_wc_pmic_opregion_probe, | |
281 | .driver = { | |
282 | .name = "cht_whiskey_cove_pmic", | |
283 | }, | |
284 | .id_table = cht_wc_opregion_id_table, | |
285 | }; | |
0d154fdd | 286 | builtin_platform_driver(intel_cht_wc_pmic_opregion_driver); |