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