xref: /OK3568_Linux_fs/kernel/drivers/media/pci/cx18/cx18-i2c.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  cx18 I2C functions
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Derived from ivtv-i2c.c
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
8*4882a593Smuzhiyun  *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.net>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include "cx18-driver.h"
12*4882a593Smuzhiyun #include "cx18-io.h"
13*4882a593Smuzhiyun #include "cx18-cards.h"
14*4882a593Smuzhiyun #include "cx18-gpio.h"
15*4882a593Smuzhiyun #include "cx18-i2c.h"
16*4882a593Smuzhiyun #include "cx18-irq.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #define CX18_REG_I2C_1_WR   0xf15000
19*4882a593Smuzhiyun #define CX18_REG_I2C_1_RD   0xf15008
20*4882a593Smuzhiyun #define CX18_REG_I2C_2_WR   0xf25100
21*4882a593Smuzhiyun #define CX18_REG_I2C_2_RD   0xf25108
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define SETSCL_BIT      0x0001
24*4882a593Smuzhiyun #define SETSDL_BIT      0x0002
25*4882a593Smuzhiyun #define GETSCL_BIT      0x0004
26*4882a593Smuzhiyun #define GETSDL_BIT      0x0008
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define CX18_CS5345_I2C_ADDR		0x4c
29*4882a593Smuzhiyun #define CX18_Z8F0811_IR_TX_I2C_ADDR	0x70
30*4882a593Smuzhiyun #define CX18_Z8F0811_IR_RX_I2C_ADDR	0x71
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /* This array should match the CX18_HW_ defines */
33*4882a593Smuzhiyun static const u8 hw_addrs[] = {
34*4882a593Smuzhiyun 	0,				/* CX18_HW_TUNER */
35*4882a593Smuzhiyun 	0,				/* CX18_HW_TVEEPROM */
36*4882a593Smuzhiyun 	CX18_CS5345_I2C_ADDR,		/* CX18_HW_CS5345 */
37*4882a593Smuzhiyun 	0,				/* CX18_HW_DVB */
38*4882a593Smuzhiyun 	0,				/* CX18_HW_418_AV */
39*4882a593Smuzhiyun 	0,				/* CX18_HW_GPIO_MUX */
40*4882a593Smuzhiyun 	0,				/* CX18_HW_GPIO_RESET_CTRL */
41*4882a593Smuzhiyun 	CX18_Z8F0811_IR_RX_I2C_ADDR,	/* CX18_HW_Z8F0811_IR_HAUP */
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun /* This array should match the CX18_HW_ defines */
45*4882a593Smuzhiyun /* This might well become a card-specific array */
46*4882a593Smuzhiyun static const u8 hw_bus[] = {
47*4882a593Smuzhiyun 	1,	/* CX18_HW_TUNER */
48*4882a593Smuzhiyun 	0,	/* CX18_HW_TVEEPROM */
49*4882a593Smuzhiyun 	0,	/* CX18_HW_CS5345 */
50*4882a593Smuzhiyun 	0,	/* CX18_HW_DVB */
51*4882a593Smuzhiyun 	0,	/* CX18_HW_418_AV */
52*4882a593Smuzhiyun 	0,	/* CX18_HW_GPIO_MUX */
53*4882a593Smuzhiyun 	0,	/* CX18_HW_GPIO_RESET_CTRL */
54*4882a593Smuzhiyun 	0,	/* CX18_HW_Z8F0811_IR_HAUP */
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /* This array should match the CX18_HW_ defines */
58*4882a593Smuzhiyun static const char * const hw_devicenames[] = {
59*4882a593Smuzhiyun 	"tuner",
60*4882a593Smuzhiyun 	"tveeprom",
61*4882a593Smuzhiyun 	"cs5345",
62*4882a593Smuzhiyun 	"cx23418_DTV",
63*4882a593Smuzhiyun 	"cx23418_AV",
64*4882a593Smuzhiyun 	"gpio_mux",
65*4882a593Smuzhiyun 	"gpio_reset_ctrl",
66*4882a593Smuzhiyun 	"ir_z8f0811_haup",
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun 
cx18_i2c_new_ir(struct cx18 * cx,struct i2c_adapter * adap,u32 hw,const char * type,u8 addr)69*4882a593Smuzhiyun static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
70*4882a593Smuzhiyun 			   const char *type, u8 addr)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	struct i2c_board_info info;
73*4882a593Smuzhiyun 	struct IR_i2c_init_data *init_data = &cx->ir_i2c_init_data;
74*4882a593Smuzhiyun 	unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	memset(&info, 0, sizeof(struct i2c_board_info));
77*4882a593Smuzhiyun 	strscpy(info.type, type, I2C_NAME_SIZE);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	/* Our default information for ir-kbd-i2c.c to use */
80*4882a593Smuzhiyun 	switch (hw) {
81*4882a593Smuzhiyun 	case CX18_HW_Z8F0811_IR_HAUP:
82*4882a593Smuzhiyun 		init_data->ir_codes = RC_MAP_HAUPPAUGE;
83*4882a593Smuzhiyun 		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
84*4882a593Smuzhiyun 		init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE |
85*4882a593Smuzhiyun 							RC_PROTO_BIT_RC6_6A_32;
86*4882a593Smuzhiyun 		init_data->name = cx->card_name;
87*4882a593Smuzhiyun 		info.platform_data = init_data;
88*4882a593Smuzhiyun 		break;
89*4882a593Smuzhiyun 	}
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	return IS_ERR(i2c_new_scanned_device(adap, &info, addr_list, NULL)) ?
92*4882a593Smuzhiyun 	       -1 : 0;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
cx18_i2c_register(struct cx18 * cx,unsigned idx)95*4882a593Smuzhiyun int cx18_i2c_register(struct cx18 *cx, unsigned idx)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	struct v4l2_subdev *sd;
98*4882a593Smuzhiyun 	int bus = hw_bus[idx];
99*4882a593Smuzhiyun 	struct i2c_adapter *adap = &cx->i2c_adap[bus];
100*4882a593Smuzhiyun 	const char *type = hw_devicenames[idx];
101*4882a593Smuzhiyun 	u32 hw = 1 << idx;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	if (hw == CX18_HW_TUNER) {
104*4882a593Smuzhiyun 		/* special tuner group handling */
105*4882a593Smuzhiyun 		sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
106*4882a593Smuzhiyun 				adap, type, 0, cx->card_i2c->radio);
107*4882a593Smuzhiyun 		if (sd != NULL)
108*4882a593Smuzhiyun 			sd->grp_id = hw;
109*4882a593Smuzhiyun 		sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
110*4882a593Smuzhiyun 				adap, type, 0, cx->card_i2c->demod);
111*4882a593Smuzhiyun 		if (sd != NULL)
112*4882a593Smuzhiyun 			sd->grp_id = hw;
113*4882a593Smuzhiyun 		sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
114*4882a593Smuzhiyun 				adap, type, 0, cx->card_i2c->tv);
115*4882a593Smuzhiyun 		if (sd != NULL)
116*4882a593Smuzhiyun 			sd->grp_id = hw;
117*4882a593Smuzhiyun 		return sd != NULL ? 0 : -1;
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (hw == CX18_HW_Z8F0811_IR_HAUP)
121*4882a593Smuzhiyun 		return cx18_i2c_new_ir(cx, adap, hw, type, hw_addrs[idx]);
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	/* Is it not an I2C device or one we do not wish to register? */
124*4882a593Smuzhiyun 	if (!hw_addrs[idx])
125*4882a593Smuzhiyun 		return -1;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/* It's an I2C device other than an analog tuner or IR chip */
128*4882a593Smuzhiyun 	sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx],
129*4882a593Smuzhiyun 				 NULL);
130*4882a593Smuzhiyun 	if (sd != NULL)
131*4882a593Smuzhiyun 		sd->grp_id = hw;
132*4882a593Smuzhiyun 	return sd != NULL ? 0 : -1;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun /* Find the first member of the subdev group id in hw */
cx18_find_hw(struct cx18 * cx,u32 hw)136*4882a593Smuzhiyun struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct v4l2_subdev *result = NULL;
139*4882a593Smuzhiyun 	struct v4l2_subdev *sd;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	spin_lock(&cx->v4l2_dev.lock);
142*4882a593Smuzhiyun 	v4l2_device_for_each_subdev(sd, &cx->v4l2_dev) {
143*4882a593Smuzhiyun 		if (sd->grp_id == hw) {
144*4882a593Smuzhiyun 			result = sd;
145*4882a593Smuzhiyun 			break;
146*4882a593Smuzhiyun 		}
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 	spin_unlock(&cx->v4l2_dev.lock);
149*4882a593Smuzhiyun 	return result;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
cx18_setscl(void * data,int state)152*4882a593Smuzhiyun static void cx18_setscl(void *data, int state)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
155*4882a593Smuzhiyun 	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
156*4882a593Smuzhiyun 	u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
157*4882a593Smuzhiyun 	u32 r = cx18_read_reg(cx, addr);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (state)
160*4882a593Smuzhiyun 		cx18_write_reg(cx, r | SETSCL_BIT, addr);
161*4882a593Smuzhiyun 	else
162*4882a593Smuzhiyun 		cx18_write_reg(cx, r & ~SETSCL_BIT, addr);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
cx18_setsda(void * data,int state)165*4882a593Smuzhiyun static void cx18_setsda(void *data, int state)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
168*4882a593Smuzhiyun 	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
169*4882a593Smuzhiyun 	u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
170*4882a593Smuzhiyun 	u32 r = cx18_read_reg(cx, addr);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	if (state)
173*4882a593Smuzhiyun 		cx18_write_reg(cx, r | SETSDL_BIT, addr);
174*4882a593Smuzhiyun 	else
175*4882a593Smuzhiyun 		cx18_write_reg(cx, r & ~SETSDL_BIT, addr);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
cx18_getscl(void * data)178*4882a593Smuzhiyun static int cx18_getscl(void *data)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
181*4882a593Smuzhiyun 	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
182*4882a593Smuzhiyun 	u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	return cx18_read_reg(cx, addr) & GETSCL_BIT;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
cx18_getsda(void * data)187*4882a593Smuzhiyun static int cx18_getsda(void *data)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
190*4882a593Smuzhiyun 	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
191*4882a593Smuzhiyun 	u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return cx18_read_reg(cx, addr) & GETSDL_BIT;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun /* template for i2c-bit-algo */
197*4882a593Smuzhiyun static const struct i2c_adapter cx18_i2c_adap_template = {
198*4882a593Smuzhiyun 	.name = "cx18 i2c driver",
199*4882a593Smuzhiyun 	.algo = NULL,                   /* set by i2c-algo-bit */
200*4882a593Smuzhiyun 	.algo_data = NULL,              /* filled from template */
201*4882a593Smuzhiyun 	.owner = THIS_MODULE,
202*4882a593Smuzhiyun };
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun #define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */
205*4882a593Smuzhiyun #define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun static const struct i2c_algo_bit_data cx18_i2c_algo_template = {
208*4882a593Smuzhiyun 	.setsda		= cx18_setsda,
209*4882a593Smuzhiyun 	.setscl		= cx18_setscl,
210*4882a593Smuzhiyun 	.getsda		= cx18_getsda,
211*4882a593Smuzhiyun 	.getscl		= cx18_getscl,
212*4882a593Smuzhiyun 	.udelay		= CX18_SCL_PERIOD/2,       /* 1/2 clock period in usec*/
213*4882a593Smuzhiyun 	.timeout	= CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
214*4882a593Smuzhiyun };
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun /* init + register i2c adapter */
init_cx18_i2c(struct cx18 * cx)217*4882a593Smuzhiyun int init_cx18_i2c(struct cx18 *cx)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	int i, err;
220*4882a593Smuzhiyun 	CX18_DEBUG_I2C("i2c init\n");
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	for (i = 0; i < 2; i++) {
223*4882a593Smuzhiyun 		/* Setup algorithm for adapter */
224*4882a593Smuzhiyun 		cx->i2c_algo[i] = cx18_i2c_algo_template;
225*4882a593Smuzhiyun 		cx->i2c_algo_cb_data[i].cx = cx;
226*4882a593Smuzhiyun 		cx->i2c_algo_cb_data[i].bus_index = i;
227*4882a593Smuzhiyun 		cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 		/* Setup adapter */
230*4882a593Smuzhiyun 		cx->i2c_adap[i] = cx18_i2c_adap_template;
231*4882a593Smuzhiyun 		cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
232*4882a593Smuzhiyun 		sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
233*4882a593Smuzhiyun 				" #%d-%d", cx->instance, i);
234*4882a593Smuzhiyun 		i2c_set_adapdata(&cx->i2c_adap[i], &cx->v4l2_dev);
235*4882a593Smuzhiyun 		cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev;
236*4882a593Smuzhiyun 	}
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
239*4882a593Smuzhiyun 		/* Reset/Unreset I2C hardware block */
240*4882a593Smuzhiyun 		/* Clock select 220MHz */
241*4882a593Smuzhiyun 		cx18_write_reg_expect(cx, 0x10000000, 0xc71004,
242*4882a593Smuzhiyun 					  0x00000000, 0x10001000);
243*4882a593Smuzhiyun 		/* Clock Enable */
244*4882a593Smuzhiyun 		cx18_write_reg_expect(cx, 0x10001000, 0xc71024,
245*4882a593Smuzhiyun 					  0x00001000, 0x10001000);
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 	/* courtesy of Steven Toth <stoth@hauppauge.com> */
248*4882a593Smuzhiyun 	cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
249*4882a593Smuzhiyun 	mdelay(10);
250*4882a593Smuzhiyun 	cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0);
251*4882a593Smuzhiyun 	mdelay(10);
252*4882a593Smuzhiyun 	cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
253*4882a593Smuzhiyun 	mdelay(10);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	/* Set to edge-triggered intrs. */
256*4882a593Smuzhiyun 	cx18_write_reg(cx, 0x00c00000, 0xc730c8);
257*4882a593Smuzhiyun 	/* Clear any stale intrs */
258*4882a593Smuzhiyun 	cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS,
259*4882a593Smuzhiyun 		       ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	/* Hw I2C1 Clock Freq ~100kHz */
262*4882a593Smuzhiyun 	cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);
263*4882a593Smuzhiyun 	cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
264*4882a593Smuzhiyun 	cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	/* Hw I2C2 Clock Freq ~100kHz */
267*4882a593Smuzhiyun 	cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR);
268*4882a593Smuzhiyun 	cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
269*4882a593Smuzhiyun 	cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
272*4882a593Smuzhiyun 		     core, reset, (u32) CX18_GPIO_RESET_I2C);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	err = i2c_bit_add_bus(&cx->i2c_adap[0]);
275*4882a593Smuzhiyun 	if (err)
276*4882a593Smuzhiyun 		goto err;
277*4882a593Smuzhiyun 	err = i2c_bit_add_bus(&cx->i2c_adap[1]);
278*4882a593Smuzhiyun 	if (err)
279*4882a593Smuzhiyun 		goto err_del_bus_0;
280*4882a593Smuzhiyun 	return 0;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun  err_del_bus_0:
283*4882a593Smuzhiyun 	i2c_del_adapter(&cx->i2c_adap[0]);
284*4882a593Smuzhiyun  err:
285*4882a593Smuzhiyun 	return err;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
exit_cx18_i2c(struct cx18 * cx)288*4882a593Smuzhiyun void exit_cx18_i2c(struct cx18 *cx)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	int i;
291*4882a593Smuzhiyun 	CX18_DEBUG_I2C("i2c exit\n");
292*4882a593Smuzhiyun 	cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4,
293*4882a593Smuzhiyun 							CX18_REG_I2C_1_WR);
294*4882a593Smuzhiyun 	cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4,
295*4882a593Smuzhiyun 							CX18_REG_I2C_2_WR);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	for (i = 0; i < 2; i++) {
298*4882a593Smuzhiyun 		i2c_del_adapter(&cx->i2c_adap[i]);
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun /*
303*4882a593Smuzhiyun    Hauppauge HVR1600 should have:
304*4882a593Smuzhiyun    32 cx24227
305*4882a593Smuzhiyun    98 unknown
306*4882a593Smuzhiyun    a0 eeprom
307*4882a593Smuzhiyun    c2 tuner
308*4882a593Smuzhiyun    e? zilog ir
309*4882a593Smuzhiyun    */
310