18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci /* 38c2ecf20Sopenharmony_ci Driver for ST STB6000 DVBS Silicon tuner 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h> 138c2ecf20Sopenharmony_ci#include <asm/types.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "stb6000.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic int debug; 188c2ecf20Sopenharmony_ci#define dprintk(args...) \ 198c2ecf20Sopenharmony_ci do { \ 208c2ecf20Sopenharmony_ci if (debug) \ 218c2ecf20Sopenharmony_ci printk(KERN_DEBUG "stb6000: " args); \ 228c2ecf20Sopenharmony_ci } while (0) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct stb6000_priv { 258c2ecf20Sopenharmony_ci /* i2c details */ 268c2ecf20Sopenharmony_ci int i2c_address; 278c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 288c2ecf20Sopenharmony_ci u32 frequency; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void stb6000_release(struct dvb_frontend *fe) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci kfree(fe->tuner_priv); 348c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int stb6000_sleep(struct dvb_frontend *fe) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct stb6000_priv *priv = fe->tuner_priv; 408c2ecf20Sopenharmony_ci int ret; 418c2ecf20Sopenharmony_ci u8 buf[] = { 10, 0 }; 428c2ecf20Sopenharmony_ci struct i2c_msg msg = { 438c2ecf20Sopenharmony_ci .addr = priv->i2c_address, 448c2ecf20Sopenharmony_ci .flags = 0, 458c2ecf20Sopenharmony_ci .buf = buf, 468c2ecf20Sopenharmony_ci .len = 2 478c2ecf20Sopenharmony_ci }; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci dprintk("%s:\n", __func__); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 528c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci ret = i2c_transfer(priv->i2c, &msg, 1); 558c2ecf20Sopenharmony_ci if (ret != 1) 568c2ecf20Sopenharmony_ci dprintk("%s: i2c error\n", __func__); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 598c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return (ret == 1) ? 0 : ret; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int stb6000_set_params(struct dvb_frontend *fe) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 678c2ecf20Sopenharmony_ci struct stb6000_priv *priv = fe->tuner_priv; 688c2ecf20Sopenharmony_ci unsigned int n, m; 698c2ecf20Sopenharmony_ci int ret; 708c2ecf20Sopenharmony_ci u32 freq_mhz; 718c2ecf20Sopenharmony_ci int bandwidth; 728c2ecf20Sopenharmony_ci u8 buf[12]; 738c2ecf20Sopenharmony_ci struct i2c_msg msg = { 748c2ecf20Sopenharmony_ci .addr = priv->i2c_address, 758c2ecf20Sopenharmony_ci .flags = 0, 768c2ecf20Sopenharmony_ci .buf = buf, 778c2ecf20Sopenharmony_ci .len = 12 788c2ecf20Sopenharmony_ci }; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci dprintk("%s:\n", __func__); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci freq_mhz = p->frequency / 1000; 838c2ecf20Sopenharmony_ci bandwidth = p->symbol_rate / 1000000; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (bandwidth > 31) 868c2ecf20Sopenharmony_ci bandwidth = 31; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if ((freq_mhz > 949) && (freq_mhz < 2151)) { 898c2ecf20Sopenharmony_ci buf[0] = 0x01; 908c2ecf20Sopenharmony_ci buf[1] = 0xac; 918c2ecf20Sopenharmony_ci if (freq_mhz < 1950) 928c2ecf20Sopenharmony_ci buf[1] = 0xaa; 938c2ecf20Sopenharmony_ci if (freq_mhz < 1800) 948c2ecf20Sopenharmony_ci buf[1] = 0xa8; 958c2ecf20Sopenharmony_ci if (freq_mhz < 1650) 968c2ecf20Sopenharmony_ci buf[1] = 0xa6; 978c2ecf20Sopenharmony_ci if (freq_mhz < 1530) 988c2ecf20Sopenharmony_ci buf[1] = 0xa5; 998c2ecf20Sopenharmony_ci if (freq_mhz < 1470) 1008c2ecf20Sopenharmony_ci buf[1] = 0xa4; 1018c2ecf20Sopenharmony_ci if (freq_mhz < 1370) 1028c2ecf20Sopenharmony_ci buf[1] = 0xa2; 1038c2ecf20Sopenharmony_ci if (freq_mhz < 1300) 1048c2ecf20Sopenharmony_ci buf[1] = 0xa1; 1058c2ecf20Sopenharmony_ci if (freq_mhz < 1200) 1068c2ecf20Sopenharmony_ci buf[1] = 0xa0; 1078c2ecf20Sopenharmony_ci if (freq_mhz < 1075) 1088c2ecf20Sopenharmony_ci buf[1] = 0xbc; 1098c2ecf20Sopenharmony_ci if (freq_mhz < 1000) 1108c2ecf20Sopenharmony_ci buf[1] = 0xba; 1118c2ecf20Sopenharmony_ci if (freq_mhz < 1075) { 1128c2ecf20Sopenharmony_ci n = freq_mhz / 8; /* vco=lo*4 */ 1138c2ecf20Sopenharmony_ci m = 2; 1148c2ecf20Sopenharmony_ci } else { 1158c2ecf20Sopenharmony_ci n = freq_mhz / 16; /* vco=lo*2 */ 1168c2ecf20Sopenharmony_ci m = 1; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci buf[2] = n >> 1; 1198c2ecf20Sopenharmony_ci buf[3] = (unsigned char)(((n & 1) << 7) | 1208c2ecf20Sopenharmony_ci (m * freq_mhz - n * 16) | 0x60); 1218c2ecf20Sopenharmony_ci buf[4] = 0x04; 1228c2ecf20Sopenharmony_ci buf[5] = 0x0e; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci buf[6] = (unsigned char)(bandwidth); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci buf[7] = 0xd8; 1278c2ecf20Sopenharmony_ci buf[8] = 0xd0; 1288c2ecf20Sopenharmony_ci buf[9] = 0x50; 1298c2ecf20Sopenharmony_ci buf[10] = 0xeb; 1308c2ecf20Sopenharmony_ci buf[11] = 0x4f; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 1338c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ret = i2c_transfer(priv->i2c, &msg, 1); 1368c2ecf20Sopenharmony_ci if (ret != 1) 1378c2ecf20Sopenharmony_ci dprintk("%s: i2c error\n", __func__); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci udelay(10); 1408c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 1418c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci buf[0] = 0x07; 1448c2ecf20Sopenharmony_ci buf[1] = 0xdf; 1458c2ecf20Sopenharmony_ci buf[2] = 0xd0; 1468c2ecf20Sopenharmony_ci buf[3] = 0x50; 1478c2ecf20Sopenharmony_ci buf[4] = 0xfb; 1488c2ecf20Sopenharmony_ci msg.len = 5; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 1518c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci ret = i2c_transfer(priv->i2c, &msg, 1); 1548c2ecf20Sopenharmony_ci if (ret != 1) 1558c2ecf20Sopenharmony_ci dprintk("%s: i2c error\n", __func__); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci udelay(10); 1588c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 1598c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci priv->frequency = freq_mhz * 1000; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return (ret == 1) ? 0 : ret; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci return -1; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct stb6000_priv *priv = fe->tuner_priv; 1718c2ecf20Sopenharmony_ci *frequency = priv->frequency; 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops stb6000_tuner_ops = { 1768c2ecf20Sopenharmony_ci .info = { 1778c2ecf20Sopenharmony_ci .name = "ST STB6000", 1788c2ecf20Sopenharmony_ci .frequency_min_hz = 950 * MHz, 1798c2ecf20Sopenharmony_ci .frequency_max_hz = 2150 * MHz 1808c2ecf20Sopenharmony_ci }, 1818c2ecf20Sopenharmony_ci .release = stb6000_release, 1828c2ecf20Sopenharmony_ci .sleep = stb6000_sleep, 1838c2ecf20Sopenharmony_ci .set_params = stb6000_set_params, 1848c2ecf20Sopenharmony_ci .get_frequency = stb6000_get_frequency, 1858c2ecf20Sopenharmony_ci}; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistruct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, 1888c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct stb6000_priv *priv = NULL; 1918c2ecf20Sopenharmony_ci u8 b0[] = { 0 }; 1928c2ecf20Sopenharmony_ci u8 b1[] = { 0, 0 }; 1938c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { 1948c2ecf20Sopenharmony_ci { 1958c2ecf20Sopenharmony_ci .addr = addr, 1968c2ecf20Sopenharmony_ci .flags = 0, 1978c2ecf20Sopenharmony_ci .buf = b0, 1988c2ecf20Sopenharmony_ci .len = 0 1998c2ecf20Sopenharmony_ci }, { 2008c2ecf20Sopenharmony_ci .addr = addr, 2018c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 2028c2ecf20Sopenharmony_ci .buf = b1, 2038c2ecf20Sopenharmony_ci .len = 2 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci }; 2068c2ecf20Sopenharmony_ci int ret; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci dprintk("%s:\n", __func__); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 2118c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* is some i2c device here ? */ 2148c2ecf20Sopenharmony_ci ret = i2c_transfer(i2c, msg, 2); 2158c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 2168c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (ret != 2) 2198c2ecf20Sopenharmony_ci return NULL; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL); 2228c2ecf20Sopenharmony_ci if (priv == NULL) 2238c2ecf20Sopenharmony_ci return NULL; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci priv->i2c_address = addr; 2268c2ecf20Sopenharmony_ci priv->i2c = i2c; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops, 2298c2ecf20Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci fe->tuner_priv = priv; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return fe; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(stb6000_attach); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 2388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DVB STB6000 driver"); 2418c2ecf20Sopenharmony_ciMODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>"); 2428c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 243