xref: /linux/drivers/acpi/dptf/dptf_power.c (revision 7b52b200cf5bdd04f3ee22121960bd6f4ec5efa1)
12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26256ebd5SSrinivas Pandruvada /*
36256ebd5SSrinivas Pandruvada  * dptf_power:  DPTF platform power driver
46256ebd5SSrinivas Pandruvada  * Copyright (c) 2016, Intel Corporation.
56256ebd5SSrinivas Pandruvada  */
66256ebd5SSrinivas Pandruvada 
76256ebd5SSrinivas Pandruvada #include <linux/kernel.h>
86256ebd5SSrinivas Pandruvada #include <linux/module.h>
96256ebd5SSrinivas Pandruvada #include <linux/acpi.h>
106256ebd5SSrinivas Pandruvada #include <linux/platform_device.h>
116256ebd5SSrinivas Pandruvada 
126256ebd5SSrinivas Pandruvada /*
13*7b52b200SSrinivas Pandruvada  * Presentation of attributes which are defined for INT3407 and INT3532.
14*7b52b200SSrinivas Pandruvada  * They are:
156256ebd5SSrinivas Pandruvada  * PMAX : Maximum platform powe
166256ebd5SSrinivas Pandruvada  * PSRC : Platform power source
176256ebd5SSrinivas Pandruvada  * ARTG : Adapter rating
186256ebd5SSrinivas Pandruvada  * CTYP : Charger type
196256ebd5SSrinivas Pandruvada  * PBSS : Battery steady power
20668ce99eSSrinivas Pandruvada  * PROP : Rest of worst case platform Power
21*7b52b200SSrinivas Pandruvada  * PBSS : Power Battery Steady State
22*7b52b200SSrinivas Pandruvada  * PBSS : Power Battery Steady State
23*7b52b200SSrinivas Pandruvada  * RBHF : High Frequency Impedance
24*7b52b200SSrinivas Pandruvada  * VBNL : Instantaneous No-Load Voltage
25*7b52b200SSrinivas Pandruvada  * CMPP : Current Discharge Capability
266256ebd5SSrinivas Pandruvada  */
276256ebd5SSrinivas Pandruvada #define DPTF_POWER_SHOW(name, object) \
286256ebd5SSrinivas Pandruvada static ssize_t name##_show(struct device *dev,\
296256ebd5SSrinivas Pandruvada 			   struct device_attribute *attr,\
306256ebd5SSrinivas Pandruvada 			   char *buf)\
316256ebd5SSrinivas Pandruvada {\
32b0f65b91SKefeng Wang 	struct acpi_device *acpi_dev = dev_get_drvdata(dev);\
336256ebd5SSrinivas Pandruvada 	unsigned long long val;\
346256ebd5SSrinivas Pandruvada 	acpi_status status;\
356256ebd5SSrinivas Pandruvada \
366256ebd5SSrinivas Pandruvada 	status = acpi_evaluate_integer(acpi_dev->handle, #object,\
376256ebd5SSrinivas Pandruvada 				       NULL, &val);\
386256ebd5SSrinivas Pandruvada 	if (ACPI_SUCCESS(status))\
396256ebd5SSrinivas Pandruvada 		return sprintf(buf, "%d\n", (int)val);\
406256ebd5SSrinivas Pandruvada 	else \
416256ebd5SSrinivas Pandruvada 		return -EINVAL;\
426256ebd5SSrinivas Pandruvada }
436256ebd5SSrinivas Pandruvada 
446256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(max_platform_power_mw, PMAX)
456256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(platform_power_source, PSRC)
466256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(adapter_rating_mw, ARTG)
476256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(battery_steady_power_mw, PBSS)
486256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(charger_type, CTYP)
49668ce99eSSrinivas Pandruvada DPTF_POWER_SHOW(rest_of_platform_power_mw, PROP)
50*7b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(max_steady_state_power_mw, PBSS)
51*7b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(high_freq_impedance_mohm, RBHF)
52*7b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(no_load_voltage_mv, VBNL)
53*7b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(current_discharge_capbility_ma, CMPP);
546256ebd5SSrinivas Pandruvada 
556256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(max_platform_power_mw);
566256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(platform_power_source);
576256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(adapter_rating_mw);
586256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(battery_steady_power_mw);
596256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(charger_type);
60668ce99eSSrinivas Pandruvada static DEVICE_ATTR_RO(rest_of_platform_power_mw);
61*7b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(max_steady_state_power_mw);
62*7b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(high_freq_impedance_mohm);
63*7b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(no_load_voltage_mv);
64*7b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(current_discharge_capbility_ma);
65668ce99eSSrinivas Pandruvada 
66668ce99eSSrinivas Pandruvada static ssize_t prochot_confirm_store(struct device *dev,
67668ce99eSSrinivas Pandruvada 				     struct device_attribute *attr,
68668ce99eSSrinivas Pandruvada 				     const char *buf, size_t count)
69668ce99eSSrinivas Pandruvada {
70668ce99eSSrinivas Pandruvada 	struct acpi_device *acpi_dev = dev_get_drvdata(dev);
71668ce99eSSrinivas Pandruvada 	acpi_status status;
72668ce99eSSrinivas Pandruvada 	int seq_no;
73668ce99eSSrinivas Pandruvada 
74668ce99eSSrinivas Pandruvada 	if (kstrtouint(buf, 0, &seq_no) < 0)
75668ce99eSSrinivas Pandruvada 		return -EINVAL;
76668ce99eSSrinivas Pandruvada 
77668ce99eSSrinivas Pandruvada 	status = acpi_execute_simple_method(acpi_dev->handle, "PBOK", seq_no);
78668ce99eSSrinivas Pandruvada 	if (ACPI_SUCCESS(status))
79668ce99eSSrinivas Pandruvada 		return count;
80668ce99eSSrinivas Pandruvada 
81668ce99eSSrinivas Pandruvada 	return -EINVAL;
82668ce99eSSrinivas Pandruvada }
83668ce99eSSrinivas Pandruvada 
84668ce99eSSrinivas Pandruvada static DEVICE_ATTR_WO(prochot_confirm);
856256ebd5SSrinivas Pandruvada 
866256ebd5SSrinivas Pandruvada static struct attribute *dptf_power_attrs[] = {
876256ebd5SSrinivas Pandruvada 	&dev_attr_max_platform_power_mw.attr,
886256ebd5SSrinivas Pandruvada 	&dev_attr_platform_power_source.attr,
896256ebd5SSrinivas Pandruvada 	&dev_attr_adapter_rating_mw.attr,
906256ebd5SSrinivas Pandruvada 	&dev_attr_battery_steady_power_mw.attr,
916256ebd5SSrinivas Pandruvada 	&dev_attr_charger_type.attr,
92668ce99eSSrinivas Pandruvada 	&dev_attr_rest_of_platform_power_mw.attr,
93668ce99eSSrinivas Pandruvada 	&dev_attr_prochot_confirm.attr,
946256ebd5SSrinivas Pandruvada 	NULL
956256ebd5SSrinivas Pandruvada };
966256ebd5SSrinivas Pandruvada 
979e4de6a8SArvind Yadav static const struct attribute_group dptf_power_attribute_group = {
986256ebd5SSrinivas Pandruvada 	.attrs = dptf_power_attrs,
996256ebd5SSrinivas Pandruvada 	.name = "dptf_power"
1006256ebd5SSrinivas Pandruvada };
1016256ebd5SSrinivas Pandruvada 
102*7b52b200SSrinivas Pandruvada static struct attribute *dptf_battery_attrs[] = {
103*7b52b200SSrinivas Pandruvada 	&dev_attr_max_platform_power_mw.attr,
104*7b52b200SSrinivas Pandruvada 	&dev_attr_max_steady_state_power_mw.attr,
105*7b52b200SSrinivas Pandruvada 	&dev_attr_high_freq_impedance_mohm.attr,
106*7b52b200SSrinivas Pandruvada 	&dev_attr_no_load_voltage_mv.attr,
107*7b52b200SSrinivas Pandruvada 	&dev_attr_current_discharge_capbility_ma.attr,
108*7b52b200SSrinivas Pandruvada 	NULL
109*7b52b200SSrinivas Pandruvada };
110*7b52b200SSrinivas Pandruvada 
111*7b52b200SSrinivas Pandruvada static const struct attribute_group dptf_battery_attribute_group = {
112*7b52b200SSrinivas Pandruvada 	.attrs = dptf_battery_attrs,
113*7b52b200SSrinivas Pandruvada 	.name = "dptf_battery"
114*7b52b200SSrinivas Pandruvada };
115*7b52b200SSrinivas Pandruvada 
116*7b52b200SSrinivas Pandruvada #define MAX_POWER_CHANGED		0x80
117668ce99eSSrinivas Pandruvada #define POWER_STATE_CHANGED		0x81
118*7b52b200SSrinivas Pandruvada #define STEADY_STATE_POWER_CHANGED	0x83
119668ce99eSSrinivas Pandruvada #define POWER_PROP_CHANGE_EVENT	0x84
120*7b52b200SSrinivas Pandruvada #define IMPEDANCED_CHNGED		0x85
121*7b52b200SSrinivas Pandruvada #define VOLTAGE_CURRENT_CHANGED	0x86
122*7b52b200SSrinivas Pandruvada 
123*7b52b200SSrinivas Pandruvada static long long dptf_participant_type(acpi_handle handle)
124*7b52b200SSrinivas Pandruvada {
125*7b52b200SSrinivas Pandruvada 	unsigned long long ptype;
126*7b52b200SSrinivas Pandruvada 	acpi_status status;
127*7b52b200SSrinivas Pandruvada 
128*7b52b200SSrinivas Pandruvada 	status = acpi_evaluate_integer(handle, "PTYP", NULL, &ptype);
129*7b52b200SSrinivas Pandruvada 	if (ACPI_FAILURE(status))
130*7b52b200SSrinivas Pandruvada 		return -ENODEV;
131*7b52b200SSrinivas Pandruvada 
132*7b52b200SSrinivas Pandruvada 	return ptype;
133*7b52b200SSrinivas Pandruvada }
134668ce99eSSrinivas Pandruvada 
135668ce99eSSrinivas Pandruvada static void dptf_power_notify(acpi_handle handle, u32 event, void *data)
136668ce99eSSrinivas Pandruvada {
137668ce99eSSrinivas Pandruvada 	struct platform_device *pdev = data;
138668ce99eSSrinivas Pandruvada 	char *attr;
139668ce99eSSrinivas Pandruvada 
140668ce99eSSrinivas Pandruvada 	switch (event) {
141668ce99eSSrinivas Pandruvada 	case POWER_STATE_CHANGED:
142668ce99eSSrinivas Pandruvada 		attr = "platform_power_source";
143668ce99eSSrinivas Pandruvada 		break;
144668ce99eSSrinivas Pandruvada 	case POWER_PROP_CHANGE_EVENT:
145668ce99eSSrinivas Pandruvada 		attr = "rest_of_platform_power_mw";
146668ce99eSSrinivas Pandruvada 		break;
147*7b52b200SSrinivas Pandruvada 	case MAX_POWER_CHANGED:
148*7b52b200SSrinivas Pandruvada 		attr = "max_platform_power_mw";
149*7b52b200SSrinivas Pandruvada 		break;
150*7b52b200SSrinivas Pandruvada 	case STEADY_STATE_POWER_CHANGED:
151*7b52b200SSrinivas Pandruvada 		attr = "max_steady_state_power_mw";
152*7b52b200SSrinivas Pandruvada 		break;
153*7b52b200SSrinivas Pandruvada 	case VOLTAGE_CURRENT_CHANGED:
154*7b52b200SSrinivas Pandruvada 		attr = "no_load_voltage_mv";
155*7b52b200SSrinivas Pandruvada 		break;
156668ce99eSSrinivas Pandruvada 	default:
157668ce99eSSrinivas Pandruvada 		dev_err(&pdev->dev, "Unsupported event [0x%x]\n", event);
158668ce99eSSrinivas Pandruvada 		return;
159668ce99eSSrinivas Pandruvada 	}
160668ce99eSSrinivas Pandruvada 
161668ce99eSSrinivas Pandruvada 	/*
162668ce99eSSrinivas Pandruvada 	 * Notify that an attribute is changed, so that user space can read
163668ce99eSSrinivas Pandruvada 	 * again.
164668ce99eSSrinivas Pandruvada 	 */
165*7b52b200SSrinivas Pandruvada 	if (dptf_participant_type(handle) == 0x0CULL)
166*7b52b200SSrinivas Pandruvada 		sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr);
167*7b52b200SSrinivas Pandruvada 	else
168668ce99eSSrinivas Pandruvada 		sysfs_notify(&pdev->dev.kobj, "dptf_power", attr);
169668ce99eSSrinivas Pandruvada }
170668ce99eSSrinivas Pandruvada 
1716256ebd5SSrinivas Pandruvada static int dptf_power_add(struct platform_device *pdev)
1726256ebd5SSrinivas Pandruvada {
173*7b52b200SSrinivas Pandruvada 	const struct attribute_group *attr_group;
1746256ebd5SSrinivas Pandruvada 	struct acpi_device *acpi_dev;
1756256ebd5SSrinivas Pandruvada 	unsigned long long ptype;
1766256ebd5SSrinivas Pandruvada 	int result;
1776256ebd5SSrinivas Pandruvada 
1786256ebd5SSrinivas Pandruvada 	acpi_dev = ACPI_COMPANION(&(pdev->dev));
1796256ebd5SSrinivas Pandruvada 	if (!acpi_dev)
1806256ebd5SSrinivas Pandruvada 		return -ENODEV;
1816256ebd5SSrinivas Pandruvada 
182*7b52b200SSrinivas Pandruvada 	ptype = dptf_participant_type(acpi_dev->handle);
183*7b52b200SSrinivas Pandruvada 	if (ptype == 0x11)
184*7b52b200SSrinivas Pandruvada 		attr_group = &dptf_power_attribute_group;
185*7b52b200SSrinivas Pandruvada 	else if (ptype == 0x0C)
186*7b52b200SSrinivas Pandruvada 		attr_group = &dptf_battery_attribute_group;
187*7b52b200SSrinivas Pandruvada 	else
1886256ebd5SSrinivas Pandruvada 		return -ENODEV;
1896256ebd5SSrinivas Pandruvada 
190668ce99eSSrinivas Pandruvada 	result = acpi_install_notify_handler(acpi_dev->handle,
191668ce99eSSrinivas Pandruvada 					     ACPI_DEVICE_NOTIFY,
192668ce99eSSrinivas Pandruvada 					     dptf_power_notify,
193668ce99eSSrinivas Pandruvada 					     (void *)pdev);
1946256ebd5SSrinivas Pandruvada 	if (result)
1956256ebd5SSrinivas Pandruvada 		return result;
1966256ebd5SSrinivas Pandruvada 
197668ce99eSSrinivas Pandruvada 	result = sysfs_create_group(&pdev->dev.kobj,
198*7b52b200SSrinivas Pandruvada 				    attr_group);
199668ce99eSSrinivas Pandruvada 	if (result) {
200668ce99eSSrinivas Pandruvada 		acpi_remove_notify_handler(acpi_dev->handle,
201668ce99eSSrinivas Pandruvada 					   ACPI_DEVICE_NOTIFY,
202668ce99eSSrinivas Pandruvada 					   dptf_power_notify);
203668ce99eSSrinivas Pandruvada 		return result;
204668ce99eSSrinivas Pandruvada 	}
205668ce99eSSrinivas Pandruvada 
2066256ebd5SSrinivas Pandruvada 	platform_set_drvdata(pdev, acpi_dev);
2076256ebd5SSrinivas Pandruvada 
2086256ebd5SSrinivas Pandruvada 	return 0;
2096256ebd5SSrinivas Pandruvada }
2106256ebd5SSrinivas Pandruvada 
2116256ebd5SSrinivas Pandruvada static int dptf_power_remove(struct platform_device *pdev)
2126256ebd5SSrinivas Pandruvada {
213668ce99eSSrinivas Pandruvada 	struct acpi_device *acpi_dev = platform_get_drvdata(pdev);
2146256ebd5SSrinivas Pandruvada 
215668ce99eSSrinivas Pandruvada 	acpi_remove_notify_handler(acpi_dev->handle,
216668ce99eSSrinivas Pandruvada 				   ACPI_DEVICE_NOTIFY,
217668ce99eSSrinivas Pandruvada 				   dptf_power_notify);
218*7b52b200SSrinivas Pandruvada 
219*7b52b200SSrinivas Pandruvada 	if (dptf_participant_type(acpi_dev->handle) == 0x0CULL)
220*7b52b200SSrinivas Pandruvada 		sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group);
221*7b52b200SSrinivas Pandruvada 	else
2226256ebd5SSrinivas Pandruvada 		sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);
2236256ebd5SSrinivas Pandruvada 
2246256ebd5SSrinivas Pandruvada 	return 0;
2256256ebd5SSrinivas Pandruvada }
2266256ebd5SSrinivas Pandruvada 
2276256ebd5SSrinivas Pandruvada static const struct acpi_device_id int3407_device_ids[] = {
2286256ebd5SSrinivas Pandruvada 	{"INT3407", 0},
229*7b52b200SSrinivas Pandruvada 	{"INT3532", 0},
230b62c770fSGayatri Kammela 	{"INTC1047", 0},
2316256ebd5SSrinivas Pandruvada 	{"", 0},
2326256ebd5SSrinivas Pandruvada };
2336256ebd5SSrinivas Pandruvada MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
2346256ebd5SSrinivas Pandruvada 
2356256ebd5SSrinivas Pandruvada static struct platform_driver dptf_power_driver = {
2366256ebd5SSrinivas Pandruvada 	.probe = dptf_power_add,
2376256ebd5SSrinivas Pandruvada 	.remove = dptf_power_remove,
2386256ebd5SSrinivas Pandruvada 	.driver = {
2396256ebd5SSrinivas Pandruvada 		.name = "DPTF Platform Power",
2406256ebd5SSrinivas Pandruvada 		.acpi_match_table = int3407_device_ids,
2416256ebd5SSrinivas Pandruvada 	},
2426256ebd5SSrinivas Pandruvada };
2436256ebd5SSrinivas Pandruvada 
2446256ebd5SSrinivas Pandruvada module_platform_driver(dptf_power_driver);
2456256ebd5SSrinivas Pandruvada 
2466256ebd5SSrinivas Pandruvada MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
2476256ebd5SSrinivas Pandruvada MODULE_LICENSE("GPL v2");
2486256ebd5SSrinivas Pandruvada MODULE_DESCRIPTION("ACPI DPTF platform power driver");
249