blob: 1a76c784cd4cbfb7a3ec9ff7b7120d2e8a9f01cb [file] [log] [blame]
Aaron Lud8139f62014-11-24 17:24:47 +08001/*
2 * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver
3 *
4 * Copyright (C) 2014 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
Paul Gortmaker6d3ef8d2016-07-11 18:05:16 -040016#include <linux/init.h>
Aaron Lud8139f62014-11-24 17:24:47 +080017#include <linux/acpi.h>
18#include <linux/mfd/axp20x.h>
19#include <linux/regmap.h>
20#include <linux/platform_device.h>
Aaron Lud8139f62014-11-24 17:24:47 +080021#include "intel_pmic.h"
22
23#define XPOWER_GPADC_LOW 0x5b
24
25static struct pmic_table power_table[] = {
26 {
27 .address = 0x00,
28 .reg = 0x13,
29 .bit = 0x05,
Hans de Goede2bde7c32017-04-21 13:48:08 +020030 }, /* ALD1 */
Aaron Lud8139f62014-11-24 17:24:47 +080031 {
32 .address = 0x04,
33 .reg = 0x13,
34 .bit = 0x06,
Hans de Goede2bde7c32017-04-21 13:48:08 +020035 }, /* ALD2 */
Aaron Lud8139f62014-11-24 17:24:47 +080036 {
37 .address = 0x08,
38 .reg = 0x13,
39 .bit = 0x07,
Hans de Goede2bde7c32017-04-21 13:48:08 +020040 }, /* ALD3 */
Aaron Lud8139f62014-11-24 17:24:47 +080041 {
42 .address = 0x0c,
43 .reg = 0x12,
44 .bit = 0x03,
Hans de Goede2bde7c32017-04-21 13:48:08 +020045 }, /* DLD1 */
Aaron Lud8139f62014-11-24 17:24:47 +080046 {
47 .address = 0x10,
48 .reg = 0x12,
49 .bit = 0x04,
Hans de Goede2bde7c32017-04-21 13:48:08 +020050 }, /* DLD2 */
Aaron Lud8139f62014-11-24 17:24:47 +080051 {
52 .address = 0x14,
53 .reg = 0x12,
54 .bit = 0x05,
Hans de Goede2bde7c32017-04-21 13:48:08 +020055 }, /* DLD3 */
Aaron Lud8139f62014-11-24 17:24:47 +080056 {
57 .address = 0x18,
58 .reg = 0x12,
59 .bit = 0x06,
Hans de Goede2bde7c32017-04-21 13:48:08 +020060 }, /* DLD4 */
Aaron Lud8139f62014-11-24 17:24:47 +080061 {
62 .address = 0x1c,
63 .reg = 0x12,
64 .bit = 0x00,
Hans de Goede2bde7c32017-04-21 13:48:08 +020065 }, /* ELD1 */
Aaron Lud8139f62014-11-24 17:24:47 +080066 {
67 .address = 0x20,
68 .reg = 0x12,
69 .bit = 0x01,
Hans de Goede2bde7c32017-04-21 13:48:08 +020070 }, /* ELD2 */
Aaron Lud8139f62014-11-24 17:24:47 +080071 {
72 .address = 0x24,
73 .reg = 0x12,
74 .bit = 0x02,
Hans de Goede2bde7c32017-04-21 13:48:08 +020075 }, /* ELD3 */
Aaron Lud8139f62014-11-24 17:24:47 +080076 {
77 .address = 0x28,
78 .reg = 0x13,
79 .bit = 0x02,
Hans de Goede2bde7c32017-04-21 13:48:08 +020080 }, /* FLD1 */
Aaron Lud8139f62014-11-24 17:24:47 +080081 {
82 .address = 0x2c,
83 .reg = 0x13,
84 .bit = 0x03,
Hans de Goede2bde7c32017-04-21 13:48:08 +020085 }, /* FLD2 */
Aaron Lud8139f62014-11-24 17:24:47 +080086 {
87 .address = 0x30,
88 .reg = 0x13,
89 .bit = 0x04,
Hans de Goede2bde7c32017-04-21 13:48:08 +020090 }, /* FLD3 */
91 {
92 .address = 0x34,
93 .reg = 0x10,
94 .bit = 0x03,
95 }, /* BUC1 */
Aaron Lud8139f62014-11-24 17:24:47 +080096 {
97 .address = 0x38,
98 .reg = 0x10,
Hans de Goede2bde7c32017-04-21 13:48:08 +020099 .bit = 0x06,
100 }, /* BUC2 */
Aaron Lud8139f62014-11-24 17:24:47 +0800101 {
102 .address = 0x3c,
103 .reg = 0x10,
Hans de Goede2bde7c32017-04-21 13:48:08 +0200104 .bit = 0x05,
105 }, /* BUC3 */
Aaron Lud8139f62014-11-24 17:24:47 +0800106 {
107 .address = 0x40,
108 .reg = 0x10,
Hans de Goede2bde7c32017-04-21 13:48:08 +0200109 .bit = 0x04,
110 }, /* BUC4 */
Aaron Lud8139f62014-11-24 17:24:47 +0800111 {
112 .address = 0x44,
113 .reg = 0x10,
Hans de Goede2bde7c32017-04-21 13:48:08 +0200114 .bit = 0x01,
115 }, /* BUC5 */
Aaron Lud8139f62014-11-24 17:24:47 +0800116 {
117 .address = 0x48,
118 .reg = 0x10,
Aaron Lud8139f62014-11-24 17:24:47 +0800119 .bit = 0x00
Hans de Goede2bde7c32017-04-21 13:48:08 +0200120 }, /* BUC6 */
Aaron Lud8139f62014-11-24 17:24:47 +0800121};
122
123/* TMP0 - TMP5 are the same, all from GPADC */
124static struct pmic_table thermal_table[] = {
125 {
126 .address = 0x00,
127 .reg = XPOWER_GPADC_LOW
128 },
129 {
130 .address = 0x0c,
131 .reg = XPOWER_GPADC_LOW
132 },
133 {
134 .address = 0x18,
135 .reg = XPOWER_GPADC_LOW
136 },
137 {
138 .address = 0x24,
139 .reg = XPOWER_GPADC_LOW
140 },
141 {
142 .address = 0x30,
143 .reg = XPOWER_GPADC_LOW
144 },
145 {
146 .address = 0x3c,
147 .reg = XPOWER_GPADC_LOW
148 },
149};
150
151static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
152 int bit, u64 *value)
153{
154 int data;
155
156 if (regmap_read(regmap, reg, &data))
157 return -EIO;
158
159 *value = (data & BIT(bit)) ? 1 : 0;
160 return 0;
161}
162
163static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
164 int bit, bool on)
165{
166 int data;
167
168 if (regmap_read(regmap, reg, &data))
169 return -EIO;
170
171 if (on)
172 data |= BIT(bit);
173 else
174 data &= ~BIT(bit);
175
176 if (regmap_write(regmap, reg, data))
177 return -EIO;
178
179 return 0;
180}
181
182/**
183 * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC
184 *
185 * @regmap: regmap of the PMIC device
186 * @reg: register to get the reading
187 *
Aaron Lud8139f62014-11-24 17:24:47 +0800188 * Return a positive value on success, errno on failure.
189 */
190static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg)
191{
Hans de Goede2e5a7f72017-04-19 15:07:00 +0200192 u8 buf[2];
Aaron Lud8139f62014-11-24 17:24:47 +0800193
Hans de Goede2e5a7f72017-04-19 15:07:00 +0200194 if (regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2))
195 return -EIO;
Aaron Lud8139f62014-11-24 17:24:47 +0800196
Hans de Goede2e5a7f72017-04-19 15:07:00 +0200197 return (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
Aaron Lud8139f62014-11-24 17:24:47 +0800198}
199
200static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {
201 .get_power = intel_xpower_pmic_get_power,
202 .update_power = intel_xpower_pmic_update_power,
203 .get_raw_temp = intel_xpower_pmic_get_raw_temp,
204 .power_table = power_table,
205 .power_table_count = ARRAY_SIZE(power_table),
206 .thermal_table = thermal_table,
207 .thermal_table_count = ARRAY_SIZE(thermal_table),
208};
209
Aaron Lu491cb352014-11-24 17:32:33 +0800210static acpi_status intel_xpower_pmic_gpio_handler(u32 function,
211 acpi_physical_address address, u32 bit_width, u64 *value,
212 void *handler_context, void *region_context)
213{
214 return AE_OK;
215}
Aaron Lud8139f62014-11-24 17:24:47 +0800216
217static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev)
218{
Aaron Lu491cb352014-11-24 17:32:33 +0800219 struct device *parent = pdev->dev.parent;
220 struct axp20x_dev *axp20x = dev_get_drvdata(parent);
221 acpi_status status;
222 int result;
223
224 status = acpi_install_address_space_handler(ACPI_HANDLE(parent),
225 ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler,
226 NULL, NULL);
227 if (ACPI_FAILURE(status))
228 return -ENODEV;
229
230 result = intel_pmic_install_opregion_handler(&pdev->dev,
231 ACPI_HANDLE(parent), axp20x->regmap,
232 &intel_xpower_pmic_opregion_data);
233 if (result)
234 acpi_remove_address_space_handler(ACPI_HANDLE(parent),
235 ACPI_ADR_SPACE_GPIO,
236 intel_xpower_pmic_gpio_handler);
237
238 return result;
Aaron Lud8139f62014-11-24 17:24:47 +0800239}
240
241static struct platform_driver intel_xpower_pmic_opregion_driver = {
242 .probe = intel_xpower_pmic_opregion_probe,
243 .driver = {
244 .name = "axp288_pmic_acpi",
245 },
246};
247
248static int __init intel_xpower_pmic_opregion_driver_init(void)
249{
250 return platform_driver_register(&intel_xpower_pmic_opregion_driver);
251}
Paul Gortmaker6d3ef8d2016-07-11 18:05:16 -0400252device_initcall(intel_xpower_pmic_opregion_driver_init);