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