xref: /openbmc/linux/drivers/media/i2c/tvaudio.c (revision aaeb31c0)
1cb7a01acSMauro Carvalho Chehab /*
2cb7a01acSMauro Carvalho Chehab  * Driver for simple i2c audio chips.
3cb7a01acSMauro Carvalho Chehab  *
4cb7a01acSMauro Carvalho Chehab  * Copyright (c) 2000 Gerd Knorr
5cb7a01acSMauro Carvalho Chehab  * based on code by:
6cb7a01acSMauro Carvalho Chehab  *   Eric Sandeen (eric_sandeen@bigfoot.com)
7cb7a01acSMauro Carvalho Chehab  *   Steve VanDeBogart (vandebo@uclink.berkeley.edu)
8cb7a01acSMauro Carvalho Chehab  *   Greg Alexander (galexand@acm.org)
9cb7a01acSMauro Carvalho Chehab  *
106a3ca5f5SHans Verkuil  * For the TDA9875 part:
116a3ca5f5SHans Verkuil  * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source
126a3ca5f5SHans Verkuil  * and Eric Sandeen
136a3ca5f5SHans Verkuil  *
14cb7a01acSMauro Carvalho Chehab  * Copyright(c) 2005-2008 Mauro Carvalho Chehab
15cb7a01acSMauro Carvalho Chehab  *	- Some cleanups, code fixes, etc
16cb7a01acSMauro Carvalho Chehab  *	- Convert it to V4L2 API
17cb7a01acSMauro Carvalho Chehab  *
18cb7a01acSMauro Carvalho Chehab  * This code is placed under the terms of the GNU General Public License
19cb7a01acSMauro Carvalho Chehab  *
20cb7a01acSMauro Carvalho Chehab  * OPTIONS:
21cb7a01acSMauro Carvalho Chehab  *   debug - set to 1 if you'd like to see debug messages
22cb7a01acSMauro Carvalho Chehab  *
23cb7a01acSMauro Carvalho Chehab  */
24cb7a01acSMauro Carvalho Chehab 
25cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
26cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h>
27cb7a01acSMauro Carvalho Chehab #include <linux/sched.h>
28cb7a01acSMauro Carvalho Chehab #include <linux/string.h>
29cb7a01acSMauro Carvalho Chehab #include <linux/timer.h>
30cb7a01acSMauro Carvalho Chehab #include <linux/delay.h>
31cb7a01acSMauro Carvalho Chehab #include <linux/errno.h>
32cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
33cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h>
34cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
35cb7a01acSMauro Carvalho Chehab #include <linux/init.h>
36cb7a01acSMauro Carvalho Chehab #include <linux/kthread.h>
37cb7a01acSMauro Carvalho Chehab #include <linux/freezer.h>
38cb7a01acSMauro Carvalho Chehab 
39b5dcee22SMauro Carvalho Chehab #include <media/i2c/tvaudio.h>
40cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
41c9114031SHans Verkuil #include <media/v4l2-ctrls.h>
42cb7a01acSMauro Carvalho Chehab 
43cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
44cb7a01acSMauro Carvalho Chehab /* insmod args                                                            */
45cb7a01acSMauro Carvalho Chehab 
46cb7a01acSMauro Carvalho Chehab static int debug;	/* insmod parameter */
47cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0644);
48cb7a01acSMauro Carvalho Chehab 
49cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("device driver for various i2c TV sound decoder / audiomux chips");
50cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Eric Sandeen, Steve VanDeBogart, Greg Alexander, Gerd Knorr");
51cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL");
52cb7a01acSMauro Carvalho Chehab 
53cb7a01acSMauro Carvalho Chehab #define UNSET    (-1U)
54cb7a01acSMauro Carvalho Chehab 
55cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
56cb7a01acSMauro Carvalho Chehab /* our structs                                                            */
57cb7a01acSMauro Carvalho Chehab 
58cb7a01acSMauro Carvalho Chehab #define MAXREGS 256
59cb7a01acSMauro Carvalho Chehab 
60cb7a01acSMauro Carvalho Chehab struct CHIPSTATE;
61cb7a01acSMauro Carvalho Chehab typedef int  (*getvalue)(int);
62cb7a01acSMauro Carvalho Chehab typedef int  (*checkit)(struct CHIPSTATE*);
63cb7a01acSMauro Carvalho Chehab typedef int  (*initialize)(struct CHIPSTATE*);
64cb7a01acSMauro Carvalho Chehab typedef int  (*getrxsubchans)(struct CHIPSTATE *);
65cb7a01acSMauro Carvalho Chehab typedef void (*setaudmode)(struct CHIPSTATE*, int mode);
66cb7a01acSMauro Carvalho Chehab 
67cb7a01acSMauro Carvalho Chehab /* i2c command */
68cb7a01acSMauro Carvalho Chehab typedef struct AUDIOCMD {
69cb7a01acSMauro Carvalho Chehab 	int             count;             /* # of bytes to send */
70cb7a01acSMauro Carvalho Chehab 	unsigned char   bytes[MAXREGS+1];  /* addr, data, data, ... */
71cb7a01acSMauro Carvalho Chehab } audiocmd;
72cb7a01acSMauro Carvalho Chehab 
73cb7a01acSMauro Carvalho Chehab /* chip description */
74cb7a01acSMauro Carvalho Chehab struct CHIPDESC {
75cb7a01acSMauro Carvalho Chehab 	char       *name;             /* chip name         */
76cb7a01acSMauro Carvalho Chehab 	int        addr_lo, addr_hi;  /* i2c address range */
77cb7a01acSMauro Carvalho Chehab 	int        registers;         /* # of registers    */
78cb7a01acSMauro Carvalho Chehab 
79cb7a01acSMauro Carvalho Chehab 	int        *insmodopt;
80cb7a01acSMauro Carvalho Chehab 	checkit    checkit;
81cb7a01acSMauro Carvalho Chehab 	initialize initialize;
82cb7a01acSMauro Carvalho Chehab 	int        flags;
83cb7a01acSMauro Carvalho Chehab #define CHIP_HAS_VOLUME      1
84cb7a01acSMauro Carvalho Chehab #define CHIP_HAS_BASSTREBLE  2
85cb7a01acSMauro Carvalho Chehab #define CHIP_HAS_INPUTSEL    4
86cb7a01acSMauro Carvalho Chehab #define CHIP_NEED_CHECKMODE  8
87cb7a01acSMauro Carvalho Chehab 
88cb7a01acSMauro Carvalho Chehab 	/* various i2c command sequences */
89cb7a01acSMauro Carvalho Chehab 	audiocmd   init;
90cb7a01acSMauro Carvalho Chehab 
91cb7a01acSMauro Carvalho Chehab 	/* which register has which value */
92cb7a01acSMauro Carvalho Chehab 	int    leftreg, rightreg, treblereg, bassreg;
93cb7a01acSMauro Carvalho Chehab 
94a346caacSHans Verkuil 	/* initialize with (defaults to 65535/32768/32768 */
95a346caacSHans Verkuil 	int    volinit, trebleinit, bassinit;
96cb7a01acSMauro Carvalho Chehab 
97cb7a01acSMauro Carvalho Chehab 	/* functions to convert the values (v4l -> chip) */
98cb7a01acSMauro Carvalho Chehab 	getvalue volfunc, treblefunc, bassfunc;
99cb7a01acSMauro Carvalho Chehab 
100cb7a01acSMauro Carvalho Chehab 	/* get/set mode */
101cb7a01acSMauro Carvalho Chehab 	getrxsubchans	getrxsubchans;
102cb7a01acSMauro Carvalho Chehab 	setaudmode	setaudmode;
103cb7a01acSMauro Carvalho Chehab 
104cb7a01acSMauro Carvalho Chehab 	/* input switch register + values for v4l inputs */
105cb7a01acSMauro Carvalho Chehab 	int  inputreg;
106cb7a01acSMauro Carvalho Chehab 	int  inputmap[4];
107cb7a01acSMauro Carvalho Chehab 	int  inputmute;
108cb7a01acSMauro Carvalho Chehab 	int  inputmask;
109cb7a01acSMauro Carvalho Chehab };
110cb7a01acSMauro Carvalho Chehab 
111cb7a01acSMauro Carvalho Chehab /* current state of the chip */
112cb7a01acSMauro Carvalho Chehab struct CHIPSTATE {
113cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev sd;
114c9114031SHans Verkuil 	struct v4l2_ctrl_handler hdl;
115c9114031SHans Verkuil 	struct {
116c9114031SHans Verkuil 		/* volume/balance cluster */
117c9114031SHans Verkuil 		struct v4l2_ctrl *volume;
118c9114031SHans Verkuil 		struct v4l2_ctrl *balance;
119c9114031SHans Verkuil 	};
120cb7a01acSMauro Carvalho Chehab 
121cb7a01acSMauro Carvalho Chehab 	/* chip-specific description - should point to
122cb7a01acSMauro Carvalho Chehab 	   an entry at CHIPDESC table */
123cb7a01acSMauro Carvalho Chehab 	struct CHIPDESC *desc;
124cb7a01acSMauro Carvalho Chehab 
125cb7a01acSMauro Carvalho Chehab 	/* shadow register set */
126cb7a01acSMauro Carvalho Chehab 	audiocmd   shadow;
127cb7a01acSMauro Carvalho Chehab 
128cb7a01acSMauro Carvalho Chehab 	/* current settings */
129c9114031SHans Verkuil 	u16 muted;
130cb7a01acSMauro Carvalho Chehab 	int prevmode;
131cb7a01acSMauro Carvalho Chehab 	int radio;
132cb7a01acSMauro Carvalho Chehab 	int input;
133cb7a01acSMauro Carvalho Chehab 
134cb7a01acSMauro Carvalho Chehab 	/* thread */
135cb7a01acSMauro Carvalho Chehab 	struct task_struct   *thread;
136cb7a01acSMauro Carvalho Chehab 	struct timer_list    wt;
137cb7a01acSMauro Carvalho Chehab 	int		     audmode;
138cb7a01acSMauro Carvalho Chehab };
139cb7a01acSMauro Carvalho Chehab 
to_state(struct v4l2_subdev * sd)140cb7a01acSMauro Carvalho Chehab static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd)
141cb7a01acSMauro Carvalho Chehab {
142cb7a01acSMauro Carvalho Chehab 	return container_of(sd, struct CHIPSTATE, sd);
143cb7a01acSMauro Carvalho Chehab }
144cb7a01acSMauro Carvalho Chehab 
to_sd(struct v4l2_ctrl * ctrl)145c9114031SHans Verkuil static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
146c9114031SHans Verkuil {
147c9114031SHans Verkuil 	return &container_of(ctrl->handler, struct CHIPSTATE, hdl)->sd;
148c9114031SHans Verkuil }
149c9114031SHans Verkuil 
150cb7a01acSMauro Carvalho Chehab 
151cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
152cb7a01acSMauro Carvalho Chehab /* i2c I/O functions                                                      */
153cb7a01acSMauro Carvalho Chehab 
chip_write(struct CHIPSTATE * chip,int subaddr,int val)154cb7a01acSMauro Carvalho Chehab static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
155cb7a01acSMauro Carvalho Chehab {
156cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
157cb7a01acSMauro Carvalho Chehab 	struct i2c_client *c = v4l2_get_subdevdata(sd);
158cb7a01acSMauro Carvalho Chehab 	unsigned char buffer[2];
159b0121ca0SMauro Carvalho Chehab 	int rc;
160cb7a01acSMauro Carvalho Chehab 
161cb7a01acSMauro Carvalho Chehab 	if (subaddr < 0) {
162cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd, "chip_write: 0x%x\n", val);
163cb7a01acSMauro Carvalho Chehab 		chip->shadow.bytes[1] = val;
164cb7a01acSMauro Carvalho Chehab 		buffer[0] = val;
165b0121ca0SMauro Carvalho Chehab 		rc = i2c_master_send(c, buffer, 1);
166b0121ca0SMauro Carvalho Chehab 		if (rc != 1) {
167cb7a01acSMauro Carvalho Chehab 			v4l2_warn(sd, "I/O error (write 0x%x)\n", val);
168b0121ca0SMauro Carvalho Chehab 			if (rc < 0)
169b0121ca0SMauro Carvalho Chehab 				return rc;
170b0121ca0SMauro Carvalho Chehab 			return -EIO;
171cb7a01acSMauro Carvalho Chehab 		}
172cb7a01acSMauro Carvalho Chehab 	} else {
173cb7a01acSMauro Carvalho Chehab 		if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
174cb7a01acSMauro Carvalho Chehab 			v4l2_info(sd,
175cb7a01acSMauro Carvalho Chehab 				"Tried to access a non-existent register: %d\n",
176cb7a01acSMauro Carvalho Chehab 				subaddr);
177cb7a01acSMauro Carvalho Chehab 			return -EINVAL;
178cb7a01acSMauro Carvalho Chehab 		}
179cb7a01acSMauro Carvalho Chehab 
180cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd, "chip_write: reg%d=0x%x\n",
181cb7a01acSMauro Carvalho Chehab 			subaddr, val);
182cb7a01acSMauro Carvalho Chehab 		chip->shadow.bytes[subaddr+1] = val;
183cb7a01acSMauro Carvalho Chehab 		buffer[0] = subaddr;
184cb7a01acSMauro Carvalho Chehab 		buffer[1] = val;
185b0121ca0SMauro Carvalho Chehab 		rc = i2c_master_send(c, buffer, 2);
186b0121ca0SMauro Carvalho Chehab 		if (rc != 2) {
187cb7a01acSMauro Carvalho Chehab 			v4l2_warn(sd, "I/O error (write reg%d=0x%x)\n",
188cb7a01acSMauro Carvalho Chehab 				subaddr, val);
189b0121ca0SMauro Carvalho Chehab 			if (rc < 0)
190b0121ca0SMauro Carvalho Chehab 				return rc;
191b0121ca0SMauro Carvalho Chehab 			return -EIO;
192cb7a01acSMauro Carvalho Chehab 		}
193cb7a01acSMauro Carvalho Chehab 	}
194cb7a01acSMauro Carvalho Chehab 	return 0;
195cb7a01acSMauro Carvalho Chehab }
196cb7a01acSMauro Carvalho Chehab 
chip_write_masked(struct CHIPSTATE * chip,int subaddr,int val,int mask)197cb7a01acSMauro Carvalho Chehab static int chip_write_masked(struct CHIPSTATE *chip,
198cb7a01acSMauro Carvalho Chehab 			     int subaddr, int val, int mask)
199cb7a01acSMauro Carvalho Chehab {
200cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
201cb7a01acSMauro Carvalho Chehab 
202cb7a01acSMauro Carvalho Chehab 	if (mask != 0) {
203cb7a01acSMauro Carvalho Chehab 		if (subaddr < 0) {
204cb7a01acSMauro Carvalho Chehab 			val = (chip->shadow.bytes[1] & ~mask) | (val & mask);
205cb7a01acSMauro Carvalho Chehab 		} else {
206cb7a01acSMauro Carvalho Chehab 			if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
207cb7a01acSMauro Carvalho Chehab 				v4l2_info(sd,
208cb7a01acSMauro Carvalho Chehab 					"Tried to access a non-existent register: %d\n",
209cb7a01acSMauro Carvalho Chehab 					subaddr);
210cb7a01acSMauro Carvalho Chehab 				return -EINVAL;
211cb7a01acSMauro Carvalho Chehab 			}
212cb7a01acSMauro Carvalho Chehab 
213cb7a01acSMauro Carvalho Chehab 			val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask);
214cb7a01acSMauro Carvalho Chehab 		}
215cb7a01acSMauro Carvalho Chehab 	}
216cb7a01acSMauro Carvalho Chehab 	return chip_write(chip, subaddr, val);
217cb7a01acSMauro Carvalho Chehab }
218cb7a01acSMauro Carvalho Chehab 
chip_read(struct CHIPSTATE * chip)219cb7a01acSMauro Carvalho Chehab static int chip_read(struct CHIPSTATE *chip)
220cb7a01acSMauro Carvalho Chehab {
221cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
222cb7a01acSMauro Carvalho Chehab 	struct i2c_client *c = v4l2_get_subdevdata(sd);
223cb7a01acSMauro Carvalho Chehab 	unsigned char buffer;
224b0121ca0SMauro Carvalho Chehab 	int rc;
225cb7a01acSMauro Carvalho Chehab 
226b0121ca0SMauro Carvalho Chehab 	rc = i2c_master_recv(c, &buffer, 1);
227b0121ca0SMauro Carvalho Chehab 	if (rc != 1) {
228cb7a01acSMauro Carvalho Chehab 		v4l2_warn(sd, "I/O error (read)\n");
229b0121ca0SMauro Carvalho Chehab 		if (rc < 0)
230b0121ca0SMauro Carvalho Chehab 			return rc;
231b0121ca0SMauro Carvalho Chehab 		return -EIO;
232cb7a01acSMauro Carvalho Chehab 	}
233cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "chip_read: 0x%x\n", buffer);
234cb7a01acSMauro Carvalho Chehab 	return buffer;
235cb7a01acSMauro Carvalho Chehab }
236cb7a01acSMauro Carvalho Chehab 
chip_read2(struct CHIPSTATE * chip,int subaddr)237cb7a01acSMauro Carvalho Chehab static int chip_read2(struct CHIPSTATE *chip, int subaddr)
238cb7a01acSMauro Carvalho Chehab {
239cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
240cb7a01acSMauro Carvalho Chehab 	struct i2c_client *c = v4l2_get_subdevdata(sd);
241b0121ca0SMauro Carvalho Chehab 	int rc;
242cb7a01acSMauro Carvalho Chehab 	unsigned char write[1];
243cb7a01acSMauro Carvalho Chehab 	unsigned char read[1];
244cb7a01acSMauro Carvalho Chehab 	struct i2c_msg msgs[2] = {
245752d283aSShubhrajyoti D 		{
246752d283aSShubhrajyoti D 			.addr = c->addr,
247752d283aSShubhrajyoti D 			.len = 1,
248752d283aSShubhrajyoti D 			.buf = write
249752d283aSShubhrajyoti D 		},
250752d283aSShubhrajyoti D 		{
251752d283aSShubhrajyoti D 			.addr = c->addr,
252752d283aSShubhrajyoti D 			.flags = I2C_M_RD,
253752d283aSShubhrajyoti D 			.len = 1,
254752d283aSShubhrajyoti D 			.buf = read
255752d283aSShubhrajyoti D 		}
256cb7a01acSMauro Carvalho Chehab 	};
257cb7a01acSMauro Carvalho Chehab 
258cb7a01acSMauro Carvalho Chehab 	write[0] = subaddr;
259cb7a01acSMauro Carvalho Chehab 
260b0121ca0SMauro Carvalho Chehab 	rc = i2c_transfer(c->adapter, msgs, 2);
261b0121ca0SMauro Carvalho Chehab 	if (rc != 2) {
262cb7a01acSMauro Carvalho Chehab 		v4l2_warn(sd, "I/O error (read2)\n");
263b0121ca0SMauro Carvalho Chehab 		if (rc < 0)
264b0121ca0SMauro Carvalho Chehab 			return rc;
265b0121ca0SMauro Carvalho Chehab 		return -EIO;
266cb7a01acSMauro Carvalho Chehab 	}
267cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "chip_read2: reg%d=0x%x\n",
268cb7a01acSMauro Carvalho Chehab 		subaddr, read[0]);
269cb7a01acSMauro Carvalho Chehab 	return read[0];
270cb7a01acSMauro Carvalho Chehab }
271cb7a01acSMauro Carvalho Chehab 
chip_cmd(struct CHIPSTATE * chip,char * name,audiocmd * cmd)272cb7a01acSMauro Carvalho Chehab static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
273cb7a01acSMauro Carvalho Chehab {
274cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
275cb7a01acSMauro Carvalho Chehab 	struct i2c_client *c = v4l2_get_subdevdata(sd);
276b0121ca0SMauro Carvalho Chehab 	int i, rc;
277cb7a01acSMauro Carvalho Chehab 
278cb7a01acSMauro Carvalho Chehab 	if (0 == cmd->count)
279cb7a01acSMauro Carvalho Chehab 		return 0;
280cb7a01acSMauro Carvalho Chehab 
281cb7a01acSMauro Carvalho Chehab 	if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
282cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd,
283cb7a01acSMauro Carvalho Chehab 			 "Tried to access a non-existent register range: %d to %d\n",
284cb7a01acSMauro Carvalho Chehab 			 cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1);
285cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
286cb7a01acSMauro Carvalho Chehab 	}
287cb7a01acSMauro Carvalho Chehab 
2885a13e40bSMauro Carvalho Chehab 	/* FIXME: it seems that the shadow bytes are wrong below !*/
289cb7a01acSMauro Carvalho Chehab 
290cb7a01acSMauro Carvalho Chehab 	/* update our shadow register set; print bytes if (debug > 0) */
291cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "chip_cmd(%s): reg=%d, data:",
292cb7a01acSMauro Carvalho Chehab 		name, cmd->bytes[0]);
293cb7a01acSMauro Carvalho Chehab 	for (i = 1; i < cmd->count; i++) {
294cb7a01acSMauro Carvalho Chehab 		if (debug)
295cb7a01acSMauro Carvalho Chehab 			printk(KERN_CONT " 0x%x", cmd->bytes[i]);
296cb7a01acSMauro Carvalho Chehab 		chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i];
297cb7a01acSMauro Carvalho Chehab 	}
298cb7a01acSMauro Carvalho Chehab 	if (debug)
299cb7a01acSMauro Carvalho Chehab 		printk(KERN_CONT "\n");
300cb7a01acSMauro Carvalho Chehab 
301cb7a01acSMauro Carvalho Chehab 	/* send data to the chip */
302b0121ca0SMauro Carvalho Chehab 	rc = i2c_master_send(c, cmd->bytes, cmd->count);
303b0121ca0SMauro Carvalho Chehab 	if (rc != cmd->count) {
304cb7a01acSMauro Carvalho Chehab 		v4l2_warn(sd, "I/O error (%s)\n", name);
305b0121ca0SMauro Carvalho Chehab 		if (rc < 0)
306b0121ca0SMauro Carvalho Chehab 			return rc;
307b0121ca0SMauro Carvalho Chehab 		return -EIO;
308cb7a01acSMauro Carvalho Chehab 	}
309cb7a01acSMauro Carvalho Chehab 	return 0;
310cb7a01acSMauro Carvalho Chehab }
311cb7a01acSMauro Carvalho Chehab 
312cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
313cb7a01acSMauro Carvalho Chehab /* kernel thread for doing i2c stuff asyncronly
314cb7a01acSMauro Carvalho Chehab  *   right now it is used only to check the audio mode (mono/stereo/whatever)
315cb7a01acSMauro Carvalho Chehab  *   some time after switching to another TV channel, then turn on stereo
316cb7a01acSMauro Carvalho Chehab  *   if available, ...
317cb7a01acSMauro Carvalho Chehab  */
318cb7a01acSMauro Carvalho Chehab 
chip_thread_wake(struct timer_list * t)31960793f4dSKees Cook static void chip_thread_wake(struct timer_list *t)
320cb7a01acSMauro Carvalho Chehab {
32160793f4dSKees Cook 	struct CHIPSTATE *chip = from_timer(chip, t, wt);
322cb7a01acSMauro Carvalho Chehab 	wake_up_process(chip->thread);
323cb7a01acSMauro Carvalho Chehab }
324cb7a01acSMauro Carvalho Chehab 
chip_thread(void * data)325cb7a01acSMauro Carvalho Chehab static int chip_thread(void *data)
326cb7a01acSMauro Carvalho Chehab {
327cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip = data;
328cb7a01acSMauro Carvalho Chehab 	struct CHIPDESC  *desc = chip->desc;
329cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
330cb7a01acSMauro Carvalho Chehab 	int mode, selected;
331cb7a01acSMauro Carvalho Chehab 
332cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "thread started\n");
333cb7a01acSMauro Carvalho Chehab 	set_freezable();
334cb7a01acSMauro Carvalho Chehab 	for (;;) {
335cb7a01acSMauro Carvalho Chehab 		set_current_state(TASK_INTERRUPTIBLE);
336cb7a01acSMauro Carvalho Chehab 		if (!kthread_should_stop())
337cb7a01acSMauro Carvalho Chehab 			schedule();
338cb7a01acSMauro Carvalho Chehab 		set_current_state(TASK_RUNNING);
339cb7a01acSMauro Carvalho Chehab 		try_to_freeze();
340cb7a01acSMauro Carvalho Chehab 		if (kthread_should_stop())
341cb7a01acSMauro Carvalho Chehab 			break;
342cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd, "thread wakeup\n");
343cb7a01acSMauro Carvalho Chehab 
344cb7a01acSMauro Carvalho Chehab 		/* don't do anything for radio */
345cb7a01acSMauro Carvalho Chehab 		if (chip->radio)
346cb7a01acSMauro Carvalho Chehab 			continue;
347cb7a01acSMauro Carvalho Chehab 
348cb7a01acSMauro Carvalho Chehab 		/* have a look what's going on */
349cb7a01acSMauro Carvalho Chehab 		mode = desc->getrxsubchans(chip);
350cb7a01acSMauro Carvalho Chehab 		if (mode == chip->prevmode)
351cb7a01acSMauro Carvalho Chehab 			continue;
352cb7a01acSMauro Carvalho Chehab 
353cb7a01acSMauro Carvalho Chehab 		/* chip detected a new audio mode - set it */
354cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd, "thread checkmode\n");
355cb7a01acSMauro Carvalho Chehab 
356cb7a01acSMauro Carvalho Chehab 		chip->prevmode = mode;
357cb7a01acSMauro Carvalho Chehab 
358cb7a01acSMauro Carvalho Chehab 		selected = V4L2_TUNER_MODE_MONO;
359cb7a01acSMauro Carvalho Chehab 		switch (chip->audmode) {
360cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_MONO:
361cb7a01acSMauro Carvalho Chehab 			if (mode & V4L2_TUNER_SUB_LANG1)
362cb7a01acSMauro Carvalho Chehab 				selected = V4L2_TUNER_MODE_LANG1;
363cb7a01acSMauro Carvalho Chehab 			break;
364cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_STEREO:
365cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_LANG1:
366cb7a01acSMauro Carvalho Chehab 			if (mode & V4L2_TUNER_SUB_LANG1)
367cb7a01acSMauro Carvalho Chehab 				selected = V4L2_TUNER_MODE_LANG1;
368cb7a01acSMauro Carvalho Chehab 			else if (mode & V4L2_TUNER_SUB_STEREO)
369cb7a01acSMauro Carvalho Chehab 				selected = V4L2_TUNER_MODE_STEREO;
370cb7a01acSMauro Carvalho Chehab 			break;
371cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_LANG2:
372cb7a01acSMauro Carvalho Chehab 			if (mode & V4L2_TUNER_SUB_LANG2)
373cb7a01acSMauro Carvalho Chehab 				selected = V4L2_TUNER_MODE_LANG2;
374cb7a01acSMauro Carvalho Chehab 			else if (mode & V4L2_TUNER_SUB_STEREO)
375cb7a01acSMauro Carvalho Chehab 				selected = V4L2_TUNER_MODE_STEREO;
376cb7a01acSMauro Carvalho Chehab 			break;
377cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_LANG1_LANG2:
378cb7a01acSMauro Carvalho Chehab 			if (mode & V4L2_TUNER_SUB_LANG2)
379cb7a01acSMauro Carvalho Chehab 				selected = V4L2_TUNER_MODE_LANG1_LANG2;
380cb7a01acSMauro Carvalho Chehab 			else if (mode & V4L2_TUNER_SUB_STEREO)
381cb7a01acSMauro Carvalho Chehab 				selected = V4L2_TUNER_MODE_STEREO;
382cb7a01acSMauro Carvalho Chehab 		}
383cb7a01acSMauro Carvalho Chehab 		desc->setaudmode(chip, selected);
384cb7a01acSMauro Carvalho Chehab 
385cb7a01acSMauro Carvalho Chehab 		/* schedule next check */
386cb7a01acSMauro Carvalho Chehab 		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
387cb7a01acSMauro Carvalho Chehab 	}
388cb7a01acSMauro Carvalho Chehab 
389cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "thread exiting\n");
390cb7a01acSMauro Carvalho Chehab 	return 0;
391cb7a01acSMauro Carvalho Chehab }
392cb7a01acSMauro Carvalho Chehab 
393cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
394cb7a01acSMauro Carvalho Chehab /* audio chip descriptions - defines+functions for tda9840                */
395cb7a01acSMauro Carvalho Chehab 
396cb7a01acSMauro Carvalho Chehab #define TDA9840_SW         0x00
397cb7a01acSMauro Carvalho Chehab #define TDA9840_LVADJ      0x02
398cb7a01acSMauro Carvalho Chehab #define TDA9840_STADJ      0x03
399cb7a01acSMauro Carvalho Chehab #define TDA9840_TEST       0x04
400cb7a01acSMauro Carvalho Chehab 
401cb7a01acSMauro Carvalho Chehab #define TDA9840_MONO       0x10
402cb7a01acSMauro Carvalho Chehab #define TDA9840_STEREO     0x2a
403cb7a01acSMauro Carvalho Chehab #define TDA9840_DUALA      0x12
404cb7a01acSMauro Carvalho Chehab #define TDA9840_DUALB      0x1e
405cb7a01acSMauro Carvalho Chehab #define TDA9840_DUALAB     0x1a
406cb7a01acSMauro Carvalho Chehab #define TDA9840_DUALBA     0x16
407cb7a01acSMauro Carvalho Chehab #define TDA9840_EXTERNAL   0x7a
408cb7a01acSMauro Carvalho Chehab 
409cb7a01acSMauro Carvalho Chehab #define TDA9840_DS_DUAL    0x20 /* Dual sound identified          */
410cb7a01acSMauro Carvalho Chehab #define TDA9840_ST_STEREO  0x40 /* Stereo sound identified        */
411cb7a01acSMauro Carvalho Chehab #define TDA9840_PONRES     0x80 /* Power-on reset detected if = 1 */
412cb7a01acSMauro Carvalho Chehab 
413cb7a01acSMauro Carvalho Chehab #define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */
414cb7a01acSMauro Carvalho Chehab #define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */
415cb7a01acSMauro Carvalho Chehab 
tda9840_getrxsubchans(struct CHIPSTATE * chip)416cb7a01acSMauro Carvalho Chehab static int tda9840_getrxsubchans(struct CHIPSTATE *chip)
417cb7a01acSMauro Carvalho Chehab {
418cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
419cb7a01acSMauro Carvalho Chehab 	int val, mode;
420cb7a01acSMauro Carvalho Chehab 
421cb7a01acSMauro Carvalho Chehab 	mode = V4L2_TUNER_SUB_MONO;
422b0121ca0SMauro Carvalho Chehab 
423b0121ca0SMauro Carvalho Chehab 	val = chip_read(chip);
424b0121ca0SMauro Carvalho Chehab 	if (val < 0)
425b0121ca0SMauro Carvalho Chehab 		return mode;
426b0121ca0SMauro Carvalho Chehab 
427cb7a01acSMauro Carvalho Chehab 	if (val & TDA9840_DS_DUAL)
428cb7a01acSMauro Carvalho Chehab 		mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
429cb7a01acSMauro Carvalho Chehab 	if (val & TDA9840_ST_STEREO)
430cb7a01acSMauro Carvalho Chehab 		mode = V4L2_TUNER_SUB_STEREO;
431cb7a01acSMauro Carvalho Chehab 
432cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd,
433cb7a01acSMauro Carvalho Chehab 		"tda9840_getrxsubchans(): raw chip read: %d, return: %d\n",
434cb7a01acSMauro Carvalho Chehab 		val, mode);
435cb7a01acSMauro Carvalho Chehab 	return mode;
436cb7a01acSMauro Carvalho Chehab }
437cb7a01acSMauro Carvalho Chehab 
tda9840_setaudmode(struct CHIPSTATE * chip,int mode)438cb7a01acSMauro Carvalho Chehab static void tda9840_setaudmode(struct CHIPSTATE *chip, int mode)
439cb7a01acSMauro Carvalho Chehab {
440cb7a01acSMauro Carvalho Chehab 	int update = 1;
441cb7a01acSMauro Carvalho Chehab 	int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e;
442cb7a01acSMauro Carvalho Chehab 
443cb7a01acSMauro Carvalho Chehab 	switch (mode) {
444cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_MONO:
445cb7a01acSMauro Carvalho Chehab 		t |= TDA9840_MONO;
446cb7a01acSMauro Carvalho Chehab 		break;
447cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_STEREO:
448cb7a01acSMauro Carvalho Chehab 		t |= TDA9840_STEREO;
449cb7a01acSMauro Carvalho Chehab 		break;
450cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1:
451cb7a01acSMauro Carvalho Chehab 		t |= TDA9840_DUALA;
452cb7a01acSMauro Carvalho Chehab 		break;
453cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG2:
454cb7a01acSMauro Carvalho Chehab 		t |= TDA9840_DUALB;
455cb7a01acSMauro Carvalho Chehab 		break;
456cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1_LANG2:
457cb7a01acSMauro Carvalho Chehab 		t |= TDA9840_DUALAB;
458cb7a01acSMauro Carvalho Chehab 		break;
459cb7a01acSMauro Carvalho Chehab 	default:
460cb7a01acSMauro Carvalho Chehab 		update = 0;
461cb7a01acSMauro Carvalho Chehab 	}
462cb7a01acSMauro Carvalho Chehab 
463cb7a01acSMauro Carvalho Chehab 	if (update)
464cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9840_SW, t);
465cb7a01acSMauro Carvalho Chehab }
466cb7a01acSMauro Carvalho Chehab 
tda9840_checkit(struct CHIPSTATE * chip)467cb7a01acSMauro Carvalho Chehab static int tda9840_checkit(struct CHIPSTATE *chip)
468cb7a01acSMauro Carvalho Chehab {
469cb7a01acSMauro Carvalho Chehab 	int rc;
470b0121ca0SMauro Carvalho Chehab 
471cb7a01acSMauro Carvalho Chehab 	rc = chip_read(chip);
472b0121ca0SMauro Carvalho Chehab 	if (rc < 0)
473b0121ca0SMauro Carvalho Chehab 		return 0;
474b0121ca0SMauro Carvalho Chehab 
475b0121ca0SMauro Carvalho Chehab 
476cb7a01acSMauro Carvalho Chehab 	/* lower 5 bits should be 0 */
477cb7a01acSMauro Carvalho Chehab 	return ((rc & 0x1f) == 0) ? 1 : 0;
478cb7a01acSMauro Carvalho Chehab }
479cb7a01acSMauro Carvalho Chehab 
480cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
481cb7a01acSMauro Carvalho Chehab /* audio chip descriptions - defines+functions for tda985x                */
482cb7a01acSMauro Carvalho Chehab 
483cb7a01acSMauro Carvalho Chehab /* subaddresses for TDA9855 */
484cb7a01acSMauro Carvalho Chehab #define TDA9855_VR	0x00 /* Volume, right */
485cb7a01acSMauro Carvalho Chehab #define TDA9855_VL	0x01 /* Volume, left */
486cb7a01acSMauro Carvalho Chehab #define TDA9855_BA	0x02 /* Bass */
487cb7a01acSMauro Carvalho Chehab #define TDA9855_TR	0x03 /* Treble */
488cb7a01acSMauro Carvalho Chehab #define TDA9855_SW	0x04 /* Subwoofer - not connected on DTV2000 */
489cb7a01acSMauro Carvalho Chehab 
490cb7a01acSMauro Carvalho Chehab /* subaddresses for TDA9850 */
491cb7a01acSMauro Carvalho Chehab #define TDA9850_C4	0x04 /* Control 1 for TDA9850 */
492cb7a01acSMauro Carvalho Chehab 
493cb7a01acSMauro Carvalho Chehab /* subaddesses for both chips */
494cb7a01acSMauro Carvalho Chehab #define TDA985x_C5	0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */
495cb7a01acSMauro Carvalho Chehab #define TDA985x_C6	0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */
496cb7a01acSMauro Carvalho Chehab #define TDA985x_C7	0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */
497cb7a01acSMauro Carvalho Chehab #define TDA985x_A1	0x08 /* Alignment 1 for both chips */
498cb7a01acSMauro Carvalho Chehab #define TDA985x_A2	0x09 /* Alignment 2 for both chips */
499cb7a01acSMauro Carvalho Chehab #define TDA985x_A3	0x0a /* Alignment 3 for both chips */
500cb7a01acSMauro Carvalho Chehab 
501cb7a01acSMauro Carvalho Chehab /* Masks for bits in TDA9855 subaddresses */
502cb7a01acSMauro Carvalho Chehab /* 0x00 - VR in TDA9855 */
503cb7a01acSMauro Carvalho Chehab /* 0x01 - VL in TDA9855 */
504cb7a01acSMauro Carvalho Chehab /* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f)
505cb7a01acSMauro Carvalho Chehab  * in 1dB steps - mute is 0x27 */
506cb7a01acSMauro Carvalho Chehab 
507cb7a01acSMauro Carvalho Chehab 
508cb7a01acSMauro Carvalho Chehab /* 0x02 - BA in TDA9855 */
509cb7a01acSMauro Carvalho Chehab /* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19)
510cb7a01acSMauro Carvalho Chehab  * in .5dB steps - 0 is 0x0E */
511cb7a01acSMauro Carvalho Chehab 
512cb7a01acSMauro Carvalho Chehab 
513cb7a01acSMauro Carvalho Chehab /* 0x03 - TR in TDA9855 */
514cb7a01acSMauro Carvalho Chehab /* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb)
515cb7a01acSMauro Carvalho Chehab  * in 3dB steps - 0 is 0x7 */
516cb7a01acSMauro Carvalho Chehab 
517cb7a01acSMauro Carvalho Chehab /* Masks for bits in both chips' subaddresses */
518cb7a01acSMauro Carvalho Chehab /* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */
519cb7a01acSMauro Carvalho Chehab /* Unique to TDA9855: */
520cb7a01acSMauro Carvalho Chehab /* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf)
521cb7a01acSMauro Carvalho Chehab  * in 3dB steps - mute is 0x0 */
522cb7a01acSMauro Carvalho Chehab 
523cb7a01acSMauro Carvalho Chehab /* Unique to TDA9850: */
524cb7a01acSMauro Carvalho Chehab /* lower 4 bits control stereo noise threshold, over which stereo turns off
525cb7a01acSMauro Carvalho Chehab  * set to values of 0x00 through 0x0f for Ster1 through Ster16 */
526cb7a01acSMauro Carvalho Chehab 
527cb7a01acSMauro Carvalho Chehab 
528cb7a01acSMauro Carvalho Chehab /* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/
529cb7a01acSMauro Carvalho Chehab /* Unique to TDA9855: */
530cb7a01acSMauro Carvalho Chehab #define TDA9855_MUTE	1<<7 /* GMU, Mute at outputs */
531cb7a01acSMauro Carvalho Chehab #define TDA9855_AVL	1<<6 /* AVL, Automatic Volume Level */
532cb7a01acSMauro Carvalho Chehab #define TDA9855_LOUD	1<<5 /* Loudness, 1==off */
533cb7a01acSMauro Carvalho Chehab #define TDA9855_SUR	1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
534cb7a01acSMauro Carvalho Chehab 			     /* Bits 0 to 3 select various combinations
535cb7a01acSMauro Carvalho Chehab 			      * of line in and line out, only the
536cb7a01acSMauro Carvalho Chehab 			      * interesting ones are defined */
537cb7a01acSMauro Carvalho Chehab #define TDA9855_EXT	1<<2 /* Selects inputs LIR and LIL.  Pins 41 & 12 */
538cb7a01acSMauro Carvalho Chehab #define TDA9855_INT	0    /* Selects inputs LOR and LOL.  (internal) */
539cb7a01acSMauro Carvalho Chehab 
540cb7a01acSMauro Carvalho Chehab /* Unique to TDA9850:  */
541f8a7647dSMauro Carvalho Chehab /* lower 4 bits control SAP noise threshold, over which SAP turns off
542cb7a01acSMauro Carvalho Chehab  * set to values of 0x00 through 0x0f for SAP1 through SAP16 */
543cb7a01acSMauro Carvalho Chehab 
544cb7a01acSMauro Carvalho Chehab 
545cb7a01acSMauro Carvalho Chehab /* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
546cb7a01acSMauro Carvalho Chehab /* Common to TDA9855 and TDA9850: */
547cb7a01acSMauro Carvalho Chehab #define TDA985x_SAP	3<<6 /* Selects SAP output, mute if not received */
548cb7a01acSMauro Carvalho Chehab #define TDA985x_MONOSAP	2<<6 /* Selects Mono on left, SAP on right */
549f8a7647dSMauro Carvalho Chehab #define TDA985x_STEREO	1<<6 /* Selects Stereo output, mono if not received */
550cb7a01acSMauro Carvalho Chehab #define TDA985x_MONO	0    /* Forces Mono output */
551cb7a01acSMauro Carvalho Chehab #define TDA985x_LMU	1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
552cb7a01acSMauro Carvalho Chehab 
553cb7a01acSMauro Carvalho Chehab /* Unique to TDA9855: */
554cb7a01acSMauro Carvalho Chehab #define TDA9855_TZCM	1<<5 /* If set, don't mute till zero crossing */
555cb7a01acSMauro Carvalho Chehab #define TDA9855_VZCM	1<<4 /* If set, don't change volume till zero crossing*/
556cb7a01acSMauro Carvalho Chehab #define TDA9855_LINEAR	0    /* Linear Stereo */
557cb7a01acSMauro Carvalho Chehab #define TDA9855_PSEUDO	1    /* Pseudo Stereo */
558cb7a01acSMauro Carvalho Chehab #define TDA9855_SPAT_30	2    /* Spatial Stereo, 30% anti-phase crosstalk */
559cb7a01acSMauro Carvalho Chehab #define TDA9855_SPAT_50	3    /* Spatial Stereo, 52% anti-phase crosstalk */
560cb7a01acSMauro Carvalho Chehab #define TDA9855_E_MONO	7    /* Forced mono - mono select elseware, so useless*/
561cb7a01acSMauro Carvalho Chehab 
562cb7a01acSMauro Carvalho Chehab /* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */
563cb7a01acSMauro Carvalho Chehab /* Common to both TDA9855 and TDA9850: */
564cb7a01acSMauro Carvalho Chehab /* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF)
565cb7a01acSMauro Carvalho Chehab  * in .5dB steps -  0dB is 0x7 */
566cb7a01acSMauro Carvalho Chehab 
567cb7a01acSMauro Carvalho Chehab /* 0x08, 0x09 - A1 and A2 (read/write) */
568cb7a01acSMauro Carvalho Chehab /* Common to both TDA9855 and TDA9850: */
569cb7a01acSMauro Carvalho Chehab /* lower 5 bites are wideband and spectral expander alignment
570cb7a01acSMauro Carvalho Chehab  * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */
571cb7a01acSMauro Carvalho Chehab #define TDA985x_STP	1<<5 /* Stereo Pilot/detect (read-only) */
572cb7a01acSMauro Carvalho Chehab #define TDA985x_SAPP	1<<6 /* SAP Pilot/detect (read-only) */
573cb7a01acSMauro Carvalho Chehab #define TDA985x_STS	1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/
574cb7a01acSMauro Carvalho Chehab 
575cb7a01acSMauro Carvalho Chehab /* 0x0a - A3 */
576cb7a01acSMauro Carvalho Chehab /* Common to both TDA9855 and TDA9850: */
577cb7a01acSMauro Carvalho Chehab /* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1),
578cb7a01acSMauro Carvalho Chehab  * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */
579cb7a01acSMauro Carvalho Chehab #define TDA985x_ADJ	1<<7 /* Stereo adjust on/off (wideband and spectral */
580cb7a01acSMauro Carvalho Chehab 
tda9855_volume(int val)581cb7a01acSMauro Carvalho Chehab static int tda9855_volume(int val) { return val/0x2e8+0x27; }
tda9855_bass(int val)582cb7a01acSMauro Carvalho Chehab static int tda9855_bass(int val)   { return val/0xccc+0x06; }
tda9855_treble(int val)583cb7a01acSMauro Carvalho Chehab static int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; }
584cb7a01acSMauro Carvalho Chehab 
tda985x_getrxsubchans(struct CHIPSTATE * chip)585cb7a01acSMauro Carvalho Chehab static int  tda985x_getrxsubchans(struct CHIPSTATE *chip)
586cb7a01acSMauro Carvalho Chehab {
587cb7a01acSMauro Carvalho Chehab 	int mode, val;
588cb7a01acSMauro Carvalho Chehab 
589cb7a01acSMauro Carvalho Chehab 	/* Add mono mode regardless of SAP and stereo */
590cb7a01acSMauro Carvalho Chehab 	/* Allows forced mono */
591cb7a01acSMauro Carvalho Chehab 	mode = V4L2_TUNER_SUB_MONO;
592cb7a01acSMauro Carvalho Chehab 	val = chip_read(chip);
593b0121ca0SMauro Carvalho Chehab 	if (val < 0)
594b0121ca0SMauro Carvalho Chehab 		return mode;
595b0121ca0SMauro Carvalho Chehab 
596cb7a01acSMauro Carvalho Chehab 	if (val & TDA985x_STP)
597cb7a01acSMauro Carvalho Chehab 		mode = V4L2_TUNER_SUB_STEREO;
598cb7a01acSMauro Carvalho Chehab 	if (val & TDA985x_SAPP)
599cb7a01acSMauro Carvalho Chehab 		mode |= V4L2_TUNER_SUB_SAP;
600cb7a01acSMauro Carvalho Chehab 	return mode;
601cb7a01acSMauro Carvalho Chehab }
602cb7a01acSMauro Carvalho Chehab 
tda985x_setaudmode(struct CHIPSTATE * chip,int mode)603cb7a01acSMauro Carvalho Chehab static void tda985x_setaudmode(struct CHIPSTATE *chip, int mode)
604cb7a01acSMauro Carvalho Chehab {
605cb7a01acSMauro Carvalho Chehab 	int update = 1;
606cb7a01acSMauro Carvalho Chehab 	int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f;
607cb7a01acSMauro Carvalho Chehab 
608cb7a01acSMauro Carvalho Chehab 	switch (mode) {
609cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_MONO:
610cb7a01acSMauro Carvalho Chehab 		c6 |= TDA985x_MONO;
611cb7a01acSMauro Carvalho Chehab 		break;
612cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_STEREO:
613cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1:
614cb7a01acSMauro Carvalho Chehab 		c6 |= TDA985x_STEREO;
615cb7a01acSMauro Carvalho Chehab 		break;
616cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_SAP:
617cb7a01acSMauro Carvalho Chehab 		c6 |= TDA985x_SAP;
618cb7a01acSMauro Carvalho Chehab 		break;
619cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1_LANG2:
620cb7a01acSMauro Carvalho Chehab 		c6 |= TDA985x_MONOSAP;
621cb7a01acSMauro Carvalho Chehab 		break;
622cb7a01acSMauro Carvalho Chehab 	default:
623cb7a01acSMauro Carvalho Chehab 		update = 0;
624cb7a01acSMauro Carvalho Chehab 	}
625cb7a01acSMauro Carvalho Chehab 	if (update)
626cb7a01acSMauro Carvalho Chehab 		chip_write(chip,TDA985x_C6,c6);
627cb7a01acSMauro Carvalho Chehab }
628cb7a01acSMauro Carvalho Chehab 
629cb7a01acSMauro Carvalho Chehab 
630cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
631cb7a01acSMauro Carvalho Chehab /* audio chip descriptions - defines+functions for tda9873h               */
632cb7a01acSMauro Carvalho Chehab 
633cb7a01acSMauro Carvalho Chehab /* Subaddresses for TDA9873H */
634cb7a01acSMauro Carvalho Chehab 
635cb7a01acSMauro Carvalho Chehab #define TDA9873_SW	0x00 /* Switching                    */
636cb7a01acSMauro Carvalho Chehab #define TDA9873_AD	0x01 /* Adjust                       */
637cb7a01acSMauro Carvalho Chehab #define TDA9873_PT	0x02 /* Port                         */
638cb7a01acSMauro Carvalho Chehab 
639cb7a01acSMauro Carvalho Chehab /* Subaddress 0x00: Switching Data
640cb7a01acSMauro Carvalho Chehab  * B7..B0:
641cb7a01acSMauro Carvalho Chehab  *
642cb7a01acSMauro Carvalho Chehab  * B1, B0: Input source selection
643cb7a01acSMauro Carvalho Chehab  *  0,  0  internal
644cb7a01acSMauro Carvalho Chehab  *  1,  0  external stereo
645cb7a01acSMauro Carvalho Chehab  *  0,  1  external mono
646cb7a01acSMauro Carvalho Chehab  */
647cb7a01acSMauro Carvalho Chehab #define TDA9873_INP_MASK    3
648cb7a01acSMauro Carvalho Chehab #define TDA9873_INTERNAL    0
649cb7a01acSMauro Carvalho Chehab #define TDA9873_EXT_STEREO  2
650cb7a01acSMauro Carvalho Chehab #define TDA9873_EXT_MONO    1
651cb7a01acSMauro Carvalho Chehab 
652cb7a01acSMauro Carvalho Chehab /*    B3, B2: output signal select
653cb7a01acSMauro Carvalho Chehab  * B4    : transmission mode
654cb7a01acSMauro Carvalho Chehab  *  0, 0, 1   Mono
655cb7a01acSMauro Carvalho Chehab  *  1, 0, 0   Stereo
656cb7a01acSMauro Carvalho Chehab  *  1, 1, 1   Stereo (reversed channel)
657cb7a01acSMauro Carvalho Chehab  *  0, 0, 0   Dual AB
658cb7a01acSMauro Carvalho Chehab  *  0, 0, 1   Dual AA
659cb7a01acSMauro Carvalho Chehab  *  0, 1, 0   Dual BB
660cb7a01acSMauro Carvalho Chehab  *  0, 1, 1   Dual BA
661cb7a01acSMauro Carvalho Chehab  */
662cb7a01acSMauro Carvalho Chehab 
663cb7a01acSMauro Carvalho Chehab #define TDA9873_TR_MASK     (7 << 2)
664cb7a01acSMauro Carvalho Chehab #define TDA9873_TR_MONO     4
665cb7a01acSMauro Carvalho Chehab #define TDA9873_TR_STEREO   1 << 4
666cb7a01acSMauro Carvalho Chehab #define TDA9873_TR_REVERSE  ((1 << 3) | (1 << 2))
667cb7a01acSMauro Carvalho Chehab #define TDA9873_TR_DUALA    1 << 2
668cb7a01acSMauro Carvalho Chehab #define TDA9873_TR_DUALB    1 << 3
669cb7a01acSMauro Carvalho Chehab #define TDA9873_TR_DUALAB   0
670cb7a01acSMauro Carvalho Chehab 
671cb7a01acSMauro Carvalho Chehab /* output level controls
672cb7a01acSMauro Carvalho Chehab  * B5:  output level switch (0 = reduced gain, 1 = normal gain)
673cb7a01acSMauro Carvalho Chehab  * B6:  mute                (1 = muted)
674cb7a01acSMauro Carvalho Chehab  * B7:  auto-mute           (1 = auto-mute enabled)
675cb7a01acSMauro Carvalho Chehab  */
676cb7a01acSMauro Carvalho Chehab 
677cb7a01acSMauro Carvalho Chehab #define TDA9873_GAIN_NORMAL 1 << 5
678cb7a01acSMauro Carvalho Chehab #define TDA9873_MUTE        1 << 6
679cb7a01acSMauro Carvalho Chehab #define TDA9873_AUTOMUTE    1 << 7
680cb7a01acSMauro Carvalho Chehab 
681cb7a01acSMauro Carvalho Chehab /* Subaddress 0x01:  Adjust/standard */
682cb7a01acSMauro Carvalho Chehab 
683cb7a01acSMauro Carvalho Chehab /* Lower 4 bits (C3..C0) control stereo adjustment on R channel (-0.6 - +0.7 dB)
684cb7a01acSMauro Carvalho Chehab  * Recommended value is +0 dB
685cb7a01acSMauro Carvalho Chehab  */
686cb7a01acSMauro Carvalho Chehab 
687cb7a01acSMauro Carvalho Chehab #define	TDA9873_STEREO_ADJ	0x06 /* 0dB gain */
688cb7a01acSMauro Carvalho Chehab 
689cb7a01acSMauro Carvalho Chehab /* Bits C6..C4 control FM stantard
690cb7a01acSMauro Carvalho Chehab  * C6, C5, C4
691cb7a01acSMauro Carvalho Chehab  *  0,  0,  0   B/G (PAL FM)
692cb7a01acSMauro Carvalho Chehab  *  0,  0,  1   M
693cb7a01acSMauro Carvalho Chehab  *  0,  1,  0   D/K(1)
694cb7a01acSMauro Carvalho Chehab  *  0,  1,  1   D/K(2)
695cb7a01acSMauro Carvalho Chehab  *  1,  0,  0   D/K(3)
696cb7a01acSMauro Carvalho Chehab  *  1,  0,  1   I
697cb7a01acSMauro Carvalho Chehab  */
698cb7a01acSMauro Carvalho Chehab #define TDA9873_BG		0
699cb7a01acSMauro Carvalho Chehab #define TDA9873_M       1
700cb7a01acSMauro Carvalho Chehab #define TDA9873_DK1     2
701cb7a01acSMauro Carvalho Chehab #define TDA9873_DK2     3
702cb7a01acSMauro Carvalho Chehab #define TDA9873_DK3     4
703cb7a01acSMauro Carvalho Chehab #define TDA9873_I       5
704cb7a01acSMauro Carvalho Chehab 
705cb7a01acSMauro Carvalho Chehab /* C7 controls identification response time (1=fast/0=normal)
706cb7a01acSMauro Carvalho Chehab  */
707cb7a01acSMauro Carvalho Chehab #define TDA9873_IDR_NORM 0
708cb7a01acSMauro Carvalho Chehab #define TDA9873_IDR_FAST 1 << 7
709cb7a01acSMauro Carvalho Chehab 
710cb7a01acSMauro Carvalho Chehab 
711cb7a01acSMauro Carvalho Chehab /* Subaddress 0x02: Port data */
712cb7a01acSMauro Carvalho Chehab 
713cb7a01acSMauro Carvalho Chehab /* E1, E0   free programmable ports P1/P2
714cb7a01acSMauro Carvalho Chehab     0,  0   both ports low
715cb7a01acSMauro Carvalho Chehab     0,  1   P1 high
716cb7a01acSMauro Carvalho Chehab     1,  0   P2 high
717cb7a01acSMauro Carvalho Chehab     1,  1   both ports high
718cb7a01acSMauro Carvalho Chehab */
719cb7a01acSMauro Carvalho Chehab 
720cb7a01acSMauro Carvalho Chehab #define TDA9873_PORTS    3
721cb7a01acSMauro Carvalho Chehab 
722cb7a01acSMauro Carvalho Chehab /* E2: test port */
723cb7a01acSMauro Carvalho Chehab #define TDA9873_TST_PORT 1 << 2
724cb7a01acSMauro Carvalho Chehab 
725cb7a01acSMauro Carvalho Chehab /* E5..E3 control mono output channel (together with transmission mode bit B4)
726cb7a01acSMauro Carvalho Chehab  *
727cb7a01acSMauro Carvalho Chehab  * E5 E4 E3 B4     OUTM
728cb7a01acSMauro Carvalho Chehab  *  0  0  0  0     mono
729cb7a01acSMauro Carvalho Chehab  *  0  0  1  0     DUAL B
730cb7a01acSMauro Carvalho Chehab  *  0  1  0  1     mono (from stereo decoder)
731cb7a01acSMauro Carvalho Chehab  */
732cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_MONO   0
733cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_FMONO  0
734cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_DUALA  0
735cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_DUALB  1 << 3
736cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_ST     1 << 4
737cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_EXTM   ((1 << 4) | (1 << 3))
738cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_EXTL   1 << 5
739cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_EXTR   ((1 << 5) | (1 << 3))
740cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_EXTLR  ((1 << 5) | (1 << 4))
741cb7a01acSMauro Carvalho Chehab #define TDA9873_MOUT_MUTE   ((1 << 5) | (1 << 4) | (1 << 3))
742cb7a01acSMauro Carvalho Chehab 
743cb7a01acSMauro Carvalho Chehab /* Status bits: (chip read) */
744cb7a01acSMauro Carvalho Chehab #define TDA9873_PONR        0 /* Power-on reset detected if = 1 */
745cb7a01acSMauro Carvalho Chehab #define TDA9873_STEREO      2 /* Stereo sound is identified     */
746cb7a01acSMauro Carvalho Chehab #define TDA9873_DUAL        4 /* Dual sound is identified       */
747cb7a01acSMauro Carvalho Chehab 
tda9873_getrxsubchans(struct CHIPSTATE * chip)748cb7a01acSMauro Carvalho Chehab static int tda9873_getrxsubchans(struct CHIPSTATE *chip)
749cb7a01acSMauro Carvalho Chehab {
750cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
751cb7a01acSMauro Carvalho Chehab 	int val,mode;
752cb7a01acSMauro Carvalho Chehab 
753cb7a01acSMauro Carvalho Chehab 	mode = V4L2_TUNER_SUB_MONO;
754b0121ca0SMauro Carvalho Chehab 
755b0121ca0SMauro Carvalho Chehab 	val = chip_read(chip);
756b0121ca0SMauro Carvalho Chehab 	if (val < 0)
757b0121ca0SMauro Carvalho Chehab 		return mode;
758b0121ca0SMauro Carvalho Chehab 
759cb7a01acSMauro Carvalho Chehab 	if (val & TDA9873_STEREO)
760cb7a01acSMauro Carvalho Chehab 		mode = V4L2_TUNER_SUB_STEREO;
761cb7a01acSMauro Carvalho Chehab 	if (val & TDA9873_DUAL)
762cb7a01acSMauro Carvalho Chehab 		mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
763cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd,
764cb7a01acSMauro Carvalho Chehab 		"tda9873_getrxsubchans(): raw chip read: %d, return: %d\n",
765cb7a01acSMauro Carvalho Chehab 		val, mode);
766cb7a01acSMauro Carvalho Chehab 	return mode;
767cb7a01acSMauro Carvalho Chehab }
768cb7a01acSMauro Carvalho Chehab 
tda9873_setaudmode(struct CHIPSTATE * chip,int mode)769cb7a01acSMauro Carvalho Chehab static void tda9873_setaudmode(struct CHIPSTATE *chip, int mode)
770cb7a01acSMauro Carvalho Chehab {
771cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
772cb7a01acSMauro Carvalho Chehab 	int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK;
773cb7a01acSMauro Carvalho Chehab 	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
774cb7a01acSMauro Carvalho Chehab 
775cb7a01acSMauro Carvalho Chehab 	if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
776cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd,
777cb7a01acSMauro Carvalho Chehab 			 "tda9873_setaudmode(): external input\n");
778cb7a01acSMauro Carvalho Chehab 		return;
779cb7a01acSMauro Carvalho Chehab 	}
780cb7a01acSMauro Carvalho Chehab 
781cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd,
782cb7a01acSMauro Carvalho Chehab 		 "tda9873_setaudmode(): chip->shadow.bytes[%d] = %d\n",
783cb7a01acSMauro Carvalho Chehab 		 TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
784cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "tda9873_setaudmode(): sw_data  = %d\n",
785cb7a01acSMauro Carvalho Chehab 		 sw_data);
786cb7a01acSMauro Carvalho Chehab 
787cb7a01acSMauro Carvalho Chehab 	switch (mode) {
788cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_MONO:
789cb7a01acSMauro Carvalho Chehab 		sw_data |= TDA9873_TR_MONO;
790cb7a01acSMauro Carvalho Chehab 		break;
791cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_STEREO:
792cb7a01acSMauro Carvalho Chehab 		sw_data |= TDA9873_TR_STEREO;
793cb7a01acSMauro Carvalho Chehab 		break;
794cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1:
795cb7a01acSMauro Carvalho Chehab 		sw_data |= TDA9873_TR_DUALA;
796cb7a01acSMauro Carvalho Chehab 		break;
797cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG2:
798cb7a01acSMauro Carvalho Chehab 		sw_data |= TDA9873_TR_DUALB;
799cb7a01acSMauro Carvalho Chehab 		break;
800cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1_LANG2:
801cb7a01acSMauro Carvalho Chehab 		sw_data |= TDA9873_TR_DUALAB;
802cb7a01acSMauro Carvalho Chehab 		break;
803cb7a01acSMauro Carvalho Chehab 	default:
804cb7a01acSMauro Carvalho Chehab 		return;
805cb7a01acSMauro Carvalho Chehab 	}
806cb7a01acSMauro Carvalho Chehab 
807cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9873_SW, sw_data);
808cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd,
809cb7a01acSMauro Carvalho Chehab 		"tda9873_setaudmode(): req. mode %d; chip_write: %d\n",
810cb7a01acSMauro Carvalho Chehab 		mode, sw_data);
811cb7a01acSMauro Carvalho Chehab }
812cb7a01acSMauro Carvalho Chehab 
tda9873_checkit(struct CHIPSTATE * chip)813cb7a01acSMauro Carvalho Chehab static int tda9873_checkit(struct CHIPSTATE *chip)
814cb7a01acSMauro Carvalho Chehab {
815cb7a01acSMauro Carvalho Chehab 	int rc;
816cb7a01acSMauro Carvalho Chehab 
817b0121ca0SMauro Carvalho Chehab 	rc = chip_read2(chip, 254);
818b0121ca0SMauro Carvalho Chehab 	if (rc < 0)
819cb7a01acSMauro Carvalho Chehab 		return 0;
820cb7a01acSMauro Carvalho Chehab 	return (rc & ~0x1f) == 0x80;
821cb7a01acSMauro Carvalho Chehab }
822cb7a01acSMauro Carvalho Chehab 
823cb7a01acSMauro Carvalho Chehab 
824cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
825cb7a01acSMauro Carvalho Chehab /* audio chip description - defines+functions for tda9874h and tda9874a   */
826cb7a01acSMauro Carvalho Chehab /* Dariusz Kowalewski <darekk@automex.pl>                                 */
827cb7a01acSMauro Carvalho Chehab 
828cb7a01acSMauro Carvalho Chehab /* Subaddresses for TDA9874H and TDA9874A (slave rx) */
829cb7a01acSMauro Carvalho Chehab #define TDA9874A_AGCGR		0x00	/* AGC gain */
830cb7a01acSMauro Carvalho Chehab #define TDA9874A_GCONR		0x01	/* general config */
831cb7a01acSMauro Carvalho Chehab #define TDA9874A_MSR		0x02	/* monitor select */
832cb7a01acSMauro Carvalho Chehab #define TDA9874A_C1FRA		0x03	/* carrier 1 freq. */
833cb7a01acSMauro Carvalho Chehab #define TDA9874A_C1FRB		0x04	/* carrier 1 freq. */
834cb7a01acSMauro Carvalho Chehab #define TDA9874A_C1FRC		0x05	/* carrier 1 freq. */
835cb7a01acSMauro Carvalho Chehab #define TDA9874A_C2FRA		0x06	/* carrier 2 freq. */
836cb7a01acSMauro Carvalho Chehab #define TDA9874A_C2FRB		0x07	/* carrier 2 freq. */
837cb7a01acSMauro Carvalho Chehab #define TDA9874A_C2FRC		0x08	/* carrier 2 freq. */
838cb7a01acSMauro Carvalho Chehab #define TDA9874A_DCR		0x09	/* demodulator config */
839cb7a01acSMauro Carvalho Chehab #define TDA9874A_FMER		0x0a	/* FM de-emphasis */
840cb7a01acSMauro Carvalho Chehab #define TDA9874A_FMMR		0x0b	/* FM dematrix */
841cb7a01acSMauro Carvalho Chehab #define TDA9874A_C1OLAR		0x0c	/* ch.1 output level adj. */
842cb7a01acSMauro Carvalho Chehab #define TDA9874A_C2OLAR		0x0d	/* ch.2 output level adj. */
843cb7a01acSMauro Carvalho Chehab #define TDA9874A_NCONR		0x0e	/* NICAM config */
844cb7a01acSMauro Carvalho Chehab #define TDA9874A_NOLAR		0x0f	/* NICAM output level adj. */
845cb7a01acSMauro Carvalho Chehab #define TDA9874A_NLELR		0x10	/* NICAM lower error limit */
846cb7a01acSMauro Carvalho Chehab #define TDA9874A_NUELR		0x11	/* NICAM upper error limit */
847cb7a01acSMauro Carvalho Chehab #define TDA9874A_AMCONR		0x12	/* audio mute control */
848cb7a01acSMauro Carvalho Chehab #define TDA9874A_SDACOSR	0x13	/* stereo DAC output select */
849cb7a01acSMauro Carvalho Chehab #define TDA9874A_AOSR		0x14	/* analog output select */
850cb7a01acSMauro Carvalho Chehab #define TDA9874A_DAICONR	0x15	/* digital audio interface config */
851cb7a01acSMauro Carvalho Chehab #define TDA9874A_I2SOSR		0x16	/* I2S-bus output select */
852cb7a01acSMauro Carvalho Chehab #define TDA9874A_I2SOLAR	0x17	/* I2S-bus output level adj. */
853cb7a01acSMauro Carvalho Chehab #define TDA9874A_MDACOSR	0x18	/* mono DAC output select (tda9874a) */
854cb7a01acSMauro Carvalho Chehab #define TDA9874A_ESP		0xFF	/* easy standard progr. (tda9874a) */
855cb7a01acSMauro Carvalho Chehab 
856cb7a01acSMauro Carvalho Chehab /* Subaddresses for TDA9874H and TDA9874A (slave tx) */
857cb7a01acSMauro Carvalho Chehab #define TDA9874A_DSR		0x00	/* device status */
858cb7a01acSMauro Carvalho Chehab #define TDA9874A_NSR		0x01	/* NICAM status */
859cb7a01acSMauro Carvalho Chehab #define TDA9874A_NECR		0x02	/* NICAM error count */
860cb7a01acSMauro Carvalho Chehab #define TDA9874A_DR1		0x03	/* add. data LSB */
861cb7a01acSMauro Carvalho Chehab #define TDA9874A_DR2		0x04	/* add. data MSB */
862cb7a01acSMauro Carvalho Chehab #define TDA9874A_LLRA		0x05	/* monitor level read-out LSB */
863cb7a01acSMauro Carvalho Chehab #define TDA9874A_LLRB		0x06	/* monitor level read-out MSB */
864cb7a01acSMauro Carvalho Chehab #define TDA9874A_SIFLR		0x07	/* SIF level */
865cb7a01acSMauro Carvalho Chehab #define TDA9874A_TR2		252	/* test reg. 2 */
866cb7a01acSMauro Carvalho Chehab #define TDA9874A_TR1		253	/* test reg. 1 */
867cb7a01acSMauro Carvalho Chehab #define TDA9874A_DIC		254	/* device id. code */
868cb7a01acSMauro Carvalho Chehab #define TDA9874A_SIC		255	/* software id. code */
869cb7a01acSMauro Carvalho Chehab 
870cb7a01acSMauro Carvalho Chehab 
871cb7a01acSMauro Carvalho Chehab static int tda9874a_mode = 1;		/* 0: A2, 1: NICAM */
872cb7a01acSMauro Carvalho Chehab static int tda9874a_GCONR = 0xc0;	/* default config. input pin: SIFSEL=0 */
873cb7a01acSMauro Carvalho Chehab static int tda9874a_NCONR = 0x01;	/* default NICAM config.: AMSEL=0,AMUTE=1 */
874cb7a01acSMauro Carvalho Chehab static int tda9874a_ESP = 0x07;		/* default standard: NICAM D/K */
875cb7a01acSMauro Carvalho Chehab static int tda9874a_dic = -1;		/* device id. code */
876cb7a01acSMauro Carvalho Chehab 
877cb7a01acSMauro Carvalho Chehab /* insmod options for tda9874a */
878cb7a01acSMauro Carvalho Chehab static unsigned int tda9874a_SIF   = UNSET;
879cb7a01acSMauro Carvalho Chehab static unsigned int tda9874a_AMSEL = UNSET;
880cb7a01acSMauro Carvalho Chehab static unsigned int tda9874a_STD   = UNSET;
881cb7a01acSMauro Carvalho Chehab module_param(tda9874a_SIF, int, 0444);
882cb7a01acSMauro Carvalho Chehab module_param(tda9874a_AMSEL, int, 0444);
883cb7a01acSMauro Carvalho Chehab module_param(tda9874a_STD, int, 0444);
884cb7a01acSMauro Carvalho Chehab 
885cb7a01acSMauro Carvalho Chehab /*
886cb7a01acSMauro Carvalho Chehab  * initialization table for tda9874 decoder:
887cb7a01acSMauro Carvalho Chehab  *  - carrier 1 freq. registers (3 bytes)
888cb7a01acSMauro Carvalho Chehab  *  - carrier 2 freq. registers (3 bytes)
889cb7a01acSMauro Carvalho Chehab  *  - demudulator config register
890cb7a01acSMauro Carvalho Chehab  *  - FM de-emphasis register (slow identification mode)
891cb7a01acSMauro Carvalho Chehab  * Note: frequency registers must be written in single i2c transfer.
892cb7a01acSMauro Carvalho Chehab  */
893cb7a01acSMauro Carvalho Chehab static struct tda9874a_MODES {
894cb7a01acSMauro Carvalho Chehab 	char *name;
895cb7a01acSMauro Carvalho Chehab 	audiocmd cmd;
896cb7a01acSMauro Carvalho Chehab } tda9874a_modelist[9] = {
897cb7a01acSMauro Carvalho Chehab   {	"A2, B/G", /* default */
898cb7a01acSMauro Carvalho Chehab 	{ 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x77,0xA0,0x00, 0x00,0x00 }} },
899cb7a01acSMauro Carvalho Chehab   {	"A2, M (Korea)",
900cb7a01acSMauro Carvalho Chehab 	{ 9, { TDA9874A_C1FRA, 0x5D,0xC0,0x00, 0x62,0x6A,0xAA, 0x20,0x22 }} },
901cb7a01acSMauro Carvalho Chehab   {	"A2, D/K (1)",
902cb7a01acSMauro Carvalho Chehab 	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x82,0x60,0x00, 0x00,0x00 }} },
903cb7a01acSMauro Carvalho Chehab   {	"A2, D/K (2)",
904cb7a01acSMauro Carvalho Chehab 	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x8C,0x75,0x55, 0x00,0x00 }} },
905cb7a01acSMauro Carvalho Chehab   {	"A2, D/K (3)",
906cb7a01acSMauro Carvalho Chehab 	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x77,0xA0,0x00, 0x00,0x00 }} },
907cb7a01acSMauro Carvalho Chehab   {	"NICAM, I",
908cb7a01acSMauro Carvalho Chehab 	{ 9, { TDA9874A_C1FRA, 0x7D,0x00,0x00, 0x88,0x8A,0xAA, 0x08,0x33 }} },
909cb7a01acSMauro Carvalho Chehab   {	"NICAM, B/G",
910cb7a01acSMauro Carvalho Chehab 	{ 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x79,0xEA,0xAA, 0x08,0x33 }} },
911cb7a01acSMauro Carvalho Chehab   {	"NICAM, D/K",
912cb7a01acSMauro Carvalho Chehab 	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x08,0x33 }} },
913cb7a01acSMauro Carvalho Chehab   {	"NICAM, L",
914cb7a01acSMauro Carvalho Chehab 	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x09,0x33 }} }
915cb7a01acSMauro Carvalho Chehab };
916cb7a01acSMauro Carvalho Chehab 
tda9874a_setup(struct CHIPSTATE * chip)917cb7a01acSMauro Carvalho Chehab static int tda9874a_setup(struct CHIPSTATE *chip)
918cb7a01acSMauro Carvalho Chehab {
919cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
920cb7a01acSMauro Carvalho Chehab 
921cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9874A_AGCGR, 0x00); /* 0 dB */
922cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9874A_GCONR, tda9874a_GCONR);
923cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9874A_MSR, (tda9874a_mode) ? 0x03:0x02);
924cb7a01acSMauro Carvalho Chehab 	if(tda9874a_dic == 0x11) {
925cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_FMMR, 0x80);
926cb7a01acSMauro Carvalho Chehab 	} else { /* dic == 0x07 */
927cb7a01acSMauro Carvalho Chehab 		chip_cmd(chip,"tda9874_modelist",&tda9874a_modelist[tda9874a_STD].cmd);
928cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_FMMR, 0x00);
929cb7a01acSMauro Carvalho Chehab 	}
930cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9874A_C1OLAR, 0x00); /* 0 dB */
931cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9874A_C2OLAR, 0x00); /* 0 dB */
932cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR);
933cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9874A_NOLAR, 0x00); /* 0 dB */
934cb7a01acSMauro Carvalho Chehab 	/* Note: If signal quality is poor you may want to change NICAM */
935cb7a01acSMauro Carvalho Chehab 	/* error limit registers (NLELR and NUELR) to some greater values. */
936cb7a01acSMauro Carvalho Chehab 	/* Then the sound would remain stereo, but won't be so clear. */
937cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9874A_NLELR, 0x14); /* default */
938cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9874A_NUELR, 0x50); /* default */
939cb7a01acSMauro Carvalho Chehab 
940cb7a01acSMauro Carvalho Chehab 	if(tda9874a_dic == 0x11) {
941cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_AMCONR, 0xf9);
942cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
943cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_AOSR, 0x80);
944cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_MDACOSR, (tda9874a_mode) ? 0x82:0x80);
945cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_ESP, tda9874a_ESP);
946cb7a01acSMauro Carvalho Chehab 	} else { /* dic == 0x07 */
947cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_AMCONR, 0xfb);
948cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
949cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
950cb7a01acSMauro Carvalho Chehab 	}
951cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "tda9874a_setup(): %s [0x%02X].\n",
952cb7a01acSMauro Carvalho Chehab 		tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
953cb7a01acSMauro Carvalho Chehab 	return 1;
954cb7a01acSMauro Carvalho Chehab }
955cb7a01acSMauro Carvalho Chehab 
tda9874a_getrxsubchans(struct CHIPSTATE * chip)956cb7a01acSMauro Carvalho Chehab static int tda9874a_getrxsubchans(struct CHIPSTATE *chip)
957cb7a01acSMauro Carvalho Chehab {
958cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
959cb7a01acSMauro Carvalho Chehab 	int dsr,nsr,mode;
960cb7a01acSMauro Carvalho Chehab 	int necr; /* just for debugging */
961cb7a01acSMauro Carvalho Chehab 
962cb7a01acSMauro Carvalho Chehab 	mode = V4L2_TUNER_SUB_MONO;
963cb7a01acSMauro Carvalho Chehab 
964b0121ca0SMauro Carvalho Chehab 	dsr = chip_read2(chip, TDA9874A_DSR);
965b0121ca0SMauro Carvalho Chehab 	if (dsr < 0)
966cb7a01acSMauro Carvalho Chehab 		return mode;
967b0121ca0SMauro Carvalho Chehab 	nsr = chip_read2(chip, TDA9874A_NSR);
968b0121ca0SMauro Carvalho Chehab 	if (nsr < 0)
969cb7a01acSMauro Carvalho Chehab 		return mode;
970b0121ca0SMauro Carvalho Chehab 	necr = chip_read2(chip, TDA9874A_NECR);
971b0121ca0SMauro Carvalho Chehab 	if (necr < 0)
972cb7a01acSMauro Carvalho Chehab 		return mode;
973cb7a01acSMauro Carvalho Chehab 
974cb7a01acSMauro Carvalho Chehab 	/* need to store dsr/nsr somewhere */
975cb7a01acSMauro Carvalho Chehab 	chip->shadow.bytes[MAXREGS-2] = dsr;
976cb7a01acSMauro Carvalho Chehab 	chip->shadow.bytes[MAXREGS-1] = nsr;
977cb7a01acSMauro Carvalho Chehab 
978cb7a01acSMauro Carvalho Chehab 	if(tda9874a_mode) {
979cb7a01acSMauro Carvalho Chehab 		/* Note: DSR.RSSF and DSR.AMSTAT bits are also checked.
980cb7a01acSMauro Carvalho Chehab 		 * If NICAM auto-muting is enabled, DSR.AMSTAT=1 indicates
981cb7a01acSMauro Carvalho Chehab 		 * that sound has (temporarily) switched from NICAM to
982cb7a01acSMauro Carvalho Chehab 		 * mono FM (or AM) on 1st sound carrier due to high NICAM bit
983cb7a01acSMauro Carvalho Chehab 		 * error count. So in fact there is no stereo in this case :-(
984cb7a01acSMauro Carvalho Chehab 		 * But changing the mode to V4L2_TUNER_MODE_MONO would switch
985cb7a01acSMauro Carvalho Chehab 		 * external 4052 multiplexer in audio_hook().
986cb7a01acSMauro Carvalho Chehab 		 */
987cb7a01acSMauro Carvalho Chehab 		if(nsr & 0x02) /* NSR.S/MB=1 */
988cb7a01acSMauro Carvalho Chehab 			mode = V4L2_TUNER_SUB_STEREO;
989cb7a01acSMauro Carvalho Chehab 		if(nsr & 0x01) /* NSR.D/SB=1 */
990cb7a01acSMauro Carvalho Chehab 			mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
991cb7a01acSMauro Carvalho Chehab 	} else {
992cb7a01acSMauro Carvalho Chehab 		if(dsr & 0x02) /* DSR.IDSTE=1 */
993cb7a01acSMauro Carvalho Chehab 			mode = V4L2_TUNER_SUB_STEREO;
994cb7a01acSMauro Carvalho Chehab 		if(dsr & 0x04) /* DSR.IDDUA=1 */
995cb7a01acSMauro Carvalho Chehab 			mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
996cb7a01acSMauro Carvalho Chehab 	}
997cb7a01acSMauro Carvalho Chehab 
998cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd,
999cb7a01acSMauro Carvalho Chehab 		 "tda9874a_getrxsubchans(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
1000cb7a01acSMauro Carvalho Chehab 		 dsr, nsr, necr, mode);
1001cb7a01acSMauro Carvalho Chehab 	return mode;
1002cb7a01acSMauro Carvalho Chehab }
1003cb7a01acSMauro Carvalho Chehab 
tda9874a_setaudmode(struct CHIPSTATE * chip,int mode)1004cb7a01acSMauro Carvalho Chehab static void tda9874a_setaudmode(struct CHIPSTATE *chip, int mode)
1005cb7a01acSMauro Carvalho Chehab {
1006cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
1007cb7a01acSMauro Carvalho Chehab 
1008cb7a01acSMauro Carvalho Chehab 	/* Disable/enable NICAM auto-muting (based on DSR.RSSF status bit). */
1009cb7a01acSMauro Carvalho Chehab 	/* If auto-muting is disabled, we can hear a signal of degrading quality. */
1010cb7a01acSMauro Carvalho Chehab 	if (tda9874a_mode) {
1011cb7a01acSMauro Carvalho Chehab 		if(chip->shadow.bytes[MAXREGS-2] & 0x20) /* DSR.RSSF=1 */
1012cb7a01acSMauro Carvalho Chehab 			tda9874a_NCONR &= 0xfe; /* enable */
1013cb7a01acSMauro Carvalho Chehab 		else
1014cb7a01acSMauro Carvalho Chehab 			tda9874a_NCONR |= 0x01; /* disable */
1015cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR);
1016cb7a01acSMauro Carvalho Chehab 	}
1017cb7a01acSMauro Carvalho Chehab 
1018cb7a01acSMauro Carvalho Chehab 	/* Note: TDA9874A supports automatic FM dematrixing (FMMR register)
1019cb7a01acSMauro Carvalho Chehab 	 * and has auto-select function for audio output (AOSR register).
1020cb7a01acSMauro Carvalho Chehab 	 * Old TDA9874H doesn't support these features.
1021cb7a01acSMauro Carvalho Chehab 	 * TDA9874A also has additional mono output pin (OUTM), which
1022cb7a01acSMauro Carvalho Chehab 	 * on same (all?) tv-cards is not used, anyway (as well as MONOIN).
1023cb7a01acSMauro Carvalho Chehab 	 */
1024cb7a01acSMauro Carvalho Chehab 	if(tda9874a_dic == 0x11) {
1025cb7a01acSMauro Carvalho Chehab 		int aosr = 0x80;
1026cb7a01acSMauro Carvalho Chehab 		int mdacosr = (tda9874a_mode) ? 0x82:0x80;
1027cb7a01acSMauro Carvalho Chehab 
1028cb7a01acSMauro Carvalho Chehab 		switch(mode) {
1029cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_MONO:
1030cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_STEREO:
1031cb7a01acSMauro Carvalho Chehab 			break;
1032cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_LANG1:
1033cb7a01acSMauro Carvalho Chehab 			aosr = 0x80; /* auto-select, dual A/A */
1034cb7a01acSMauro Carvalho Chehab 			mdacosr = (tda9874a_mode) ? 0x82:0x80;
1035cb7a01acSMauro Carvalho Chehab 			break;
1036cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_LANG2:
1037cb7a01acSMauro Carvalho Chehab 			aosr = 0xa0; /* auto-select, dual B/B */
1038cb7a01acSMauro Carvalho Chehab 			mdacosr = (tda9874a_mode) ? 0x83:0x81;
1039cb7a01acSMauro Carvalho Chehab 			break;
1040cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_LANG1_LANG2:
1041cb7a01acSMauro Carvalho Chehab 			aosr = 0x00; /* always route L to L and R to R */
1042cb7a01acSMauro Carvalho Chehab 			mdacosr = (tda9874a_mode) ? 0x82:0x80;
1043cb7a01acSMauro Carvalho Chehab 			break;
1044cb7a01acSMauro Carvalho Chehab 		default:
1045cb7a01acSMauro Carvalho Chehab 			return;
1046cb7a01acSMauro Carvalho Chehab 		}
1047cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_AOSR, aosr);
1048cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_MDACOSR, mdacosr);
1049cb7a01acSMauro Carvalho Chehab 
1050cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd,
1051cb7a01acSMauro Carvalho Chehab 			"tda9874a_setaudmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
1052cb7a01acSMauro Carvalho Chehab 			mode, aosr, mdacosr);
1053cb7a01acSMauro Carvalho Chehab 
1054cb7a01acSMauro Carvalho Chehab 	} else { /* dic == 0x07 */
1055cb7a01acSMauro Carvalho Chehab 		int fmmr,aosr;
1056cb7a01acSMauro Carvalho Chehab 
1057cb7a01acSMauro Carvalho Chehab 		switch(mode) {
1058cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_MONO:
1059cb7a01acSMauro Carvalho Chehab 			fmmr = 0x00; /* mono */
1060cb7a01acSMauro Carvalho Chehab 			aosr = 0x10; /* A/A */
1061cb7a01acSMauro Carvalho Chehab 			break;
1062cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_STEREO:
1063cb7a01acSMauro Carvalho Chehab 			if(tda9874a_mode) {
1064cb7a01acSMauro Carvalho Chehab 				fmmr = 0x00;
1065cb7a01acSMauro Carvalho Chehab 				aosr = 0x00; /* handled by NICAM auto-mute */
1066cb7a01acSMauro Carvalho Chehab 			} else {
1067cb7a01acSMauro Carvalho Chehab 				fmmr = (tda9874a_ESP == 1) ? 0x05 : 0x04; /* stereo */
1068cb7a01acSMauro Carvalho Chehab 				aosr = 0x00;
1069cb7a01acSMauro Carvalho Chehab 			}
1070cb7a01acSMauro Carvalho Chehab 			break;
1071cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_LANG1:
1072cb7a01acSMauro Carvalho Chehab 			fmmr = 0x02; /* dual */
1073cb7a01acSMauro Carvalho Chehab 			aosr = 0x10; /* dual A/A */
1074cb7a01acSMauro Carvalho Chehab 			break;
1075cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_LANG2:
1076cb7a01acSMauro Carvalho Chehab 			fmmr = 0x02; /* dual */
1077cb7a01acSMauro Carvalho Chehab 			aosr = 0x20; /* dual B/B */
1078cb7a01acSMauro Carvalho Chehab 			break;
1079cb7a01acSMauro Carvalho Chehab 		case V4L2_TUNER_MODE_LANG1_LANG2:
1080cb7a01acSMauro Carvalho Chehab 			fmmr = 0x02; /* dual */
1081cb7a01acSMauro Carvalho Chehab 			aosr = 0x00; /* dual A/B */
1082cb7a01acSMauro Carvalho Chehab 			break;
1083cb7a01acSMauro Carvalho Chehab 		default:
1084cb7a01acSMauro Carvalho Chehab 			return;
1085cb7a01acSMauro Carvalho Chehab 		}
1086cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_FMMR, fmmr);
1087cb7a01acSMauro Carvalho Chehab 		chip_write(chip, TDA9874A_AOSR, aosr);
1088cb7a01acSMauro Carvalho Chehab 
1089cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd,
1090cb7a01acSMauro Carvalho Chehab 			"tda9874a_setaudmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
1091cb7a01acSMauro Carvalho Chehab 			mode, fmmr, aosr);
1092cb7a01acSMauro Carvalho Chehab 	}
1093cb7a01acSMauro Carvalho Chehab }
1094cb7a01acSMauro Carvalho Chehab 
tda9874a_checkit(struct CHIPSTATE * chip)1095cb7a01acSMauro Carvalho Chehab static int tda9874a_checkit(struct CHIPSTATE *chip)
1096cb7a01acSMauro Carvalho Chehab {
1097cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
1098cb7a01acSMauro Carvalho Chehab 	int dic,sic;	/* device id. and software id. codes */
1099cb7a01acSMauro Carvalho Chehab 
1100b0121ca0SMauro Carvalho Chehab 	dic = chip_read2(chip, TDA9874A_DIC);
1101b0121ca0SMauro Carvalho Chehab 	if (dic < 0)
1102cb7a01acSMauro Carvalho Chehab 		return 0;
1103b0121ca0SMauro Carvalho Chehab 	sic = chip_read2(chip, TDA9874A_SIC);
1104b0121ca0SMauro Carvalho Chehab 	if (sic < 0)
1105cb7a01acSMauro Carvalho Chehab 		return 0;
1106cb7a01acSMauro Carvalho Chehab 
1107cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
1108cb7a01acSMauro Carvalho Chehab 
1109cb7a01acSMauro Carvalho Chehab 	if((dic == 0x11)||(dic == 0x07)) {
1110cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "found tda9874%s.\n", (dic == 0x11) ? "a" : "h");
1111cb7a01acSMauro Carvalho Chehab 		tda9874a_dic = dic;	/* remember device id. */
1112cb7a01acSMauro Carvalho Chehab 		return 1;
1113cb7a01acSMauro Carvalho Chehab 	}
1114cb7a01acSMauro Carvalho Chehab 	return 0;	/* not found */
1115cb7a01acSMauro Carvalho Chehab }
1116cb7a01acSMauro Carvalho Chehab 
tda9874a_initialize(struct CHIPSTATE * chip)1117cb7a01acSMauro Carvalho Chehab static int tda9874a_initialize(struct CHIPSTATE *chip)
1118cb7a01acSMauro Carvalho Chehab {
1119cb7a01acSMauro Carvalho Chehab 	if (tda9874a_SIF > 2)
1120cb7a01acSMauro Carvalho Chehab 		tda9874a_SIF = 1;
1121cb7a01acSMauro Carvalho Chehab 	if (tda9874a_STD >= ARRAY_SIZE(tda9874a_modelist))
1122cb7a01acSMauro Carvalho Chehab 		tda9874a_STD = 0;
1123cb7a01acSMauro Carvalho Chehab 	if(tda9874a_AMSEL > 1)
1124cb7a01acSMauro Carvalho Chehab 		tda9874a_AMSEL = 0;
1125cb7a01acSMauro Carvalho Chehab 
1126cb7a01acSMauro Carvalho Chehab 	if(tda9874a_SIF == 1)
1127cb7a01acSMauro Carvalho Chehab 		tda9874a_GCONR = 0xc0;	/* sound IF input 1 */
1128cb7a01acSMauro Carvalho Chehab 	else
1129cb7a01acSMauro Carvalho Chehab 		tda9874a_GCONR = 0xc1;	/* sound IF input 2 */
1130cb7a01acSMauro Carvalho Chehab 
1131cb7a01acSMauro Carvalho Chehab 	tda9874a_ESP = tda9874a_STD;
1132cb7a01acSMauro Carvalho Chehab 	tda9874a_mode = (tda9874a_STD < 5) ? 0 : 1;
1133cb7a01acSMauro Carvalho Chehab 
1134cb7a01acSMauro Carvalho Chehab 	if(tda9874a_AMSEL == 0)
1135cb7a01acSMauro Carvalho Chehab 		tda9874a_NCONR = 0x01; /* auto-mute: analog mono input */
1136cb7a01acSMauro Carvalho Chehab 	else
1137cb7a01acSMauro Carvalho Chehab 		tda9874a_NCONR = 0x05; /* auto-mute: 1st carrier FM or AM */
1138cb7a01acSMauro Carvalho Chehab 
1139cb7a01acSMauro Carvalho Chehab 	tda9874a_setup(chip);
1140cb7a01acSMauro Carvalho Chehab 	return 0;
1141cb7a01acSMauro Carvalho Chehab }
1142cb7a01acSMauro Carvalho Chehab 
1143cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
1144cb7a01acSMauro Carvalho Chehab /* audio chip description - defines+functions for tda9875                 */
1145cb7a01acSMauro Carvalho Chehab /* The TDA9875 is made by Philips Semiconductor
1146cb7a01acSMauro Carvalho Chehab  * http://www.semiconductors.philips.com
1147cb7a01acSMauro Carvalho Chehab  * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator
1148cb7a01acSMauro Carvalho Chehab  *
1149cb7a01acSMauro Carvalho Chehab  */
1150cb7a01acSMauro Carvalho Chehab 
1151cb7a01acSMauro Carvalho Chehab /* subaddresses for TDA9875 */
1152cb7a01acSMauro Carvalho Chehab #define TDA9875_MUT         0x12  /*General mute  (value --> 0b11001100*/
1153cb7a01acSMauro Carvalho Chehab #define TDA9875_CFG         0x01  /* Config register (value --> 0b00000000 */
1154cb7a01acSMauro Carvalho Chehab #define TDA9875_DACOS       0x13  /*DAC i/o select (ADC) 0b0000100*/
1155cb7a01acSMauro Carvalho Chehab #define TDA9875_LOSR        0x16  /*Line output select regirter 0b0100 0001*/
1156cb7a01acSMauro Carvalho Chehab 
1157cb7a01acSMauro Carvalho Chehab #define TDA9875_CH1V        0x0c  /*Channel 1 volume (mute)*/
1158cb7a01acSMauro Carvalho Chehab #define TDA9875_CH2V        0x0d  /*Channel 2 volume (mute)*/
1159cb7a01acSMauro Carvalho Chehab #define TDA9875_SC1         0x14  /*SCART 1 in (mono)*/
1160cb7a01acSMauro Carvalho Chehab #define TDA9875_SC2         0x15  /*SCART 2 in (mono)*/
1161cb7a01acSMauro Carvalho Chehab 
1162cb7a01acSMauro Carvalho Chehab #define TDA9875_ADCIS       0x17  /*ADC input select (mono) 0b0110 000*/
1163cb7a01acSMauro Carvalho Chehab #define TDA9875_AER         0x19  /*Audio effect (AVL+Pseudo) 0b0000 0110*/
1164cb7a01acSMauro Carvalho Chehab #define TDA9875_MCS         0x18  /*Main channel select (DAC) 0b0000100*/
1165cb7a01acSMauro Carvalho Chehab #define TDA9875_MVL         0x1a  /* Main volume gauche */
1166cb7a01acSMauro Carvalho Chehab #define TDA9875_MVR         0x1b  /* Main volume droite */
1167cb7a01acSMauro Carvalho Chehab #define TDA9875_MBA         0x1d  /* Main Basse */
1168cb7a01acSMauro Carvalho Chehab #define TDA9875_MTR         0x1e  /* Main treble */
1169cb7a01acSMauro Carvalho Chehab #define TDA9875_ACS         0x1f  /* Auxiliary channel select (FM) 0b0000000*/
1170cb7a01acSMauro Carvalho Chehab #define TDA9875_AVL         0x20  /* Auxiliary volume gauche */
1171cb7a01acSMauro Carvalho Chehab #define TDA9875_AVR         0x21  /* Auxiliary volume droite */
1172cb7a01acSMauro Carvalho Chehab #define TDA9875_ABA         0x22  /* Auxiliary Basse */
1173cb7a01acSMauro Carvalho Chehab #define TDA9875_ATR         0x23  /* Auxiliary treble */
1174cb7a01acSMauro Carvalho Chehab 
1175cb7a01acSMauro Carvalho Chehab #define TDA9875_MSR         0x02  /* Monitor select register */
1176cb7a01acSMauro Carvalho Chehab #define TDA9875_C1MSB       0x03  /* Carrier 1 (FM) frequency register MSB */
1177cb7a01acSMauro Carvalho Chehab #define TDA9875_C1MIB       0x04  /* Carrier 1 (FM) frequency register (16-8]b */
1178cb7a01acSMauro Carvalho Chehab #define TDA9875_C1LSB       0x05  /* Carrier 1 (FM) frequency register LSB */
1179cb7a01acSMauro Carvalho Chehab #define TDA9875_C2MSB       0x06  /* Carrier 2 (nicam) frequency register MSB */
1180cb7a01acSMauro Carvalho Chehab #define TDA9875_C2MIB       0x07  /* Carrier 2 (nicam) frequency register (16-8]b */
1181cb7a01acSMauro Carvalho Chehab #define TDA9875_C2LSB       0x08  /* Carrier 2 (nicam) frequency register LSB */
1182cb7a01acSMauro Carvalho Chehab #define TDA9875_DCR         0x09  /* Demodulateur configuration regirter*/
1183cb7a01acSMauro Carvalho Chehab #define TDA9875_DEEM        0x0a  /* FM de-emphasis regirter*/
1184cb7a01acSMauro Carvalho Chehab #define TDA9875_FMAT        0x0b  /* FM Matrix regirter*/
1185cb7a01acSMauro Carvalho Chehab 
1186cb7a01acSMauro Carvalho Chehab /* values */
1187cb7a01acSMauro Carvalho Chehab #define TDA9875_MUTE_ON	    0xff /* general mute */
1188cb7a01acSMauro Carvalho Chehab #define TDA9875_MUTE_OFF    0xcc /* general no mute */
1189cb7a01acSMauro Carvalho Chehab 
tda9875_initialize(struct CHIPSTATE * chip)1190cb7a01acSMauro Carvalho Chehab static int tda9875_initialize(struct CHIPSTATE *chip)
1191cb7a01acSMauro Carvalho Chehab {
1192cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
1193cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_MSR, 0x03);    /* Monitor 0b00000XXX*/
1194cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_C1MSB, 0x00);  /*Car1(FM) MSB XMHz*/
1195cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_C1MIB, 0x00);  /*Car1(FM) MIB XMHz*/
1196cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_C1LSB, 0x00);  /*Car1(FM) LSB XMHz*/
1197cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_C2MSB, 0x00);  /*Car2(NICAM) MSB XMHz*/
1198cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_C2MIB, 0x00);  /*Car2(NICAM) MIB XMHz*/
1199cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_C2LSB, 0x00);  /*Car2(NICAM) LSB XMHz*/
1200cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_DCR, 0x00);    /*Demod config 0x00*/
1201cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_DEEM, 0x44);   /*DE-Emph 0b0100 0100*/
1202cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_FMAT, 0x00);   /*FM Matrix reg 0x00*/
1203cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_SC1, 0x00);    /* SCART 1 (SC1)*/
1204cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_SC2, 0x01);    /* SCART 2 (sc2)*/
1205cb7a01acSMauro Carvalho Chehab 
1206cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_CH1V, 0x10);  /* Channel volume 1 mute*/
1207cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_CH2V, 0x10);  /* Channel volume 2 mute */
1208cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/
1209cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/
1210cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_LOSR, 0x00);  /* line out (in:mono)*/
1211cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_AER, 0x00);   /*06 Effect (AVL+PSEUDO) */
1212cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_MCS, 0x44);   /* Main ch select (DAC) */
1213cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_MVL, 0x03);   /* Vol Main left 10dB */
1214cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_MVR, 0x03);   /* Vol Main right 10dB*/
1215cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_MBA, 0x00);   /* Main Bass Main 0dB*/
1216cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_MTR, 0x00);   /* Main Treble Main 0dB*/
1217cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_ACS, 0x44);   /* Aux chan select (dac)*/
1218cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_AVL, 0x00);   /* Vol Aux left 0dB*/
1219cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_AVR, 0x00);   /* Vol Aux right 0dB*/
1220cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_ABA, 0x00);   /* Aux Bass Main 0dB*/
1221cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_ATR, 0x00);   /* Aux Aigus Main 0dB*/
1222cb7a01acSMauro Carvalho Chehab 
1223cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TDA9875_MUT, 0xcc);   /* General mute  */
1224cb7a01acSMauro Carvalho Chehab 	return 0;
1225cb7a01acSMauro Carvalho Chehab }
1226cb7a01acSMauro Carvalho Chehab 
tda9875_volume(int val)1227cb7a01acSMauro Carvalho Chehab static int tda9875_volume(int val) { return (unsigned char)(val / 602 - 84); }
tda9875_bass(int val)1228cb7a01acSMauro Carvalho Chehab static int tda9875_bass(int val) { return (unsigned char)(max(-12, val / 2115 - 15)); }
tda9875_treble(int val)1229cb7a01acSMauro Carvalho Chehab static int tda9875_treble(int val) { return (unsigned char)(val / 2622 - 12); }
1230cb7a01acSMauro Carvalho Chehab 
1231cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1232cb7a01acSMauro Carvalho Chehab 
1233cb7a01acSMauro Carvalho Chehab 
1234cb7a01acSMauro Carvalho Chehab /* *********************** *
1235cb7a01acSMauro Carvalho Chehab  * i2c interface functions *
1236cb7a01acSMauro Carvalho Chehab  * *********************** */
1237cb7a01acSMauro Carvalho Chehab 
tda9875_checkit(struct CHIPSTATE * chip)1238cb7a01acSMauro Carvalho Chehab static int tda9875_checkit(struct CHIPSTATE *chip)
1239cb7a01acSMauro Carvalho Chehab {
1240cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
1241cb7a01acSMauro Carvalho Chehab 	int dic, rev;
1242cb7a01acSMauro Carvalho Chehab 
1243cb7a01acSMauro Carvalho Chehab 	dic = chip_read2(chip, 254);
1244b0121ca0SMauro Carvalho Chehab 	if (dic < 0)
1245b0121ca0SMauro Carvalho Chehab 		return 0;
1246cb7a01acSMauro Carvalho Chehab 	rev = chip_read2(chip, 255);
1247b0121ca0SMauro Carvalho Chehab 	if (rev < 0)
1248b0121ca0SMauro Carvalho Chehab 		return 0;
1249cb7a01acSMauro Carvalho Chehab 
1250cb7a01acSMauro Carvalho Chehab 	if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
1251cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "found tda9875%s rev. %d.\n",
1252cb7a01acSMauro Carvalho Chehab 			dic == 0 ? "" : "A", rev);
1253cb7a01acSMauro Carvalho Chehab 		return 1;
1254cb7a01acSMauro Carvalho Chehab 	}
1255cb7a01acSMauro Carvalho Chehab 	return 0;
1256cb7a01acSMauro Carvalho Chehab }
1257cb7a01acSMauro Carvalho Chehab 
1258cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
1259cb7a01acSMauro Carvalho Chehab /* audio chip descriptions - defines+functions for tea6420                */
1260cb7a01acSMauro Carvalho Chehab 
1261cb7a01acSMauro Carvalho Chehab #define TEA6300_VL         0x00  /* volume left */
1262cb7a01acSMauro Carvalho Chehab #define TEA6300_VR         0x01  /* volume right */
1263cb7a01acSMauro Carvalho Chehab #define TEA6300_BA         0x02  /* bass */
1264cb7a01acSMauro Carvalho Chehab #define TEA6300_TR         0x03  /* treble */
1265cb7a01acSMauro Carvalho Chehab #define TEA6300_FA         0x04  /* fader control */
1266cb7a01acSMauro Carvalho Chehab #define TEA6300_S          0x05  /* switch register */
1267cb7a01acSMauro Carvalho Chehab 				 /* values for those registers: */
1268cb7a01acSMauro Carvalho Chehab #define TEA6300_S_SA       0x01  /* stereo A input */
1269cb7a01acSMauro Carvalho Chehab #define TEA6300_S_SB       0x02  /* stereo B */
1270cb7a01acSMauro Carvalho Chehab #define TEA6300_S_SC       0x04  /* stereo C */
1271cb7a01acSMauro Carvalho Chehab #define TEA6300_S_GMU      0x80  /* general mute */
1272cb7a01acSMauro Carvalho Chehab 
1273cb7a01acSMauro Carvalho Chehab #define TEA6320_V          0x00  /* volume (0-5)/loudness off (6)/zero crossing mute(7) */
1274cb7a01acSMauro Carvalho Chehab #define TEA6320_FFR        0x01  /* fader front right (0-5) */
1275cb7a01acSMauro Carvalho Chehab #define TEA6320_FFL        0x02  /* fader front left (0-5) */
1276cb7a01acSMauro Carvalho Chehab #define TEA6320_FRR        0x03  /* fader rear right (0-5) */
1277cb7a01acSMauro Carvalho Chehab #define TEA6320_FRL        0x04  /* fader rear left (0-5) */
1278cb7a01acSMauro Carvalho Chehab #define TEA6320_BA         0x05  /* bass (0-4) */
1279cb7a01acSMauro Carvalho Chehab #define TEA6320_TR         0x06  /* treble (0-4) */
1280cb7a01acSMauro Carvalho Chehab #define TEA6320_S          0x07  /* switch register */
1281cb7a01acSMauro Carvalho Chehab 				 /* values for those registers: */
1282cb7a01acSMauro Carvalho Chehab #define TEA6320_S_SA       0x07  /* stereo A input */
1283cb7a01acSMauro Carvalho Chehab #define TEA6320_S_SB       0x06  /* stereo B */
1284cb7a01acSMauro Carvalho Chehab #define TEA6320_S_SC       0x05  /* stereo C */
1285cb7a01acSMauro Carvalho Chehab #define TEA6320_S_SD       0x04  /* stereo D */
1286cb7a01acSMauro Carvalho Chehab #define TEA6320_S_GMU      0x80  /* general mute */
1287cb7a01acSMauro Carvalho Chehab 
1288cb7a01acSMauro Carvalho Chehab #define TEA6420_S_SA       0x00  /* stereo A input */
1289cb7a01acSMauro Carvalho Chehab #define TEA6420_S_SB       0x01  /* stereo B */
1290cb7a01acSMauro Carvalho Chehab #define TEA6420_S_SC       0x02  /* stereo C */
1291cb7a01acSMauro Carvalho Chehab #define TEA6420_S_SD       0x03  /* stereo D */
1292cb7a01acSMauro Carvalho Chehab #define TEA6420_S_SE       0x04  /* stereo E */
1293cb7a01acSMauro Carvalho Chehab #define TEA6420_S_GMU      0x05  /* general mute */
1294cb7a01acSMauro Carvalho Chehab 
tea6300_shift10(int val)1295cb7a01acSMauro Carvalho Chehab static int tea6300_shift10(int val) { return val >> 10; }
tea6300_shift12(int val)1296cb7a01acSMauro Carvalho Chehab static int tea6300_shift12(int val) { return val >> 12; }
1297cb7a01acSMauro Carvalho Chehab 
1298cb7a01acSMauro Carvalho Chehab /* Assumes 16bit input (values 0x3f to 0x0c are unique, values less than */
1299cb7a01acSMauro Carvalho Chehab /* 0x0c mirror those immediately higher) */
tea6320_volume(int val)1300cb7a01acSMauro Carvalho Chehab static int tea6320_volume(int val) { return (val / (65535/(63-12)) + 12) & 0x3f; }
tea6320_shift11(int val)1301cb7a01acSMauro Carvalho Chehab static int tea6320_shift11(int val) { return val >> 11; }
tea6320_initialize(struct CHIPSTATE * chip)1302cb7a01acSMauro Carvalho Chehab static int tea6320_initialize(struct CHIPSTATE * chip)
1303cb7a01acSMauro Carvalho Chehab {
1304cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TEA6320_FFR, 0x3f);
1305cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TEA6320_FFL, 0x3f);
1306cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TEA6320_FRR, 0x3f);
1307cb7a01acSMauro Carvalho Chehab 	chip_write(chip, TEA6320_FRL, 0x3f);
1308cb7a01acSMauro Carvalho Chehab 
1309cb7a01acSMauro Carvalho Chehab 	return 0;
1310cb7a01acSMauro Carvalho Chehab }
1311cb7a01acSMauro Carvalho Chehab 
1312cb7a01acSMauro Carvalho Chehab 
1313cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
1314cb7a01acSMauro Carvalho Chehab /* audio chip descriptions - defines+functions for tda8425                */
1315cb7a01acSMauro Carvalho Chehab 
1316cb7a01acSMauro Carvalho Chehab #define TDA8425_VL         0x00  /* volume left */
1317cb7a01acSMauro Carvalho Chehab #define TDA8425_VR         0x01  /* volume right */
1318cb7a01acSMauro Carvalho Chehab #define TDA8425_BA         0x02  /* bass */
1319cb7a01acSMauro Carvalho Chehab #define TDA8425_TR         0x03  /* treble */
1320cb7a01acSMauro Carvalho Chehab #define TDA8425_S1         0x08  /* switch functions */
1321cb7a01acSMauro Carvalho Chehab 				 /* values for those registers: */
1322cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_OFF     0xEE  /* audio off (mute on) */
1323cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_CH1     0xCE  /* audio channel 1 (mute off) - "linear stereo" mode */
1324cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_CH2     0xCF  /* audio channel 2 (mute off) - "linear stereo" mode */
1325cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_MU      0x20  /* mute bit */
1326cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_STEREO  0x18  /* stereo bits */
1327cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_STEREO_SPATIAL 0x18 /* spatial stereo */
1328cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_STEREO_LINEAR  0x08 /* linear stereo */
1329cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_STEREO_PSEUDO  0x10 /* pseudo stereo */
1330cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_STEREO_MONO    0x00 /* forced mono */
1331cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_ML      0x06        /* language selector */
1332cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_ML_SOUND_A 0x02     /* sound a */
1333cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_ML_SOUND_B 0x04     /* sound b */
1334cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_ML_STEREO  0x06     /* stereo */
1335cb7a01acSMauro Carvalho Chehab #define TDA8425_S1_IS      0x01        /* channel selector */
1336cb7a01acSMauro Carvalho Chehab 
1337cb7a01acSMauro Carvalho Chehab 
tda8425_shift10(int val)1338cb7a01acSMauro Carvalho Chehab static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
tda8425_shift12(int val)1339cb7a01acSMauro Carvalho Chehab static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
1340cb7a01acSMauro Carvalho Chehab 
tda8425_setaudmode(struct CHIPSTATE * chip,int mode)1341cb7a01acSMauro Carvalho Chehab static void tda8425_setaudmode(struct CHIPSTATE *chip, int mode)
1342cb7a01acSMauro Carvalho Chehab {
1343cb7a01acSMauro Carvalho Chehab 	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
1344cb7a01acSMauro Carvalho Chehab 
1345cb7a01acSMauro Carvalho Chehab 	switch (mode) {
1346cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1:
1347cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_ML_SOUND_A;
1348cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_STEREO_PSEUDO;
1349cb7a01acSMauro Carvalho Chehab 		break;
1350cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG2:
1351cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_ML_SOUND_B;
1352cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_STEREO_PSEUDO;
1353cb7a01acSMauro Carvalho Chehab 		break;
1354cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1_LANG2:
1355cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_ML_STEREO;
1356cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_STEREO_LINEAR;
1357cb7a01acSMauro Carvalho Chehab 		break;
1358cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_MONO:
1359cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_ML_STEREO;
1360cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_STEREO_MONO;
1361cb7a01acSMauro Carvalho Chehab 		break;
1362cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_STEREO:
1363cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_ML_STEREO;
1364cb7a01acSMauro Carvalho Chehab 		s1 |= TDA8425_S1_STEREO_SPATIAL;
1365cb7a01acSMauro Carvalho Chehab 		break;
1366cb7a01acSMauro Carvalho Chehab 	default:
1367cb7a01acSMauro Carvalho Chehab 		return;
1368cb7a01acSMauro Carvalho Chehab 	}
1369cb7a01acSMauro Carvalho Chehab 	chip_write(chip,TDA8425_S1,s1);
1370cb7a01acSMauro Carvalho Chehab }
1371cb7a01acSMauro Carvalho Chehab 
1372cb7a01acSMauro Carvalho Chehab 
1373cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
1374cb7a01acSMauro Carvalho Chehab /* audio chip descriptions - defines+functions for pic16c54 (PV951)       */
1375cb7a01acSMauro Carvalho Chehab 
1376cb7a01acSMauro Carvalho Chehab /* the registers of 16C54, I2C sub address. */
1377cb7a01acSMauro Carvalho Chehab #define PIC16C54_REG_KEY_CODE     0x01	       /* Not use. */
1378cb7a01acSMauro Carvalho Chehab #define PIC16C54_REG_MISC         0x02
1379cb7a01acSMauro Carvalho Chehab 
1380cb7a01acSMauro Carvalho Chehab /* bit definition of the RESET register, I2C data. */
1381cb7a01acSMauro Carvalho Chehab #define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */
1382cb7a01acSMauro Carvalho Chehab 					    /*        code of remote controller */
1383cb7a01acSMauro Carvalho Chehab #define PIC16C54_MISC_MTS_MAIN         0x02 /* bit 1 */
1384cb7a01acSMauro Carvalho Chehab #define PIC16C54_MISC_MTS_SAP          0x04 /* bit 2 */
1385cb7a01acSMauro Carvalho Chehab #define PIC16C54_MISC_MTS_BOTH         0x08 /* bit 3 */
1386cb7a01acSMauro Carvalho Chehab #define PIC16C54_MISC_SND_MUTE         0x10 /* bit 4, Mute Audio(Line-in and Tuner) */
1387cb7a01acSMauro Carvalho Chehab #define PIC16C54_MISC_SND_NOTMUTE      0x20 /* bit 5 */
1388cb7a01acSMauro Carvalho Chehab #define PIC16C54_MISC_SWITCH_TUNER     0x40 /* bit 6	, Switch to Line-in */
1389cb7a01acSMauro Carvalho Chehab #define PIC16C54_MISC_SWITCH_LINE      0x80 /* bit 7	, Switch to Tuner */
1390cb7a01acSMauro Carvalho Chehab 
1391cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
1392cb7a01acSMauro Carvalho Chehab /* audio chip descriptions - defines+functions for TA8874Z                */
1393cb7a01acSMauro Carvalho Chehab 
1394cb7a01acSMauro Carvalho Chehab /* write 1st byte */
1395cb7a01acSMauro Carvalho Chehab #define TA8874Z_LED_STE	0x80
1396cb7a01acSMauro Carvalho Chehab #define TA8874Z_LED_BIL	0x40
1397cb7a01acSMauro Carvalho Chehab #define TA8874Z_LED_EXT	0x20
1398cb7a01acSMauro Carvalho Chehab #define TA8874Z_MONO_SET	0x10
1399cb7a01acSMauro Carvalho Chehab #define TA8874Z_MUTE	0x08
1400cb7a01acSMauro Carvalho Chehab #define TA8874Z_F_MONO	0x04
1401cb7a01acSMauro Carvalho Chehab #define TA8874Z_MODE_SUB	0x02
1402cb7a01acSMauro Carvalho Chehab #define TA8874Z_MODE_MAIN	0x01
1403cb7a01acSMauro Carvalho Chehab 
1404cb7a01acSMauro Carvalho Chehab /* write 2nd byte */
1405cb7a01acSMauro Carvalho Chehab /*#define TA8874Z_TI	0x80  */ /* test mode */
1406cb7a01acSMauro Carvalho Chehab #define TA8874Z_SEPARATION	0x3f
1407cb7a01acSMauro Carvalho Chehab #define TA8874Z_SEPARATION_DEFAULT	0x10
1408cb7a01acSMauro Carvalho Chehab 
1409cb7a01acSMauro Carvalho Chehab /* read */
1410cb7a01acSMauro Carvalho Chehab #define TA8874Z_B1	0x80
1411cb7a01acSMauro Carvalho Chehab #define TA8874Z_B0	0x40
1412cb7a01acSMauro Carvalho Chehab #define TA8874Z_CHAG_FLAG	0x20
1413cb7a01acSMauro Carvalho Chehab 
1414cb7a01acSMauro Carvalho Chehab /*
1415cb7a01acSMauro Carvalho Chehab  *        B1 B0
1416cb7a01acSMauro Carvalho Chehab  * mono    L  H
1417cb7a01acSMauro Carvalho Chehab  * stereo  L  L
1418cb7a01acSMauro Carvalho Chehab  * BIL     H  L
1419cb7a01acSMauro Carvalho Chehab  */
ta8874z_getrxsubchans(struct CHIPSTATE * chip)1420cb7a01acSMauro Carvalho Chehab static int ta8874z_getrxsubchans(struct CHIPSTATE *chip)
1421cb7a01acSMauro Carvalho Chehab {
1422cb7a01acSMauro Carvalho Chehab 	int val, mode;
1423cb7a01acSMauro Carvalho Chehab 
1424cb7a01acSMauro Carvalho Chehab 	mode = V4L2_TUNER_SUB_MONO;
1425b0121ca0SMauro Carvalho Chehab 
1426b0121ca0SMauro Carvalho Chehab 	val = chip_read(chip);
1427b0121ca0SMauro Carvalho Chehab 	if (val < 0)
1428b0121ca0SMauro Carvalho Chehab 		return mode;
1429b0121ca0SMauro Carvalho Chehab 
1430cb7a01acSMauro Carvalho Chehab 	if (val & TA8874Z_B1){
1431cb7a01acSMauro Carvalho Chehab 		mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
1432cb7a01acSMauro Carvalho Chehab 	}else if (!(val & TA8874Z_B0)){
1433cb7a01acSMauro Carvalho Chehab 		mode = V4L2_TUNER_SUB_STEREO;
1434cb7a01acSMauro Carvalho Chehab 	}
1435cb7a01acSMauro Carvalho Chehab 	/* v4l2_dbg(1, debug, &chip->sd,
1436cb7a01acSMauro Carvalho Chehab 		 "ta8874z_getrxsubchans(): raw chip read: 0x%02x, return: 0x%02x\n",
1437cb7a01acSMauro Carvalho Chehab 		 val, mode); */
1438cb7a01acSMauro Carvalho Chehab 	return mode;
1439cb7a01acSMauro Carvalho Chehab }
1440cb7a01acSMauro Carvalho Chehab 
1441cb7a01acSMauro Carvalho Chehab static audiocmd ta8874z_stereo = { 2, {0, TA8874Z_SEPARATION_DEFAULT}};
1442cb7a01acSMauro Carvalho Chehab static audiocmd ta8874z_mono = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}};
1443cb7a01acSMauro Carvalho Chehab static audiocmd ta8874z_main = {2, { 0, TA8874Z_SEPARATION_DEFAULT}};
1444cb7a01acSMauro Carvalho Chehab static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
1445cb7a01acSMauro Carvalho Chehab static audiocmd ta8874z_both = {2, { TA8874Z_MODE_MAIN | TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
1446cb7a01acSMauro Carvalho Chehab 
ta8874z_setaudmode(struct CHIPSTATE * chip,int mode)1447cb7a01acSMauro Carvalho Chehab static void ta8874z_setaudmode(struct CHIPSTATE *chip, int mode)
1448cb7a01acSMauro Carvalho Chehab {
1449cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = &chip->sd;
1450cb7a01acSMauro Carvalho Chehab 	int update = 1;
1451cb7a01acSMauro Carvalho Chehab 	audiocmd *t = NULL;
1452cb7a01acSMauro Carvalho Chehab 
1453cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "ta8874z_setaudmode(): mode: 0x%02x\n", mode);
1454cb7a01acSMauro Carvalho Chehab 
1455cb7a01acSMauro Carvalho Chehab 	switch(mode){
1456cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_MONO:
1457cb7a01acSMauro Carvalho Chehab 		t = &ta8874z_mono;
1458cb7a01acSMauro Carvalho Chehab 		break;
1459cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_STEREO:
1460cb7a01acSMauro Carvalho Chehab 		t = &ta8874z_stereo;
1461cb7a01acSMauro Carvalho Chehab 		break;
1462cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1:
1463cb7a01acSMauro Carvalho Chehab 		t = &ta8874z_main;
1464cb7a01acSMauro Carvalho Chehab 		break;
1465cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG2:
1466cb7a01acSMauro Carvalho Chehab 		t = &ta8874z_sub;
1467cb7a01acSMauro Carvalho Chehab 		break;
1468cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1_LANG2:
1469cb7a01acSMauro Carvalho Chehab 		t = &ta8874z_both;
1470cb7a01acSMauro Carvalho Chehab 		break;
1471cb7a01acSMauro Carvalho Chehab 	default:
1472cb7a01acSMauro Carvalho Chehab 		update = 0;
1473cb7a01acSMauro Carvalho Chehab 	}
1474cb7a01acSMauro Carvalho Chehab 
1475cb7a01acSMauro Carvalho Chehab 	if(update)
1476cb7a01acSMauro Carvalho Chehab 		chip_cmd(chip, "TA8874Z", t);
1477cb7a01acSMauro Carvalho Chehab }
1478cb7a01acSMauro Carvalho Chehab 
ta8874z_checkit(struct CHIPSTATE * chip)1479cb7a01acSMauro Carvalho Chehab static int ta8874z_checkit(struct CHIPSTATE *chip)
1480cb7a01acSMauro Carvalho Chehab {
1481cb7a01acSMauro Carvalho Chehab 	int rc;
1482b0121ca0SMauro Carvalho Chehab 
1483cb7a01acSMauro Carvalho Chehab 	rc = chip_read(chip);
1484b0121ca0SMauro Carvalho Chehab 	if (rc < 0)
1485b0121ca0SMauro Carvalho Chehab 		return rc;
1486b0121ca0SMauro Carvalho Chehab 
1487cb7a01acSMauro Carvalho Chehab 	return ((rc & 0x1f) == 0x1f) ? 1 : 0;
1488cb7a01acSMauro Carvalho Chehab }
1489cb7a01acSMauro Carvalho Chehab 
1490cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
1491cb7a01acSMauro Carvalho Chehab /* audio chip descriptions - struct CHIPDESC                              */
1492cb7a01acSMauro Carvalho Chehab 
1493cb7a01acSMauro Carvalho Chehab /* insmod options to enable/disable individual audio chips */
1494cb7a01acSMauro Carvalho Chehab static int tda8425  = 1;
1495cb7a01acSMauro Carvalho Chehab static int tda9840  = 1;
1496cb7a01acSMauro Carvalho Chehab static int tda9850  = 1;
1497cb7a01acSMauro Carvalho Chehab static int tda9855  = 1;
1498cb7a01acSMauro Carvalho Chehab static int tda9873  = 1;
1499cb7a01acSMauro Carvalho Chehab static int tda9874a = 1;
1500cb7a01acSMauro Carvalho Chehab static int tda9875  = 1;
1501cb7a01acSMauro Carvalho Chehab static int tea6300;	/* default 0 - address clash with msp34xx */
1502cb7a01acSMauro Carvalho Chehab static int tea6320;	/* default 0 - address clash with msp34xx */
1503cb7a01acSMauro Carvalho Chehab static int tea6420  = 1;
1504cb7a01acSMauro Carvalho Chehab static int pic16c54 = 1;
1505cb7a01acSMauro Carvalho Chehab static int ta8874z;	/* default 0 - address clash with tda9840 */
1506cb7a01acSMauro Carvalho Chehab 
1507cb7a01acSMauro Carvalho Chehab module_param(tda8425, int, 0444);
1508cb7a01acSMauro Carvalho Chehab module_param(tda9840, int, 0444);
1509cb7a01acSMauro Carvalho Chehab module_param(tda9850, int, 0444);
1510cb7a01acSMauro Carvalho Chehab module_param(tda9855, int, 0444);
1511cb7a01acSMauro Carvalho Chehab module_param(tda9873, int, 0444);
1512cb7a01acSMauro Carvalho Chehab module_param(tda9874a, int, 0444);
1513cb7a01acSMauro Carvalho Chehab module_param(tda9875, int, 0444);
1514cb7a01acSMauro Carvalho Chehab module_param(tea6300, int, 0444);
1515cb7a01acSMauro Carvalho Chehab module_param(tea6320, int, 0444);
1516cb7a01acSMauro Carvalho Chehab module_param(tea6420, int, 0444);
1517cb7a01acSMauro Carvalho Chehab module_param(pic16c54, int, 0444);
1518cb7a01acSMauro Carvalho Chehab module_param(ta8874z, int, 0444);
1519cb7a01acSMauro Carvalho Chehab 
1520cb7a01acSMauro Carvalho Chehab static struct CHIPDESC chiplist[] = {
1521cb7a01acSMauro Carvalho Chehab 	{
1522cb7a01acSMauro Carvalho Chehab 		.name       = "tda9840",
1523cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tda9840,
1524cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TDA9840 >> 1,
1525cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TDA9840 >> 1,
1526cb7a01acSMauro Carvalho Chehab 		.registers  = 5,
1527cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_NEED_CHECKMODE,
1528cb7a01acSMauro Carvalho Chehab 
1529cb7a01acSMauro Carvalho Chehab 		/* callbacks */
1530cb7a01acSMauro Carvalho Chehab 		.checkit    = tda9840_checkit,
1531cb7a01acSMauro Carvalho Chehab 		.getrxsubchans = tda9840_getrxsubchans,
1532cb7a01acSMauro Carvalho Chehab 		.setaudmode = tda9840_setaudmode,
1533cb7a01acSMauro Carvalho Chehab 
1534cb7a01acSMauro Carvalho Chehab 		.init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
1535cb7a01acSMauro Carvalho Chehab 				/* ,TDA9840_SW, TDA9840_MONO */} }
1536cb7a01acSMauro Carvalho Chehab 	},
1537cb7a01acSMauro Carvalho Chehab 	{
1538cb7a01acSMauro Carvalho Chehab 		.name       = "tda9873h",
1539cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tda9873,
1540cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TDA985x_L >> 1,
1541cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TDA985x_H >> 1,
1542cb7a01acSMauro Carvalho Chehab 		.registers  = 3,
1543cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_HAS_INPUTSEL | CHIP_NEED_CHECKMODE,
1544cb7a01acSMauro Carvalho Chehab 
1545cb7a01acSMauro Carvalho Chehab 		/* callbacks */
1546cb7a01acSMauro Carvalho Chehab 		.checkit    = tda9873_checkit,
1547cb7a01acSMauro Carvalho Chehab 		.getrxsubchans = tda9873_getrxsubchans,
1548cb7a01acSMauro Carvalho Chehab 		.setaudmode = tda9873_setaudmode,
1549cb7a01acSMauro Carvalho Chehab 
1550cb7a01acSMauro Carvalho Chehab 		.init       = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
1551cb7a01acSMauro Carvalho Chehab 		.inputreg   = TDA9873_SW,
1552cb7a01acSMauro Carvalho Chehab 		.inputmute  = TDA9873_MUTE | TDA9873_AUTOMUTE,
1553cb7a01acSMauro Carvalho Chehab 		.inputmap   = {0xa0, 0xa2, 0xa0, 0xa0},
1554cb7a01acSMauro Carvalho Chehab 		.inputmask  = TDA9873_INP_MASK|TDA9873_MUTE|TDA9873_AUTOMUTE,
1555cb7a01acSMauro Carvalho Chehab 
1556cb7a01acSMauro Carvalho Chehab 	},
1557cb7a01acSMauro Carvalho Chehab 	{
1558cb7a01acSMauro Carvalho Chehab 		.name       = "tda9874h/a",
1559cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tda9874a,
1560cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TDA9874 >> 1,
1561cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TDA9874 >> 1,
1562cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_NEED_CHECKMODE,
1563cb7a01acSMauro Carvalho Chehab 
1564cb7a01acSMauro Carvalho Chehab 		/* callbacks */
1565cb7a01acSMauro Carvalho Chehab 		.initialize = tda9874a_initialize,
1566cb7a01acSMauro Carvalho Chehab 		.checkit    = tda9874a_checkit,
1567cb7a01acSMauro Carvalho Chehab 		.getrxsubchans = tda9874a_getrxsubchans,
1568cb7a01acSMauro Carvalho Chehab 		.setaudmode = tda9874a_setaudmode,
1569cb7a01acSMauro Carvalho Chehab 	},
1570cb7a01acSMauro Carvalho Chehab 	{
1571cb7a01acSMauro Carvalho Chehab 		.name       = "tda9875",
1572cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tda9875,
1573cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TDA9875 >> 1,
1574cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TDA9875 >> 1,
1575cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
1576cb7a01acSMauro Carvalho Chehab 
1577cb7a01acSMauro Carvalho Chehab 		/* callbacks */
1578cb7a01acSMauro Carvalho Chehab 		.initialize = tda9875_initialize,
1579cb7a01acSMauro Carvalho Chehab 		.checkit    = tda9875_checkit,
1580cb7a01acSMauro Carvalho Chehab 		.volfunc    = tda9875_volume,
1581cb7a01acSMauro Carvalho Chehab 		.bassfunc   = tda9875_bass,
1582cb7a01acSMauro Carvalho Chehab 		.treblefunc = tda9875_treble,
1583cb7a01acSMauro Carvalho Chehab 		.leftreg    = TDA9875_MVL,
1584cb7a01acSMauro Carvalho Chehab 		.rightreg   = TDA9875_MVR,
1585cb7a01acSMauro Carvalho Chehab 		.bassreg    = TDA9875_MBA,
1586cb7a01acSMauro Carvalho Chehab 		.treblereg  = TDA9875_MTR,
1587a346caacSHans Verkuil 		.volinit    = 58880,
1588cb7a01acSMauro Carvalho Chehab 	},
1589cb7a01acSMauro Carvalho Chehab 	{
1590cb7a01acSMauro Carvalho Chehab 		.name       = "tda9850",
1591cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tda9850,
1592cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TDA985x_L >> 1,
1593cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TDA985x_H >> 1,
1594cb7a01acSMauro Carvalho Chehab 		.registers  = 11,
1595cb7a01acSMauro Carvalho Chehab 
1596cb7a01acSMauro Carvalho Chehab 		.getrxsubchans = tda985x_getrxsubchans,
1597cb7a01acSMauro Carvalho Chehab 		.setaudmode = tda985x_setaudmode,
1598cb7a01acSMauro Carvalho Chehab 
1599cb7a01acSMauro Carvalho Chehab 		.init       = { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
1600cb7a01acSMauro Carvalho Chehab 	},
1601cb7a01acSMauro Carvalho Chehab 	{
1602cb7a01acSMauro Carvalho Chehab 		.name       = "tda9855",
1603cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tda9855,
1604cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TDA985x_L >> 1,
1605cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TDA985x_H >> 1,
1606cb7a01acSMauro Carvalho Chehab 		.registers  = 11,
1607cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
1608cb7a01acSMauro Carvalho Chehab 
1609cb7a01acSMauro Carvalho Chehab 		.leftreg    = TDA9855_VL,
1610cb7a01acSMauro Carvalho Chehab 		.rightreg   = TDA9855_VR,
1611cb7a01acSMauro Carvalho Chehab 		.bassreg    = TDA9855_BA,
1612cb7a01acSMauro Carvalho Chehab 		.treblereg  = TDA9855_TR,
1613cb7a01acSMauro Carvalho Chehab 
1614cb7a01acSMauro Carvalho Chehab 		/* callbacks */
1615cb7a01acSMauro Carvalho Chehab 		.volfunc    = tda9855_volume,
1616cb7a01acSMauro Carvalho Chehab 		.bassfunc   = tda9855_bass,
1617cb7a01acSMauro Carvalho Chehab 		.treblefunc = tda9855_treble,
1618cb7a01acSMauro Carvalho Chehab 		.getrxsubchans = tda985x_getrxsubchans,
1619cb7a01acSMauro Carvalho Chehab 		.setaudmode = tda985x_setaudmode,
1620cb7a01acSMauro Carvalho Chehab 
1621cb7a01acSMauro Carvalho Chehab 		.init       = { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2,
1622cb7a01acSMauro Carvalho Chehab 				    TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT,
1623cb7a01acSMauro Carvalho Chehab 				    TDA985x_STEREO | TDA9855_LINEAR | TDA9855_TZCM | TDA9855_VZCM,
1624cb7a01acSMauro Carvalho Chehab 				    0x07, 0x10, 0x10, 0x03 }}
1625cb7a01acSMauro Carvalho Chehab 	},
1626cb7a01acSMauro Carvalho Chehab 	{
1627cb7a01acSMauro Carvalho Chehab 		.name       = "tea6300",
1628cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tea6300,
1629cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TEA6300 >> 1,
1630cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TEA6300 >> 1,
1631cb7a01acSMauro Carvalho Chehab 		.registers  = 6,
1632cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
1633cb7a01acSMauro Carvalho Chehab 
1634cb7a01acSMauro Carvalho Chehab 		.leftreg    = TEA6300_VR,
1635cb7a01acSMauro Carvalho Chehab 		.rightreg   = TEA6300_VL,
1636cb7a01acSMauro Carvalho Chehab 		.bassreg    = TEA6300_BA,
1637cb7a01acSMauro Carvalho Chehab 		.treblereg  = TEA6300_TR,
1638cb7a01acSMauro Carvalho Chehab 
1639cb7a01acSMauro Carvalho Chehab 		/* callbacks */
1640cb7a01acSMauro Carvalho Chehab 		.volfunc    = tea6300_shift10,
1641cb7a01acSMauro Carvalho Chehab 		.bassfunc   = tea6300_shift12,
1642cb7a01acSMauro Carvalho Chehab 		.treblefunc = tea6300_shift12,
1643cb7a01acSMauro Carvalho Chehab 
1644cb7a01acSMauro Carvalho Chehab 		.inputreg   = TEA6300_S,
1645cb7a01acSMauro Carvalho Chehab 		.inputmap   = { TEA6300_S_SA, TEA6300_S_SB, TEA6300_S_SC },
1646cb7a01acSMauro Carvalho Chehab 		.inputmute  = TEA6300_S_GMU,
1647cb7a01acSMauro Carvalho Chehab 	},
1648cb7a01acSMauro Carvalho Chehab 	{
1649cb7a01acSMauro Carvalho Chehab 		.name       = "tea6320",
1650cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tea6320,
1651cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TEA6300 >> 1,
1652cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TEA6300 >> 1,
1653cb7a01acSMauro Carvalho Chehab 		.registers  = 8,
1654cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
1655cb7a01acSMauro Carvalho Chehab 
1656cb7a01acSMauro Carvalho Chehab 		.leftreg    = TEA6320_V,
1657cb7a01acSMauro Carvalho Chehab 		.rightreg   = TEA6320_V,
1658cb7a01acSMauro Carvalho Chehab 		.bassreg    = TEA6320_BA,
1659cb7a01acSMauro Carvalho Chehab 		.treblereg  = TEA6320_TR,
1660cb7a01acSMauro Carvalho Chehab 
1661cb7a01acSMauro Carvalho Chehab 		/* callbacks */
1662cb7a01acSMauro Carvalho Chehab 		.initialize = tea6320_initialize,
1663cb7a01acSMauro Carvalho Chehab 		.volfunc    = tea6320_volume,
1664cb7a01acSMauro Carvalho Chehab 		.bassfunc   = tea6320_shift11,
1665cb7a01acSMauro Carvalho Chehab 		.treblefunc = tea6320_shift11,
1666cb7a01acSMauro Carvalho Chehab 
1667cb7a01acSMauro Carvalho Chehab 		.inputreg   = TEA6320_S,
1668cb7a01acSMauro Carvalho Chehab 		.inputmap   = { TEA6320_S_SA, TEA6420_S_SB, TEA6300_S_SC, TEA6320_S_SD },
1669cb7a01acSMauro Carvalho Chehab 		.inputmute  = TEA6300_S_GMU,
1670cb7a01acSMauro Carvalho Chehab 	},
1671cb7a01acSMauro Carvalho Chehab 	{
1672cb7a01acSMauro Carvalho Chehab 		.name       = "tea6420",
1673cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tea6420,
1674cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TEA6420 >> 1,
1675cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TEA6420 >> 1,
1676cb7a01acSMauro Carvalho Chehab 		.registers  = 1,
1677cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_HAS_INPUTSEL,
1678cb7a01acSMauro Carvalho Chehab 
1679cb7a01acSMauro Carvalho Chehab 		.inputreg   = -1,
1680cb7a01acSMauro Carvalho Chehab 		.inputmap   = { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC },
168171df09bcSHans Verkuil 		.inputmute  = TEA6420_S_GMU,
168271df09bcSHans Verkuil 		.inputmask  = 0x07,
1683cb7a01acSMauro Carvalho Chehab 	},
1684cb7a01acSMauro Carvalho Chehab 	{
1685cb7a01acSMauro Carvalho Chehab 		.name       = "tda8425",
1686cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &tda8425,
1687cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TDA8425 >> 1,
1688cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TDA8425 >> 1,
1689cb7a01acSMauro Carvalho Chehab 		.registers  = 9,
1690cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
1691cb7a01acSMauro Carvalho Chehab 
1692cb7a01acSMauro Carvalho Chehab 		.leftreg    = TDA8425_VL,
1693cb7a01acSMauro Carvalho Chehab 		.rightreg   = TDA8425_VR,
1694cb7a01acSMauro Carvalho Chehab 		.bassreg    = TDA8425_BA,
1695cb7a01acSMauro Carvalho Chehab 		.treblereg  = TDA8425_TR,
1696cb7a01acSMauro Carvalho Chehab 
1697cb7a01acSMauro Carvalho Chehab 		/* callbacks */
1698cb7a01acSMauro Carvalho Chehab 		.volfunc    = tda8425_shift10,
1699cb7a01acSMauro Carvalho Chehab 		.bassfunc   = tda8425_shift12,
1700cb7a01acSMauro Carvalho Chehab 		.treblefunc = tda8425_shift12,
1701cb7a01acSMauro Carvalho Chehab 		.setaudmode = tda8425_setaudmode,
1702cb7a01acSMauro Carvalho Chehab 
1703cb7a01acSMauro Carvalho Chehab 		.inputreg   = TDA8425_S1,
1704cb7a01acSMauro Carvalho Chehab 		.inputmap   = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
1705cb7a01acSMauro Carvalho Chehab 		.inputmute  = TDA8425_S1_OFF,
1706cb7a01acSMauro Carvalho Chehab 
1707cb7a01acSMauro Carvalho Chehab 	},
1708cb7a01acSMauro Carvalho Chehab 	{
1709cb7a01acSMauro Carvalho Chehab 		.name       = "pic16c54 (PV951)",
1710cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &pic16c54,
1711cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_PIC16C54 >> 1,
1712cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_PIC16C54>> 1,
1713cb7a01acSMauro Carvalho Chehab 		.registers  = 2,
1714cb7a01acSMauro Carvalho Chehab 		.flags      = CHIP_HAS_INPUTSEL,
1715cb7a01acSMauro Carvalho Chehab 
1716cb7a01acSMauro Carvalho Chehab 		.inputreg   = PIC16C54_REG_MISC,
1717cb7a01acSMauro Carvalho Chehab 		.inputmap   = {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
1718cb7a01acSMauro Carvalho Chehab 			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
1719cb7a01acSMauro Carvalho Chehab 			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
1720cb7a01acSMauro Carvalho Chehab 			     PIC16C54_MISC_SND_MUTE},
1721cb7a01acSMauro Carvalho Chehab 		.inputmute  = PIC16C54_MISC_SND_MUTE,
1722cb7a01acSMauro Carvalho Chehab 	},
1723cb7a01acSMauro Carvalho Chehab 	{
1724cb7a01acSMauro Carvalho Chehab 		.name       = "ta8874z",
1725cb7a01acSMauro Carvalho Chehab 		.checkit    = ta8874z_checkit,
1726cb7a01acSMauro Carvalho Chehab 		.insmodopt  = &ta8874z,
1727cb7a01acSMauro Carvalho Chehab 		.addr_lo    = I2C_ADDR_TDA9840 >> 1,
1728cb7a01acSMauro Carvalho Chehab 		.addr_hi    = I2C_ADDR_TDA9840 >> 1,
1729cb7a01acSMauro Carvalho Chehab 		.registers  = 2,
1730cb7a01acSMauro Carvalho Chehab 
1731cb7a01acSMauro Carvalho Chehab 		/* callbacks */
1732cb7a01acSMauro Carvalho Chehab 		.getrxsubchans = ta8874z_getrxsubchans,
1733cb7a01acSMauro Carvalho Chehab 		.setaudmode = ta8874z_setaudmode,
1734cb7a01acSMauro Carvalho Chehab 
1735cb7a01acSMauro Carvalho Chehab 		.init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
1736cb7a01acSMauro Carvalho Chehab 	},
1737cb7a01acSMauro Carvalho Chehab 	{ .name = NULL } /* EOF */
1738cb7a01acSMauro Carvalho Chehab };
1739cb7a01acSMauro Carvalho Chehab 
1740cb7a01acSMauro Carvalho Chehab 
1741cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
1742cb7a01acSMauro Carvalho Chehab 
tvaudio_s_ctrl(struct v4l2_ctrl * ctrl)1743c9114031SHans Verkuil static int tvaudio_s_ctrl(struct v4l2_ctrl *ctrl)
1744cb7a01acSMauro Carvalho Chehab {
1745c9114031SHans Verkuil 	struct v4l2_subdev *sd = to_sd(ctrl);
1746cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip = to_state(sd);
1747cb7a01acSMauro Carvalho Chehab 	struct CHIPDESC *desc = chip->desc;
1748cb7a01acSMauro Carvalho Chehab 
1749cb7a01acSMauro Carvalho Chehab 	switch (ctrl->id) {
1750cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_AUDIO_MUTE:
1751c9114031SHans Verkuil 		chip->muted = ctrl->val;
1752cb7a01acSMauro Carvalho Chehab 		if (chip->muted)
1753cb7a01acSMauro Carvalho Chehab 			chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask);
1754cb7a01acSMauro Carvalho Chehab 		else
1755cb7a01acSMauro Carvalho Chehab 			chip_write_masked(chip,desc->inputreg,
1756cb7a01acSMauro Carvalho Chehab 					desc->inputmap[chip->input],desc->inputmask);
1757cb7a01acSMauro Carvalho Chehab 		return 0;
1758c9114031SHans Verkuil 	case V4L2_CID_AUDIO_VOLUME: {
1759a346caacSHans Verkuil 		u32 volume, balance;
1760a346caacSHans Verkuil 		u32 left, right;
1761cb7a01acSMauro Carvalho Chehab 
1762c9114031SHans Verkuil 		volume = chip->volume->val;
1763c9114031SHans Verkuil 		balance = chip->balance->val;
1764a346caacSHans Verkuil 		left = (min(65536U - balance, 32768U) * volume) / 32768U;
1765a346caacSHans Verkuil 		right = (min(balance, 32768U) * volume) / 32768U;
1766cb7a01acSMauro Carvalho Chehab 
1767a346caacSHans Verkuil 		chip_write(chip, desc->leftreg, desc->volfunc(left));
1768a346caacSHans Verkuil 		chip_write(chip, desc->rightreg, desc->volfunc(right));
1769cb7a01acSMauro Carvalho Chehab 		return 0;
1770cb7a01acSMauro Carvalho Chehab 	}
1771cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_AUDIO_BASS:
1772c9114031SHans Verkuil 		chip_write(chip, desc->bassreg, desc->bassfunc(ctrl->val));
1773cb7a01acSMauro Carvalho Chehab 		return 0;
1774cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_AUDIO_TREBLE:
1775c9114031SHans Verkuil 		chip_write(chip, desc->treblereg, desc->treblefunc(ctrl->val));
1776cb7a01acSMauro Carvalho Chehab 		return 0;
1777cb7a01acSMauro Carvalho Chehab 	}
1778cb7a01acSMauro Carvalho Chehab 	return -EINVAL;
1779cb7a01acSMauro Carvalho Chehab }
1780cb7a01acSMauro Carvalho Chehab 
1781cb7a01acSMauro Carvalho Chehab 
1782cb7a01acSMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
1783cb7a01acSMauro Carvalho Chehab /* video4linux interface                                                  */
1784cb7a01acSMauro Carvalho Chehab 
tvaudio_s_radio(struct v4l2_subdev * sd)1785cb7a01acSMauro Carvalho Chehab static int tvaudio_s_radio(struct v4l2_subdev *sd)
1786cb7a01acSMauro Carvalho Chehab {
1787cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip = to_state(sd);
1788cb7a01acSMauro Carvalho Chehab 
1789cb7a01acSMauro Carvalho Chehab 	chip->radio = 1;
1790cb7a01acSMauro Carvalho Chehab 	/* del_timer(&chip->wt); */
1791cb7a01acSMauro Carvalho Chehab 	return 0;
1792cb7a01acSMauro Carvalho Chehab }
1793cb7a01acSMauro Carvalho Chehab 
tvaudio_s_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)1794cb7a01acSMauro Carvalho Chehab static int tvaudio_s_routing(struct v4l2_subdev *sd,
1795cb7a01acSMauro Carvalho Chehab 			     u32 input, u32 output, u32 config)
1796cb7a01acSMauro Carvalho Chehab {
1797cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip = to_state(sd);
1798cb7a01acSMauro Carvalho Chehab 	struct CHIPDESC *desc = chip->desc;
1799cb7a01acSMauro Carvalho Chehab 
1800cb7a01acSMauro Carvalho Chehab 	if (!(desc->flags & CHIP_HAS_INPUTSEL))
1801cb7a01acSMauro Carvalho Chehab 		return 0;
1802cb7a01acSMauro Carvalho Chehab 	if (input >= 4)
1803cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1804cb7a01acSMauro Carvalho Chehab 	/* There are four inputs: tuner, radio, extern and intern. */
1805cb7a01acSMauro Carvalho Chehab 	chip->input = input;
1806cb7a01acSMauro Carvalho Chehab 	if (chip->muted)
1807cb7a01acSMauro Carvalho Chehab 		return 0;
1808cb7a01acSMauro Carvalho Chehab 	chip_write_masked(chip, desc->inputreg,
1809cb7a01acSMauro Carvalho Chehab 			desc->inputmap[chip->input], desc->inputmask);
1810cb7a01acSMauro Carvalho Chehab 	return 0;
1811cb7a01acSMauro Carvalho Chehab }
1812cb7a01acSMauro Carvalho Chehab 
tvaudio_s_tuner(struct v4l2_subdev * sd,const struct v4l2_tuner * vt)18132f73c7c5SHans Verkuil static int tvaudio_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
1814cb7a01acSMauro Carvalho Chehab {
1815cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip = to_state(sd);
1816cb7a01acSMauro Carvalho Chehab 	struct CHIPDESC *desc = chip->desc;
1817cb7a01acSMauro Carvalho Chehab 
1818cb7a01acSMauro Carvalho Chehab 	if (!desc->setaudmode)
1819cb7a01acSMauro Carvalho Chehab 		return 0;
1820cb7a01acSMauro Carvalho Chehab 	if (chip->radio)
1821cb7a01acSMauro Carvalho Chehab 		return 0;
1822cb7a01acSMauro Carvalho Chehab 
1823cb7a01acSMauro Carvalho Chehab 	switch (vt->audmode) {
1824cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_MONO:
1825cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_STEREO:
1826cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1:
1827cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG2:
1828cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1_LANG2:
1829cb7a01acSMauro Carvalho Chehab 		break;
1830cb7a01acSMauro Carvalho Chehab 	default:
1831cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1832cb7a01acSMauro Carvalho Chehab 	}
1833cb7a01acSMauro Carvalho Chehab 	chip->audmode = vt->audmode;
1834cb7a01acSMauro Carvalho Chehab 
1835cb7a01acSMauro Carvalho Chehab 	if (chip->thread)
1836cb7a01acSMauro Carvalho Chehab 		wake_up_process(chip->thread);
1837cb7a01acSMauro Carvalho Chehab 	else
1838cb7a01acSMauro Carvalho Chehab 		desc->setaudmode(chip, vt->audmode);
1839cb7a01acSMauro Carvalho Chehab 
1840cb7a01acSMauro Carvalho Chehab 	return 0;
1841cb7a01acSMauro Carvalho Chehab }
1842cb7a01acSMauro Carvalho Chehab 
tvaudio_g_tuner(struct v4l2_subdev * sd,struct v4l2_tuner * vt)1843cb7a01acSMauro Carvalho Chehab static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1844cb7a01acSMauro Carvalho Chehab {
1845cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip = to_state(sd);
1846cb7a01acSMauro Carvalho Chehab 	struct CHIPDESC *desc = chip->desc;
1847cb7a01acSMauro Carvalho Chehab 
1848cb7a01acSMauro Carvalho Chehab 	if (!desc->getrxsubchans)
1849cb7a01acSMauro Carvalho Chehab 		return 0;
1850cb7a01acSMauro Carvalho Chehab 	if (chip->radio)
1851cb7a01acSMauro Carvalho Chehab 		return 0;
1852cb7a01acSMauro Carvalho Chehab 
1853cb7a01acSMauro Carvalho Chehab 	vt->audmode = chip->audmode;
1854cb7a01acSMauro Carvalho Chehab 	vt->rxsubchans = desc->getrxsubchans(chip);
18553d4b8035SHans Verkuil 	vt->capability |= V4L2_TUNER_CAP_STEREO |
1856cb7a01acSMauro Carvalho Chehab 		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
1857cb7a01acSMauro Carvalho Chehab 
1858cb7a01acSMauro Carvalho Chehab 	return 0;
1859cb7a01acSMauro Carvalho Chehab }
1860cb7a01acSMauro Carvalho Chehab 
tvaudio_s_std(struct v4l2_subdev * sd,v4l2_std_id std)1861cb7a01acSMauro Carvalho Chehab static int tvaudio_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1862cb7a01acSMauro Carvalho Chehab {
1863cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip = to_state(sd);
1864cb7a01acSMauro Carvalho Chehab 
1865cb7a01acSMauro Carvalho Chehab 	chip->radio = 0;
1866cb7a01acSMauro Carvalho Chehab 	return 0;
1867cb7a01acSMauro Carvalho Chehab }
1868cb7a01acSMauro Carvalho Chehab 
tvaudio_s_frequency(struct v4l2_subdev * sd,const struct v4l2_frequency * freq)1869b530a447SHans Verkuil static int tvaudio_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
1870cb7a01acSMauro Carvalho Chehab {
1871cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip = to_state(sd);
1872cb7a01acSMauro Carvalho Chehab 	struct CHIPDESC *desc = chip->desc;
1873cb7a01acSMauro Carvalho Chehab 
1874cb7a01acSMauro Carvalho Chehab 	/* For chips that provide getrxsubchans and setaudmode, and doesn't
1875cb7a01acSMauro Carvalho Chehab 	   automatically follows the stereo carrier, a kthread is
1876cb7a01acSMauro Carvalho Chehab 	   created to set the audio standard. In this case, when then
1877cb7a01acSMauro Carvalho Chehab 	   the video channel is changed, tvaudio starts on MONO mode.
1878cb7a01acSMauro Carvalho Chehab 	   After waiting for 2 seconds, the kernel thread is called,
1879cb7a01acSMauro Carvalho Chehab 	   to follow whatever audio standard is pointed by the
1880cb7a01acSMauro Carvalho Chehab 	   audio carrier.
1881cb7a01acSMauro Carvalho Chehab 	 */
1882cb7a01acSMauro Carvalho Chehab 	if (chip->thread) {
1883cb7a01acSMauro Carvalho Chehab 		desc->setaudmode(chip, V4L2_TUNER_MODE_MONO);
1884cb7a01acSMauro Carvalho Chehab 		chip->prevmode = -1; /* reset previous mode */
1885cb7a01acSMauro Carvalho Chehab 		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
1886cb7a01acSMauro Carvalho Chehab 	}
1887cb7a01acSMauro Carvalho Chehab 	return 0;
1888cb7a01acSMauro Carvalho Chehab }
1889cb7a01acSMauro Carvalho Chehab 
tvaudio_log_status(struct v4l2_subdev * sd)1890c9114031SHans Verkuil static int tvaudio_log_status(struct v4l2_subdev *sd)
1891c9114031SHans Verkuil {
1892c9114031SHans Verkuil 	struct CHIPSTATE *chip = to_state(sd);
1893c9114031SHans Verkuil 	struct CHIPDESC *desc = chip->desc;
1894c9114031SHans Verkuil 
1895c9114031SHans Verkuil 	v4l2_info(sd, "Chip: %s\n", desc->name);
1896c9114031SHans Verkuil 	v4l2_ctrl_handler_log_status(&chip->hdl, sd->name);
1897c9114031SHans Verkuil 	return 0;
1898c9114031SHans Verkuil }
1899c9114031SHans Verkuil 
1900cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1901cb7a01acSMauro Carvalho Chehab 
1902c9114031SHans Verkuil static const struct v4l2_ctrl_ops tvaudio_ctrl_ops = {
1903cb7a01acSMauro Carvalho Chehab 	.s_ctrl = tvaudio_s_ctrl,
1904c9114031SHans Verkuil };
1905c9114031SHans Verkuil 
1906c9114031SHans Verkuil static const struct v4l2_subdev_core_ops tvaudio_core_ops = {
1907c9114031SHans Verkuil 	.log_status = tvaudio_log_status,
1908cb7a01acSMauro Carvalho Chehab };
1909cb7a01acSMauro Carvalho Chehab 
1910cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = {
1911cb7a01acSMauro Carvalho Chehab 	.s_radio = tvaudio_s_radio,
1912cb7a01acSMauro Carvalho Chehab 	.s_frequency = tvaudio_s_frequency,
1913cb7a01acSMauro Carvalho Chehab 	.s_tuner = tvaudio_s_tuner,
1914cb7a01acSMauro Carvalho Chehab 	.g_tuner = tvaudio_g_tuner,
1915cb7a01acSMauro Carvalho Chehab };
1916cb7a01acSMauro Carvalho Chehab 
1917cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_audio_ops tvaudio_audio_ops = {
1918cb7a01acSMauro Carvalho Chehab 	.s_routing = tvaudio_s_routing,
1919cb7a01acSMauro Carvalho Chehab };
1920cb7a01acSMauro Carvalho Chehab 
19218774bed9SLaurent Pinchart static const struct v4l2_subdev_video_ops tvaudio_video_ops = {
19228774bed9SLaurent Pinchart 	.s_std = tvaudio_s_std,
19238774bed9SLaurent Pinchart };
19248774bed9SLaurent Pinchart 
1925cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tvaudio_ops = {
1926cb7a01acSMauro Carvalho Chehab 	.core = &tvaudio_core_ops,
1927cb7a01acSMauro Carvalho Chehab 	.tuner = &tvaudio_tuner_ops,
1928cb7a01acSMauro Carvalho Chehab 	.audio = &tvaudio_audio_ops,
19298774bed9SLaurent Pinchart 	.video = &tvaudio_video_ops,
1930cb7a01acSMauro Carvalho Chehab };
1931cb7a01acSMauro Carvalho Chehab 
1932cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1933cb7a01acSMauro Carvalho Chehab 
1934cb7a01acSMauro Carvalho Chehab 
1935cb7a01acSMauro Carvalho Chehab /* i2c registration                                                       */
1936cb7a01acSMauro Carvalho Chehab 
tvaudio_probe(struct i2c_client * client)19377db820b1SUwe Kleine-König static int tvaudio_probe(struct i2c_client *client)
1938cb7a01acSMauro Carvalho Chehab {
19397db820b1SUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
1940cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip;
1941cb7a01acSMauro Carvalho Chehab 	struct CHIPDESC  *desc;
1942cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
1943cb7a01acSMauro Carvalho Chehab 
1944cb7a01acSMauro Carvalho Chehab 	if (debug) {
1945cb7a01acSMauro Carvalho Chehab 		printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
1946cb7a01acSMauro Carvalho Chehab 		printk(KERN_INFO "tvaudio: known chips: ");
1947cb7a01acSMauro Carvalho Chehab 		for (desc = chiplist; desc->name != NULL; desc++)
1948178991e0SMauro Carvalho Chehab 			printk(KERN_CONT "%s%s",
1949178991e0SMauro Carvalho Chehab 			       (desc == chiplist) ? "" : ", ", desc->name);
1950178991e0SMauro Carvalho Chehab 		printk(KERN_CONT "\n");
1951cb7a01acSMauro Carvalho Chehab 	}
1952cb7a01acSMauro Carvalho Chehab 
1953c02b211dSLaurent Pinchart 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
1954cb7a01acSMauro Carvalho Chehab 	if (!chip)
1955cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
1956cb7a01acSMauro Carvalho Chehab 	sd = &chip->sd;
1957cb7a01acSMauro Carvalho Chehab 	v4l2_i2c_subdev_init(sd, client, &tvaudio_ops);
1958cb7a01acSMauro Carvalho Chehab 
1959cb7a01acSMauro Carvalho Chehab 	/* find description for the chip */
1960cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "chip found @ 0x%x\n", client->addr<<1);
1961cb7a01acSMauro Carvalho Chehab 	for (desc = chiplist; desc->name != NULL; desc++) {
1962cb7a01acSMauro Carvalho Chehab 		if (0 == *(desc->insmodopt))
1963cb7a01acSMauro Carvalho Chehab 			continue;
1964cb7a01acSMauro Carvalho Chehab 		if (client->addr < desc->addr_lo ||
1965cb7a01acSMauro Carvalho Chehab 		    client->addr > desc->addr_hi)
1966cb7a01acSMauro Carvalho Chehab 			continue;
1967cb7a01acSMauro Carvalho Chehab 		if (desc->checkit && !desc->checkit(chip))
1968cb7a01acSMauro Carvalho Chehab 			continue;
1969cb7a01acSMauro Carvalho Chehab 		break;
1970cb7a01acSMauro Carvalho Chehab 	}
1971cb7a01acSMauro Carvalho Chehab 	if (desc->name == NULL) {
1972cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd, "no matching chip description found\n");
1973cb7a01acSMauro Carvalho Chehab 		return -EIO;
1974cb7a01acSMauro Carvalho Chehab 	}
1975cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
1976cb7a01acSMauro Carvalho Chehab 	if (desc->flags) {
1977cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd, "matches:%s%s%s.\n",
1978cb7a01acSMauro Carvalho Chehab 			(desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
1979cb7a01acSMauro Carvalho Chehab 			(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
1980cb7a01acSMauro Carvalho Chehab 			(desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
1981cb7a01acSMauro Carvalho Chehab 	}
1982cb7a01acSMauro Carvalho Chehab 
1983cb7a01acSMauro Carvalho Chehab 	/* fill required data structures */
1984cb7a01acSMauro Carvalho Chehab 	if (!id)
1985c0decac1SMauro Carvalho Chehab 		strscpy(client->name, desc->name, I2C_NAME_SIZE);
1986cb7a01acSMauro Carvalho Chehab 	chip->desc = desc;
1987cb7a01acSMauro Carvalho Chehab 	chip->shadow.count = desc->registers+1;
1988cb7a01acSMauro Carvalho Chehab 	chip->prevmode = -1;
1989cb7a01acSMauro Carvalho Chehab 	chip->audmode = V4L2_TUNER_MODE_LANG1;
1990cb7a01acSMauro Carvalho Chehab 
1991cb7a01acSMauro Carvalho Chehab 	/* initialization  */
1992cb7a01acSMauro Carvalho Chehab 	if (desc->initialize != NULL)
1993cb7a01acSMauro Carvalho Chehab 		desc->initialize(chip);
1994cb7a01acSMauro Carvalho Chehab 	else
1995cb7a01acSMauro Carvalho Chehab 		chip_cmd(chip, "init", &desc->init);
1996cb7a01acSMauro Carvalho Chehab 
1997c9114031SHans Verkuil 	v4l2_ctrl_handler_init(&chip->hdl, 5);
1998c9114031SHans Verkuil 	if (desc->flags & CHIP_HAS_INPUTSEL)
1999c9114031SHans Verkuil 		v4l2_ctrl_new_std(&chip->hdl, &tvaudio_ctrl_ops,
2000c9114031SHans Verkuil 			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
2001cb7a01acSMauro Carvalho Chehab 	if (desc->flags & CHIP_HAS_VOLUME) {
2002cb7a01acSMauro Carvalho Chehab 		if (!desc->volfunc) {
2003cb7a01acSMauro Carvalho Chehab 			/* This shouldn't be happen. Warn user, but keep working
2004cb7a01acSMauro Carvalho Chehab 			   without volume controls
2005cb7a01acSMauro Carvalho Chehab 			 */
2006cb7a01acSMauro Carvalho Chehab 			v4l2_info(sd, "volume callback undefined!\n");
2007cb7a01acSMauro Carvalho Chehab 			desc->flags &= ~CHIP_HAS_VOLUME;
2008cb7a01acSMauro Carvalho Chehab 		} else {
2009c9114031SHans Verkuil 			chip->volume = v4l2_ctrl_new_std(&chip->hdl,
2010c9114031SHans Verkuil 				&tvaudio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
2011c9114031SHans Verkuil 				0, 65535, 65535 / 100,
2012c9114031SHans Verkuil 				desc->volinit ? desc->volinit : 65535);
2013c9114031SHans Verkuil 			chip->balance = v4l2_ctrl_new_std(&chip->hdl,
2014c9114031SHans Verkuil 				&tvaudio_ctrl_ops, V4L2_CID_AUDIO_BALANCE,
2015c9114031SHans Verkuil 				0, 65535, 65535 / 100, 32768);
2016c9114031SHans Verkuil 			v4l2_ctrl_cluster(2, &chip->volume);
2017cb7a01acSMauro Carvalho Chehab 		}
2018cb7a01acSMauro Carvalho Chehab 	}
2019cb7a01acSMauro Carvalho Chehab 	if (desc->flags & CHIP_HAS_BASSTREBLE) {
2020cb7a01acSMauro Carvalho Chehab 		if (!desc->bassfunc || !desc->treblefunc) {
2021cb7a01acSMauro Carvalho Chehab 			/* This shouldn't be happen. Warn user, but keep working
2022cb7a01acSMauro Carvalho Chehab 			   without bass/treble controls
2023cb7a01acSMauro Carvalho Chehab 			 */
2024cb7a01acSMauro Carvalho Chehab 			v4l2_info(sd, "bass/treble callbacks undefined!\n");
2025cb7a01acSMauro Carvalho Chehab 			desc->flags &= ~CHIP_HAS_BASSTREBLE;
2026cb7a01acSMauro Carvalho Chehab 		} else {
2027c9114031SHans Verkuil 			v4l2_ctrl_new_std(&chip->hdl,
2028c9114031SHans Verkuil 				&tvaudio_ctrl_ops, V4L2_CID_AUDIO_BASS,
2029c9114031SHans Verkuil 				0, 65535, 65535 / 100,
2030c9114031SHans Verkuil 				desc->bassinit ? desc->bassinit : 32768);
2031c9114031SHans Verkuil 			v4l2_ctrl_new_std(&chip->hdl,
2032c9114031SHans Verkuil 				&tvaudio_ctrl_ops, V4L2_CID_AUDIO_TREBLE,
2033c9114031SHans Verkuil 				0, 65535, 65535 / 100,
2034c9114031SHans Verkuil 				desc->trebleinit ? desc->trebleinit : 32768);
2035cb7a01acSMauro Carvalho Chehab 		}
2036cb7a01acSMauro Carvalho Chehab 	}
2037cb7a01acSMauro Carvalho Chehab 
2038c9114031SHans Verkuil 	sd->ctrl_handler = &chip->hdl;
2039c9114031SHans Verkuil 	if (chip->hdl.error) {
2040c9114031SHans Verkuil 		int err = chip->hdl.error;
2041c9114031SHans Verkuil 
2042c9114031SHans Verkuil 		v4l2_ctrl_handler_free(&chip->hdl);
2043c9114031SHans Verkuil 		return err;
2044c9114031SHans Verkuil 	}
2045c9114031SHans Verkuil 	/* set controls to the default values */
2046c9114031SHans Verkuil 	v4l2_ctrl_handler_setup(&chip->hdl);
2047c9114031SHans Verkuil 
2048cb7a01acSMauro Carvalho Chehab 	chip->thread = NULL;
204960793f4dSKees Cook 	timer_setup(&chip->wt, chip_thread_wake, 0);
2050cb7a01acSMauro Carvalho Chehab 	if (desc->flags & CHIP_NEED_CHECKMODE) {
2051cb7a01acSMauro Carvalho Chehab 		if (!desc->getrxsubchans || !desc->setaudmode) {
2052cb7a01acSMauro Carvalho Chehab 			/* This shouldn't be happen. Warn user, but keep working
2053cb7a01acSMauro Carvalho Chehab 			   without kthread
2054cb7a01acSMauro Carvalho Chehab 			 */
2055cb7a01acSMauro Carvalho Chehab 			v4l2_info(sd, "set/get mode callbacks undefined!\n");
2056cb7a01acSMauro Carvalho Chehab 			return 0;
2057cb7a01acSMauro Carvalho Chehab 		}
2058cb7a01acSMauro Carvalho Chehab 		/* start async thread */
2059f170168bSKees Cook 		chip->thread = kthread_run(chip_thread, chip, "%s",
2060f170168bSKees Cook 					   client->name);
2061cb7a01acSMauro Carvalho Chehab 		if (IS_ERR(chip->thread)) {
2062cb7a01acSMauro Carvalho Chehab 			v4l2_warn(sd, "failed to create kthread\n");
2063cb7a01acSMauro Carvalho Chehab 			chip->thread = NULL;
2064cb7a01acSMauro Carvalho Chehab 		}
2065cb7a01acSMauro Carvalho Chehab 	}
2066cb7a01acSMauro Carvalho Chehab 	return 0;
2067cb7a01acSMauro Carvalho Chehab }
2068cb7a01acSMauro Carvalho Chehab 
tvaudio_remove(struct i2c_client * client)2069ed5c2f5fSUwe Kleine-König static void tvaudio_remove(struct i2c_client *client)
2070cb7a01acSMauro Carvalho Chehab {
2071cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
2072cb7a01acSMauro Carvalho Chehab 	struct CHIPSTATE *chip = to_state(sd);
2073cb7a01acSMauro Carvalho Chehab 
2074cb7a01acSMauro Carvalho Chehab 	del_timer_sync(&chip->wt);
2075cb7a01acSMauro Carvalho Chehab 	if (chip->thread) {
2076cb7a01acSMauro Carvalho Chehab 		/* shutdown async thread */
2077cb7a01acSMauro Carvalho Chehab 		kthread_stop(chip->thread);
2078cb7a01acSMauro Carvalho Chehab 		chip->thread = NULL;
2079cb7a01acSMauro Carvalho Chehab 	}
2080cb7a01acSMauro Carvalho Chehab 
2081cb7a01acSMauro Carvalho Chehab 	v4l2_device_unregister_subdev(sd);
2082c9114031SHans Verkuil 	v4l2_ctrl_handler_free(&chip->hdl);
2083cb7a01acSMauro Carvalho Chehab }
2084cb7a01acSMauro Carvalho Chehab 
2085cb7a01acSMauro Carvalho Chehab /* This driver supports many devices and the idea is to let the driver
2086cb7a01acSMauro Carvalho Chehab    detect which device is present. So rather than listing all supported
2087cb7a01acSMauro Carvalho Chehab    devices here, we pretend to support a single, fake device type. */
2088cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tvaudio_id[] = {
2089cb7a01acSMauro Carvalho Chehab 	{ "tvaudio", 0 },
2090cb7a01acSMauro Carvalho Chehab 	{ }
2091cb7a01acSMauro Carvalho Chehab };
2092cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tvaudio_id);
2093cb7a01acSMauro Carvalho Chehab 
2094cb7a01acSMauro Carvalho Chehab static struct i2c_driver tvaudio_driver = {
2095cb7a01acSMauro Carvalho Chehab 	.driver = {
2096cb7a01acSMauro Carvalho Chehab 		.name	= "tvaudio",
2097cb7a01acSMauro Carvalho Chehab 	},
2098*aaeb31c0SUwe Kleine-König 	.probe		= tvaudio_probe,
2099cb7a01acSMauro Carvalho Chehab 	.remove		= tvaudio_remove,
2100cb7a01acSMauro Carvalho Chehab 	.id_table	= tvaudio_id,
2101cb7a01acSMauro Carvalho Chehab };
2102cb7a01acSMauro Carvalho Chehab 
2103cb7a01acSMauro Carvalho Chehab module_i2c_driver(tvaudio_driver);
2104