xref: /openbmc/linux/drivers/acpi/pmic/intel_pmic_bxtwc.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
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  
27  static 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  
180  static 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  
intel_bxtwc_pmic_get_power(struct regmap * regmap,int reg,int bit,u64 * value)273  static 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  
intel_bxtwc_pmic_update_power(struct regmap * regmap,int reg,int bit,bool on)285  static 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  
intel_bxtwc_pmic_get_raw_temp(struct regmap * regmap,int reg)298  static 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  
323  static int
intel_bxtwc_pmic_update_aux(struct regmap * regmap,int reg,int raw)324  intel_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  
350  static int
intel_bxtwc_pmic_get_policy(struct regmap * regmap,int reg,int bit,u64 * value)351  intel_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  
363  static int
intel_bxtwc_pmic_update_policy(struct regmap * regmap,int reg,int bit,int enable)364  intel_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  
372  static 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  
intel_bxtwc_pmic_opregion_probe(struct platform_device * pdev)386  static 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  
396  static const struct platform_device_id bxt_wc_opregion_id_table[] = {
397  	{ .name = "bxt_wcove_region" },
398  	{},
399  };
400  
401  static 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  };
408  builtin_platform_driver(intel_bxtwc_pmic_opregion_driver);
409