1 // SPDX-License-Identifier: GPL-2.0
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.
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 
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 
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 const 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,
259 	.exec_mipi_pmic_seq_element = intel_cht_wc_exec_mipi_pmic_seq_element,
260 	.lpat_raw_to_temp	= acpi_lpat_raw_to_temp,
261 	.power_table		= power_table,
262 	.power_table_count	= ARRAY_SIZE(power_table),
263 };
264 
265 static int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev)
266 {
267 	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
268 
269 	return intel_pmic_install_opregion_handler(&pdev->dev,
270 			ACPI_HANDLE(pdev->dev.parent),
271 			pmic->regmap,
272 			&intel_cht_wc_pmic_opregion_data);
273 }
274 
275 static const struct platform_device_id cht_wc_opregion_id_table[] = {
276 	{ .name = "cht_wcove_region" },
277 	{},
278 };
279 
280 static struct platform_driver intel_cht_wc_pmic_opregion_driver = {
281 	.probe = intel_cht_wc_pmic_opregion_probe,
282 	.driver = {
283 		.name = "cht_whiskey_cove_pmic",
284 	},
285 	.id_table = cht_wc_opregion_id_table,
286 };
287 builtin_platform_driver(intel_cht_wc_pmic_opregion_driver);
288