xref: /linux/drivers/acpi/dptf/dptf_power.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
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:
15290a2078SSumeet 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 
prochot_confirm_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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
11842e5ed06SSumeet Pawnikar #define IMPEDANCE_CHANGED		0x85
1197b52b200SSrinivas Pandruvada #define VOLTAGE_CURRENT_CHANGED	0x86
1207b52b200SSrinivas Pandruvada 
dptf_participant_type(acpi_handle handle)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 
dptf_power_notify(acpi_handle handle,u32 event,void * data)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;
15142e5ed06SSumeet Pawnikar 	case IMPEDANCE_CHANGED:
15242e5ed06SSumeet Pawnikar 		attr = "high_freq_impedance_mohm";
15342e5ed06SSumeet Pawnikar 		break;
1547b52b200SSrinivas Pandruvada 	case VOLTAGE_CURRENT_CHANGED:
1557b52b200SSrinivas Pandruvada 		attr = "no_load_voltage_mv";
1567b52b200SSrinivas Pandruvada 		break;
157668ce99eSSrinivas Pandruvada 	default:
158668ce99eSSrinivas Pandruvada 		dev_err(&pdev->dev, "Unsupported event [0x%x]\n", event);
159668ce99eSSrinivas Pandruvada 		return;
160668ce99eSSrinivas Pandruvada 	}
161668ce99eSSrinivas Pandruvada 
162668ce99eSSrinivas Pandruvada 	/*
163668ce99eSSrinivas Pandruvada 	 * Notify that an attribute is changed, so that user space can read
164668ce99eSSrinivas Pandruvada 	 * again.
165668ce99eSSrinivas Pandruvada 	 */
1667b52b200SSrinivas Pandruvada 	if (dptf_participant_type(handle) == 0x0CULL)
1677b52b200SSrinivas Pandruvada 		sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr);
1687b52b200SSrinivas Pandruvada 	else
169668ce99eSSrinivas Pandruvada 		sysfs_notify(&pdev->dev.kobj, "dptf_power", attr);
170668ce99eSSrinivas Pandruvada }
171668ce99eSSrinivas Pandruvada 
dptf_power_add(struct platform_device * pdev)1726256ebd5SSrinivas Pandruvada static int dptf_power_add(struct platform_device *pdev)
1736256ebd5SSrinivas Pandruvada {
1747b52b200SSrinivas Pandruvada 	const struct attribute_group *attr_group;
1756256ebd5SSrinivas Pandruvada 	struct acpi_device *acpi_dev;
1766256ebd5SSrinivas Pandruvada 	unsigned long long ptype;
1776256ebd5SSrinivas Pandruvada 	int result;
1786256ebd5SSrinivas Pandruvada 
1796256ebd5SSrinivas Pandruvada 	acpi_dev = ACPI_COMPANION(&(pdev->dev));
1806256ebd5SSrinivas Pandruvada 	if (!acpi_dev)
1816256ebd5SSrinivas Pandruvada 		return -ENODEV;
1826256ebd5SSrinivas Pandruvada 
1837b52b200SSrinivas Pandruvada 	ptype = dptf_participant_type(acpi_dev->handle);
1847b52b200SSrinivas Pandruvada 	if (ptype == 0x11)
1857b52b200SSrinivas Pandruvada 		attr_group = &dptf_power_attribute_group;
1867b52b200SSrinivas Pandruvada 	else if (ptype == 0x0C)
1877b52b200SSrinivas Pandruvada 		attr_group = &dptf_battery_attribute_group;
1887b52b200SSrinivas Pandruvada 	else
1896256ebd5SSrinivas Pandruvada 		return -ENODEV;
1906256ebd5SSrinivas Pandruvada 
191668ce99eSSrinivas Pandruvada 	result = acpi_install_notify_handler(acpi_dev->handle,
192668ce99eSSrinivas Pandruvada 					     ACPI_DEVICE_NOTIFY,
193668ce99eSSrinivas Pandruvada 					     dptf_power_notify,
194668ce99eSSrinivas Pandruvada 					     (void *)pdev);
1956256ebd5SSrinivas Pandruvada 	if (result)
1966256ebd5SSrinivas Pandruvada 		return result;
1976256ebd5SSrinivas Pandruvada 
198668ce99eSSrinivas Pandruvada 	result = sysfs_create_group(&pdev->dev.kobj,
1997b52b200SSrinivas Pandruvada 				    attr_group);
200668ce99eSSrinivas Pandruvada 	if (result) {
201668ce99eSSrinivas Pandruvada 		acpi_remove_notify_handler(acpi_dev->handle,
202668ce99eSSrinivas Pandruvada 					   ACPI_DEVICE_NOTIFY,
203668ce99eSSrinivas Pandruvada 					   dptf_power_notify);
204668ce99eSSrinivas Pandruvada 		return result;
205668ce99eSSrinivas Pandruvada 	}
206668ce99eSSrinivas Pandruvada 
2076256ebd5SSrinivas Pandruvada 	platform_set_drvdata(pdev, acpi_dev);
2086256ebd5SSrinivas Pandruvada 
2096256ebd5SSrinivas Pandruvada 	return 0;
2106256ebd5SSrinivas Pandruvada }
2116256ebd5SSrinivas Pandruvada 
dptf_power_remove(struct platform_device * pdev)212da22084dSUwe Kleine-König static void dptf_power_remove(struct platform_device *pdev)
2136256ebd5SSrinivas Pandruvada {
214668ce99eSSrinivas Pandruvada 	struct acpi_device *acpi_dev = platform_get_drvdata(pdev);
2156256ebd5SSrinivas Pandruvada 
216668ce99eSSrinivas Pandruvada 	acpi_remove_notify_handler(acpi_dev->handle,
217668ce99eSSrinivas Pandruvada 				   ACPI_DEVICE_NOTIFY,
218668ce99eSSrinivas Pandruvada 				   dptf_power_notify);
2197b52b200SSrinivas Pandruvada 
2207b52b200SSrinivas Pandruvada 	if (dptf_participant_type(acpi_dev->handle) == 0x0CULL)
2217b52b200SSrinivas Pandruvada 		sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group);
2227b52b200SSrinivas Pandruvada 	else
2236256ebd5SSrinivas Pandruvada 		sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);
2246256ebd5SSrinivas Pandruvada }
2256256ebd5SSrinivas Pandruvada 
2266256ebd5SSrinivas Pandruvada static const struct acpi_device_id int3407_device_ids[] = {
2276256ebd5SSrinivas Pandruvada 	{"INT3407", 0},
2287b52b200SSrinivas Pandruvada 	{"INT3532", 0},
229b62c770fSGayatri Kammela 	{"INTC1047", 0},
2301e05dacaSSrinivas Pandruvada 	{"INTC1050", 0},
23138748bcbSSrinivas Pandruvada 	{"INTC1060", 0},
23238748bcbSSrinivas Pandruvada 	{"INTC1061", 0},
233657b95d3SSumeet Pawnikar 	{"INTC1065", 0},
234657b95d3SSumeet Pawnikar 	{"INTC1066", 0},
235*79b510c4SSumeet Pawnikar 	{"INTC106C", 0},
236*79b510c4SSumeet Pawnikar 	{"INTC106D", 0},
237a510c78eSSrinivas Pandruvada 	{"INTC10A4", 0},
238a510c78eSSrinivas Pandruvada 	{"INTC10A5", 0},
2396256ebd5SSrinivas Pandruvada 	{"", 0},
2406256ebd5SSrinivas Pandruvada };
2416256ebd5SSrinivas Pandruvada MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
2426256ebd5SSrinivas Pandruvada 
2436256ebd5SSrinivas Pandruvada static struct platform_driver dptf_power_driver = {
2446256ebd5SSrinivas Pandruvada 	.probe = dptf_power_add,
245da22084dSUwe Kleine-König 	.remove_new = dptf_power_remove,
2466256ebd5SSrinivas Pandruvada 	.driver = {
247ff44fe3eSRafael J. Wysocki 		.name = "dptf_power",
2486256ebd5SSrinivas Pandruvada 		.acpi_match_table = int3407_device_ids,
2496256ebd5SSrinivas Pandruvada 	},
2506256ebd5SSrinivas Pandruvada };
2516256ebd5SSrinivas Pandruvada 
2526256ebd5SSrinivas Pandruvada module_platform_driver(dptf_power_driver);
2536256ebd5SSrinivas Pandruvada 
2546256ebd5SSrinivas Pandruvada MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
2556256ebd5SSrinivas Pandruvada MODULE_LICENSE("GPL v2");
2566256ebd5SSrinivas Pandruvada MODULE_DESCRIPTION("ACPI DPTF platform power driver");
257