Linux Audio

Check our new training course

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