1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Intel Bay Trail Crystal Cove PMIC operation region driver
4 *
5 * Copyright (C) 2014 Intel Corporation. All rights reserved.
6 */
7
8#include <linux/acpi.h>
9#include <linux/init.h>
10#include <linux/mfd/intel_soc_pmic.h>
11#include <linux/platform_device.h>
12#include <linux/regmap.h>
13#include "intel_pmic.h"
14
15#define PWR_SOURCE_SELECT	BIT(1)
16
17#define PMIC_A0LOCK_REG		0xc5
18
19static struct pmic_table power_table[] = {
20/*	{
21		.address = 0x00,
22		.reg = ??,
23		.bit = ??,
24	}, ** VSYS */
25	{
26		.address = 0x04,
27		.reg = 0x63,
28		.bit = 0x00,
29	}, /* SYSX -> VSYS_SX */
30	{
31		.address = 0x08,
32		.reg = 0x62,
33		.bit = 0x00,
34	}, /* SYSU -> VSYS_U */
35	{
36		.address = 0x0c,
37		.reg = 0x64,
38		.bit = 0x00,
39	}, /* SYSS -> VSYS_S */
40	{
41		.address = 0x10,
42		.reg = 0x6a,
43		.bit = 0x00,
44	}, /* V50S -> V5P0S */
45	{
46		.address = 0x14,
47		.reg = 0x6b,
48		.bit = 0x00,
49	}, /* HOST -> VHOST, USB2/3 host */
50	{
51		.address = 0x18,
52		.reg = 0x6c,
53		.bit = 0x00,
54	}, /* VBUS -> VBUS, USB2/3 OTG */
55	{
56		.address = 0x1c,
57		.reg = 0x6d,
58		.bit = 0x00,
59	}, /* HDMI -> VHDMI */
60/*	{
61		.address = 0x20,
62		.reg = ??,
63		.bit = ??,
64	}, ** S285 */
65	{
66		.address = 0x24,
67		.reg = 0x66,
68		.bit = 0x00,
69	}, /* X285 -> V2P85SX, camera */
70/*	{
71		.address = 0x28,
72		.reg = ??,
73		.bit = ??,
74	}, ** V33A */
75	{
76		.address = 0x2c,
77		.reg = 0x69,
78		.bit = 0x00,
79	}, /* V33S -> V3P3S, display/ssd/audio */
80	{
81		.address = 0x30,
82		.reg = 0x68,
83		.bit = 0x00,
84	}, /* V33U -> V3P3U, SDIO wifi&bt */
85/*	{
86		.address = 0x34 .. 0x40,
87		.reg = ??,
88		.bit = ??,
89	}, ** V33I, V18A, REFQ, V12A */
90	{
91		.address = 0x44,
92		.reg = 0x5c,
93		.bit = 0x00,
94	}, /* V18S -> V1P8S, SOC/USB PHY/SIM */
95	{
96		.address = 0x48,
97		.reg = 0x5d,
98		.bit = 0x00,
99	}, /* V18X -> V1P8SX, eMMC/camara/audio */
100	{
101		.address = 0x4c,
102		.reg = 0x5b,
103		.bit = 0x00,
104	}, /* V18U -> V1P8U, LPDDR */
105	{
106		.address = 0x50,
107		.reg = 0x61,
108		.bit = 0x00,
109	}, /* V12X -> V1P2SX, SOC SFR */
110	{
111		.address = 0x54,
112		.reg = 0x60,
113		.bit = 0x00,
114	}, /* V12S -> V1P2S, MIPI */
115/*	{
116		.address = 0x58,
117		.reg = ??,
118		.bit = ??,
119	}, ** V10A */
120	{
121		.address = 0x5c,
122		.reg = 0x56,
123		.bit = 0x00,
124	}, /* V10S -> V1P0S, SOC GFX */
125	{
126		.address = 0x60,
127		.reg = 0x57,
128		.bit = 0x00,
129	}, /* V10X -> V1P0SX, SOC display/DDR IO/PCIe */
130	{
131		.address = 0x64,
132		.reg = 0x59,
133		.bit = 0x00,
134	}, /* V105 -> V1P05S, L2 SRAM */
135};
136
137static struct pmic_table thermal_table[] = {
138	{
139		.address = 0x00,
140		.reg = 0x75
141	},
142	{
143		.address = 0x04,
144		.reg = 0x95
145	},
146	{
147		.address = 0x08,
148		.reg = 0x97
149	},
150	{
151		.address = 0x0c,
152		.reg = 0x77
153	},
154	{
155		.address = 0x10,
156		.reg = 0x9a
157	},
158	{
159		.address = 0x14,
160		.reg = 0x9c
161	},
162	{
163		.address = 0x18,
164		.reg = 0x79
165	},
166	{
167		.address = 0x1c,
168		.reg = 0x9f
169	},
170	{
171		.address = 0x20,
172		.reg = 0xa1
173	},
174	{
175		.address = 0x48,
176		.reg = 0x94
177	},
178	{
179		.address = 0x4c,
180		.reg = 0x99
181	},
182	{
183		.address = 0x50,
184		.reg = 0x9e
185	},
186};
187
188static int intel_crc_pmic_get_power(struct regmap *regmap, int reg,
189				    int bit, u64 *value)
190{
191	int data;
192
193	if (regmap_read(regmap, reg, &data))
194		return -EIO;
195
196	*value = (data & PWR_SOURCE_SELECT) && (data & BIT(bit)) ? 1 : 0;
197	return 0;
198}
199
200static int intel_crc_pmic_update_power(struct regmap *regmap, int reg,
201				       int bit, bool on)
202{
203	int data;
204
205	if (regmap_read(regmap, reg, &data))
206		return -EIO;
207
208	if (on) {
209		data |= PWR_SOURCE_SELECT | BIT(bit);
210	} else {
211		data &= ~BIT(bit);
212		data |= PWR_SOURCE_SELECT;
213	}
214
215	if (regmap_write(regmap, reg, data))
216		return -EIO;
217	return 0;
218}
219
220static int intel_crc_pmic_get_raw_temp(struct regmap *regmap, int reg)
221{
222	int temp_l, temp_h;
223
224	/*
225	 * Raw temperature value is 10bits: 8bits in reg
226	 * and 2bits in reg-1: bit0,1
227	 */
228	if (regmap_read(regmap, reg, &temp_l) ||
229	    regmap_read(regmap, reg - 1, &temp_h))
230		return -EIO;
231
232	return temp_l | (temp_h & 0x3) << 8;
233}
234
235static int intel_crc_pmic_update_aux(struct regmap *regmap, int reg, int raw)
236{
237	return regmap_write(regmap, reg, raw) ||
238		regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0;
239}
240
241static int intel_crc_pmic_get_policy(struct regmap *regmap,
242					int reg, int bit, u64 *value)
243{
244	int pen;
245
246	if (regmap_read(regmap, reg, &pen))
247		return -EIO;
248	*value = pen >> 7;
249	return 0;
250}
251
252static int intel_crc_pmic_update_policy(struct regmap *regmap,
253					int reg, int bit, int enable)
254{
255	int alert0;
256
257	/* Update to policy enable bit requires unlocking a0lock */
258	if (regmap_read(regmap, PMIC_A0LOCK_REG, &alert0))
259		return -EIO;
260
261	if (regmap_update_bits(regmap, PMIC_A0LOCK_REG, 0x01, 0))
262		return -EIO;
263
264	if (regmap_update_bits(regmap, reg, 0x80, enable << 7))
265		return -EIO;
266
267	/* restore alert0 */
268	if (regmap_write(regmap, PMIC_A0LOCK_REG, alert0))
269		return -EIO;
270
271	return 0;
272}
273
274static const struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = {
275	.get_power	= intel_crc_pmic_get_power,
276	.update_power	= intel_crc_pmic_update_power,
277	.get_raw_temp	= intel_crc_pmic_get_raw_temp,
278	.update_aux	= intel_crc_pmic_update_aux,
279	.get_policy	= intel_crc_pmic_get_policy,
280	.update_policy	= intel_crc_pmic_update_policy,
281	.lpat_raw_to_temp = acpi_lpat_raw_to_temp,
282	.power_table	= power_table,
283	.power_table_count= ARRAY_SIZE(power_table),
284	.thermal_table	= thermal_table,
285	.thermal_table_count = ARRAY_SIZE(thermal_table),
286	.pmic_i2c_address = 0x6e,
287};
288
289static int intel_crc_pmic_opregion_probe(struct platform_device *pdev)
290{
291	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
292	return intel_pmic_install_opregion_handler(&pdev->dev,
293			ACPI_HANDLE(pdev->dev.parent), pmic->regmap,
294			&intel_crc_pmic_opregion_data);
295}
296
297static struct platform_driver intel_crc_pmic_opregion_driver = {
298	.probe = intel_crc_pmic_opregion_probe,
299	.driver = {
300		.name = "byt_crystal_cove_pmic",
301	},
302};
303builtin_platform_driver(intel_crc_pmic_opregion_driver);
304