1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2022 Rockchip Electronics Co. Ltd.
4 *
5 * Author: Jianwei Fan <jianwei.fan@rock-chips.com>
6 *
7 * V0.0X01.0X00 first version.
8 * V0.0X01.0X01 add device attr hdmirxsel.
9 * V0.0X01.0X02 add device attr hdmiautoswitch.
10 *
11 */
12
13 // #define DEBUG
14 #include <linux/miscdevice.h>
15 #include <linux/cdev.h>
16 #include <linux/device.h>
17 #include <linux/fs.h>
18 #include <linux/i2c-dev.h>
19 #include <linux/i2c.h>
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/notifier.h>
24 #include <linux/slab.h>
25 #include <linux/uaccess.h>
26 #include <linux/compat.h>
27 #include <linux/printk.h>
28 #include <linux/kobject.h>
29 #include <linux/version.h>
30 #include <linux/time.h>
31 #include <linux/timer.h>
32 #include <linux/workqueue.h>
33
34 #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02)
35 #define DRIVER_NAME "EP9461E"
36
37 /*control reg*/
38 #define RX_SIGNAL_DETECT 0x00
39 #define GENERAL_CONTROL 0x08
40 #define RX_SEL_CONTROL 0x09
41 #define EDID_ENABLE 0x0B
42 #define ENTER_CODE 0x07
43
44 /*control mask*/
45 #define MASK_RX0_SIGNAL 0x10
46 #define MASK_AUTO_SWITCH 0x40
47 #define MASK_CEC_SWITCH 0x20
48 #define MASK_POWER 0x80
49 #define MASK_RX_SEL 0x0f
50
51 struct ep9461e_dev {
52 struct device *dev;
53 struct miscdevice miscdev;
54 struct i2c_client *client;
55 struct mutex confctl_mutex;
56 struct timer_list timer;
57 struct delayed_work work_i2c_poll;
58 bool auto_switch_en;
59 bool power_up_chip_en;
60 bool cec_switch_en;
61 bool nosignal;
62 u32 hdmi_rx_sel;
63 int err_cnt;
64 };
65
66 static struct ep9461e_dev *g_ep9461e;
67 static struct ep9461e_dev *ep9461e;
68
69 static void ep9461e_rx_select(struct ep9461e_dev *ep9461e);
70 static void ep9461e_rx_manual_select(struct ep9461e_dev *ep9461e);
71
i2c_wr(struct ep9461e_dev * ep9461e,u16 reg,u8 * val,u32 n)72 static void i2c_wr(struct ep9461e_dev *ep9461e, u16 reg, u8 *val, u32 n)
73 {
74 struct i2c_msg msg;
75 struct i2c_client *client = ep9461e->client;
76 int err;
77 u8 data[128];
78
79 data[0] = reg;
80 memcpy(&data[1], val, n);
81 msg.addr = client->addr;
82 msg.flags = 0;
83 msg.buf = data;
84 msg.len = n + 1;
85
86 err = i2c_transfer(client->adapter, &msg, 1);
87 if (err != 1) {
88 dev_err(ep9461e->dev, "writing register 0x%x from 0x%x failed\n",
89 reg, client->addr);
90 } else {
91 switch (n) {
92 case 1:
93 dev_dbg(ep9461e->dev, "I2C write 0x%02x = 0x%02x\n",
94 reg, data[1]);
95 break;
96 case 2:
97 dev_dbg(ep9461e->dev,
98 "I2C write 0x%02x = 0x%02x%02x\n",
99 reg, data[2], data[1]);
100 break;
101 case 4:
102 dev_dbg(ep9461e->dev,
103 "I2C write 0x%02x = 0x%02x%02x%02x%02x\n",
104 reg, data[4], data[3], data[2], data[1]);
105 break;
106 default:
107 dev_dbg(ep9461e->dev,
108 "I2C write %d bytes from address 0x%02x\n",
109 n, reg);
110 }
111 }
112 }
113
i2c_rd(struct ep9461e_dev * ep9461e,u16 reg,u8 * val,u32 n)114 static void i2c_rd(struct ep9461e_dev *ep9461e, u16 reg, u8 *val, u32 n)
115 {
116 struct i2c_msg msg[2];
117 struct i2c_client *client = ep9461e->client;
118 int err;
119 u8 buf[1] = { reg };
120
121 /*msg[0] addr to read*/
122 msg[0].addr = client->addr;
123 msg[0].flags = 0;
124 msg[0].buf = buf;
125 msg[0].len = 1;
126
127 /*msg[1] read data*/
128 msg[1].addr = client->addr;
129 msg[1].flags = I2C_M_RD;
130 msg[1].buf = val;
131 msg[1].len = n;
132
133 err = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
134 if (err != ARRAY_SIZE(msg)) {
135 dev_err(ep9461e->dev, "reading register 0x%x from 0x%x failed\n",
136 reg, client->addr);
137 }
138 }
139
i2c_rd8(struct ep9461e_dev * ep9461e,u16 reg,u8 * val)140 static void i2c_rd8(struct ep9461e_dev *ep9461e, u16 reg, u8 *val)
141 {
142 i2c_rd(ep9461e, reg, val, 1);
143 }
144
i2c_wr8(struct ep9461e_dev * ep9461e,u16 reg,u8 buf)145 static void i2c_wr8(struct ep9461e_dev *ep9461e, u16 reg, u8 buf)
146 {
147 i2c_wr(ep9461e, reg, &buf, 1);
148 }
149
i2c_wr8_and_or(struct ep9461e_dev * ep9461e,u16 reg,u32 mask,u32 val)150 static void i2c_wr8_and_or(struct ep9461e_dev *ep9461e, u16 reg, u32 mask,
151 u32 val)
152 {
153 u8 val_p;
154
155 i2c_rd8(ep9461e, reg, &val_p);
156 i2c_wr8(ep9461e, reg, (val_p & mask) | val);
157 }
158
ep9461e_ioctl(struct file * file,uint32_t cmd,unsigned long arg)159 static long ep9461e_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
160 {
161 return 0;
162 }
163
ep9461e_write(struct file * file,const char __user * buf,size_t size,loff_t * ppos)164 static ssize_t ep9461e_write(struct file *file, const char __user *buf,
165 size_t size, loff_t *ppos)
166 {
167 return 1;
168 }
169
ep9461e_read(struct file * file,char __user * buf,size_t size,loff_t * ppos)170 static ssize_t ep9461e_read(struct file *file, char __user *buf, size_t size,
171 loff_t *ppos)
172 {
173 return 1;
174 }
175
hdmirxsel_show(struct device * dev,struct device_attribute * attr,char * buf)176 static ssize_t hdmirxsel_show(struct device *dev,
177 struct device_attribute *attr, char *buf)
178 {
179 struct ep9461e_dev *ep9461e = g_ep9461e;
180
181 dev_info(ep9461e->dev, "%s: hdmi rx select state: %d\n",
182 __func__, ep9461e->hdmi_rx_sel);
183
184 return sprintf(buf, "%d\n", ep9461e->hdmi_rx_sel);
185 }
186
hdmirxsel_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)187 static ssize_t hdmirxsel_store(struct device *dev,
188 struct device_attribute *attr,
189 const char *buf, size_t count)
190 {
191 struct ep9461e_dev *ep9461e = g_ep9461e;
192 u32 hdmirxstate = 0;
193 int ret;
194
195 ret = kstrtouint(buf, 10, &hdmirxstate);
196 if (!ret) {
197 dev_dbg(ep9461e->dev, "state: %d\n", hdmirxstate);
198 ep9461e->hdmi_rx_sel = hdmirxstate;
199 if (ep9461e->auto_switch_en | ep9461e->cec_switch_en)
200 ep9461e->auto_switch_en = ep9461e->cec_switch_en = 0;
201 ep9461e_rx_select(ep9461e);
202 } else {
203 dev_err(ep9461e->dev, "write hdmi_rx_sel failed!!!\n");
204 }
205
206 return count;
207 }
208
hdmiautoswitch_show(struct device * dev,struct device_attribute * attr,char * buf)209 static ssize_t hdmiautoswitch_show(struct device *dev,
210 struct device_attribute *attr, char *buf)
211 {
212 struct ep9461e_dev *ep9461e = g_ep9461e;
213
214 dev_info(ep9461e->dev, "hdmi rx select auto_switch state: %d\n",
215 ep9461e->auto_switch_en);
216
217 return sprintf(buf, "%d\n", ep9461e->auto_switch_en);
218 }
219
hdmiautoswitch_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)220 static ssize_t hdmiautoswitch_store(struct device *dev,
221 struct device_attribute *attr,
222 const char *buf, size_t count)
223 {
224 struct ep9461e_dev *ep9461e = g_ep9461e;
225 u32 hdmiautoswitch = 0;
226 int ret;
227
228 ret = kstrtouint(buf, 10, &hdmiautoswitch);
229 if (!ret) {
230 dev_dbg(ep9461e->dev, "state: %d\n", hdmiautoswitch);
231 ep9461e->auto_switch_en = hdmiautoswitch;
232 ep9461e_rx_select(ep9461e);
233 } else {
234 dev_err(ep9461e->dev, "write hdmi auto switch failed!!!\n");
235 }
236
237 return count;
238 }
239
240 static DEVICE_ATTR_RW(hdmirxsel);
241 static DEVICE_ATTR_RW(hdmiautoswitch);
242
detect_rx_signal(struct ep9461e_dev * ep9461e)243 static inline bool detect_rx_signal(struct ep9461e_dev *ep9461e)
244 {
245 u8 val;
246
247 i2c_rd8(ep9461e, RX_SIGNAL_DETECT, &val);
248 if (!(val & MASK_RX0_SIGNAL))
249 return false;
250 else
251 return true;
252 }
253
ep9461e_init(struct ep9461e_dev * ep9461e)254 static void ep9461e_init(struct ep9461e_dev *ep9461e)
255 {
256 ep9461e->power_up_chip_en = false;
257 ep9461e->auto_switch_en = false;
258 ep9461e->hdmi_rx_sel = 0;
259 ep9461e->err_cnt = 0;
260
261 if (ep9461e->power_up_chip_en) {
262 i2c_wr8_and_or(ep9461e, GENERAL_CONTROL, ~MASK_POWER,
263 MASK_POWER);
264 }
265 ep9461e_rx_select(ep9461e);
266 schedule_delayed_work(&ep9461e->work_i2c_poll, msecs_to_jiffies(1000));
267 }
268
ep9461e_rx_manual_select(struct ep9461e_dev * ep9461e)269 static void ep9461e_rx_manual_select(struct ep9461e_dev *ep9461e)
270 {
271 i2c_wr8(ep9461e, RX_SEL_CONTROL, ep9461e->hdmi_rx_sel);
272 }
273
ep9461e_rx_select(struct ep9461e_dev * ep9461e)274 static void ep9461e_rx_select(struct ep9461e_dev *ep9461e)
275 {
276 int ret;
277
278 if (ep9461e->auto_switch_en) {
279 i2c_wr8_and_or(ep9461e, GENERAL_CONTROL, ~MASK_AUTO_SWITCH,
280 MASK_AUTO_SWITCH);
281 } else {
282 ep9461e_rx_manual_select(ep9461e);
283 }
284
285 ret = detect_rx_signal(ep9461e);
286 if (ret)
287 dev_info(ep9461e->dev, "Detect HDMI RX valid signal!\n");
288 else
289 dev_err(ep9461e->dev, "HDMI RX has no valid signal!\n");
290 }
291
292
ep9461e_work_i2c_poll(struct work_struct * work)293 static void ep9461e_work_i2c_poll(struct work_struct *work)
294 {
295 int ret;
296 struct delayed_work *dwork = to_delayed_work(work);
297 struct ep9461e_dev *ep9461e =
298 container_of(dwork, struct ep9461e_dev, work_i2c_poll);
299
300 ret = detect_rx_signal(ep9461e);
301 if (!ret && (ep9461e->err_cnt < 10)) {
302 ep9461e->err_cnt++;
303 dev_err(ep9461e->dev,
304 "ERROR: HDMI RX has no valid signal, err cnt: %d\n",
305 ep9461e->err_cnt);
306 if (ep9461e->err_cnt >= 10)
307 dev_err(ep9461e->dev,
308 "error count greater than 10, please check HDMIRX!");
309 } else if (ret) {
310 ep9461e->err_cnt = 0;
311 }
312 schedule_delayed_work(&ep9461e->work_i2c_poll, msecs_to_jiffies(1000));
313 }
314
315 static const struct file_operations ep9461e_fops = {
316 .owner = THIS_MODULE,
317 .read = ep9461e_read,
318 .write = ep9461e_write,
319 .unlocked_ioctl = ep9461e_ioctl,
320 };
321
322 struct miscdevice ep9461e_miscdev = {
323 .minor = MISC_DYNAMIC_MINOR,
324 .name = "ep9461e_dev",
325 .fops = &ep9461e_fops,
326 };
327
ep9461e_probe(struct i2c_client * client,const struct i2c_device_id * id)328 static int ep9461e_probe(struct i2c_client *client,
329 const struct i2c_device_id *id)
330 {
331 struct ep9461e_dev *ep9461e;
332 struct device *dev = &client->dev;
333 int ret;
334
335 dev_info(dev, "driver version: %02x.%02x.%02x",
336 DRIVER_VERSION >> 16,
337 (DRIVER_VERSION & 0xff00) >> 8,
338 DRIVER_VERSION & 0x00ff);
339
340 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
341 return -EIO;
342 dev_info(dev, "chip found @ 0x%x (%s)\n", client->addr << 1,
343 client->adapter->name);
344
345 ep9461e = devm_kzalloc(dev, sizeof(struct ep9461e_dev), GFP_KERNEL);
346 if (!ep9461e)
347 return -ENOMEM;
348
349 ep9461e->client = client;
350 ep9461e->dev = dev;
351 client->flags |= I2C_CLIENT_SCCB;
352
353 ret = misc_register(&ep9461e_miscdev);
354 if (ret) {
355 dev_err(ep9461e->dev,
356 "EP9461E ERROR: could not register ep9461e device\n");
357 return ret;
358 }
359
360 mutex_init(&ep9461e->confctl_mutex);
361 ret = device_create_file(ep9461e_miscdev.this_device,
362 &dev_attr_hdmirxsel);
363 if (ret) {
364 dev_err(ep9461e->dev, "failed to create attr hdmirxsel!\n");
365 goto err1;
366 }
367
368 ret = device_create_file(ep9461e_miscdev.this_device,
369 &dev_attr_hdmiautoswitch);
370 if (ret) {
371 dev_err(ep9461e->dev,
372 "failed to create attr hdmiautoswitch!\n");
373 goto err;
374 }
375
376 INIT_DELAYED_WORK(&ep9461e->work_i2c_poll, ep9461e_work_i2c_poll);
377
378 ep9461e_init(ep9461e);
379 g_ep9461e = ep9461e;
380
381 dev_info(ep9461e->dev, "%s found @ 0x%x (%s)\n",
382 client->name, client->addr << 1,
383 client->adapter->name);
384
385 return 0;
386
387 err:
388 device_remove_file(ep9461e_miscdev.this_device,
389 &dev_attr_hdmirxsel);
390 err1:
391 misc_deregister(&ep9461e_miscdev);
392 return ret;
393 }
394
ep9461e_remove(struct i2c_client * client)395 static int ep9461e_remove(struct i2c_client *client)
396 {
397 cancel_delayed_work_sync(&ep9461e->work_i2c_poll);
398 device_remove_file(ep9461e_miscdev.this_device,
399 &dev_attr_hdmirxsel);
400 device_remove_file(ep9461e_miscdev.this_device,
401 &dev_attr_hdmiautoswitch);
402 mutex_destroy(&ep9461e->confctl_mutex);
403 misc_deregister(&ep9461e_miscdev);
404
405 return 0;
406 }
407
408 static const struct of_device_id ep9461e_of_match[] = {
409 { .compatible = "semiconn,ep9461e" },
410 {}
411 };
412 MODULE_DEVICE_TABLE(of, ep9461e_of_match);
413
414 static struct i2c_driver ep9461e_driver = {
415 .probe = ep9461e_probe,
416 .remove = ep9461e_remove,
417 .driver = {
418 .owner = THIS_MODULE,
419 .name = DRIVER_NAME,
420 .of_match_table = of_match_ptr(ep9461e_of_match),
421 },
422 };
423
ep9461e_driver_init(void)424 static int __init ep9461e_driver_init(void)
425 {
426 return i2c_add_driver(&ep9461e_driver);
427 }
428
ep9461e_driver_exit(void)429 static void __exit ep9461e_driver_exit(void)
430 {
431 i2c_del_driver(&ep9461e_driver);
432 }
433
434 device_initcall_sync(ep9461e_driver_init);
435 module_exit(ep9461e_driver_exit);
436
437 MODULE_DESCRIPTION("semiconn EP9461E 4 HDMI in switch driver");
438 MODULE_AUTHOR("Jianwei Fan <jianwei.fan@rock-chips.com>");
439 MODULE_LICENSE("GPL v2");
440