0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/acpi.h>
0010 #include <linux/platform_device.h>
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #define DPTF_POWER_SHOW(name, object) \
0026 static ssize_t name##_show(struct device *dev,\
0027 struct device_attribute *attr,\
0028 char *buf)\
0029 {\
0030 struct acpi_device *acpi_dev = dev_get_drvdata(dev);\
0031 unsigned long long val;\
0032 acpi_status status;\
0033 \
0034 status = acpi_evaluate_integer(acpi_dev->handle, #object,\
0035 NULL, &val);\
0036 if (ACPI_SUCCESS(status))\
0037 return sprintf(buf, "%d\n", (int)val);\
0038 else \
0039 return -EINVAL;\
0040 }
0041
0042 DPTF_POWER_SHOW(max_platform_power_mw, PMAX)
0043 DPTF_POWER_SHOW(platform_power_source, PSRC)
0044 DPTF_POWER_SHOW(adapter_rating_mw, ARTG)
0045 DPTF_POWER_SHOW(battery_steady_power_mw, PBSS)
0046 DPTF_POWER_SHOW(charger_type, CTYP)
0047 DPTF_POWER_SHOW(rest_of_platform_power_mw, PROP)
0048 DPTF_POWER_SHOW(max_steady_state_power_mw, PBSS)
0049 DPTF_POWER_SHOW(high_freq_impedance_mohm, RBHF)
0050 DPTF_POWER_SHOW(no_load_voltage_mv, VBNL)
0051 DPTF_POWER_SHOW(current_discharge_capbility_ma, CMPP);
0052
0053 static DEVICE_ATTR_RO(max_platform_power_mw);
0054 static DEVICE_ATTR_RO(platform_power_source);
0055 static DEVICE_ATTR_RO(adapter_rating_mw);
0056 static DEVICE_ATTR_RO(battery_steady_power_mw);
0057 static DEVICE_ATTR_RO(charger_type);
0058 static DEVICE_ATTR_RO(rest_of_platform_power_mw);
0059 static DEVICE_ATTR_RO(max_steady_state_power_mw);
0060 static DEVICE_ATTR_RO(high_freq_impedance_mohm);
0061 static DEVICE_ATTR_RO(no_load_voltage_mv);
0062 static DEVICE_ATTR_RO(current_discharge_capbility_ma);
0063
0064 static ssize_t prochot_confirm_store(struct device *dev,
0065 struct device_attribute *attr,
0066 const char *buf, size_t count)
0067 {
0068 struct acpi_device *acpi_dev = dev_get_drvdata(dev);
0069 acpi_status status;
0070 int seq_no;
0071
0072 if (kstrtouint(buf, 0, &seq_no) < 0)
0073 return -EINVAL;
0074
0075 status = acpi_execute_simple_method(acpi_dev->handle, "PBOK", seq_no);
0076 if (ACPI_SUCCESS(status))
0077 return count;
0078
0079 return -EINVAL;
0080 }
0081
0082 static DEVICE_ATTR_WO(prochot_confirm);
0083
0084 static struct attribute *dptf_power_attrs[] = {
0085 &dev_attr_max_platform_power_mw.attr,
0086 &dev_attr_platform_power_source.attr,
0087 &dev_attr_adapter_rating_mw.attr,
0088 &dev_attr_battery_steady_power_mw.attr,
0089 &dev_attr_charger_type.attr,
0090 &dev_attr_rest_of_platform_power_mw.attr,
0091 &dev_attr_prochot_confirm.attr,
0092 NULL
0093 };
0094
0095 static const struct attribute_group dptf_power_attribute_group = {
0096 .attrs = dptf_power_attrs,
0097 .name = "dptf_power"
0098 };
0099
0100 static struct attribute *dptf_battery_attrs[] = {
0101 &dev_attr_max_platform_power_mw.attr,
0102 &dev_attr_max_steady_state_power_mw.attr,
0103 &dev_attr_high_freq_impedance_mohm.attr,
0104 &dev_attr_no_load_voltage_mv.attr,
0105 &dev_attr_current_discharge_capbility_ma.attr,
0106 NULL
0107 };
0108
0109 static const struct attribute_group dptf_battery_attribute_group = {
0110 .attrs = dptf_battery_attrs,
0111 .name = "dptf_battery"
0112 };
0113
0114 #define MAX_POWER_CHANGED 0x80
0115 #define POWER_STATE_CHANGED 0x81
0116 #define STEADY_STATE_POWER_CHANGED 0x83
0117 #define POWER_PROP_CHANGE_EVENT 0x84
0118 #define IMPEDANCE_CHANGED 0x85
0119 #define VOLTAGE_CURRENT_CHANGED 0x86
0120
0121 static long long dptf_participant_type(acpi_handle handle)
0122 {
0123 unsigned long long ptype;
0124 acpi_status status;
0125
0126 status = acpi_evaluate_integer(handle, "PTYP", NULL, &ptype);
0127 if (ACPI_FAILURE(status))
0128 return -ENODEV;
0129
0130 return ptype;
0131 }
0132
0133 static void dptf_power_notify(acpi_handle handle, u32 event, void *data)
0134 {
0135 struct platform_device *pdev = data;
0136 char *attr;
0137
0138 switch (event) {
0139 case POWER_STATE_CHANGED:
0140 attr = "platform_power_source";
0141 break;
0142 case POWER_PROP_CHANGE_EVENT:
0143 attr = "rest_of_platform_power_mw";
0144 break;
0145 case MAX_POWER_CHANGED:
0146 attr = "max_platform_power_mw";
0147 break;
0148 case STEADY_STATE_POWER_CHANGED:
0149 attr = "max_steady_state_power_mw";
0150 break;
0151 case IMPEDANCE_CHANGED:
0152 attr = "high_freq_impedance_mohm";
0153 break;
0154 case VOLTAGE_CURRENT_CHANGED:
0155 attr = "no_load_voltage_mv";
0156 break;
0157 default:
0158 dev_err(&pdev->dev, "Unsupported event [0x%x]\n", event);
0159 return;
0160 }
0161
0162
0163
0164
0165
0166 if (dptf_participant_type(handle) == 0x0CULL)
0167 sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr);
0168 else
0169 sysfs_notify(&pdev->dev.kobj, "dptf_power", attr);
0170 }
0171
0172 static int dptf_power_add(struct platform_device *pdev)
0173 {
0174 const struct attribute_group *attr_group;
0175 struct acpi_device *acpi_dev;
0176 unsigned long long ptype;
0177 int result;
0178
0179 acpi_dev = ACPI_COMPANION(&(pdev->dev));
0180 if (!acpi_dev)
0181 return -ENODEV;
0182
0183 ptype = dptf_participant_type(acpi_dev->handle);
0184 if (ptype == 0x11)
0185 attr_group = &dptf_power_attribute_group;
0186 else if (ptype == 0x0C)
0187 attr_group = &dptf_battery_attribute_group;
0188 else
0189 return -ENODEV;
0190
0191 result = acpi_install_notify_handler(acpi_dev->handle,
0192 ACPI_DEVICE_NOTIFY,
0193 dptf_power_notify,
0194 (void *)pdev);
0195 if (result)
0196 return result;
0197
0198 result = sysfs_create_group(&pdev->dev.kobj,
0199 attr_group);
0200 if (result) {
0201 acpi_remove_notify_handler(acpi_dev->handle,
0202 ACPI_DEVICE_NOTIFY,
0203 dptf_power_notify);
0204 return result;
0205 }
0206
0207 platform_set_drvdata(pdev, acpi_dev);
0208
0209 return 0;
0210 }
0211
0212 static int dptf_power_remove(struct platform_device *pdev)
0213 {
0214 struct acpi_device *acpi_dev = platform_get_drvdata(pdev);
0215
0216 acpi_remove_notify_handler(acpi_dev->handle,
0217 ACPI_DEVICE_NOTIFY,
0218 dptf_power_notify);
0219
0220 if (dptf_participant_type(acpi_dev->handle) == 0x0CULL)
0221 sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group);
0222 else
0223 sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);
0224
0225 return 0;
0226 }
0227
0228 static const struct acpi_device_id int3407_device_ids[] = {
0229 {"INT3407", 0},
0230 {"INT3532", 0},
0231 {"INTC1047", 0},
0232 {"INTC1050", 0},
0233 {"INTC1060", 0},
0234 {"INTC1061", 0},
0235 {"INTC1065", 0},
0236 {"INTC1066", 0},
0237 {"INTC10A4", 0},
0238 {"INTC10A5", 0},
0239 {"", 0},
0240 };
0241 MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
0242
0243 static struct platform_driver dptf_power_driver = {
0244 .probe = dptf_power_add,
0245 .remove = dptf_power_remove,
0246 .driver = {
0247 .name = "dptf_power",
0248 .acpi_match_table = int3407_device_ids,
0249 },
0250 };
0251
0252 module_platform_driver(dptf_power_driver);
0253
0254 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
0255 MODULE_LICENSE("GPL v2");
0256 MODULE_DESCRIPTION("ACPI DPTF platform power driver");