0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/init.h>
0010 #include <linux/types.h>
0011 #include <linux/acpi.h>
0012 #include <linux/thermal.h>
0013 #include <linux/platform_device.h>
0014 #include "int340x_thermal_zone.h"
0015
0016 #define INT3403_TYPE_SENSOR 0x03
0017 #define INT3403_TYPE_CHARGER 0x0B
0018 #define INT3403_TYPE_BATTERY 0x0C
0019 #define INT3403_PERF_CHANGED_EVENT 0x80
0020 #define INT3403_PERF_TRIP_POINT_CHANGED 0x81
0021 #define INT3403_THERMAL_EVENT 0x90
0022
0023
0024 struct int3403_sensor {
0025 struct int34x_thermal_zone *int340x_zone;
0026 };
0027
0028 struct int3403_performance_state {
0029 u64 performance;
0030 u64 power;
0031 u64 latency;
0032 u64 linear;
0033 u64 control;
0034 u64 raw_performace;
0035 char *raw_unit;
0036 int reserved;
0037 };
0038
0039 struct int3403_cdev {
0040 struct thermal_cooling_device *cdev;
0041 unsigned long max_state;
0042 };
0043
0044 struct int3403_priv {
0045 struct platform_device *pdev;
0046 struct acpi_device *adev;
0047 unsigned long long type;
0048 void *priv;
0049 };
0050
0051 static void int3403_notify(acpi_handle handle,
0052 u32 event, void *data)
0053 {
0054 struct int3403_priv *priv = data;
0055 struct int3403_sensor *obj;
0056
0057 if (!priv)
0058 return;
0059
0060 obj = priv->priv;
0061 if (priv->type != INT3403_TYPE_SENSOR || !obj)
0062 return;
0063
0064 switch (event) {
0065 case INT3403_PERF_CHANGED_EVENT:
0066 break;
0067 case INT3403_THERMAL_EVENT:
0068 int340x_thermal_zone_device_update(obj->int340x_zone,
0069 THERMAL_TRIP_VIOLATED);
0070 break;
0071 case INT3403_PERF_TRIP_POINT_CHANGED:
0072 int340x_thermal_read_trips(obj->int340x_zone);
0073 int340x_thermal_zone_device_update(obj->int340x_zone,
0074 THERMAL_TRIP_CHANGED);
0075 break;
0076 default:
0077 dev_dbg(&priv->pdev->dev, "Unsupported event [0x%x]\n", event);
0078 break;
0079 }
0080 }
0081
0082 static int int3403_sensor_add(struct int3403_priv *priv)
0083 {
0084 int result = 0;
0085 struct int3403_sensor *obj;
0086
0087 obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL);
0088 if (!obj)
0089 return -ENOMEM;
0090
0091 priv->priv = obj;
0092
0093 obj->int340x_zone = int340x_thermal_zone_add(priv->adev, NULL);
0094 if (IS_ERR(obj->int340x_zone))
0095 return PTR_ERR(obj->int340x_zone);
0096
0097 result = acpi_install_notify_handler(priv->adev->handle,
0098 ACPI_DEVICE_NOTIFY, int3403_notify,
0099 (void *)priv);
0100 if (result)
0101 goto err_free_obj;
0102
0103 return 0;
0104
0105 err_free_obj:
0106 int340x_thermal_zone_remove(obj->int340x_zone);
0107 return result;
0108 }
0109
0110 static int int3403_sensor_remove(struct int3403_priv *priv)
0111 {
0112 struct int3403_sensor *obj = priv->priv;
0113
0114 acpi_remove_notify_handler(priv->adev->handle,
0115 ACPI_DEVICE_NOTIFY, int3403_notify);
0116 int340x_thermal_zone_remove(obj->int340x_zone);
0117
0118 return 0;
0119 }
0120
0121
0122 static int int3403_get_max_state(struct thermal_cooling_device *cdev,
0123 unsigned long *state)
0124 {
0125 struct int3403_priv *priv = cdev->devdata;
0126 struct int3403_cdev *obj = priv->priv;
0127
0128 *state = obj->max_state;
0129 return 0;
0130 }
0131
0132 static int int3403_get_cur_state(struct thermal_cooling_device *cdev,
0133 unsigned long *state)
0134 {
0135 struct int3403_priv *priv = cdev->devdata;
0136 unsigned long long level;
0137 acpi_status status;
0138
0139 status = acpi_evaluate_integer(priv->adev->handle, "PPPC", NULL, &level);
0140 if (ACPI_SUCCESS(status)) {
0141 *state = level;
0142 return 0;
0143 } else
0144 return -EINVAL;
0145 }
0146
0147 static int
0148 int3403_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
0149 {
0150 struct int3403_priv *priv = cdev->devdata;
0151 acpi_status status;
0152
0153 status = acpi_execute_simple_method(priv->adev->handle, "SPPC", state);
0154 if (ACPI_SUCCESS(status))
0155 return 0;
0156 else
0157 return -EINVAL;
0158 }
0159
0160 static const struct thermal_cooling_device_ops int3403_cooling_ops = {
0161 .get_max_state = int3403_get_max_state,
0162 .get_cur_state = int3403_get_cur_state,
0163 .set_cur_state = int3403_set_cur_state,
0164 };
0165
0166 static int int3403_cdev_add(struct int3403_priv *priv)
0167 {
0168 int result = 0;
0169 acpi_status status;
0170 struct int3403_cdev *obj;
0171 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
0172 union acpi_object *p;
0173
0174 obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL);
0175 if (!obj)
0176 return -ENOMEM;
0177
0178 status = acpi_evaluate_object(priv->adev->handle, "PPSS", NULL, &buf);
0179 if (ACPI_FAILURE(status))
0180 return -ENODEV;
0181
0182 p = buf.pointer;
0183 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
0184 pr_warn("Invalid PPSS data\n");
0185 kfree(buf.pointer);
0186 return -EFAULT;
0187 }
0188
0189 priv->priv = obj;
0190 obj->max_state = p->package.count - 1;
0191 obj->cdev =
0192 thermal_cooling_device_register(acpi_device_bid(priv->adev),
0193 priv, &int3403_cooling_ops);
0194 if (IS_ERR(obj->cdev))
0195 result = PTR_ERR(obj->cdev);
0196
0197 kfree(buf.pointer);
0198
0199
0200 return result;
0201 }
0202
0203 static int int3403_cdev_remove(struct int3403_priv *priv)
0204 {
0205 struct int3403_cdev *obj = priv->priv;
0206
0207 thermal_cooling_device_unregister(obj->cdev);
0208 return 0;
0209 }
0210
0211 static int int3403_add(struct platform_device *pdev)
0212 {
0213 struct int3403_priv *priv;
0214 int result = 0;
0215 unsigned long long tmp;
0216 acpi_status status;
0217
0218 priv = devm_kzalloc(&pdev->dev, sizeof(struct int3403_priv),
0219 GFP_KERNEL);
0220 if (!priv)
0221 return -ENOMEM;
0222
0223 priv->pdev = pdev;
0224 priv->adev = ACPI_COMPANION(&(pdev->dev));
0225 if (!priv->adev) {
0226 result = -EINVAL;
0227 goto err;
0228 }
0229
0230
0231 status = acpi_evaluate_integer(priv->adev->handle, "_TMP",
0232 NULL, &tmp);
0233 if (ACPI_FAILURE(status)) {
0234 status = acpi_evaluate_integer(priv->adev->handle, "PTYP",
0235 NULL, &priv->type);
0236 if (ACPI_FAILURE(status)) {
0237 result = -EINVAL;
0238 goto err;
0239 }
0240 } else {
0241 priv->type = INT3403_TYPE_SENSOR;
0242 }
0243
0244 platform_set_drvdata(pdev, priv);
0245 switch (priv->type) {
0246 case INT3403_TYPE_SENSOR:
0247 result = int3403_sensor_add(priv);
0248 break;
0249 case INT3403_TYPE_CHARGER:
0250 case INT3403_TYPE_BATTERY:
0251 result = int3403_cdev_add(priv);
0252 break;
0253 default:
0254 result = -EINVAL;
0255 }
0256
0257 if (result)
0258 goto err;
0259 return result;
0260
0261 err:
0262 return result;
0263 }
0264
0265 static int int3403_remove(struct platform_device *pdev)
0266 {
0267 struct int3403_priv *priv = platform_get_drvdata(pdev);
0268
0269 switch (priv->type) {
0270 case INT3403_TYPE_SENSOR:
0271 int3403_sensor_remove(priv);
0272 break;
0273 case INT3403_TYPE_CHARGER:
0274 case INT3403_TYPE_BATTERY:
0275 int3403_cdev_remove(priv);
0276 break;
0277 default:
0278 break;
0279 }
0280
0281 return 0;
0282 }
0283
0284 static const struct acpi_device_id int3403_device_ids[] = {
0285 {"INT3403", 0},
0286 {"INTC1043", 0},
0287 {"INTC1046", 0},
0288 {"INTC1062", 0},
0289 {"INTC10A1", 0},
0290 {"", 0},
0291 };
0292 MODULE_DEVICE_TABLE(acpi, int3403_device_ids);
0293
0294 static struct platform_driver int3403_driver = {
0295 .probe = int3403_add,
0296 .remove = int3403_remove,
0297 .driver = {
0298 .name = "int3403 thermal",
0299 .acpi_match_table = int3403_device_ids,
0300 },
0301 };
0302
0303 module_platform_driver(int3403_driver);
0304
0305 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
0306 MODULE_LICENSE("GPL v2");
0307 MODULE_DESCRIPTION("ACPI INT3403 thermal driver");