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