1*758b62e5SInochi Amaoto // SPDX-License-Identifier: GPL-2.0-only
2*758b62e5SInochi Amaoto /*
3*758b62e5SInochi Amaoto * Copyright (c) 2024 Inochi Amaoto <inochiama@outlook.com>
4*758b62e5SInochi Amaoto *
5*758b62e5SInochi Amaoto * Sophgo power control mcu for SG2042
6*758b62e5SInochi Amaoto */
7*758b62e5SInochi Amaoto
8*758b62e5SInochi Amaoto #include <linux/cleanup.h>
9*758b62e5SInochi Amaoto #include <linux/debugfs.h>
10*758b62e5SInochi Amaoto #include <linux/err.h>
11*758b62e5SInochi Amaoto #include <linux/hwmon.h>
12*758b62e5SInochi Amaoto #include <linux/i2c.h>
13*758b62e5SInochi Amaoto #include <linux/kernel.h>
14*758b62e5SInochi Amaoto #include <linux/module.h>
15*758b62e5SInochi Amaoto #include <linux/mutex.h>
16*758b62e5SInochi Amaoto
17*758b62e5SInochi Amaoto /* fixed MCU registers */
18*758b62e5SInochi Amaoto #define REG_BOARD_TYPE 0x00
19*758b62e5SInochi Amaoto #define REG_MCU_FIRMWARE_VERSION 0x01
20*758b62e5SInochi Amaoto #define REG_PCB_VERSION 0x02
21*758b62e5SInochi Amaoto #define REG_PWR_CTRL 0x03
22*758b62e5SInochi Amaoto #define REG_SOC_TEMP 0x04
23*758b62e5SInochi Amaoto #define REG_BOARD_TEMP 0x05
24*758b62e5SInochi Amaoto #define REG_RST_COUNT 0x0a
25*758b62e5SInochi Amaoto #define REG_UPTIME 0x0b
26*758b62e5SInochi Amaoto #define REG_RESET_REASON 0x0d
27*758b62e5SInochi Amaoto #define REG_MCU_TYPE 0x18
28*758b62e5SInochi Amaoto #define REG_REPOWER_POLICY 0x65
29*758b62e5SInochi Amaoto #define REG_CRITICAL_TEMP 0x66
30*758b62e5SInochi Amaoto #define REG_REPOWER_TEMP 0x67
31*758b62e5SInochi Amaoto
32*758b62e5SInochi Amaoto #define REPOWER_POLICY_REBOOT 1
33*758b62e5SInochi Amaoto #define REPOWER_POLICY_KEEP_OFF 2
34*758b62e5SInochi Amaoto
35*758b62e5SInochi Amaoto #define MCU_POWER_MAX 0xff
36*758b62e5SInochi Amaoto
37*758b62e5SInochi Amaoto #define DEFINE_MCU_DEBUG_ATTR(_name, _reg, _format) \
38*758b62e5SInochi Amaoto static int _name##_show(struct seq_file *seqf, \
39*758b62e5SInochi Amaoto void *unused) \
40*758b62e5SInochi Amaoto { \
41*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu = seqf->private; \
42*758b62e5SInochi Amaoto int ret; \
43*758b62e5SInochi Amaoto ret = i2c_smbus_read_byte_data(mcu->client, (_reg)); \
44*758b62e5SInochi Amaoto if (ret < 0) \
45*758b62e5SInochi Amaoto return ret; \
46*758b62e5SInochi Amaoto seq_printf(seqf, _format "\n", ret); \
47*758b62e5SInochi Amaoto return 0; \
48*758b62e5SInochi Amaoto } \
49*758b62e5SInochi Amaoto DEFINE_SHOW_ATTRIBUTE(_name) \
50*758b62e5SInochi Amaoto
51*758b62e5SInochi Amaoto struct sg2042_mcu_data {
52*758b62e5SInochi Amaoto struct i2c_client *client;
53*758b62e5SInochi Amaoto struct dentry *debugfs;
54*758b62e5SInochi Amaoto struct mutex mutex;
55*758b62e5SInochi Amaoto };
56*758b62e5SInochi Amaoto
57*758b62e5SInochi Amaoto static struct dentry *sgmcu_debugfs;
58*758b62e5SInochi Amaoto
reset_count_show(struct device * dev,struct device_attribute * attr,char * buf)59*758b62e5SInochi Amaoto static ssize_t reset_count_show(struct device *dev,
60*758b62e5SInochi Amaoto struct device_attribute *attr,
61*758b62e5SInochi Amaoto char *buf)
62*758b62e5SInochi Amaoto {
63*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu = dev_get_drvdata(dev);
64*758b62e5SInochi Amaoto int ret;
65*758b62e5SInochi Amaoto
66*758b62e5SInochi Amaoto ret = i2c_smbus_read_byte_data(mcu->client, REG_RST_COUNT);
67*758b62e5SInochi Amaoto if (ret < 0)
68*758b62e5SInochi Amaoto return ret;
69*758b62e5SInochi Amaoto
70*758b62e5SInochi Amaoto return sprintf(buf, "%d\n", ret);
71*758b62e5SInochi Amaoto }
72*758b62e5SInochi Amaoto
uptime_show(struct device * dev,struct device_attribute * attr,char * buf)73*758b62e5SInochi Amaoto static ssize_t uptime_show(struct device *dev,
74*758b62e5SInochi Amaoto struct device_attribute *attr,
75*758b62e5SInochi Amaoto char *buf)
76*758b62e5SInochi Amaoto {
77*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu = dev_get_drvdata(dev);
78*758b62e5SInochi Amaoto u8 time_val[2];
79*758b62e5SInochi Amaoto int ret;
80*758b62e5SInochi Amaoto
81*758b62e5SInochi Amaoto ret = i2c_smbus_read_i2c_block_data(mcu->client, REG_UPTIME,
82*758b62e5SInochi Amaoto sizeof(time_val), time_val);
83*758b62e5SInochi Amaoto if (ret < 0)
84*758b62e5SInochi Amaoto return ret;
85*758b62e5SInochi Amaoto
86*758b62e5SInochi Amaoto return sprintf(buf, "%d\n",
87*758b62e5SInochi Amaoto (time_val[0]) | (time_val[1] << 8));
88*758b62e5SInochi Amaoto }
89*758b62e5SInochi Amaoto
reset_reason_show(struct device * dev,struct device_attribute * attr,char * buf)90*758b62e5SInochi Amaoto static ssize_t reset_reason_show(struct device *dev,
91*758b62e5SInochi Amaoto struct device_attribute *attr,
92*758b62e5SInochi Amaoto char *buf)
93*758b62e5SInochi Amaoto {
94*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu = dev_get_drvdata(dev);
95*758b62e5SInochi Amaoto int ret;
96*758b62e5SInochi Amaoto
97*758b62e5SInochi Amaoto ret = i2c_smbus_read_byte_data(mcu->client, REG_RESET_REASON);
98*758b62e5SInochi Amaoto if (ret < 0)
99*758b62e5SInochi Amaoto return ret;
100*758b62e5SInochi Amaoto
101*758b62e5SInochi Amaoto return sprintf(buf, "0x%02x\n", ret);
102*758b62e5SInochi Amaoto }
103*758b62e5SInochi Amaoto
repower_policy_show(struct device * dev,struct device_attribute * attr,char * buf)104*758b62e5SInochi Amaoto static ssize_t repower_policy_show(struct device *dev,
105*758b62e5SInochi Amaoto struct device_attribute *attr,
106*758b62e5SInochi Amaoto char *buf)
107*758b62e5SInochi Amaoto {
108*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu = dev_get_drvdata(dev);
109*758b62e5SInochi Amaoto int ret;
110*758b62e5SInochi Amaoto const char *action;
111*758b62e5SInochi Amaoto
112*758b62e5SInochi Amaoto ret = i2c_smbus_read_byte_data(mcu->client, REG_REPOWER_POLICY);
113*758b62e5SInochi Amaoto if (ret < 0)
114*758b62e5SInochi Amaoto return ret;
115*758b62e5SInochi Amaoto
116*758b62e5SInochi Amaoto if (ret == REPOWER_POLICY_REBOOT)
117*758b62e5SInochi Amaoto action = "repower";
118*758b62e5SInochi Amaoto else if (ret == REPOWER_POLICY_KEEP_OFF)
119*758b62e5SInochi Amaoto action = "keep";
120*758b62e5SInochi Amaoto else
121*758b62e5SInochi Amaoto action = "unknown";
122*758b62e5SInochi Amaoto
123*758b62e5SInochi Amaoto return sprintf(buf, "%s\n", action);
124*758b62e5SInochi Amaoto }
125*758b62e5SInochi Amaoto
repower_policy_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)126*758b62e5SInochi Amaoto static ssize_t repower_policy_store(struct device *dev,
127*758b62e5SInochi Amaoto struct device_attribute *attr,
128*758b62e5SInochi Amaoto const char *buf, size_t count)
129*758b62e5SInochi Amaoto {
130*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu = dev_get_drvdata(dev);
131*758b62e5SInochi Amaoto u8 value;
132*758b62e5SInochi Amaoto int ret;
133*758b62e5SInochi Amaoto
134*758b62e5SInochi Amaoto if (sysfs_streq("repower", buf))
135*758b62e5SInochi Amaoto value = REPOWER_POLICY_REBOOT;
136*758b62e5SInochi Amaoto else if (sysfs_streq("keep", buf))
137*758b62e5SInochi Amaoto value = REPOWER_POLICY_KEEP_OFF;
138*758b62e5SInochi Amaoto else
139*758b62e5SInochi Amaoto return -EINVAL;
140*758b62e5SInochi Amaoto
141*758b62e5SInochi Amaoto ret = i2c_smbus_write_byte_data(mcu->client,
142*758b62e5SInochi Amaoto REG_REPOWER_POLICY, value);
143*758b62e5SInochi Amaoto if (ret < 0)
144*758b62e5SInochi Amaoto return ret;
145*758b62e5SInochi Amaoto
146*758b62e5SInochi Amaoto return count;
147*758b62e5SInochi Amaoto }
148*758b62e5SInochi Amaoto
149*758b62e5SInochi Amaoto static DEVICE_ATTR_RO(reset_count);
150*758b62e5SInochi Amaoto static DEVICE_ATTR_RO(uptime);
151*758b62e5SInochi Amaoto static DEVICE_ATTR_RO(reset_reason);
152*758b62e5SInochi Amaoto static DEVICE_ATTR_RW(repower_policy);
153*758b62e5SInochi Amaoto
154*758b62e5SInochi Amaoto DEFINE_MCU_DEBUG_ATTR(firmware_version, REG_MCU_FIRMWARE_VERSION, "0x%02x");
155*758b62e5SInochi Amaoto DEFINE_MCU_DEBUG_ATTR(pcb_version, REG_PCB_VERSION, "0x%02x");
156*758b62e5SInochi Amaoto DEFINE_MCU_DEBUG_ATTR(board_type, REG_BOARD_TYPE, "0x%02x");
157*758b62e5SInochi Amaoto DEFINE_MCU_DEBUG_ATTR(mcu_type, REG_MCU_TYPE, "%d");
158*758b62e5SInochi Amaoto
159*758b62e5SInochi Amaoto static struct attribute *sg2042_mcu_attrs[] = {
160*758b62e5SInochi Amaoto &dev_attr_reset_count.attr,
161*758b62e5SInochi Amaoto &dev_attr_uptime.attr,
162*758b62e5SInochi Amaoto &dev_attr_reset_reason.attr,
163*758b62e5SInochi Amaoto &dev_attr_repower_policy.attr,
164*758b62e5SInochi Amaoto NULL
165*758b62e5SInochi Amaoto };
166*758b62e5SInochi Amaoto
167*758b62e5SInochi Amaoto static const struct attribute_group sg2042_mcu_attr_group = {
168*758b62e5SInochi Amaoto .attrs = sg2042_mcu_attrs,
169*758b62e5SInochi Amaoto };
170*758b62e5SInochi Amaoto
171*758b62e5SInochi Amaoto static const struct attribute_group *sg2042_mcu_groups[] = {
172*758b62e5SInochi Amaoto &sg2042_mcu_attr_group,
173*758b62e5SInochi Amaoto NULL
174*758b62e5SInochi Amaoto };
175*758b62e5SInochi Amaoto
176*758b62e5SInochi Amaoto static const struct hwmon_channel_info * const sg2042_mcu_info[] = {
177*758b62e5SInochi Amaoto HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
178*758b62e5SInochi Amaoto HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_CRIT |
179*758b62e5SInochi Amaoto HWMON_T_CRIT_HYST,
180*758b62e5SInochi Amaoto HWMON_T_INPUT),
181*758b62e5SInochi Amaoto NULL
182*758b62e5SInochi Amaoto };
183*758b62e5SInochi Amaoto
sg2042_mcu_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)184*758b62e5SInochi Amaoto static int sg2042_mcu_read(struct device *dev,
185*758b62e5SInochi Amaoto enum hwmon_sensor_types type,
186*758b62e5SInochi Amaoto u32 attr, int channel, long *val)
187*758b62e5SInochi Amaoto {
188*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu = dev_get_drvdata(dev);
189*758b62e5SInochi Amaoto int tmp;
190*758b62e5SInochi Amaoto u8 reg;
191*758b62e5SInochi Amaoto
192*758b62e5SInochi Amaoto switch (attr) {
193*758b62e5SInochi Amaoto case hwmon_temp_input:
194*758b62e5SInochi Amaoto reg = channel ? REG_BOARD_TEMP : REG_SOC_TEMP;
195*758b62e5SInochi Amaoto break;
196*758b62e5SInochi Amaoto case hwmon_temp_crit:
197*758b62e5SInochi Amaoto reg = REG_CRITICAL_TEMP;
198*758b62e5SInochi Amaoto break;
199*758b62e5SInochi Amaoto case hwmon_temp_crit_hyst:
200*758b62e5SInochi Amaoto reg = REG_REPOWER_TEMP;
201*758b62e5SInochi Amaoto break;
202*758b62e5SInochi Amaoto default:
203*758b62e5SInochi Amaoto return -EOPNOTSUPP;
204*758b62e5SInochi Amaoto }
205*758b62e5SInochi Amaoto
206*758b62e5SInochi Amaoto tmp = i2c_smbus_read_byte_data(mcu->client, reg);
207*758b62e5SInochi Amaoto if (tmp < 0)
208*758b62e5SInochi Amaoto return tmp;
209*758b62e5SInochi Amaoto *val = tmp * 1000;
210*758b62e5SInochi Amaoto
211*758b62e5SInochi Amaoto return 0;
212*758b62e5SInochi Amaoto }
213*758b62e5SInochi Amaoto
sg2042_mcu_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)214*758b62e5SInochi Amaoto static int sg2042_mcu_write(struct device *dev,
215*758b62e5SInochi Amaoto enum hwmon_sensor_types type,
216*758b62e5SInochi Amaoto u32 attr, int channel, long val)
217*758b62e5SInochi Amaoto {
218*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu = dev_get_drvdata(dev);
219*758b62e5SInochi Amaoto int temp = val / 1000;
220*758b62e5SInochi Amaoto int hyst_temp, crit_temp;
221*758b62e5SInochi Amaoto u8 reg;
222*758b62e5SInochi Amaoto
223*758b62e5SInochi Amaoto temp = clamp_val(temp, 0, MCU_POWER_MAX);
224*758b62e5SInochi Amaoto
225*758b62e5SInochi Amaoto guard(mutex)(&mcu->mutex);
226*758b62e5SInochi Amaoto
227*758b62e5SInochi Amaoto switch (attr) {
228*758b62e5SInochi Amaoto case hwmon_temp_crit:
229*758b62e5SInochi Amaoto hyst_temp = i2c_smbus_read_byte_data(mcu->client,
230*758b62e5SInochi Amaoto REG_REPOWER_TEMP);
231*758b62e5SInochi Amaoto if (hyst_temp < 0)
232*758b62e5SInochi Amaoto return hyst_temp;
233*758b62e5SInochi Amaoto
234*758b62e5SInochi Amaoto crit_temp = temp;
235*758b62e5SInochi Amaoto reg = REG_CRITICAL_TEMP;
236*758b62e5SInochi Amaoto break;
237*758b62e5SInochi Amaoto case hwmon_temp_crit_hyst:
238*758b62e5SInochi Amaoto crit_temp = i2c_smbus_read_byte_data(mcu->client,
239*758b62e5SInochi Amaoto REG_CRITICAL_TEMP);
240*758b62e5SInochi Amaoto if (crit_temp < 0)
241*758b62e5SInochi Amaoto return crit_temp;
242*758b62e5SInochi Amaoto
243*758b62e5SInochi Amaoto hyst_temp = temp;
244*758b62e5SInochi Amaoto reg = REG_REPOWER_TEMP;
245*758b62e5SInochi Amaoto break;
246*758b62e5SInochi Amaoto default:
247*758b62e5SInochi Amaoto return -EOPNOTSUPP;
248*758b62e5SInochi Amaoto }
249*758b62e5SInochi Amaoto
250*758b62e5SInochi Amaoto /*
251*758b62e5SInochi Amaoto * ensure hyst_temp is smaller to avoid MCU from
252*758b62e5SInochi Amaoto * keeping triggering repower event.
253*758b62e5SInochi Amaoto */
254*758b62e5SInochi Amaoto if (crit_temp < hyst_temp)
255*758b62e5SInochi Amaoto return -EINVAL;
256*758b62e5SInochi Amaoto
257*758b62e5SInochi Amaoto return i2c_smbus_write_byte_data(mcu->client, reg, temp);
258*758b62e5SInochi Amaoto }
259*758b62e5SInochi Amaoto
sg2042_mcu_is_visible(const void * _data,enum hwmon_sensor_types type,u32 attr,int channel)260*758b62e5SInochi Amaoto static umode_t sg2042_mcu_is_visible(const void *_data,
261*758b62e5SInochi Amaoto enum hwmon_sensor_types type,
262*758b62e5SInochi Amaoto u32 attr, int channel)
263*758b62e5SInochi Amaoto {
264*758b62e5SInochi Amaoto switch (type) {
265*758b62e5SInochi Amaoto case hwmon_temp:
266*758b62e5SInochi Amaoto switch (attr) {
267*758b62e5SInochi Amaoto case hwmon_temp_input:
268*758b62e5SInochi Amaoto return 0444;
269*758b62e5SInochi Amaoto case hwmon_temp_crit:
270*758b62e5SInochi Amaoto case hwmon_temp_crit_hyst:
271*758b62e5SInochi Amaoto if (channel == 0)
272*758b62e5SInochi Amaoto return 0644;
273*758b62e5SInochi Amaoto break;
274*758b62e5SInochi Amaoto default:
275*758b62e5SInochi Amaoto break;
276*758b62e5SInochi Amaoto }
277*758b62e5SInochi Amaoto break;
278*758b62e5SInochi Amaoto default:
279*758b62e5SInochi Amaoto break;
280*758b62e5SInochi Amaoto }
281*758b62e5SInochi Amaoto return 0;
282*758b62e5SInochi Amaoto }
283*758b62e5SInochi Amaoto
284*758b62e5SInochi Amaoto static const struct hwmon_ops sg2042_mcu_ops = {
285*758b62e5SInochi Amaoto .is_visible = sg2042_mcu_is_visible,
286*758b62e5SInochi Amaoto .read = sg2042_mcu_read,
287*758b62e5SInochi Amaoto .write = sg2042_mcu_write,
288*758b62e5SInochi Amaoto };
289*758b62e5SInochi Amaoto
290*758b62e5SInochi Amaoto static const struct hwmon_chip_info sg2042_mcu_chip_info = {
291*758b62e5SInochi Amaoto .ops = &sg2042_mcu_ops,
292*758b62e5SInochi Amaoto .info = sg2042_mcu_info,
293*758b62e5SInochi Amaoto };
294*758b62e5SInochi Amaoto
sg2042_mcu_debugfs_init(struct sg2042_mcu_data * mcu,struct device * dev)295*758b62e5SInochi Amaoto static void sg2042_mcu_debugfs_init(struct sg2042_mcu_data *mcu,
296*758b62e5SInochi Amaoto struct device *dev)
297*758b62e5SInochi Amaoto {
298*758b62e5SInochi Amaoto mcu->debugfs = debugfs_create_dir(dev_name(dev), sgmcu_debugfs);
299*758b62e5SInochi Amaoto
300*758b62e5SInochi Amaoto debugfs_create_file("firmware_version", 0444, mcu->debugfs,
301*758b62e5SInochi Amaoto mcu, &firmware_version_fops);
302*758b62e5SInochi Amaoto debugfs_create_file("pcb_version", 0444, mcu->debugfs, mcu,
303*758b62e5SInochi Amaoto &pcb_version_fops);
304*758b62e5SInochi Amaoto debugfs_create_file("mcu_type", 0444, mcu->debugfs, mcu,
305*758b62e5SInochi Amaoto &mcu_type_fops);
306*758b62e5SInochi Amaoto debugfs_create_file("board_type", 0444, mcu->debugfs, mcu,
307*758b62e5SInochi Amaoto &board_type_fops);
308*758b62e5SInochi Amaoto }
309*758b62e5SInochi Amaoto
sg2042_mcu_i2c_probe(struct i2c_client * client)310*758b62e5SInochi Amaoto static int sg2042_mcu_i2c_probe(struct i2c_client *client)
311*758b62e5SInochi Amaoto {
312*758b62e5SInochi Amaoto struct device *dev = &client->dev;
313*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu;
314*758b62e5SInochi Amaoto struct device *hwmon_dev;
315*758b62e5SInochi Amaoto
316*758b62e5SInochi Amaoto if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
317*758b62e5SInochi Amaoto I2C_FUNC_SMBUS_BLOCK_DATA))
318*758b62e5SInochi Amaoto return -ENODEV;
319*758b62e5SInochi Amaoto
320*758b62e5SInochi Amaoto mcu = devm_kmalloc(dev, sizeof(*mcu), GFP_KERNEL);
321*758b62e5SInochi Amaoto if (!mcu)
322*758b62e5SInochi Amaoto return -ENOMEM;
323*758b62e5SInochi Amaoto
324*758b62e5SInochi Amaoto mutex_init(&mcu->mutex);
325*758b62e5SInochi Amaoto mcu->client = client;
326*758b62e5SInochi Amaoto
327*758b62e5SInochi Amaoto i2c_set_clientdata(client, mcu);
328*758b62e5SInochi Amaoto
329*758b62e5SInochi Amaoto hwmon_dev = devm_hwmon_device_register_with_info(dev, "sg2042_mcu",
330*758b62e5SInochi Amaoto mcu,
331*758b62e5SInochi Amaoto &sg2042_mcu_chip_info,
332*758b62e5SInochi Amaoto NULL);
333*758b62e5SInochi Amaoto if (IS_ERR(hwmon_dev))
334*758b62e5SInochi Amaoto return PTR_ERR(hwmon_dev);
335*758b62e5SInochi Amaoto
336*758b62e5SInochi Amaoto sg2042_mcu_debugfs_init(mcu, dev);
337*758b62e5SInochi Amaoto
338*758b62e5SInochi Amaoto return 0;
339*758b62e5SInochi Amaoto }
340*758b62e5SInochi Amaoto
sg2042_mcu_i2c_remove(struct i2c_client * client)341*758b62e5SInochi Amaoto static void sg2042_mcu_i2c_remove(struct i2c_client *client)
342*758b62e5SInochi Amaoto {
343*758b62e5SInochi Amaoto struct sg2042_mcu_data *mcu = i2c_get_clientdata(client);
344*758b62e5SInochi Amaoto
345*758b62e5SInochi Amaoto debugfs_remove_recursive(mcu->debugfs);
346*758b62e5SInochi Amaoto }
347*758b62e5SInochi Amaoto
348*758b62e5SInochi Amaoto static const struct i2c_device_id sg2042_mcu_id[] = {
349*758b62e5SInochi Amaoto { "sg2042-hwmon-mcu", 0 },
350*758b62e5SInochi Amaoto {},
351*758b62e5SInochi Amaoto };
352*758b62e5SInochi Amaoto MODULE_DEVICE_TABLE(i2c, sg2042_mcu_id);
353*758b62e5SInochi Amaoto
354*758b62e5SInochi Amaoto static const struct of_device_id sg2042_mcu_of_id[] = {
355*758b62e5SInochi Amaoto { .compatible = "sophgo,sg2042-hwmon-mcu" },
356*758b62e5SInochi Amaoto {},
357*758b62e5SInochi Amaoto };
358*758b62e5SInochi Amaoto MODULE_DEVICE_TABLE(of, sg2042_mcu_of_id);
359*758b62e5SInochi Amaoto
360*758b62e5SInochi Amaoto static struct i2c_driver sg2042_mcu_driver = {
361*758b62e5SInochi Amaoto .driver = {
362*758b62e5SInochi Amaoto .name = "sg2042-mcu",
363*758b62e5SInochi Amaoto .of_match_table = sg2042_mcu_of_id,
364*758b62e5SInochi Amaoto .dev_groups = sg2042_mcu_groups,
365*758b62e5SInochi Amaoto },
366*758b62e5SInochi Amaoto .probe = sg2042_mcu_i2c_probe,
367*758b62e5SInochi Amaoto .remove = sg2042_mcu_i2c_remove,
368*758b62e5SInochi Amaoto .id_table = sg2042_mcu_id,
369*758b62e5SInochi Amaoto };
370*758b62e5SInochi Amaoto
sg2042_mcu_init(void)371*758b62e5SInochi Amaoto static int __init sg2042_mcu_init(void)
372*758b62e5SInochi Amaoto {
373*758b62e5SInochi Amaoto sgmcu_debugfs = debugfs_create_dir("sg2042-mcu", NULL);
374*758b62e5SInochi Amaoto return i2c_add_driver(&sg2042_mcu_driver);
375*758b62e5SInochi Amaoto }
376*758b62e5SInochi Amaoto
sg2042_mcu_exit(void)377*758b62e5SInochi Amaoto static void __exit sg2042_mcu_exit(void)
378*758b62e5SInochi Amaoto {
379*758b62e5SInochi Amaoto debugfs_remove_recursive(sgmcu_debugfs);
380*758b62e5SInochi Amaoto i2c_del_driver(&sg2042_mcu_driver);
381*758b62e5SInochi Amaoto }
382*758b62e5SInochi Amaoto
383*758b62e5SInochi Amaoto module_init(sg2042_mcu_init);
384*758b62e5SInochi Amaoto module_exit(sg2042_mcu_exit);
385*758b62e5SInochi Amaoto
386*758b62e5SInochi Amaoto MODULE_AUTHOR("Inochi Amaoto <inochiama@outlook.com>");
387*758b62e5SInochi Amaoto MODULE_DESCRIPTION("MCU I2C driver for SG2042 soc platform");
388*758b62e5SInochi Amaoto MODULE_LICENSE("GPL");
389