xref: /linux/drivers/acpi/dptf/dptf_power.c (revision 290a20782ac6d1bfbd70541cacddaf9acbe1f1f5)
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 /*
137b52b200SSrinivas Pandruvada  * Presentation of attributes which are defined for INT3407 and INT3532.
147b52b200SSrinivas Pandruvada  * They are:
15*290a2078SSumeet Pawnikar  * PMAX : Maximum platform power
166256ebd5SSrinivas Pandruvada  * PSRC : Platform power source
176256ebd5SSrinivas Pandruvada  * ARTG : Adapter rating
186256ebd5SSrinivas Pandruvada  * CTYP : Charger type
19668ce99eSSrinivas Pandruvada  * PROP : Rest of worst case platform Power
207b52b200SSrinivas Pandruvada  * PBSS : Power Battery Steady State
217b52b200SSrinivas Pandruvada  * RBHF : High Frequency Impedance
227b52b200SSrinivas Pandruvada  * VBNL : Instantaneous No-Load Voltage
237b52b200SSrinivas Pandruvada  * CMPP : Current Discharge Capability
246256ebd5SSrinivas Pandruvada  */
256256ebd5SSrinivas Pandruvada #define DPTF_POWER_SHOW(name, object) \
266256ebd5SSrinivas Pandruvada static ssize_t name##_show(struct device *dev,\
276256ebd5SSrinivas Pandruvada 			   struct device_attribute *attr,\
286256ebd5SSrinivas Pandruvada 			   char *buf)\
296256ebd5SSrinivas Pandruvada {\
30b0f65b91SKefeng Wang 	struct acpi_device *acpi_dev = dev_get_drvdata(dev);\
316256ebd5SSrinivas Pandruvada 	unsigned long long val;\
326256ebd5SSrinivas Pandruvada 	acpi_status status;\
336256ebd5SSrinivas Pandruvada \
346256ebd5SSrinivas Pandruvada 	status = acpi_evaluate_integer(acpi_dev->handle, #object,\
356256ebd5SSrinivas Pandruvada 				       NULL, &val);\
366256ebd5SSrinivas Pandruvada 	if (ACPI_SUCCESS(status))\
376256ebd5SSrinivas Pandruvada 		return sprintf(buf, "%d\n", (int)val);\
386256ebd5SSrinivas Pandruvada 	else \
396256ebd5SSrinivas Pandruvada 		return -EINVAL;\
406256ebd5SSrinivas Pandruvada }
416256ebd5SSrinivas Pandruvada 
426256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(max_platform_power_mw, PMAX)
436256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(platform_power_source, PSRC)
446256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(adapter_rating_mw, ARTG)
456256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(battery_steady_power_mw, PBSS)
466256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(charger_type, CTYP)
47668ce99eSSrinivas Pandruvada DPTF_POWER_SHOW(rest_of_platform_power_mw, PROP)
487b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(max_steady_state_power_mw, PBSS)
497b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(high_freq_impedance_mohm, RBHF)
507b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(no_load_voltage_mv, VBNL)
517b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(current_discharge_capbility_ma, CMPP);
526256ebd5SSrinivas Pandruvada 
536256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(max_platform_power_mw);
546256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(platform_power_source);
556256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(adapter_rating_mw);
566256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(battery_steady_power_mw);
576256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(charger_type);
58668ce99eSSrinivas Pandruvada static DEVICE_ATTR_RO(rest_of_platform_power_mw);
597b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(max_steady_state_power_mw);
607b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(high_freq_impedance_mohm);
617b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(no_load_voltage_mv);
627b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(current_discharge_capbility_ma);
63668ce99eSSrinivas Pandruvada 
64668ce99eSSrinivas Pandruvada static ssize_t prochot_confirm_store(struct device *dev,
65668ce99eSSrinivas Pandruvada 				     struct device_attribute *attr,
66668ce99eSSrinivas Pandruvada 				     const char *buf, size_t count)
67668ce99eSSrinivas Pandruvada {
68668ce99eSSrinivas Pandruvada 	struct acpi_device *acpi_dev = dev_get_drvdata(dev);
69668ce99eSSrinivas Pandruvada 	acpi_status status;
70668ce99eSSrinivas Pandruvada 	int seq_no;
71668ce99eSSrinivas Pandruvada 
72668ce99eSSrinivas Pandruvada 	if (kstrtouint(buf, 0, &seq_no) < 0)
73668ce99eSSrinivas Pandruvada 		return -EINVAL;
74668ce99eSSrinivas Pandruvada 
75668ce99eSSrinivas Pandruvada 	status = acpi_execute_simple_method(acpi_dev->handle, "PBOK", seq_no);
76668ce99eSSrinivas Pandruvada 	if (ACPI_SUCCESS(status))
77668ce99eSSrinivas Pandruvada 		return count;
78668ce99eSSrinivas Pandruvada 
79668ce99eSSrinivas Pandruvada 	return -EINVAL;
80668ce99eSSrinivas Pandruvada }
81668ce99eSSrinivas Pandruvada 
82668ce99eSSrinivas Pandruvada static DEVICE_ATTR_WO(prochot_confirm);
836256ebd5SSrinivas Pandruvada 
846256ebd5SSrinivas Pandruvada static struct attribute *dptf_power_attrs[] = {
856256ebd5SSrinivas Pandruvada 	&dev_attr_max_platform_power_mw.attr,
866256ebd5SSrinivas Pandruvada 	&dev_attr_platform_power_source.attr,
876256ebd5SSrinivas Pandruvada 	&dev_attr_adapter_rating_mw.attr,
886256ebd5SSrinivas Pandruvada 	&dev_attr_battery_steady_power_mw.attr,
896256ebd5SSrinivas Pandruvada 	&dev_attr_charger_type.attr,
90668ce99eSSrinivas Pandruvada 	&dev_attr_rest_of_platform_power_mw.attr,
91668ce99eSSrinivas Pandruvada 	&dev_attr_prochot_confirm.attr,
926256ebd5SSrinivas Pandruvada 	NULL
936256ebd5SSrinivas Pandruvada };
946256ebd5SSrinivas Pandruvada 
959e4de6a8SArvind Yadav static const struct attribute_group dptf_power_attribute_group = {
966256ebd5SSrinivas Pandruvada 	.attrs = dptf_power_attrs,
976256ebd5SSrinivas Pandruvada 	.name = "dptf_power"
986256ebd5SSrinivas Pandruvada };
996256ebd5SSrinivas Pandruvada 
1007b52b200SSrinivas Pandruvada static struct attribute *dptf_battery_attrs[] = {
1017b52b200SSrinivas Pandruvada 	&dev_attr_max_platform_power_mw.attr,
1027b52b200SSrinivas Pandruvada 	&dev_attr_max_steady_state_power_mw.attr,
1037b52b200SSrinivas Pandruvada 	&dev_attr_high_freq_impedance_mohm.attr,
1047b52b200SSrinivas Pandruvada 	&dev_attr_no_load_voltage_mv.attr,
1057b52b200SSrinivas Pandruvada 	&dev_attr_current_discharge_capbility_ma.attr,
1067b52b200SSrinivas Pandruvada 	NULL
1077b52b200SSrinivas Pandruvada };
1087b52b200SSrinivas Pandruvada 
1097b52b200SSrinivas Pandruvada static const struct attribute_group dptf_battery_attribute_group = {
1107b52b200SSrinivas Pandruvada 	.attrs = dptf_battery_attrs,
1117b52b200SSrinivas Pandruvada 	.name = "dptf_battery"
1127b52b200SSrinivas Pandruvada };
1137b52b200SSrinivas Pandruvada 
1147b52b200SSrinivas Pandruvada #define MAX_POWER_CHANGED		0x80
115668ce99eSSrinivas Pandruvada #define POWER_STATE_CHANGED		0x81
1167b52b200SSrinivas Pandruvada #define STEADY_STATE_POWER_CHANGED	0x83
117668ce99eSSrinivas Pandruvada #define POWER_PROP_CHANGE_EVENT	0x84
1187b52b200SSrinivas Pandruvada #define IMPEDANCED_CHNGED		0x85
1197b52b200SSrinivas Pandruvada #define VOLTAGE_CURRENT_CHANGED	0x86
1207b52b200SSrinivas Pandruvada 
1217b52b200SSrinivas Pandruvada static long long dptf_participant_type(acpi_handle handle)
1227b52b200SSrinivas Pandruvada {
1237b52b200SSrinivas Pandruvada 	unsigned long long ptype;
1247b52b200SSrinivas Pandruvada 	acpi_status status;
1257b52b200SSrinivas Pandruvada 
1267b52b200SSrinivas Pandruvada 	status = acpi_evaluate_integer(handle, "PTYP", NULL, &ptype);
1277b52b200SSrinivas Pandruvada 	if (ACPI_FAILURE(status))
1287b52b200SSrinivas Pandruvada 		return -ENODEV;
1297b52b200SSrinivas Pandruvada 
1307b52b200SSrinivas Pandruvada 	return ptype;
1317b52b200SSrinivas Pandruvada }
132668ce99eSSrinivas Pandruvada 
133668ce99eSSrinivas Pandruvada static void dptf_power_notify(acpi_handle handle, u32 event, void *data)
134668ce99eSSrinivas Pandruvada {
135668ce99eSSrinivas Pandruvada 	struct platform_device *pdev = data;
136668ce99eSSrinivas Pandruvada 	char *attr;
137668ce99eSSrinivas Pandruvada 
138668ce99eSSrinivas Pandruvada 	switch (event) {
139668ce99eSSrinivas Pandruvada 	case POWER_STATE_CHANGED:
140668ce99eSSrinivas Pandruvada 		attr = "platform_power_source";
141668ce99eSSrinivas Pandruvada 		break;
142668ce99eSSrinivas Pandruvada 	case POWER_PROP_CHANGE_EVENT:
143668ce99eSSrinivas Pandruvada 		attr = "rest_of_platform_power_mw";
144668ce99eSSrinivas Pandruvada 		break;
1457b52b200SSrinivas Pandruvada 	case MAX_POWER_CHANGED:
1467b52b200SSrinivas Pandruvada 		attr = "max_platform_power_mw";
1477b52b200SSrinivas Pandruvada 		break;
1487b52b200SSrinivas Pandruvada 	case STEADY_STATE_POWER_CHANGED:
1497b52b200SSrinivas Pandruvada 		attr = "max_steady_state_power_mw";
1507b52b200SSrinivas Pandruvada 		break;
1517b52b200SSrinivas Pandruvada 	case VOLTAGE_CURRENT_CHANGED:
1527b52b200SSrinivas Pandruvada 		attr = "no_load_voltage_mv";
1537b52b200SSrinivas Pandruvada 		break;
154668ce99eSSrinivas Pandruvada 	default:
155668ce99eSSrinivas Pandruvada 		dev_err(&pdev->dev, "Unsupported event [0x%x]\n", event);
156668ce99eSSrinivas Pandruvada 		return;
157668ce99eSSrinivas Pandruvada 	}
158668ce99eSSrinivas Pandruvada 
159668ce99eSSrinivas Pandruvada 	/*
160668ce99eSSrinivas Pandruvada 	 * Notify that an attribute is changed, so that user space can read
161668ce99eSSrinivas Pandruvada 	 * again.
162668ce99eSSrinivas Pandruvada 	 */
1637b52b200SSrinivas Pandruvada 	if (dptf_participant_type(handle) == 0x0CULL)
1647b52b200SSrinivas Pandruvada 		sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr);
1657b52b200SSrinivas Pandruvada 	else
166668ce99eSSrinivas Pandruvada 		sysfs_notify(&pdev->dev.kobj, "dptf_power", attr);
167668ce99eSSrinivas Pandruvada }
168668ce99eSSrinivas Pandruvada 
1696256ebd5SSrinivas Pandruvada static int dptf_power_add(struct platform_device *pdev)
1706256ebd5SSrinivas Pandruvada {
1717b52b200SSrinivas Pandruvada 	const struct attribute_group *attr_group;
1726256ebd5SSrinivas Pandruvada 	struct acpi_device *acpi_dev;
1736256ebd5SSrinivas Pandruvada 	unsigned long long ptype;
1746256ebd5SSrinivas Pandruvada 	int result;
1756256ebd5SSrinivas Pandruvada 
1766256ebd5SSrinivas Pandruvada 	acpi_dev = ACPI_COMPANION(&(pdev->dev));
1776256ebd5SSrinivas Pandruvada 	if (!acpi_dev)
1786256ebd5SSrinivas Pandruvada 		return -ENODEV;
1796256ebd5SSrinivas Pandruvada 
1807b52b200SSrinivas Pandruvada 	ptype = dptf_participant_type(acpi_dev->handle);
1817b52b200SSrinivas Pandruvada 	if (ptype == 0x11)
1827b52b200SSrinivas Pandruvada 		attr_group = &dptf_power_attribute_group;
1837b52b200SSrinivas Pandruvada 	else if (ptype == 0x0C)
1847b52b200SSrinivas Pandruvada 		attr_group = &dptf_battery_attribute_group;
1857b52b200SSrinivas Pandruvada 	else
1866256ebd5SSrinivas Pandruvada 		return -ENODEV;
1876256ebd5SSrinivas Pandruvada 
188668ce99eSSrinivas Pandruvada 	result = acpi_install_notify_handler(acpi_dev->handle,
189668ce99eSSrinivas Pandruvada 					     ACPI_DEVICE_NOTIFY,
190668ce99eSSrinivas Pandruvada 					     dptf_power_notify,
191668ce99eSSrinivas Pandruvada 					     (void *)pdev);
1926256ebd5SSrinivas Pandruvada 	if (result)
1936256ebd5SSrinivas Pandruvada 		return result;
1946256ebd5SSrinivas Pandruvada 
195668ce99eSSrinivas Pandruvada 	result = sysfs_create_group(&pdev->dev.kobj,
1967b52b200SSrinivas Pandruvada 				    attr_group);
197668ce99eSSrinivas Pandruvada 	if (result) {
198668ce99eSSrinivas Pandruvada 		acpi_remove_notify_handler(acpi_dev->handle,
199668ce99eSSrinivas Pandruvada 					   ACPI_DEVICE_NOTIFY,
200668ce99eSSrinivas Pandruvada 					   dptf_power_notify);
201668ce99eSSrinivas Pandruvada 		return result;
202668ce99eSSrinivas Pandruvada 	}
203668ce99eSSrinivas Pandruvada 
2046256ebd5SSrinivas Pandruvada 	platform_set_drvdata(pdev, acpi_dev);
2056256ebd5SSrinivas Pandruvada 
2066256ebd5SSrinivas Pandruvada 	return 0;
2076256ebd5SSrinivas Pandruvada }
2086256ebd5SSrinivas Pandruvada 
2096256ebd5SSrinivas Pandruvada static int dptf_power_remove(struct platform_device *pdev)
2106256ebd5SSrinivas Pandruvada {
211668ce99eSSrinivas Pandruvada 	struct acpi_device *acpi_dev = platform_get_drvdata(pdev);
2126256ebd5SSrinivas Pandruvada 
213668ce99eSSrinivas Pandruvada 	acpi_remove_notify_handler(acpi_dev->handle,
214668ce99eSSrinivas Pandruvada 				   ACPI_DEVICE_NOTIFY,
215668ce99eSSrinivas Pandruvada 				   dptf_power_notify);
2167b52b200SSrinivas Pandruvada 
2177b52b200SSrinivas Pandruvada 	if (dptf_participant_type(acpi_dev->handle) == 0x0CULL)
2187b52b200SSrinivas Pandruvada 		sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group);
2197b52b200SSrinivas Pandruvada 	else
2206256ebd5SSrinivas Pandruvada 		sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);
2216256ebd5SSrinivas Pandruvada 
2226256ebd5SSrinivas Pandruvada 	return 0;
2236256ebd5SSrinivas Pandruvada }
2246256ebd5SSrinivas Pandruvada 
2256256ebd5SSrinivas Pandruvada static const struct acpi_device_id int3407_device_ids[] = {
2266256ebd5SSrinivas Pandruvada 	{"INT3407", 0},
2277b52b200SSrinivas Pandruvada 	{"INT3532", 0},
228b62c770fSGayatri Kammela 	{"INTC1047", 0},
2291e05dacaSSrinivas Pandruvada 	{"INTC1050", 0},
23038748bcbSSrinivas Pandruvada 	{"INTC1060", 0},
23138748bcbSSrinivas Pandruvada 	{"INTC1061", 0},
232a510c78eSSrinivas Pandruvada 	{"INTC10A4", 0},
233a510c78eSSrinivas Pandruvada 	{"INTC10A5", 0},
2346256ebd5SSrinivas Pandruvada 	{"", 0},
2356256ebd5SSrinivas Pandruvada };
2366256ebd5SSrinivas Pandruvada MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
2376256ebd5SSrinivas Pandruvada 
2386256ebd5SSrinivas Pandruvada static struct platform_driver dptf_power_driver = {
2396256ebd5SSrinivas Pandruvada 	.probe = dptf_power_add,
2406256ebd5SSrinivas Pandruvada 	.remove = dptf_power_remove,
2416256ebd5SSrinivas Pandruvada 	.driver = {
242ff44fe3eSRafael J. Wysocki 		.name = "dptf_power",
2436256ebd5SSrinivas Pandruvada 		.acpi_match_table = int3407_device_ids,
2446256ebd5SSrinivas Pandruvada 	},
2456256ebd5SSrinivas Pandruvada };
2466256ebd5SSrinivas Pandruvada 
2476256ebd5SSrinivas Pandruvada module_platform_driver(dptf_power_driver);
2486256ebd5SSrinivas Pandruvada 
2496256ebd5SSrinivas Pandruvada MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
2506256ebd5SSrinivas Pandruvada MODULE_LICENSE("GPL v2");
2516256ebd5SSrinivas Pandruvada MODULE_DESCRIPTION("ACPI DPTF platform power driver");
252