OSDN Git Service

apm821xx: add support for kernel 5.15 for testing
[immortalwrt/immortalwrt.git] / target / linux / apm821xx / patches-5.15 / 010-hwmon-tc654-add-thermal_cooling-device.patch
1 From 4d49367c5303e3ebd17502a45b74de280f6be539 Mon Sep 17 00:00:00 2001
2 From: Christian Lamparter <chunkeey@gmail.com>
3 Date: Sun, 13 Feb 2022 01:47:33 +0100
4 Subject: hwmon: (tc654) Add thermal_cooling device support
5
6 Adds thermal_cooling device support to the tc654/tc655
7 driver. This make it possible to integrate it into a
8 device-tree supported thermal-zone node as a
9 cooling device.
10
11 I have been using this patch as part of the Netgear WNDR4700
12 Centria NAS Router support within OpenWrt since 2016.
13
14 Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
15 Link: https://lore.kernel.org/r/20220213004733.2421193-1-chunkeey@gmail.com
16 Signed-off-by: Guenter Roeck <linux@roeck-us.net>
17 ---
18 --- a/drivers/hwmon/tc654.c
19 +++ b/drivers/hwmon/tc654.c
20 @@ -15,6 +15,7 @@
21  #include <linux/module.h>
22  #include <linux/mutex.h>
23  #include <linux/slab.h>
24 +#include <linux/thermal.h>
25  #include <linux/util_macros.h>
26  
27  enum tc654_regs {
28 @@ -379,28 +380,20 @@ static ssize_t pwm_show(struct device *d
29         return sprintf(buf, "%d\n", pwm);
30  }
31  
32 -static ssize_t pwm_store(struct device *dev, struct device_attribute *da,
33 -                        const char *buf, size_t count)
34 +static int _set_pwm(struct tc654_data *data, unsigned long val)
35  {
36 -       struct tc654_data *data = dev_get_drvdata(dev);
37         struct i2c_client *client = data->client;
38 -       unsigned long val;
39         int ret;
40  
41 -       if (kstrtoul(buf, 10, &val))
42 -               return -EINVAL;
43 -       if (val > 255)
44 -               return -EINVAL;
45 -
46         mutex_lock(&data->update_lock);
47  
48 -       if (val == 0)
49 +       if (val == 0) {
50                 data->config |= TC654_REG_CONFIG_SDM;
51 -       else
52 +               data->duty_cycle = 0;
53 +       } else {
54                 data->config &= ~TC654_REG_CONFIG_SDM;
55 -
56 -       data->duty_cycle = find_closest(val, tc654_pwm_map,
57 -                                       ARRAY_SIZE(tc654_pwm_map));
58 +               data->duty_cycle = val - 1;
59 +       }
60  
61         ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config);
62         if (ret < 0)
63 @@ -411,6 +404,24 @@ static ssize_t pwm_store(struct device *
64  
65  out:
66         mutex_unlock(&data->update_lock);
67 +       return ret;
68 +}
69 +
70 +static ssize_t pwm_store(struct device *dev, struct device_attribute *da,
71 +                        const char *buf, size_t count)
72 +{
73 +       struct tc654_data *data = dev_get_drvdata(dev);
74 +       unsigned long val;
75 +       int ret;
76 +
77 +       if (kstrtoul(buf, 10, &val))
78 +               return -EINVAL;
79 +       if (val > 255)
80 +               return -EINVAL;
81 +       if (val > 0)
82 +               val = find_closest(val, tc654_pwm_map, ARRAY_SIZE(tc654_pwm_map)) + 1;
83 +
84 +       ret = _set_pwm(data, val);
85         return ret < 0 ? ret : count;
86  }
87  
88 @@ -443,6 +454,58 @@ static struct attribute *tc654_attrs[] =
89  ATTRIBUTE_GROUPS(tc654);
90  
91  /*
92 + * thermal cooling device functions
93 + *
94 + * Account for the "ShutDown Mode (SDM)" state by offsetting
95 + * the 16 PWM duty cycle states by 1.
96 + *
97 + * State  0 =   0% PWM | Shutdown - Fan(s) are off
98 + * State  1 =  30% PWM | duty_cycle =  0
99 + * State  2 = ~35% PWM | duty_cycle =  1
100 + * [...]
101 + * State 15 = ~95% PWM | duty_cycle = 14
102 + * State 16 = 100% PWM | duty_cycle = 15
103 + */
104 +#define TC654_MAX_COOLING_STATE        16
105 +
106 +static int tc654_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state)
107 +{
108 +       *state = TC654_MAX_COOLING_STATE;
109 +       return 0;
110 +}
111 +
112 +static int tc654_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state)
113 +{
114 +       struct tc654_data *data = tc654_update_client(cdev->devdata);
115 +
116 +       if (IS_ERR(data))
117 +               return PTR_ERR(data);
118 +
119 +       if (data->config & TC654_REG_CONFIG_SDM)
120 +               *state = 0;     /* FAN is off */
121 +       else
122 +               *state = data->duty_cycle + 1;  /* offset PWM States by 1 */
123 +
124 +       return 0;
125 +}
126 +
127 +static int tc654_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
128 +{
129 +       struct tc654_data *data = tc654_update_client(cdev->devdata);
130 +
131 +       if (IS_ERR(data))
132 +               return PTR_ERR(data);
133 +
134 +       return _set_pwm(data, clamp_val(state, 0, TC654_MAX_COOLING_STATE));
135 +}
136 +
137 +static const struct thermal_cooling_device_ops tc654_fan_cool_ops = {
138 +       .get_max_state = tc654_get_max_state,
139 +       .get_cur_state = tc654_get_cur_state,
140 +       .set_cur_state = tc654_set_cur_state,
141 +};
142 +
143 +/*
144   * device probe and removal
145   */
146  
147 @@ -472,7 +535,18 @@ static int tc654_probe(struct i2c_client
148         hwmon_dev =
149             devm_hwmon_device_register_with_groups(dev, client->name, data,
150                                                    tc654_groups);
151 -       return PTR_ERR_OR_ZERO(hwmon_dev);
152 +       if (IS_ERR(hwmon_dev))
153 +               return PTR_ERR(hwmon_dev);
154 +
155 +       if (IS_ENABLED(CONFIG_THERMAL)) {
156 +               struct thermal_cooling_device *cdev;
157 +
158 +               cdev = devm_thermal_of_cooling_device_register(dev, dev->of_node, client->name,
159 +                                                              hwmon_dev, &tc654_fan_cool_ops);
160 +               return PTR_ERR_OR_ZERO(cdev);
161 +       }
162 +
163 +       return 0;
164  }
165  
166  static const struct i2c_device_id tc654_id[] = {