xref: /linux/drivers/media/dvb-frontends/isl6423.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
1*74ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2e415c689SManu Abraham /*
3e415c689SManu Abraham 	Intersil ISL6423 SEC and LNB Power supply controller
4e415c689SManu Abraham 
5e415c689SManu Abraham 	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
6e415c689SManu Abraham 
7e415c689SManu Abraham */
8e415c689SManu Abraham 
9e415c689SManu Abraham #include <linux/delay.h>
10e415c689SManu Abraham #include <linux/errno.h>
11e415c689SManu Abraham #include <linux/init.h>
12e415c689SManu Abraham #include <linux/kernel.h>
13e415c689SManu Abraham #include <linux/module.h>
14e415c689SManu Abraham #include <linux/string.h>
15e415c689SManu Abraham #include <linux/slab.h>
16e415c689SManu Abraham 
17fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
18e415c689SManu Abraham #include "isl6423.h"
19e415c689SManu Abraham 
20e415c689SManu Abraham static unsigned int verbose;
21e415c689SManu Abraham module_param(verbose, int, 0644);
22e415c689SManu Abraham MODULE_PARM_DESC(verbose, "Set Verbosity level");
23e415c689SManu Abraham 
24e415c689SManu Abraham #define FE_ERROR				0
25e415c689SManu Abraham #define FE_NOTICE				1
26e415c689SManu Abraham #define FE_INFO					2
27e415c689SManu Abraham #define FE_DEBUG				3
28e415c689SManu Abraham #define FE_DEBUGREG				4
29e415c689SManu Abraham 
30e415c689SManu Abraham #define dprintk(__y, __z, format, arg...) do {						\
31e415c689SManu Abraham 	if (__z) {									\
32e415c689SManu Abraham 		if	((verbose > FE_ERROR) && (verbose > __y))			\
33e415c689SManu Abraham 			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
34e415c689SManu Abraham 		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
35e415c689SManu Abraham 			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
36e415c689SManu Abraham 		else if ((verbose > FE_INFO) && (verbose > __y))			\
37e415c689SManu Abraham 			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
38e415c689SManu Abraham 		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
39e415c689SManu Abraham 			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
40e415c689SManu Abraham 	} else {									\
41e415c689SManu Abraham 		if (verbose > __y)							\
42e415c689SManu Abraham 			printk(format, ##arg);						\
43e415c689SManu Abraham 	}										\
44e415c689SManu Abraham } while (0)
45e415c689SManu Abraham 
46e415c689SManu Abraham struct isl6423_dev {
47e415c689SManu Abraham 	const struct isl6423_config	*config;
48e415c689SManu Abraham 	struct i2c_adapter		*i2c;
49e415c689SManu Abraham 
50e415c689SManu Abraham 	u8 reg_3;
51e415c689SManu Abraham 	u8 reg_4;
52e415c689SManu Abraham 
53e415c689SManu Abraham 	unsigned int verbose;
54e415c689SManu Abraham };
55e415c689SManu Abraham 
56e415c689SManu Abraham static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
57e415c689SManu Abraham {
58e415c689SManu Abraham 	struct i2c_adapter *i2c = isl6423->i2c;
59e415c689SManu Abraham 	u8 addr			= isl6423->config->addr;
60e415c689SManu Abraham 	int err = 0;
61e415c689SManu Abraham 
62e415c689SManu Abraham 	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
63e415c689SManu Abraham 
6454d859ecSAndreas Regel 	dprintk(FE_DEBUG, 1, "write reg %02X", reg);
65e415c689SManu Abraham 	err = i2c_transfer(i2c, &msg, 1);
66e415c689SManu Abraham 	if (err < 0)
67e415c689SManu Abraham 		goto exit;
68e415c689SManu Abraham 	return 0;
69e415c689SManu Abraham 
70e415c689SManu Abraham exit:
71e415c689SManu Abraham 	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
72e415c689SManu Abraham 	return err;
73e415c689SManu Abraham }
74e415c689SManu Abraham 
75e415c689SManu Abraham static int isl6423_set_modulation(struct dvb_frontend *fe)
76e415c689SManu Abraham {
77e415c689SManu Abraham 	struct isl6423_dev *isl6423		= (struct isl6423_dev *) fe->sec_priv;
78e415c689SManu Abraham 	const struct isl6423_config *config	= isl6423->config;
79e415c689SManu Abraham 	int err = 0;
80e415c689SManu Abraham 	u8 reg_2 = 0;
81e415c689SManu Abraham 
82e415c689SManu Abraham 	reg_2 = 0x01 << 5;
83e415c689SManu Abraham 
84e415c689SManu Abraham 	if (config->mod_extern)
85e415c689SManu Abraham 		reg_2 |= (1 << 3);
86e415c689SManu Abraham 	else
87e415c689SManu Abraham 		reg_2 |= (1 << 4);
88e415c689SManu Abraham 
89e415c689SManu Abraham 	err = isl6423_write(isl6423, reg_2);
90e415c689SManu Abraham 	if (err < 0)
91e415c689SManu Abraham 		goto exit;
92e415c689SManu Abraham 	return 0;
93e415c689SManu Abraham 
94e415c689SManu Abraham exit:
95e415c689SManu Abraham 	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
96e415c689SManu Abraham 	return err;
97e415c689SManu Abraham }
98e415c689SManu Abraham 
99e415c689SManu Abraham static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
100e415c689SManu Abraham {
101e415c689SManu Abraham 	struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
102e415c689SManu Abraham 	u8 reg_3 = isl6423->reg_3;
103e415c689SManu Abraham 	u8 reg_4 = isl6423->reg_4;
104e415c689SManu Abraham 	int err = 0;
105e415c689SManu Abraham 
106e415c689SManu Abraham 	if (arg) {
107e415c689SManu Abraham 		/* EN = 1, VSPEN = 1, VBOT = 1 */
108e415c689SManu Abraham 		reg_4 |= (1 << 4);
109e415c689SManu Abraham 		reg_4 |= 0x1;
110e415c689SManu Abraham 		reg_3 |= (1 << 3);
111e415c689SManu Abraham 	} else {
112e415c689SManu Abraham 		/* EN = 1, VSPEN = 1, VBOT = 0 */
113e415c689SManu Abraham 		reg_4 |= (1 << 4);
114e415c689SManu Abraham 		reg_4 &= ~0x1;
115e415c689SManu Abraham 		reg_3 |= (1 << 3);
116e415c689SManu Abraham 	}
117e415c689SManu Abraham 	err = isl6423_write(isl6423, reg_3);
118e415c689SManu Abraham 	if (err < 0)
119e415c689SManu Abraham 		goto exit;
120e415c689SManu Abraham 
121e415c689SManu Abraham 	err = isl6423_write(isl6423, reg_4);
122e415c689SManu Abraham 	if (err < 0)
123e415c689SManu Abraham 		goto exit;
124e415c689SManu Abraham 
12554d859ecSAndreas Regel 	isl6423->reg_3 = reg_3;
12654d859ecSAndreas Regel 	isl6423->reg_4 = reg_4;
12754d859ecSAndreas Regel 
128e415c689SManu Abraham 	return 0;
129e415c689SManu Abraham exit:
130e415c689SManu Abraham 	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
131e415c689SManu Abraham 	return err;
132e415c689SManu Abraham }
133e415c689SManu Abraham 
134e415c689SManu Abraham 
135e415c689SManu Abraham static int isl6423_set_voltage(struct dvb_frontend *fe,
136e415c689SManu Abraham 			       enum fe_sec_voltage voltage)
137e415c689SManu Abraham {
138e415c689SManu Abraham 	struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
13954d859ecSAndreas Regel 	u8 reg_3 = isl6423->reg_3;
140e415c689SManu Abraham 	u8 reg_4 = isl6423->reg_4;
141e415c689SManu Abraham 	int err = 0;
142e415c689SManu Abraham 
143e415c689SManu Abraham 	switch (voltage) {
144e415c689SManu Abraham 	case SEC_VOLTAGE_OFF:
145e415c689SManu Abraham 		/* EN = 0 */
146e415c689SManu Abraham 		reg_4 &= ~(1 << 4);
147e415c689SManu Abraham 		break;
148e415c689SManu Abraham 
149e415c689SManu Abraham 	case SEC_VOLTAGE_13:
150e415c689SManu Abraham 		/* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
151e415c689SManu Abraham 		reg_4 |= (1 << 4);
152e415c689SManu Abraham 		reg_4 &= ~0x3;
15354d859ecSAndreas Regel 		reg_3 |= (1 << 3);
154e415c689SManu Abraham 		break;
155e415c689SManu Abraham 
156e415c689SManu Abraham 	case SEC_VOLTAGE_18:
157e415c689SManu Abraham 		/* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
158e415c689SManu Abraham 		reg_4 |= (1 << 4);
159e415c689SManu Abraham 		reg_4 |=  0x2;
160e415c689SManu Abraham 		reg_4 &= ~0x1;
16154d859ecSAndreas Regel 		reg_3 |= (1 << 3);
162e415c689SManu Abraham 		break;
163e415c689SManu Abraham 
164e415c689SManu Abraham 	default:
165e415c689SManu Abraham 		break;
166e415c689SManu Abraham 	}
16754d859ecSAndreas Regel 	err = isl6423_write(isl6423, reg_3);
16854d859ecSAndreas Regel 	if (err < 0)
16954d859ecSAndreas Regel 		goto exit;
17054d859ecSAndreas Regel 
171e415c689SManu Abraham 	err = isl6423_write(isl6423, reg_4);
172e415c689SManu Abraham 	if (err < 0)
173e415c689SManu Abraham 		goto exit;
174e415c689SManu Abraham 
17554d859ecSAndreas Regel 	isl6423->reg_3 = reg_3;
17654d859ecSAndreas Regel 	isl6423->reg_4 = reg_4;
17754d859ecSAndreas Regel 
178e415c689SManu Abraham 	return 0;
179e415c689SManu Abraham exit:
180e415c689SManu Abraham 	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
181e415c689SManu Abraham 	return err;
182e415c689SManu Abraham }
183e415c689SManu Abraham 
184e415c689SManu Abraham static int isl6423_set_current(struct dvb_frontend *fe)
185e415c689SManu Abraham {
186e415c689SManu Abraham 	struct isl6423_dev *isl6423		= (struct isl6423_dev *) fe->sec_priv;
187e415c689SManu Abraham 	u8 reg_3 = isl6423->reg_3;
188e415c689SManu Abraham 	const struct isl6423_config *config	= isl6423->config;
189e415c689SManu Abraham 	int err = 0;
190e415c689SManu Abraham 
191e415c689SManu Abraham 	switch (config->current_max) {
192e415c689SManu Abraham 	case SEC_CURRENT_275m:
193e415c689SManu Abraham 		/* 275mA */
194e415c689SManu Abraham 		/* ISELH = 0, ISELL = 0 */
195e415c689SManu Abraham 		reg_3 &= ~0x3;
196e415c689SManu Abraham 		break;
197e415c689SManu Abraham 
198e415c689SManu Abraham 	case SEC_CURRENT_515m:
199e415c689SManu Abraham 		/* 515mA */
200e415c689SManu Abraham 		/* ISELH = 0, ISELL = 1 */
201e415c689SManu Abraham 		reg_3 &= ~0x2;
202e415c689SManu Abraham 		reg_3 |=  0x1;
203e415c689SManu Abraham 		break;
204e415c689SManu Abraham 
205e415c689SManu Abraham 	case SEC_CURRENT_635m:
206e415c689SManu Abraham 		/* 635mA */
207e415c689SManu Abraham 		/* ISELH = 1, ISELL = 0 */
208e415c689SManu Abraham 		reg_3 &= ~0x1;
209e415c689SManu Abraham 		reg_3 |=  0x2;
210e415c689SManu Abraham 		break;
211e415c689SManu Abraham 
212e415c689SManu Abraham 	case SEC_CURRENT_800m:
213e415c689SManu Abraham 		/* 800mA */
214e415c689SManu Abraham 		/* ISELH = 1, ISELL = 1 */
215e415c689SManu Abraham 		reg_3 |= 0x3;
216e415c689SManu Abraham 		break;
217e415c689SManu Abraham 	}
218e415c689SManu Abraham 
219e415c689SManu Abraham 	err = isl6423_write(isl6423, reg_3);
220e415c689SManu Abraham 	if (err < 0)
221e415c689SManu Abraham 		goto exit;
222e415c689SManu Abraham 
223e415c689SManu Abraham 	switch (config->curlim) {
224e415c689SManu Abraham 	case SEC_CURRENT_LIM_ON:
22554d859ecSAndreas Regel 		/* DCL = 0 */
22654d859ecSAndreas Regel 		reg_3 &= ~0x10;
227e415c689SManu Abraham 		break;
228e415c689SManu Abraham 
229e415c689SManu Abraham 	case SEC_CURRENT_LIM_OFF:
23054d859ecSAndreas Regel 		/* DCL = 1 */
23154d859ecSAndreas Regel 		reg_3 |= 0x10;
232e415c689SManu Abraham 		break;
233e415c689SManu Abraham 	}
234e415c689SManu Abraham 
235e415c689SManu Abraham 	err = isl6423_write(isl6423, reg_3);
236e415c689SManu Abraham 	if (err < 0)
237e415c689SManu Abraham 		goto exit;
238e415c689SManu Abraham 
23954d859ecSAndreas Regel 	isl6423->reg_3 = reg_3;
24054d859ecSAndreas Regel 
241e415c689SManu Abraham 	return 0;
242e415c689SManu Abraham exit:
243e415c689SManu Abraham 	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
244e415c689SManu Abraham 	return err;
245e415c689SManu Abraham }
246e415c689SManu Abraham 
247e415c689SManu Abraham static void isl6423_release(struct dvb_frontend *fe)
248e415c689SManu Abraham {
249e415c689SManu Abraham 	isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
250e415c689SManu Abraham 
251e415c689SManu Abraham 	kfree(fe->sec_priv);
252e415c689SManu Abraham 	fe->sec_priv = NULL;
253e415c689SManu Abraham }
254e415c689SManu Abraham 
255e415c689SManu Abraham struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
256e415c689SManu Abraham 				    struct i2c_adapter *i2c,
257e415c689SManu Abraham 				    const struct isl6423_config *config)
258e415c689SManu Abraham {
259e415c689SManu Abraham 	struct isl6423_dev *isl6423;
260e415c689SManu Abraham 
261e415c689SManu Abraham 	isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
262e415c689SManu Abraham 	if (!isl6423)
263e415c689SManu Abraham 		return NULL;
264e415c689SManu Abraham 
265e415c689SManu Abraham 	isl6423->config	= config;
266e415c689SManu Abraham 	isl6423->i2c	= i2c;
267e415c689SManu Abraham 	fe->sec_priv	= isl6423;
268e415c689SManu Abraham 
26954d859ecSAndreas Regel 	/* SR3H = 0, SR3M = 1, SR3L = 0 */
27054d859ecSAndreas Regel 	isl6423->reg_3 = 0x02 << 5;
27154d859ecSAndreas Regel 	/* SR4H = 0, SR4M = 1, SR4L = 1 */
27254d859ecSAndreas Regel 	isl6423->reg_4 = 0x03 << 5;
27354d859ecSAndreas Regel 
274e415c689SManu Abraham 	if (isl6423_set_current(fe))
275e415c689SManu Abraham 		goto exit;
276e415c689SManu Abraham 
277e415c689SManu Abraham 	if (isl6423_set_modulation(fe))
278e415c689SManu Abraham 		goto exit;
279e415c689SManu Abraham 
280e415c689SManu Abraham 	fe->ops.release_sec		= isl6423_release;
281e415c689SManu Abraham 	fe->ops.set_voltage		= isl6423_set_voltage;
282e415c689SManu Abraham 	fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
283e415c689SManu Abraham 	isl6423->verbose		= verbose;
284e415c689SManu Abraham 
285e415c689SManu Abraham 	return fe;
286e415c689SManu Abraham 
287e415c689SManu Abraham exit:
288e415c689SManu Abraham 	kfree(isl6423);
289e415c689SManu Abraham 	fe->sec_priv = NULL;
290e415c689SManu Abraham 	return NULL;
291e415c689SManu Abraham }
292e415c689SManu Abraham EXPORT_SYMBOL(isl6423_attach);
293e415c689SManu Abraham 
294e415c689SManu Abraham MODULE_DESCRIPTION("ISL6423 SEC");
295e415c689SManu Abraham MODULE_AUTHOR("Manu Abraham");
296e415c689SManu Abraham MODULE_LICENSE("GPL");
297