1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Intel CHT Whiskey Cove PMIC operation region driver
4 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
5 *
6 * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
7 * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
8 */
9
10#include <linux/acpi.h>
11#include <linux/init.h>
12#include <linux/mfd/intel_soc_pmic.h>
13#include <linux/platform_device.h>
14#include <linux/regmap.h>
15#include "intel_pmic.h"
16
17#define CHT_WC_V1P05A_CTRL 0x6e3b
18#define CHT_WC_V1P15_CTRL 0x6e3c
19#define CHT_WC_V1P05A_VSEL 0x6e3d
20#define CHT_WC_V1P15_VSEL 0x6e3e
21#define CHT_WC_V1P8A_CTRL 0x6e56
22#define CHT_WC_V1P8SX_CTRL 0x6e57
23#define CHT_WC_VDDQ_CTRL 0x6e58
24#define CHT_WC_V1P2A_CTRL 0x6e59
25#define CHT_WC_V1P2SX_CTRL 0x6e5a
26#define CHT_WC_V1P8A_VSEL 0x6e5b
27#define CHT_WC_VDDQ_VSEL 0x6e5c
28#define CHT_WC_V2P8SX_CTRL 0x6e5d
29#define CHT_WC_V3P3A_CTRL 0x6e5e
30#define CHT_WC_V3P3SD_CTRL 0x6e5f
31#define CHT_WC_VSDIO_CTRL 0x6e67
32#define CHT_WC_V3P3A_VSEL 0x6e68
33#define CHT_WC_VPROG1A_CTRL 0x6e90
34#define CHT_WC_VPROG1B_CTRL 0x6e91
35#define CHT_WC_VPROG1F_CTRL 0x6e95
36#define CHT_WC_VPROG2D_CTRL 0x6e99
37#define CHT_WC_VPROG3A_CTRL 0x6e9a
38#define CHT_WC_VPROG3B_CTRL 0x6e9b
39#define CHT_WC_VPROG4A_CTRL 0x6e9c
40#define CHT_WC_VPROG4B_CTRL 0x6e9d
41#define CHT_WC_VPROG4C_CTRL 0x6e9e
42#define CHT_WC_VPROG4D_CTRL 0x6e9f
43#define CHT_WC_VPROG5A_CTRL 0x6ea0
44#define CHT_WC_VPROG5B_CTRL 0x6ea1
45#define CHT_WC_VPROG6A_CTRL 0x6ea2
46#define CHT_WC_VPROG6B_CTRL 0x6ea3
47#define CHT_WC_VPROG1A_VSEL 0x6ec0
48#define CHT_WC_VPROG1B_VSEL 0x6ec1
49#define CHT_WC_V1P8SX_VSEL 0x6ec2
50#define CHT_WC_V1P2SX_VSEL 0x6ec3
51#define CHT_WC_V1P2A_VSEL 0x6ec4
52#define CHT_WC_VPROG1F_VSEL 0x6ec5
53#define CHT_WC_VSDIO_VSEL 0x6ec6
54#define CHT_WC_V2P8SX_VSEL 0x6ec7
55#define CHT_WC_V3P3SD_VSEL 0x6ec8
56#define CHT_WC_VPROG2D_VSEL 0x6ec9
57#define CHT_WC_VPROG3A_VSEL 0x6eca
58#define CHT_WC_VPROG3B_VSEL 0x6ecb
59#define CHT_WC_VPROG4A_VSEL 0x6ecc
60#define CHT_WC_VPROG4B_VSEL 0x6ecd
61#define CHT_WC_VPROG4C_VSEL 0x6ece
62#define CHT_WC_VPROG4D_VSEL 0x6ecf
63#define CHT_WC_VPROG5A_VSEL 0x6ed0
64#define CHT_WC_VPROG5B_VSEL 0x6ed1
65#define CHT_WC_VPROG6A_VSEL 0x6ed2
66#define CHT_WC_VPROG6B_VSEL 0x6ed3
67
68/*
69 * Regulator support is based on the non upstream patch:
70 * "regulator: whiskey_cove: implements Whiskey Cove pmic VRF support"
71 * https://github.com/intel-aero/meta-intel-aero/blob/master/recipes-kernel/linux/linux-yocto/0019-regulator-whiskey_cove-implements-WhiskeyCove-pmic-V.patch
72 */
73static struct pmic_table power_table[] = {
74 {
75 .address = 0x0,
76 .reg = CHT_WC_V1P8A_CTRL,
77 .bit = 0x01,
78 }, /* V18A */
79 {
80 .address = 0x04,
81 .reg = CHT_WC_V1P8SX_CTRL,
82 .bit = 0x07,
83 }, /* V18X */
84 {
85 .address = 0x08,
86 .reg = CHT_WC_VDDQ_CTRL,
87 .bit = 0x01,
88 }, /* VDDQ */
89 {
90 .address = 0x0c,
91 .reg = CHT_WC_V1P2A_CTRL,
92 .bit = 0x07,
93 }, /* V12A */
94 {
95 .address = 0x10,
96 .reg = CHT_WC_V1P2SX_CTRL,
97 .bit = 0x07,
98 }, /* V12X */
99 {
100 .address = 0x14,
101 .reg = CHT_WC_V2P8SX_CTRL,
102 .bit = 0x07,
103 }, /* V28X */
104 {
105 .address = 0x18,
106 .reg = CHT_WC_V3P3A_CTRL,
107 .bit = 0x01,
108 }, /* V33A */
109 {
110 .address = 0x1c,
111 .reg = CHT_WC_V3P3SD_CTRL,
112 .bit = 0x07,
113 }, /* V3SD */
114 {
115 .address = 0x20,
116 .reg = CHT_WC_VSDIO_CTRL,
117 .bit = 0x07,
118 }, /* VSD */
119/* {
120 .address = 0x24,
121 .reg = ??,
122 .bit = ??,
123 }, ** VSW2 */
124/* {
125 .address = 0x28,
126 .reg = ??,
127 .bit = ??,
128 }, ** VSW1 */
129/* {
130 .address = 0x2c,
131 .reg = ??,
132 .bit = ??,
133 }, ** VUPY */
134/* {
135 .address = 0x30,
136 .reg = ??,
137 .bit = ??,
138 }, ** VRSO */
139 {
140 .address = 0x34,
141 .reg = CHT_WC_VPROG1A_CTRL,
142 .bit = 0x07,
143 }, /* VP1A */
144 {
145 .address = 0x38,
146 .reg = CHT_WC_VPROG1B_CTRL,
147 .bit = 0x07,
148 }, /* VP1B */
149 {
150 .address = 0x3c,
151 .reg = CHT_WC_VPROG1F_CTRL,
152 .bit = 0x07,
153 }, /* VP1F */
154 {
155 .address = 0x40,
156 .reg = CHT_WC_VPROG2D_CTRL,
157 .bit = 0x07,
158 }, /* VP2D */
159 {
160 .address = 0x44,
161 .reg = CHT_WC_VPROG3A_CTRL,
162 .bit = 0x07,
163 }, /* VP3A */
164 {
165 .address = 0x48,
166 .reg = CHT_WC_VPROG3B_CTRL,
167 .bit = 0x07,
168 }, /* VP3B */
169 {
170 .address = 0x4c,
171 .reg = CHT_WC_VPROG4A_CTRL,
172 .bit = 0x07,
173 }, /* VP4A */
174 {
175 .address = 0x50,
176 .reg = CHT_WC_VPROG4B_CTRL,
177 .bit = 0x07,
178 }, /* VP4B */
179 {
180 .address = 0x54,
181 .reg = CHT_WC_VPROG4C_CTRL,
182 .bit = 0x07,
183 }, /* VP4C */
184 {
185 .address = 0x58,
186 .reg = CHT_WC_VPROG4D_CTRL,
187 .bit = 0x07,
188 }, /* VP4D */
189 {
190 .address = 0x5c,
191 .reg = CHT_WC_VPROG5A_CTRL,
192 .bit = 0x07,
193 }, /* VP5A */
194 {
195 .address = 0x60,
196 .reg = CHT_WC_VPROG5B_CTRL,
197 .bit = 0x07,
198 }, /* VP5B */
199 {
200 .address = 0x64,
201 .reg = CHT_WC_VPROG6A_CTRL,
202 .bit = 0x07,
203 }, /* VP6A */
204 {
205 .address = 0x68,
206 .reg = CHT_WC_VPROG6B_CTRL,
207 .bit = 0x07,
208 }, /* VP6B */
209/* {
210 .address = 0x6c,
211 .reg = ??,
212 .bit = ??,
213 } ** VP7A */
214};
215
216static int intel_cht_wc_pmic_get_power(struct regmap *regmap, int reg,
217 int bit, u64 *value)
218{
219 int data;
220
221 if (regmap_read(map: regmap, reg, val: &data))
222 return -EIO;
223
224 *value = (data & bit) ? 1 : 0;
225 return 0;
226}
227
228static int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg,
229 int bitmask, bool on)
230{
231 return regmap_update_bits(map: regmap, reg, mask: bitmask, val: on ? 1 : 0);
232}
233
234static int intel_cht_wc_exec_mipi_pmic_seq_element(struct regmap *regmap,
235 u16 i2c_client_address,
236 u32 reg_address,
237 u32 value, u32 mask)
238{
239 u32 address;
240
241 if (i2c_client_address > 0xff || reg_address > 0xff) {
242 pr_warn("%s warning addresses too big client 0x%x reg 0x%x\n",
243 __func__, i2c_client_address, reg_address);
244 return -ERANGE;
245 }
246
247 address = (i2c_client_address << 8) | reg_address;
248
249 return regmap_update_bits(map: regmap, reg: address, mask, val: value);
250}
251
252/*
253 * The thermal table and ops are empty, we do not support the Thermal opregion
254 * (DPTF) due to lacking documentation.
255 */
256static const struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = {
257 .get_power = intel_cht_wc_pmic_get_power,
258 .update_power = intel_cht_wc_pmic_update_power,
259 .exec_mipi_pmic_seq_element = intel_cht_wc_exec_mipi_pmic_seq_element,
260 .lpat_raw_to_temp = acpi_lpat_raw_to_temp,
261 .power_table = power_table,
262 .power_table_count = ARRAY_SIZE(power_table),
263};
264
265static int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev)
266{
267 struct intel_soc_pmic *pmic = dev_get_drvdata(dev: pdev->dev.parent);
268
269 return intel_pmic_install_opregion_handler(dev: &pdev->dev,
270 ACPI_HANDLE(pdev->dev.parent),
271 regmap: pmic->regmap,
272 d: &intel_cht_wc_pmic_opregion_data);
273}
274
275static const struct platform_device_id cht_wc_opregion_id_table[] = {
276 { .name = "cht_wcove_region" },
277 {},
278};
279
280static struct platform_driver intel_cht_wc_pmic_opregion_driver = {
281 .probe = intel_cht_wc_pmic_opregion_probe,
282 .driver = {
283 .name = "cht_whiskey_cove_pmic",
284 },
285 .id_table = cht_wc_opregion_id_table,
286};
287builtin_platform_driver(intel_cht_wc_pmic_opregion_driver);
288

source code of linux/drivers/acpi/pmic/intel_pmic_chtwc.c