1 // SPDX-License-Identifier: GPL-2.0-or-later
4 Copyright (C) Manu Abraham (abraham.manu@gmail.com)
8 #include <linux/init.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
13 #include <media/dvb_frontend.h>
16 struct tda665x_state
{
17 struct dvb_frontend
*fe
;
18 struct i2c_adapter
*i2c
;
19 const struct tda665x_config
*config
;
25 static int tda665x_read(struct tda665x_state
*state
, u8
*buf
)
27 const struct tda665x_config
*config
= state
->config
;
29 struct i2c_msg msg
= { .addr
= config
->addr
, .flags
= I2C_M_RD
, .buf
= buf
, .len
= 2 };
31 err
= i2c_transfer(state
->i2c
, &msg
, 1);
37 printk(KERN_ERR
"%s: I/O Error err=<%d>\n", __func__
, err
);
41 static int tda665x_write(struct tda665x_state
*state
, u8
*buf
, u8 length
)
43 const struct tda665x_config
*config
= state
->config
;
45 struct i2c_msg msg
= { .addr
= config
->addr
, .flags
= 0, .buf
= buf
, .len
= length
};
47 err
= i2c_transfer(state
->i2c
, &msg
, 1);
53 printk(KERN_ERR
"%s: I/O Error err=<%d>\n", __func__
, err
);
57 static int tda665x_get_frequency(struct dvb_frontend
*fe
, u32
*frequency
)
59 struct tda665x_state
*state
= fe
->tuner_priv
;
61 *frequency
= state
->frequency
;
66 static int tda665x_get_status(struct dvb_frontend
*fe
, u32
*status
)
68 struct tda665x_state
*state
= fe
->tuner_priv
;
74 err
= tda665x_read(state
, &result
);
78 if ((result
>> 6) & 0x01) {
79 printk(KERN_DEBUG
"%s: Tuner Phase Locked\n", __func__
);
85 printk(KERN_ERR
"%s: I/O Error\n", __func__
);
89 static int tda665x_set_frequency(struct dvb_frontend
*fe
,
92 struct tda665x_state
*state
= fe
->tuner_priv
;
93 const struct tda665x_config
*config
= state
->config
;
94 u32 frequency
, status
= 0;
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
);
105 frequency
= new_frequency
;
107 frequency
+= config
->frequency_offst
;
108 frequency
*= config
->ref_multiplier
;
109 frequency
+= config
->ref_divider
>> 1;
110 frequency
/= config
->ref_divider
;
112 buf
[0] = (u8
) ((frequency
& 0x7f00) >> 8);
113 buf
[1] = (u8
) (frequency
& 0x00ff) >> 0;
114 buf
[2] = 0x80 | 0x40 | 0x02;
117 /* restore frequency */
118 frequency
= new_frequency
;
120 if (frequency
< 153000000) {
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 */
130 buf
[3] |= 0xa0; /* 254uA */
131 } else if (frequency
< 438000000) {
133 buf
[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
134 if (frequency
< 230000000)
136 if (frequency
< 300000000)
142 buf
[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
143 if (frequency
< 470000000)
145 if (frequency
< 526000000)
152 err
= tda665x_write(state
, buf
, 5);
156 /* sleep for some time */
157 printk(KERN_DEBUG
"%s: Waiting to Phase LOCK\n", __func__
);
160 err
= tda665x_get_status(fe
, &status
);
165 printk(KERN_DEBUG
"%s: Tuner Phase locked: status=%d\n",
167 state
->frequency
= frequency
; /* cache successful state */
169 printk(KERN_ERR
"%s: No Phase lock: status=%d\n",
175 printk(KERN_ERR
"%s: I/O Error\n", __func__
);
179 static int tda665x_set_params(struct dvb_frontend
*fe
)
181 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
183 tda665x_set_frequency(fe
, c
->frequency
);
188 static void tda665x_release(struct dvb_frontend
*fe
)
190 struct tda665x_state
*state
= fe
->tuner_priv
;
192 fe
->tuner_priv
= NULL
;
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
203 struct dvb_frontend
*tda665x_attach(struct dvb_frontend
*fe
,
204 const struct tda665x_config
*config
,
205 struct i2c_adapter
*i2c
)
207 struct tda665x_state
*state
= NULL
;
208 struct dvb_tuner_info
*info
;
210 state
= kzalloc(sizeof(struct tda665x_state
), GFP_KERNEL
);
214 state
->config
= config
;
217 fe
->tuner_priv
= state
;
218 fe
->ops
.tuner_ops
= tda665x_ops
;
219 info
= &fe
->ops
.tuner_ops
.info
;
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
;
226 printk(KERN_DEBUG
"%s: Attaching TDA665x (%s) tuner\n", __func__
, info
->name
);
230 EXPORT_SYMBOL(tda665x_attach
);
232 MODULE_DESCRIPTION("TDA665x driver");
233 MODULE_AUTHOR("Manu Abraham");
234 MODULE_LICENSE("GPL");