xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/ep9461e.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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