243 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 /*3 Driver for ST STB6000 DVBS Silicon tuner4 5 Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)6 7 8 */9 10#include <linux/slab.h>11#include <linux/module.h>12#include <linux/dvb/frontend.h>13#include <asm/types.h>14 15#include "stb6000.h"16 17static int debug;18#define dprintk(args...) \19 do { \20 if (debug) \21 printk(KERN_DEBUG "stb6000: " args); \22 } while (0)23 24struct stb6000_priv {25 /* i2c details */26 int i2c_address;27 struct i2c_adapter *i2c;28 u32 frequency;29};30 31static void stb6000_release(struct dvb_frontend *fe)32{33 kfree(fe->tuner_priv);34 fe->tuner_priv = NULL;35}36 37static int stb6000_sleep(struct dvb_frontend *fe)38{39 struct stb6000_priv *priv = fe->tuner_priv;40 int ret;41 u8 buf[] = { 10, 0 };42 struct i2c_msg msg = {43 .addr = priv->i2c_address,44 .flags = 0,45 .buf = buf,46 .len = 247 };48 49 dprintk("%s:\n", __func__);50 51 if (fe->ops.i2c_gate_ctrl)52 fe->ops.i2c_gate_ctrl(fe, 1);53 54 ret = i2c_transfer(priv->i2c, &msg, 1);55 if (ret != 1)56 dprintk("%s: i2c error\n", __func__);57 58 if (fe->ops.i2c_gate_ctrl)59 fe->ops.i2c_gate_ctrl(fe, 0);60 61 return (ret == 1) ? 0 : ret;62}63 64static int stb6000_set_params(struct dvb_frontend *fe)65{66 struct dtv_frontend_properties *p = &fe->dtv_property_cache;67 struct stb6000_priv *priv = fe->tuner_priv;68 unsigned int n, m;69 int ret;70 u32 freq_mhz;71 int bandwidth;72 u8 buf[12];73 struct i2c_msg msg = {74 .addr = priv->i2c_address,75 .flags = 0,76 .buf = buf,77 .len = 1278 };79 80 dprintk("%s:\n", __func__);81 82 freq_mhz = p->frequency / 1000;83 bandwidth = p->symbol_rate / 1000000;84 85 if (bandwidth > 31)86 bandwidth = 31;87 88 if ((freq_mhz > 949) && (freq_mhz < 2151)) {89 buf[0] = 0x01;90 buf[1] = 0xac;91 if (freq_mhz < 1950)92 buf[1] = 0xaa;93 if (freq_mhz < 1800)94 buf[1] = 0xa8;95 if (freq_mhz < 1650)96 buf[1] = 0xa6;97 if (freq_mhz < 1530)98 buf[1] = 0xa5;99 if (freq_mhz < 1470)100 buf[1] = 0xa4;101 if (freq_mhz < 1370)102 buf[1] = 0xa2;103 if (freq_mhz < 1300)104 buf[1] = 0xa1;105 if (freq_mhz < 1200)106 buf[1] = 0xa0;107 if (freq_mhz < 1075)108 buf[1] = 0xbc;109 if (freq_mhz < 1000)110 buf[1] = 0xba;111 if (freq_mhz < 1075) {112 n = freq_mhz / 8; /* vco=lo*4 */113 m = 2;114 } else {115 n = freq_mhz / 16; /* vco=lo*2 */116 m = 1;117 }118 buf[2] = n >> 1;119 buf[3] = (unsigned char)(((n & 1) << 7) |120 (m * freq_mhz - n * 16) | 0x60);121 buf[4] = 0x04;122 buf[5] = 0x0e;123 124 buf[6] = (unsigned char)(bandwidth);125 126 buf[7] = 0xd8;127 buf[8] = 0xd0;128 buf[9] = 0x50;129 buf[10] = 0xeb;130 buf[11] = 0x4f;131 132 if (fe->ops.i2c_gate_ctrl)133 fe->ops.i2c_gate_ctrl(fe, 1);134 135 ret = i2c_transfer(priv->i2c, &msg, 1);136 if (ret != 1)137 dprintk("%s: i2c error\n", __func__);138 139 udelay(10);140 if (fe->ops.i2c_gate_ctrl)141 fe->ops.i2c_gate_ctrl(fe, 0);142 143 buf[0] = 0x07;144 buf[1] = 0xdf;145 buf[2] = 0xd0;146 buf[3] = 0x50;147 buf[4] = 0xfb;148 msg.len = 5;149 150 if (fe->ops.i2c_gate_ctrl)151 fe->ops.i2c_gate_ctrl(fe, 1);152 153 ret = i2c_transfer(priv->i2c, &msg, 1);154 if (ret != 1)155 dprintk("%s: i2c error\n", __func__);156 157 udelay(10);158 if (fe->ops.i2c_gate_ctrl)159 fe->ops.i2c_gate_ctrl(fe, 0);160 161 priv->frequency = freq_mhz * 1000;162 163 return (ret == 1) ? 0 : ret;164 }165 return -1;166}167 168static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency)169{170 struct stb6000_priv *priv = fe->tuner_priv;171 *frequency = priv->frequency;172 return 0;173}174 175static const struct dvb_tuner_ops stb6000_tuner_ops = {176 .info = {177 .name = "ST STB6000",178 .frequency_min_hz = 950 * MHz,179 .frequency_max_hz = 2150 * MHz180 },181 .release = stb6000_release,182 .sleep = stb6000_sleep,183 .set_params = stb6000_set_params,184 .get_frequency = stb6000_get_frequency,185};186 187struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,188 struct i2c_adapter *i2c)189{190 struct stb6000_priv *priv = NULL;191 u8 b0[] = { 0 };192 u8 b1[] = { 0, 0 };193 struct i2c_msg msg[2] = {194 {195 .addr = addr,196 .flags = 0,197 .buf = b0,198 .len = 0199 }, {200 .addr = addr,201 .flags = I2C_M_RD,202 .buf = b1,203 .len = 2204 }205 };206 int ret;207 208 dprintk("%s:\n", __func__);209 210 if (fe->ops.i2c_gate_ctrl)211 fe->ops.i2c_gate_ctrl(fe, 1);212 213 /* is some i2c device here ? */214 ret = i2c_transfer(i2c, msg, 2);215 if (fe->ops.i2c_gate_ctrl)216 fe->ops.i2c_gate_ctrl(fe, 0);217 218 if (ret != 2)219 return NULL;220 221 priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL);222 if (priv == NULL)223 return NULL;224 225 priv->i2c_address = addr;226 priv->i2c = i2c;227 228 memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops,229 sizeof(struct dvb_tuner_ops));230 231 fe->tuner_priv = priv;232 233 return fe;234}235EXPORT_SYMBOL_GPL(stb6000_attach);236 237module_param(debug, int, 0644);238MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");239 240MODULE_DESCRIPTION("DVB STB6000 driver");241MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");242MODULE_LICENSE("GPL");243