Merge branch 'sh-latest' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal...
[pandora-kernel.git] / drivers / media / common / tuners / tda18212.c
1 /*
2  * NXP TDA18212HN silicon tuner driver
3  *
4  * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
5  *
6  *    This program is free software; you can redistribute it and/or modify
7  *    it under the terms of the GNU General Public License as published by
8  *    the Free Software Foundation; either version 2 of the License, or
9  *    (at your option) any later version.
10  *
11  *    This program is distributed in the hope that it will be useful,
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *    GNU General Public License for more details.
15  *
16  *    You should have received a copy of the GNU General Public License along
17  *    with this program; if not, write to the Free Software Foundation, Inc.,
18  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "tda18212_priv.h"
22
23 static int debug;
24 module_param(debug, int, 0644);
25 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
26
27 /* write multiple registers */
28 static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
29         int len)
30 {
31         int ret;
32         u8 buf[len+1];
33         struct i2c_msg msg[1] = {
34                 {
35                         .addr = priv->cfg->i2c_address,
36                         .flags = 0,
37                         .len = sizeof(buf),
38                         .buf = buf,
39                 }
40         };
41
42         buf[0] = reg;
43         memcpy(&buf[1], val, len);
44
45         ret = i2c_transfer(priv->i2c, msg, 1);
46         if (ret == 1) {
47                 ret = 0;
48         } else {
49                 warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
50                 ret = -EREMOTEIO;
51         }
52         return ret;
53 }
54
55 /* read multiple registers */
56 static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
57         int len)
58 {
59         int ret;
60         u8 buf[len];
61         struct i2c_msg msg[2] = {
62                 {
63                         .addr = priv->cfg->i2c_address,
64                         .flags = 0,
65                         .len = 1,
66                         .buf = &reg,
67                 }, {
68                         .addr = priv->cfg->i2c_address,
69                         .flags = I2C_M_RD,
70                         .len = sizeof(buf),
71                         .buf = buf,
72                 }
73         };
74
75         ret = i2c_transfer(priv->i2c, msg, 2);
76         if (ret == 2) {
77                 memcpy(val, buf, len);
78                 ret = 0;
79         } else {
80                 warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
81                 ret = -EREMOTEIO;
82         }
83
84         return ret;
85 }
86
87 /* write single register */
88 static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
89 {
90         return tda18212_wr_regs(priv, reg, &val, 1);
91 }
92
93 /* read single register */
94 static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
95 {
96         return tda18212_rd_regs(priv, reg, val, 1);
97 }
98
99 #if 0 /* keep, useful when developing driver */
100 static void tda18212_dump_regs(struct tda18212_priv *priv)
101 {
102         int i;
103         u8 buf[256];
104
105         #define TDA18212_RD_LEN 32
106         for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
107                 tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
108
109         print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
110                 sizeof(buf), true);
111
112         return;
113 }
114 #endif
115
116 static int tda18212_set_params(struct dvb_frontend *fe,
117         struct dvb_frontend_parameters *p)
118 {
119         struct tda18212_priv *priv = fe->tuner_priv;
120         struct dtv_frontend_properties *c = &fe->dtv_property_cache;
121         int ret, i;
122         u32 if_khz;
123         u8 buf[9];
124         static const u8 bw_params[][3] = {
125                 /*  0f    13    23 */
126                 { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */
127                 { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */
128                 { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */
129                 { 0x92, 0x53, 0x03 }, /* DVB-C */
130         };
131
132         dbg("%s: delsys=%d RF=%d BW=%d", __func__,
133                 c->delivery_system, c->frequency, c->bandwidth_hz);
134
135         if (fe->ops.i2c_gate_ctrl)
136                 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
137
138         switch (c->delivery_system) {
139         case SYS_DVBT:
140                 switch (c->bandwidth_hz) {
141                 case 6000000:
142                         if_khz = priv->cfg->if_dvbt_6;
143                         i = 0;
144                         break;
145                 case 7000000:
146                         if_khz = priv->cfg->if_dvbt_7;
147                         i = 1;
148                         break;
149                 case 8000000:
150                         if_khz = priv->cfg->if_dvbt_8;
151                         i = 2;
152                         break;
153                 default:
154                         ret = -EINVAL;
155                         goto error;
156                 }
157                 break;
158         case SYS_DVBC_ANNEX_AC:
159                 if_khz = priv->cfg->if_dvbc;
160                 i = 3;
161                 break;
162         default:
163                 ret = -EINVAL;
164                 goto error;
165         }
166
167         ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
168         if (ret)
169                 goto error;
170
171         ret = tda18212_wr_reg(priv, 0x06, 0x00);
172         if (ret)
173                 goto error;
174
175         ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
176         if (ret)
177                 goto error;
178
179         buf[0] = 0x02;
180         buf[1] = bw_params[i][1];
181         buf[2] = 0x03; /* default value */
182         buf[3] = if_khz / 50;
183         buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
184         buf[5] = ((c->frequency / 1000) >>  8) & 0xff;
185         buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
186         buf[7] = 0xc1;
187         buf[8] = 0x01;
188         ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
189         if (ret)
190                 goto error;
191
192 exit:
193         if (fe->ops.i2c_gate_ctrl)
194                 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
195
196         return ret;
197
198 error:
199         dbg("%s: failed:%d", __func__, ret);
200         goto exit;
201 }
202
203 static int tda18212_release(struct dvb_frontend *fe)
204 {
205         kfree(fe->tuner_priv);
206         fe->tuner_priv = NULL;
207         return 0;
208 }
209
210 static const struct dvb_tuner_ops tda18212_tuner_ops = {
211         .info = {
212                 .name           = "NXP TDA18212",
213
214                 .frequency_min  =  48000000,
215                 .frequency_max  = 864000000,
216                 .frequency_step =      1000,
217         },
218
219         .release       = tda18212_release,
220
221         .set_params    = tda18212_set_params,
222 };
223
224 struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
225         struct i2c_adapter *i2c, struct tda18212_config *cfg)
226 {
227         struct tda18212_priv *priv = NULL;
228         int ret;
229         u8 val;
230
231         priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
232         if (priv == NULL)
233                 return NULL;
234
235         priv->cfg = cfg;
236         priv->i2c = i2c;
237         fe->tuner_priv = priv;
238
239         if (fe->ops.i2c_gate_ctrl)
240                 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
241
242         /* check if the tuner is there */
243         ret = tda18212_rd_reg(priv, 0x00, &val);
244
245         if (fe->ops.i2c_gate_ctrl)
246                 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
247
248         dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
249         if (ret || val != 0xc7) {
250                 kfree(priv);
251                 return NULL;
252         }
253
254         info("NXP TDA18212HN successfully identified.");
255
256         memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
257                 sizeof(struct dvb_tuner_ops));
258
259         return fe;
260 }
261 EXPORT_SYMBOL(tda18212_attach);
262
263 MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
264 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
265 MODULE_LICENSE("GPL");