1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Intel BXT WhiskeyCove PMIC operation region driver
4 *
5 * Copyright (C) 2015 Intel Corporation. All rights reserved.
6 */
7
8#include <linux/init.h>
9#include <linux/acpi.h>
10#include <linux/mfd/intel_soc_pmic.h>
11#include <linux/regmap.h>
12#include <linux/platform_device.h>
13#include "intel_pmic.h"
14
15#define WHISKEY_COVE_ALRT_HIGH_BIT_MASK 0x0F
16#define WHISKEY_COVE_ADC_HIGH_BIT(x)	(((x & 0x0F) << 8))
17#define WHISKEY_COVE_ADC_CURSRC(x)	(((x & 0xF0) >> 4))
18#define VR_MODE_DISABLED        0
19#define VR_MODE_AUTO            BIT(0)
20#define VR_MODE_NORMAL          BIT(1)
21#define VR_MODE_SWITCH          BIT(2)
22#define VR_MODE_ECO             (BIT(0)|BIT(1))
23#define VSWITCH2_OUTPUT         BIT(5)
24#define VSWITCH1_OUTPUT         BIT(4)
25#define VUSBPHY_CHARGE          BIT(1)
26
27static struct pmic_table power_table[] = {
28	{
29		.address = 0x0,
30		.reg = 0x63,
31		.bit = VR_MODE_AUTO,
32	}, /* VDD1 -> VDD1CNT */
33	{
34		.address = 0x04,
35		.reg = 0x65,
36		.bit = VR_MODE_AUTO,
37	}, /* VDD2 -> VDD2CNT */
38	{
39		.address = 0x08,
40		.reg = 0x67,
41		.bit = VR_MODE_AUTO,
42	}, /* VDD3 -> VDD3CNT */
43	{
44		.address = 0x0c,
45		.reg = 0x6d,
46		.bit = VR_MODE_AUTO,
47	}, /* VLFX -> VFLEXCNT */
48	{
49		.address = 0x10,
50		.reg = 0x6f,
51		.bit = VR_MODE_NORMAL,
52	}, /* VP1A -> VPROG1ACNT */
53	{
54		.address = 0x14,
55		.reg = 0x70,
56		.bit = VR_MODE_NORMAL,
57	}, /* VP1B -> VPROG1BCNT */
58	{
59		.address = 0x18,
60		.reg = 0x71,
61		.bit = VR_MODE_NORMAL,
62	}, /* VP1C -> VPROG1CCNT */
63	{
64		.address = 0x1c,
65		.reg = 0x72,
66		.bit = VR_MODE_NORMAL,
67	}, /* VP1D -> VPROG1DCNT */
68	{
69		.address = 0x20,
70		.reg = 0x73,
71		.bit = VR_MODE_NORMAL,
72	}, /* VP2A -> VPROG2ACNT */
73	{
74		.address = 0x24,
75		.reg = 0x74,
76		.bit = VR_MODE_NORMAL,
77	}, /* VP2B -> VPROG2BCNT */
78	{
79		.address = 0x28,
80		.reg = 0x75,
81		.bit = VR_MODE_NORMAL,
82	}, /* VP2C -> VPROG2CCNT */
83	{
84		.address = 0x2c,
85		.reg = 0x76,
86		.bit = VR_MODE_NORMAL,
87	}, /* VP3A -> VPROG3ACNT */
88	{
89		.address = 0x30,
90		.reg = 0x77,
91		.bit = VR_MODE_NORMAL,
92	}, /* VP3B -> VPROG3BCNT */
93	{
94		.address = 0x34,
95		.reg = 0x78,
96		.bit = VSWITCH2_OUTPUT,
97	}, /* VSW2 -> VLD0CNT Bit 5*/
98	{
99		.address = 0x38,
100		.reg = 0x78,
101		.bit = VSWITCH1_OUTPUT,
102	}, /* VSW1 -> VLD0CNT Bit 4 */
103	{
104		.address = 0x3c,
105		.reg = 0x78,
106		.bit = VUSBPHY_CHARGE,
107	}, /* VUPY -> VLDOCNT Bit 1 */
108	{
109		.address = 0x40,
110		.reg = 0x7b,
111		.bit = VR_MODE_NORMAL,
112	}, /* VRSO -> VREFSOCCNT*/
113	{
114		.address = 0x44,
115		.reg = 0xA0,
116		.bit = VR_MODE_NORMAL,
117	}, /* VP1E -> VPROG1ECNT */
118	{
119		.address = 0x48,
120		.reg = 0xA1,
121		.bit = VR_MODE_NORMAL,
122	}, /* VP1F -> VPROG1FCNT */
123	{
124		.address = 0x4c,
125		.reg = 0xA2,
126		.bit = VR_MODE_NORMAL,
127	}, /* VP2D -> VPROG2DCNT */
128	{
129		.address = 0x50,
130		.reg = 0xA3,
131		.bit = VR_MODE_NORMAL,
132	}, /* VP4A -> VPROG4ACNT */
133	{
134		.address = 0x54,
135		.reg = 0xA4,
136		.bit = VR_MODE_NORMAL,
137	}, /* VP4B -> VPROG4BCNT */
138	{
139		.address = 0x58,
140		.reg = 0xA5,
141		.bit = VR_MODE_NORMAL,
142	}, /* VP4C -> VPROG4CCNT */
143	{
144		.address = 0x5c,
145		.reg = 0xA6,
146		.bit = VR_MODE_NORMAL,
147	}, /* VP4D -> VPROG4DCNT */
148	{
149		.address = 0x60,
150		.reg = 0xA7,
151		.bit = VR_MODE_NORMAL,
152	}, /* VP5A -> VPROG5ACNT */
153	{
154		.address = 0x64,
155		.reg = 0xA8,
156		.bit = VR_MODE_NORMAL,
157	}, /* VP5B -> VPROG5BCNT */
158	{
159		.address = 0x68,
160		.reg = 0xA9,
161		.bit = VR_MODE_NORMAL,
162	}, /* VP6A -> VPROG6ACNT */
163	{
164		.address = 0x6c,
165		.reg = 0xAA,
166		.bit = VR_MODE_NORMAL,
167	}, /* VP6B -> VPROG6BCNT */
168	{
169		.address = 0x70,
170		.reg = 0x36,
171		.bit = BIT(2),
172	}, /* SDWN_N -> MODEMCTRL Bit 2 */
173	{
174		.address = 0x74,
175		.reg = 0x36,
176		.bit = BIT(0),
177	} /* MOFF -> MODEMCTRL Bit 0 */
178};
179
180static struct pmic_table thermal_table[] = {
181	{
182		.address = 0x00,
183		.reg = 0x4F39
184	},
185	{
186		.address = 0x04,
187		.reg = 0x4F24
188	},
189	{
190		.address = 0x08,
191		.reg = 0x4F26
192	},
193	{
194		.address = 0x0c,
195		.reg = 0x4F3B
196	},
197	{
198		.address = 0x10,
199		.reg = 0x4F28
200	},
201	{
202		.address = 0x14,
203		.reg = 0x4F2A
204	},
205	{
206		.address = 0x18,
207		.reg = 0x4F3D
208	},
209	{
210		.address = 0x1c,
211		.reg = 0x4F2C
212	},
213	{
214		.address = 0x20,
215		.reg = 0x4F2E
216	},
217	{
218		.address = 0x24,
219		.reg = 0x4F3F
220	},
221	{
222		.address = 0x28,
223		.reg = 0x4F30
224	},
225	{
226		.address = 0x30,
227		.reg = 0x4F41
228	},
229	{
230		.address = 0x34,
231		.reg = 0x4F32
232	},
233	{
234		.address = 0x3c,
235		.reg = 0x4F43
236	},
237	{
238		.address = 0x40,
239		.reg = 0x4F34
240	},
241	{
242		.address = 0x48,
243		.reg = 0x4F6A,
244		.bit = 0,
245	},
246	{
247		.address = 0x4C,
248		.reg = 0x4F6A,
249		.bit = 1
250	},
251	{
252		.address = 0x50,
253		.reg = 0x4F6A,
254		.bit = 2
255	},
256	{
257		.address = 0x54,
258		.reg = 0x4F6A,
259		.bit = 4
260	},
261	{
262		.address = 0x58,
263		.reg = 0x4F6A,
264		.bit = 5
265	},
266	{
267		.address = 0x5C,
268		.reg = 0x4F6A,
269		.bit = 3
270	},
271};
272
273static int intel_bxtwc_pmic_get_power(struct regmap *regmap, int reg,
274		int bit, u64 *value)
275{
276	int data;
277
278	if (regmap_read(regmap, reg, &data))
279		return -EIO;
280
281	*value = (data & bit) ? 1 : 0;
282	return 0;
283}
284
285static int intel_bxtwc_pmic_update_power(struct regmap *regmap, int reg,
286		int bit, bool on)
287{
288	u8 val, mask = bit;
289
290	if (on)
291		val = 0xFF;
292	else
293		val = 0x0;
294
295	return regmap_update_bits(regmap, reg, mask, val);
296}
297
298static int intel_bxtwc_pmic_get_raw_temp(struct regmap *regmap, int reg)
299{
300	unsigned int val, adc_val, reg_val;
301	u8 temp_l, temp_h, cursrc;
302	unsigned long rlsb;
303	static const unsigned long rlsb_array[] = {
304		0, 260420, 130210, 65100, 32550, 16280,
305		8140, 4070, 2030, 0, 260420, 130210 };
306
307	if (regmap_read(regmap, reg, &val))
308		return -EIO;
309	temp_l = (u8) val;
310
311	if (regmap_read(regmap, (reg - 1), &val))
312		return -EIO;
313	temp_h = (u8) val;
314
315	reg_val = temp_l | WHISKEY_COVE_ADC_HIGH_BIT(temp_h);
316	cursrc = WHISKEY_COVE_ADC_CURSRC(temp_h);
317	rlsb = rlsb_array[cursrc];
318	adc_val = reg_val * rlsb / 1000;
319
320	return adc_val;
321}
322
323static int
324intel_bxtwc_pmic_update_aux(struct regmap *regmap, int reg, int raw)
325{
326	u32 bsr_num;
327	u16 resi_val, count = 0, thrsh = 0;
328	u8 alrt_h, alrt_l, cursel = 0;
329
330	bsr_num = raw;
331	bsr_num /= (1 << 5);
332
333	count = fls(bsr_num) - 1;
334
335	cursel = clamp_t(s8, (count - 7), 0, 7);
336	thrsh = raw / (1 << (4 + cursel));
337
338	resi_val = (cursel << 9) | thrsh;
339	alrt_h = (resi_val >> 8) & WHISKEY_COVE_ALRT_HIGH_BIT_MASK;
340	if (regmap_update_bits(regmap,
341				reg - 1,
342				WHISKEY_COVE_ALRT_HIGH_BIT_MASK,
343				alrt_h))
344		return -EIO;
345
346	alrt_l = (u8)resi_val;
347	return regmap_write(regmap, reg, alrt_l);
348}
349
350static int
351intel_bxtwc_pmic_get_policy(struct regmap *regmap, int reg, int bit, u64 *value)
352{
353	u8 mask = BIT(bit);
354	unsigned int val;
355
356	if (regmap_read(regmap, reg, &val))
357		return -EIO;
358
359	*value = (val & mask) >> bit;
360	return 0;
361}
362
363static int
364intel_bxtwc_pmic_update_policy(struct regmap *regmap,
365				int reg, int bit, int enable)
366{
367	u8 mask = BIT(bit), val = enable << bit;
368
369	return regmap_update_bits(regmap, reg, mask, val);
370}
371
372static const struct intel_pmic_opregion_data intel_bxtwc_pmic_opregion_data = {
373	.get_power      = intel_bxtwc_pmic_get_power,
374	.update_power   = intel_bxtwc_pmic_update_power,
375	.get_raw_temp   = intel_bxtwc_pmic_get_raw_temp,
376	.update_aux     = intel_bxtwc_pmic_update_aux,
377	.get_policy     = intel_bxtwc_pmic_get_policy,
378	.update_policy  = intel_bxtwc_pmic_update_policy,
379	.lpat_raw_to_temp = acpi_lpat_raw_to_temp,
380	.power_table      = power_table,
381	.power_table_count = ARRAY_SIZE(power_table),
382	.thermal_table     = thermal_table,
383	.thermal_table_count = ARRAY_SIZE(thermal_table),
384};
385
386static int intel_bxtwc_pmic_opregion_probe(struct platform_device *pdev)
387{
388	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
389
390	return intel_pmic_install_opregion_handler(&pdev->dev,
391			ACPI_HANDLE(pdev->dev.parent),
392			pmic->regmap,
393			&intel_bxtwc_pmic_opregion_data);
394}
395
396static const struct platform_device_id bxt_wc_opregion_id_table[] = {
397	{ .name = "bxt_wcove_region" },
398	{},
399};
400
401static struct platform_driver intel_bxtwc_pmic_opregion_driver = {
402	.probe = intel_bxtwc_pmic_opregion_probe,
403	.driver = {
404		.name = "bxt_whiskey_cove_pmic",
405	},
406	.id_table = bxt_wc_opregion_id_table,
407};
408builtin_platform_driver(intel_bxtwc_pmic_opregion_driver);
409