Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / media / dvb-frontends / tda665x.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3         TDA665x tuner driver
4         Copyright (C) Manu Abraham (abraham.manu@gmail.com)
5
6 */
7
8 #include <linux/init.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12
13 #include <media/dvb_frontend.h>
14 #include "tda665x.h"
15
16 struct tda665x_state {
17         struct dvb_frontend             *fe;
18         struct i2c_adapter              *i2c;
19         const struct tda665x_config     *config;
20
21         u32 frequency;
22         u32 bandwidth;
23 };
24
25 static int tda665x_read(struct tda665x_state *state, u8 *buf)
26 {
27         const struct tda665x_config *config = state->config;
28         int err = 0;
29         struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
30
31         err = i2c_transfer(state->i2c, &msg, 1);
32         if (err != 1)
33                 goto exit;
34
35         return err;
36 exit:
37         printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
38         return err;
39 }
40
41 static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
42 {
43         const struct tda665x_config *config = state->config;
44         int err = 0;
45         struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
46
47         err = i2c_transfer(state->i2c, &msg, 1);
48         if (err != 1)
49                 goto exit;
50
51         return err;
52 exit:
53         printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
54         return err;
55 }
56
57 static int tda665x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
58 {
59         struct tda665x_state *state = fe->tuner_priv;
60
61         *frequency = state->frequency;
62
63         return 0;
64 }
65
66 static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
67 {
68         struct tda665x_state *state = fe->tuner_priv;
69         u8 result = 0;
70         int err = 0;
71
72         *status = 0;
73
74         err = tda665x_read(state, &result);
75         if (err < 0)
76                 goto exit;
77
78         if ((result >> 6) & 0x01) {
79                 printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
80                 *status = 1;
81         }
82
83         return err;
84 exit:
85         printk(KERN_ERR "%s: I/O Error\n", __func__);
86         return err;
87 }
88
89 static int tda665x_set_frequency(struct dvb_frontend *fe,
90                                  u32 new_frequency)
91 {
92         struct tda665x_state *state = fe->tuner_priv;
93         const struct tda665x_config *config = state->config;
94         u32 frequency, status = 0;
95         u8 buf[4];
96         int err = 0;
97
98         if ((new_frequency < config->frequency_max)
99             || (new_frequency > config->frequency_min)) {
100                 printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n",
101                        __func__, new_frequency);
102                 return -EINVAL;
103         }
104
105         frequency = new_frequency;
106
107         frequency += config->frequency_offst;
108         frequency *= config->ref_multiplier;
109         frequency += config->ref_divider >> 1;
110         frequency /= config->ref_divider;
111
112         buf[0] = (u8) ((frequency & 0x7f00) >> 8);
113         buf[1] = (u8) (frequency & 0x00ff) >> 0;
114         buf[2] = 0x80 | 0x40 | 0x02;
115         buf[3] = 0x00;
116
117         /* restore frequency */
118         frequency = new_frequency;
119
120         if (frequency < 153000000) {
121                 /* VHF-L */
122                 buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
123                 if (frequency < 68000000)
124                         buf[3] |= 0x40; /* 83uA */
125                 if (frequency < 1040000000)
126                         buf[3] |= 0x60; /* 122uA */
127                 if (frequency < 1250000000)
128                         buf[3] |= 0x80; /* 163uA */
129                 else
130                         buf[3] |= 0xa0; /* 254uA */
131         } else if (frequency < 438000000) {
132                 /* VHF-H */
133                 buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
134                 if (frequency < 230000000)
135                         buf[3] |= 0x40;
136                 if (frequency < 300000000)
137                         buf[3] |= 0x60;
138                 else
139                         buf[3] |= 0x80;
140         } else {
141                 /* UHF */
142                 buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
143                 if (frequency < 470000000)
144                         buf[3] |= 0x60;
145                 if (frequency < 526000000)
146                         buf[3] |= 0x80;
147                 else
148                         buf[3] |= 0xa0;
149         }
150
151         /* Set params */
152         err = tda665x_write(state, buf, 5);
153         if (err < 0)
154                 goto exit;
155
156         /* sleep for some time */
157         printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
158         msleep(20);
159         /* check status */
160         err = tda665x_get_status(fe, &status);
161         if (err < 0)
162                 goto exit;
163
164         if (status == 1) {
165                 printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n",
166                        __func__, status);
167                 state->frequency = frequency; /* cache successful state */
168         } else {
169                 printk(KERN_ERR "%s: No Phase lock: status=%d\n",
170                        __func__, status);
171         }
172
173         return 0;
174 exit:
175         printk(KERN_ERR "%s: I/O Error\n", __func__);
176         return err;
177 }
178
179 static int tda665x_set_params(struct dvb_frontend *fe)
180 {
181         struct dtv_frontend_properties *c = &fe->dtv_property_cache;
182
183         tda665x_set_frequency(fe, c->frequency);
184
185         return 0;
186 }
187
188 static void tda665x_release(struct dvb_frontend *fe)
189 {
190         struct tda665x_state *state = fe->tuner_priv;
191
192         fe->tuner_priv = NULL;
193         kfree(state);
194 }
195
196 static const struct dvb_tuner_ops tda665x_ops = {
197         .get_status     = tda665x_get_status,
198         .set_params     = tda665x_set_params,
199         .get_frequency  = tda665x_get_frequency,
200         .release        = tda665x_release
201 };
202
203 struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
204                                     const struct tda665x_config *config,
205                                     struct i2c_adapter *i2c)
206 {
207         struct tda665x_state *state = NULL;
208         struct dvb_tuner_info *info;
209
210         state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
211         if (!state)
212                 return NULL;
213
214         state->config           = config;
215         state->i2c              = i2c;
216         state->fe               = fe;
217         fe->tuner_priv          = state;
218         fe->ops.tuner_ops       = tda665x_ops;
219         info                     = &fe->ops.tuner_ops.info;
220
221         memcpy(info->name, config->name, sizeof(config->name));
222         info->frequency_min_hz  = config->frequency_min;
223         info->frequency_max_hz  = config->frequency_max;
224         info->frequency_step_hz = config->frequency_offst;
225
226         printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
227
228         return fe;
229 }
230 EXPORT_SYMBOL(tda665x_attach);
231
232 MODULE_DESCRIPTION("TDA665x driver");
233 MODULE_AUTHOR("Manu Abraham");
234 MODULE_LICENSE("GPL");