blob: 2579675b7082b76e593a095771f50e9c8e07bca9 [file] [log] [blame]
Andy Shevchenko78cd96f2018-08-30 19:51:03 +03001// SPDX-License-Identifier: GPL-2.0
Aaron Lud8139f62014-11-24 17:24:47 +08002/*
Andy Shevchenko78cd96f2018-08-30 19:51:03 +03003 * XPower AXP288 PMIC operation region driver
Aaron Lud8139f62014-11-24 17:24:47 +08004 *
5 * Copyright (C) 2014 Intel Corporation. All rights reserved.
Aaron Lud8139f62014-11-24 17:24:47 +08006 */
7
Aaron Lud8139f62014-11-24 17:24:47 +08008#include <linux/acpi.h>
Andy Shevchenko36b83512018-08-30 19:51:02 +03009#include <linux/init.h>
Aaron Lud8139f62014-11-24 17:24:47 +080010#include <linux/mfd/axp20x.h>
Andy Shevchenko36b83512018-08-30 19:51:02 +030011#include <linux/regmap.h>
Hans de Goede3c670dba2018-10-11 16:29:10 +020012#include <linux/platform_device.h>
13#include <asm/iosf_mbi.h>
Aaron Lud8139f62014-11-24 17:24:47 +080014#include "intel_pmic.h"
15
16#define XPOWER_GPADC_LOW 0x5b
Hans de Goede72ebe5a2017-05-14 23:35:39 +020017#define XPOWER_GPI1_CTRL 0x92
18
19#define GPI1_LDO_MASK GENMASK(2, 0)
20#define GPI1_LDO_ON (3 << 0)
21#define GPI1_LDO_OFF (4 << 0)
Aaron Lud8139f62014-11-24 17:24:47 +080022
Hans de Goede58eefe22017-07-08 15:40:08 +020023#define AXP288_ADC_TS_PIN_GPADC 0xf2
24#define AXP288_ADC_TS_PIN_ON 0xf3
25
Aaron Lud8139f62014-11-24 17:24:47 +080026static struct pmic_table power_table[] = {
27 {
28 .address = 0x00,
29 .reg = 0x13,
30 .bit = 0x05,
Hans de Goede2bde7c32017-04-21 13:48:08 +020031 }, /* ALD1 */
Aaron Lud8139f62014-11-24 17:24:47 +080032 {
33 .address = 0x04,
34 .reg = 0x13,
35 .bit = 0x06,
Hans de Goede2bde7c32017-04-21 13:48:08 +020036 }, /* ALD2 */
Aaron Lud8139f62014-11-24 17:24:47 +080037 {
38 .address = 0x08,
39 .reg = 0x13,
40 .bit = 0x07,
Hans de Goede2bde7c32017-04-21 13:48:08 +020041 }, /* ALD3 */
Aaron Lud8139f62014-11-24 17:24:47 +080042 {
43 .address = 0x0c,
44 .reg = 0x12,
45 .bit = 0x03,
Hans de Goede2bde7c32017-04-21 13:48:08 +020046 }, /* DLD1 */
Aaron Lud8139f62014-11-24 17:24:47 +080047 {
48 .address = 0x10,
49 .reg = 0x12,
50 .bit = 0x04,
Hans de Goede2bde7c32017-04-21 13:48:08 +020051 }, /* DLD2 */
Aaron Lud8139f62014-11-24 17:24:47 +080052 {
53 .address = 0x14,
54 .reg = 0x12,
55 .bit = 0x05,
Hans de Goede2bde7c32017-04-21 13:48:08 +020056 }, /* DLD3 */
Aaron Lud8139f62014-11-24 17:24:47 +080057 {
58 .address = 0x18,
59 .reg = 0x12,
60 .bit = 0x06,
Hans de Goede2bde7c32017-04-21 13:48:08 +020061 }, /* DLD4 */
Aaron Lud8139f62014-11-24 17:24:47 +080062 {
63 .address = 0x1c,
64 .reg = 0x12,
65 .bit = 0x00,
Hans de Goede2bde7c32017-04-21 13:48:08 +020066 }, /* ELD1 */
Aaron Lud8139f62014-11-24 17:24:47 +080067 {
68 .address = 0x20,
69 .reg = 0x12,
70 .bit = 0x01,
Hans de Goede2bde7c32017-04-21 13:48:08 +020071 }, /* ELD2 */
Aaron Lud8139f62014-11-24 17:24:47 +080072 {
73 .address = 0x24,
74 .reg = 0x12,
75 .bit = 0x02,
Hans de Goede2bde7c32017-04-21 13:48:08 +020076 }, /* ELD3 */
Aaron Lud8139f62014-11-24 17:24:47 +080077 {
78 .address = 0x28,
79 .reg = 0x13,
80 .bit = 0x02,
Hans de Goede2bde7c32017-04-21 13:48:08 +020081 }, /* FLD1 */
Aaron Lud8139f62014-11-24 17:24:47 +080082 {
83 .address = 0x2c,
84 .reg = 0x13,
85 .bit = 0x03,
Hans de Goede2bde7c32017-04-21 13:48:08 +020086 }, /* FLD2 */
Aaron Lud8139f62014-11-24 17:24:47 +080087 {
88 .address = 0x30,
89 .reg = 0x13,
90 .bit = 0x04,
Hans de Goede2bde7c32017-04-21 13:48:08 +020091 }, /* FLD3 */
92 {
93 .address = 0x34,
94 .reg = 0x10,
95 .bit = 0x03,
96 }, /* BUC1 */
Aaron Lud8139f62014-11-24 17:24:47 +080097 {
98 .address = 0x38,
99 .reg = 0x10,
Hans de Goede2bde7c32017-04-21 13:48:08 +0200100 .bit = 0x06,
101 }, /* BUC2 */
Aaron Lud8139f62014-11-24 17:24:47 +0800102 {
103 .address = 0x3c,
104 .reg = 0x10,
Hans de Goede2bde7c32017-04-21 13:48:08 +0200105 .bit = 0x05,
106 }, /* BUC3 */
Aaron Lud8139f62014-11-24 17:24:47 +0800107 {
108 .address = 0x40,
109 .reg = 0x10,
Hans de Goede2bde7c32017-04-21 13:48:08 +0200110 .bit = 0x04,
111 }, /* BUC4 */
Aaron Lud8139f62014-11-24 17:24:47 +0800112 {
113 .address = 0x44,
114 .reg = 0x10,
Hans de Goede2bde7c32017-04-21 13:48:08 +0200115 .bit = 0x01,
116 }, /* BUC5 */
Aaron Lud8139f62014-11-24 17:24:47 +0800117 {
118 .address = 0x48,
119 .reg = 0x10,
Aaron Lud8139f62014-11-24 17:24:47 +0800120 .bit = 0x00
Hans de Goede2bde7c32017-04-21 13:48:08 +0200121 }, /* BUC6 */
Hans de Goede72ebe5a2017-05-14 23:35:39 +0200122 {
123 .address = 0x4c,
124 .reg = 0x92,
125 }, /* GPI1 */
Aaron Lud8139f62014-11-24 17:24:47 +0800126};
127
128/* TMP0 - TMP5 are the same, all from GPADC */
129static struct pmic_table thermal_table[] = {
130 {
131 .address = 0x00,
132 .reg = XPOWER_GPADC_LOW
133 },
134 {
135 .address = 0x0c,
136 .reg = XPOWER_GPADC_LOW
137 },
138 {
139 .address = 0x18,
140 .reg = XPOWER_GPADC_LOW
141 },
142 {
143 .address = 0x24,
144 .reg = XPOWER_GPADC_LOW
145 },
146 {
147 .address = 0x30,
148 .reg = XPOWER_GPADC_LOW
149 },
150 {
151 .address = 0x3c,
152 .reg = XPOWER_GPADC_LOW
153 },
154};
155
156static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
157 int bit, u64 *value)
158{
159 int data;
160
161 if (regmap_read(regmap, reg, &data))
162 return -EIO;
163
Hans de Goede72ebe5a2017-05-14 23:35:39 +0200164 /* GPIO1 LDO regulator needs special handling */
165 if (reg == XPOWER_GPI1_CTRL)
166 *value = ((data & GPI1_LDO_MASK) == GPI1_LDO_ON);
167 else
168 *value = (data & BIT(bit)) ? 1 : 0;
169
Aaron Lud8139f62014-11-24 17:24:47 +0800170 return 0;
171}
172
173static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
174 int bit, bool on)
175{
Hans de Goede3c670dba2018-10-11 16:29:10 +0200176 int data, ret;
Aaron Lud8139f62014-11-24 17:24:47 +0800177
Hans de Goede72ebe5a2017-05-14 23:35:39 +0200178 /* GPIO1 LDO regulator needs special handling */
179 if (reg == XPOWER_GPI1_CTRL)
180 return regmap_update_bits(regmap, reg, GPI1_LDO_MASK,
181 on ? GPI1_LDO_ON : GPI1_LDO_OFF);
182
Hans de Goede3c670dba2018-10-11 16:29:10 +0200183 ret = iosf_mbi_block_punit_i2c_access();
184 if (ret)
185 return ret;
186
187 if (regmap_read(regmap, reg, &data)) {
188 ret = -EIO;
189 goto out;
190 }
Aaron Lud8139f62014-11-24 17:24:47 +0800191
192 if (on)
193 data |= BIT(bit);
194 else
195 data &= ~BIT(bit);
196
197 if (regmap_write(regmap, reg, data))
Hans de Goede3c670dba2018-10-11 16:29:10 +0200198 ret = -EIO;
199out:
200 iosf_mbi_unblock_punit_i2c_access();
Aaron Lud8139f62014-11-24 17:24:47 +0800201
Hans de Goede3c670dba2018-10-11 16:29:10 +0200202 return ret;
Aaron Lud8139f62014-11-24 17:24:47 +0800203}
204
205/**
206 * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC
207 *
208 * @regmap: regmap of the PMIC device
209 * @reg: register to get the reading
210 *
Aaron Lud8139f62014-11-24 17:24:47 +0800211 * Return a positive value on success, errno on failure.
212 */
213static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg)
214{
Hans de Goede2e5a7f72017-04-19 15:07:00 +0200215 u8 buf[2];
Hans de Goede58eefe22017-07-08 15:40:08 +0200216 int ret;
Aaron Lud8139f62014-11-24 17:24:47 +0800217
Hans de Goede58eefe22017-07-08 15:40:08 +0200218 ret = regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL,
219 AXP288_ADC_TS_PIN_GPADC);
220 if (ret)
221 return ret;
Aaron Lud8139f62014-11-24 17:24:47 +0800222
Hans de Goede58eefe22017-07-08 15:40:08 +0200223 /* After switching to the GPADC pin give things some time to settle */
224 usleep_range(6000, 10000);
225
226 ret = regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2);
227 if (ret == 0)
228 ret = (buf[0] << 4) + ((buf[1] >> 4) & 0x0f);
229
230 regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON);
231
232 return ret;
Aaron Lud8139f62014-11-24 17:24:47 +0800233}
234
235static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {
236 .get_power = intel_xpower_pmic_get_power,
237 .update_power = intel_xpower_pmic_update_power,
238 .get_raw_temp = intel_xpower_pmic_get_raw_temp,
239 .power_table = power_table,
240 .power_table_count = ARRAY_SIZE(power_table),
241 .thermal_table = thermal_table,
242 .thermal_table_count = ARRAY_SIZE(thermal_table),
243};
244
Aaron Lu491cb352014-11-24 17:32:33 +0800245static acpi_status intel_xpower_pmic_gpio_handler(u32 function,
246 acpi_physical_address address, u32 bit_width, u64 *value,
247 void *handler_context, void *region_context)
248{
249 return AE_OK;
250}
Aaron Lud8139f62014-11-24 17:24:47 +0800251
252static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev)
253{
Aaron Lu491cb352014-11-24 17:32:33 +0800254 struct device *parent = pdev->dev.parent;
255 struct axp20x_dev *axp20x = dev_get_drvdata(parent);
256 acpi_status status;
257 int result;
258
259 status = acpi_install_address_space_handler(ACPI_HANDLE(parent),
260 ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler,
261 NULL, NULL);
262 if (ACPI_FAILURE(status))
263 return -ENODEV;
264
265 result = intel_pmic_install_opregion_handler(&pdev->dev,
266 ACPI_HANDLE(parent), axp20x->regmap,
267 &intel_xpower_pmic_opregion_data);
268 if (result)
269 acpi_remove_address_space_handler(ACPI_HANDLE(parent),
270 ACPI_ADR_SPACE_GPIO,
271 intel_xpower_pmic_gpio_handler);
272
273 return result;
Aaron Lud8139f62014-11-24 17:24:47 +0800274}
275
276static struct platform_driver intel_xpower_pmic_opregion_driver = {
277 .probe = intel_xpower_pmic_opregion_probe,
278 .driver = {
279 .name = "axp288_pmic_acpi",
280 },
281};
Andy Shevchenko0d154fd2018-01-09 22:26:58 +0200282builtin_platform_driver(intel_xpower_pmic_opregion_driver);