18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ascot2e.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Sony Ascot3E DVB-T/T2/C/C2 tuner driver 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright 2012 Sony Corporation 88c2ecf20Sopenharmony_ci * Copyright (C) 2014 NetUP Inc. 98c2ecf20Sopenharmony_ci * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru> 108c2ecf20Sopenharmony_ci * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h> 168c2ecf20Sopenharmony_ci#include <linux/types.h> 178c2ecf20Sopenharmony_ci#include "ascot2e.h" 188c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define MAX_WRITE_REGSIZE 10 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cienum ascot2e_state { 238c2ecf20Sopenharmony_ci STATE_UNKNOWN, 248c2ecf20Sopenharmony_ci STATE_SLEEP, 258c2ecf20Sopenharmony_ci STATE_ACTIVE 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct ascot2e_priv { 298c2ecf20Sopenharmony_ci u32 frequency; 308c2ecf20Sopenharmony_ci u8 i2c_address; 318c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 328c2ecf20Sopenharmony_ci enum ascot2e_state state; 338c2ecf20Sopenharmony_ci void *set_tuner_data; 348c2ecf20Sopenharmony_ci int (*set_tuner)(void *, int); 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cienum ascot2e_tv_system_t { 388c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBT_5, 398c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBT_6, 408c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBT_7, 418c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBT_8, 428c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBT2_1_7, 438c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBT2_5, 448c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBT2_6, 458c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBT2_7, 468c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBT2_8, 478c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBC_6, 488c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBC_8, 498c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBC2_6, 508c2ecf20Sopenharmony_ci ASCOT2E_DTV_DVBC2_8, 518c2ecf20Sopenharmony_ci ASCOT2E_DTV_UNKNOWN 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistruct ascot2e_band_sett { 558c2ecf20Sopenharmony_ci u8 if_out_sel; 568c2ecf20Sopenharmony_ci u8 agc_sel; 578c2ecf20Sopenharmony_ci u8 mix_oll; 588c2ecf20Sopenharmony_ci u8 rf_gain; 598c2ecf20Sopenharmony_ci u8 if_bpf_gc; 608c2ecf20Sopenharmony_ci u8 fif_offset; 618c2ecf20Sopenharmony_ci u8 bw_offset; 628c2ecf20Sopenharmony_ci u8 bw; 638c2ecf20Sopenharmony_ci u8 rf_oldet; 648c2ecf20Sopenharmony_ci u8 if_bpf_f0; 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define ASCOT2E_AUTO 0xff 688c2ecf20Sopenharmony_ci#define ASCOT2E_OFFSET(ofs) ((u8)(ofs) & 0x1F) 698c2ecf20Sopenharmony_ci#define ASCOT2E_BW_6 0x00 708c2ecf20Sopenharmony_ci#define ASCOT2E_BW_7 0x01 718c2ecf20Sopenharmony_ci#define ASCOT2E_BW_8 0x02 728c2ecf20Sopenharmony_ci#define ASCOT2E_BW_1_7 0x03 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic struct ascot2e_band_sett ascot2e_sett[] = { 758c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06, 768c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-8), ASCOT2E_OFFSET(-6), ASCOT2E_BW_6, 0x0B, 0x00 }, 778c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06, 788c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-8), ASCOT2E_OFFSET(-6), ASCOT2E_BW_6, 0x0B, 0x00 }, 798c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06, 808c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-6), ASCOT2E_OFFSET(-4), ASCOT2E_BW_7, 0x0B, 0x00 }, 818c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06, 828c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-4), ASCOT2E_OFFSET(-2), ASCOT2E_BW_8, 0x0B, 0x00 }, 838c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06, 848c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-10), ASCOT2E_OFFSET(-16), ASCOT2E_BW_1_7, 0x0B, 0x00 }, 858c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06, 868c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-8), ASCOT2E_OFFSET(-6), ASCOT2E_BW_6, 0x0B, 0x00 }, 878c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06, 888c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-8), ASCOT2E_OFFSET(-6), ASCOT2E_BW_6, 0x0B, 0x00 }, 898c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06, 908c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-6), ASCOT2E_OFFSET(-4), ASCOT2E_BW_7, 0x0B, 0x00 }, 918c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06, 928c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-4), ASCOT2E_OFFSET(-2), ASCOT2E_BW_8, 0x0B, 0x00 }, 938c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x02, ASCOT2E_AUTO, 0x03, 948c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-6), ASCOT2E_OFFSET(-8), ASCOT2E_BW_6, 0x09, 0x00 }, 958c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x02, ASCOT2E_AUTO, 0x03, 968c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-2), ASCOT2E_OFFSET(-1), ASCOT2E_BW_8, 0x09, 0x00 }, 978c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x01, 988c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-6), ASCOT2E_OFFSET(-4), ASCOT2E_BW_6, 0x09, 0x00 }, 998c2ecf20Sopenharmony_ci { ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x01, 1008c2ecf20Sopenharmony_ci ASCOT2E_OFFSET(-2), ASCOT2E_OFFSET(2), ASCOT2E_BW_8, 0x09, 0x00 } 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void ascot2e_i2c_debug(struct ascot2e_priv *priv, 1048c2ecf20Sopenharmony_ci u8 reg, u8 write, const u8 *data, u32 len) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci dev_dbg(&priv->i2c->dev, "ascot2e: I2C %s reg 0x%02x size %d\n", 1078c2ecf20Sopenharmony_ci (write == 0 ? "read" : "write"), reg, len); 1088c2ecf20Sopenharmony_ci print_hex_dump_bytes("ascot2e: I2C data: ", 1098c2ecf20Sopenharmony_ci DUMP_PREFIX_OFFSET, data, len); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int ascot2e_write_regs(struct ascot2e_priv *priv, 1138c2ecf20Sopenharmony_ci u8 reg, const u8 *data, u32 len) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci int ret; 1168c2ecf20Sopenharmony_ci u8 buf[MAX_WRITE_REGSIZE + 1]; 1178c2ecf20Sopenharmony_ci struct i2c_msg msg[1] = { 1188c2ecf20Sopenharmony_ci { 1198c2ecf20Sopenharmony_ci .addr = priv->i2c_address, 1208c2ecf20Sopenharmony_ci .flags = 0, 1218c2ecf20Sopenharmony_ci .len = len + 1, 1228c2ecf20Sopenharmony_ci .buf = buf, 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci }; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (len + 1 > sizeof(buf)) { 1278c2ecf20Sopenharmony_ci dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", 1288c2ecf20Sopenharmony_ci reg, len + 1); 1298c2ecf20Sopenharmony_ci return -E2BIG; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci ascot2e_i2c_debug(priv, reg, 1, data, len); 1338c2ecf20Sopenharmony_ci buf[0] = reg; 1348c2ecf20Sopenharmony_ci memcpy(&buf[1], data, len); 1358c2ecf20Sopenharmony_ci ret = i2c_transfer(priv->i2c, msg, 1); 1368c2ecf20Sopenharmony_ci if (ret >= 0 && ret != 1) 1378c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 1388c2ecf20Sopenharmony_ci if (ret < 0) { 1398c2ecf20Sopenharmony_ci dev_warn(&priv->i2c->dev, 1408c2ecf20Sopenharmony_ci "%s: i2c wr failed=%d reg=%02x len=%d\n", 1418c2ecf20Sopenharmony_ci KBUILD_MODNAME, ret, reg, len); 1428c2ecf20Sopenharmony_ci return ret; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int ascot2e_write_reg(struct ascot2e_priv *priv, u8 reg, u8 val) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */ 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return ascot2e_write_regs(priv, reg, &tmp, 1); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic int ascot2e_read_regs(struct ascot2e_priv *priv, 1558c2ecf20Sopenharmony_ci u8 reg, u8 *val, u32 len) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci int ret; 1588c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { 1598c2ecf20Sopenharmony_ci { 1608c2ecf20Sopenharmony_ci .addr = priv->i2c_address, 1618c2ecf20Sopenharmony_ci .flags = 0, 1628c2ecf20Sopenharmony_ci .len = 1, 1638c2ecf20Sopenharmony_ci .buf = ®, 1648c2ecf20Sopenharmony_ci }, { 1658c2ecf20Sopenharmony_ci .addr = priv->i2c_address, 1668c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 1678c2ecf20Sopenharmony_ci .len = len, 1688c2ecf20Sopenharmony_ci .buf = val, 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci }; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci ret = i2c_transfer(priv->i2c, &msg[0], 1); 1738c2ecf20Sopenharmony_ci if (ret >= 0 && ret != 1) 1748c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 1758c2ecf20Sopenharmony_ci if (ret < 0) { 1768c2ecf20Sopenharmony_ci dev_warn(&priv->i2c->dev, 1778c2ecf20Sopenharmony_ci "%s: I2C rw failed=%d addr=%02x reg=%02x\n", 1788c2ecf20Sopenharmony_ci KBUILD_MODNAME, ret, priv->i2c_address, reg); 1798c2ecf20Sopenharmony_ci return ret; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci ret = i2c_transfer(priv->i2c, &msg[1], 1); 1828c2ecf20Sopenharmony_ci if (ret >= 0 && ret != 1) 1838c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 1848c2ecf20Sopenharmony_ci if (ret < 0) { 1858c2ecf20Sopenharmony_ci dev_warn(&priv->i2c->dev, 1868c2ecf20Sopenharmony_ci "%s: i2c rd failed=%d addr=%02x reg=%02x\n", 1878c2ecf20Sopenharmony_ci KBUILD_MODNAME, ret, priv->i2c_address, reg); 1888c2ecf20Sopenharmony_ci return ret; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci ascot2e_i2c_debug(priv, reg, 0, val, len); 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int ascot2e_read_reg(struct ascot2e_priv *priv, u8 reg, u8 *val) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci return ascot2e_read_regs(priv, reg, val, 1); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int ascot2e_set_reg_bits(struct ascot2e_priv *priv, 2008c2ecf20Sopenharmony_ci u8 reg, u8 data, u8 mask) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci int res; 2038c2ecf20Sopenharmony_ci u8 rdata; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (mask != 0xff) { 2068c2ecf20Sopenharmony_ci res = ascot2e_read_reg(priv, reg, &rdata); 2078c2ecf20Sopenharmony_ci if (res != 0) 2088c2ecf20Sopenharmony_ci return res; 2098c2ecf20Sopenharmony_ci data = ((data & mask) | (rdata & (mask ^ 0xFF))); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci return ascot2e_write_reg(priv, reg, data); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int ascot2e_enter_power_save(struct ascot2e_priv *priv) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci u8 data[2]; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 2198c2ecf20Sopenharmony_ci if (priv->state == STATE_SLEEP) 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci data[0] = 0x00; 2228c2ecf20Sopenharmony_ci data[1] = 0x04; 2238c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x14, data, 2); 2248c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x50, 0x01); 2258c2ecf20Sopenharmony_ci priv->state = STATE_SLEEP; 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int ascot2e_leave_power_save(struct ascot2e_priv *priv) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci u8 data[2] = { 0xFB, 0x0F }; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 2348c2ecf20Sopenharmony_ci if (priv->state == STATE_ACTIVE) 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x14, data, 2); 2378c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x50, 0x00); 2388c2ecf20Sopenharmony_ci priv->state = STATE_ACTIVE; 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int ascot2e_init(struct dvb_frontend *fe) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct ascot2e_priv *priv = fe->tuner_priv; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 2478c2ecf20Sopenharmony_ci return ascot2e_leave_power_save(priv); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void ascot2e_release(struct dvb_frontend *fe) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct ascot2e_priv *priv = fe->tuner_priv; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 2558c2ecf20Sopenharmony_ci kfree(fe->tuner_priv); 2568c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int ascot2e_sleep(struct dvb_frontend *fe) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct ascot2e_priv *priv = fe->tuner_priv; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 2648c2ecf20Sopenharmony_ci ascot2e_enter_power_save(priv); 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic enum ascot2e_tv_system_t ascot2e_get_tv_system(struct dvb_frontend *fe) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci enum ascot2e_tv_system_t system = ASCOT2E_DTV_UNKNOWN; 2718c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 2728c2ecf20Sopenharmony_ci struct ascot2e_priv *priv = fe->tuner_priv; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (p->delivery_system == SYS_DVBT) { 2758c2ecf20Sopenharmony_ci if (p->bandwidth_hz <= 5000000) 2768c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT_5; 2778c2ecf20Sopenharmony_ci else if (p->bandwidth_hz <= 6000000) 2788c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT_6; 2798c2ecf20Sopenharmony_ci else if (p->bandwidth_hz <= 7000000) 2808c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT_7; 2818c2ecf20Sopenharmony_ci else if (p->bandwidth_hz <= 8000000) 2828c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT_8; 2838c2ecf20Sopenharmony_ci else { 2848c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT_8; 2858c2ecf20Sopenharmony_ci p->bandwidth_hz = 8000000; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci } else if (p->delivery_system == SYS_DVBT2) { 2888c2ecf20Sopenharmony_ci if (p->bandwidth_hz <= 5000000) 2898c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT2_5; 2908c2ecf20Sopenharmony_ci else if (p->bandwidth_hz <= 6000000) 2918c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT2_6; 2928c2ecf20Sopenharmony_ci else if (p->bandwidth_hz <= 7000000) 2938c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT2_7; 2948c2ecf20Sopenharmony_ci else if (p->bandwidth_hz <= 8000000) 2958c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT2_8; 2968c2ecf20Sopenharmony_ci else { 2978c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBT2_8; 2988c2ecf20Sopenharmony_ci p->bandwidth_hz = 8000000; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci } else if (p->delivery_system == SYS_DVBC_ANNEX_A) { 3018c2ecf20Sopenharmony_ci if (p->bandwidth_hz <= 6000000) 3028c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBC_6; 3038c2ecf20Sopenharmony_ci else if (p->bandwidth_hz <= 8000000) 3048c2ecf20Sopenharmony_ci system = ASCOT2E_DTV_DVBC_8; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci dev_dbg(&priv->i2c->dev, 3078c2ecf20Sopenharmony_ci "%s(): ASCOT2E DTV system %d (delsys %d, bandwidth %d)\n", 3088c2ecf20Sopenharmony_ci __func__, (int)system, p->delivery_system, p->bandwidth_hz); 3098c2ecf20Sopenharmony_ci return system; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int ascot2e_set_params(struct dvb_frontend *fe) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci u8 data[10]; 3158c2ecf20Sopenharmony_ci u32 frequency; 3168c2ecf20Sopenharmony_ci enum ascot2e_tv_system_t tv_system; 3178c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 3188c2ecf20Sopenharmony_ci struct ascot2e_priv *priv = fe->tuner_priv; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci dev_dbg(&priv->i2c->dev, "%s(): tune frequency %dkHz\n", 3218c2ecf20Sopenharmony_ci __func__, p->frequency / 1000); 3228c2ecf20Sopenharmony_ci tv_system = ascot2e_get_tv_system(fe); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (tv_system == ASCOT2E_DTV_UNKNOWN) { 3258c2ecf20Sopenharmony_ci dev_dbg(&priv->i2c->dev, "%s(): unknown DTV system\n", 3268c2ecf20Sopenharmony_ci __func__); 3278c2ecf20Sopenharmony_ci return -EINVAL; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci if (priv->set_tuner) 3308c2ecf20Sopenharmony_ci priv->set_tuner(priv->set_tuner_data, 1); 3318c2ecf20Sopenharmony_ci frequency = roundup(p->frequency / 1000, 25); 3328c2ecf20Sopenharmony_ci if (priv->state == STATE_SLEEP) 3338c2ecf20Sopenharmony_ci ascot2e_leave_power_save(priv); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* IF_OUT_SEL / AGC_SEL setting */ 3368c2ecf20Sopenharmony_ci data[0] = 0x00; 3378c2ecf20Sopenharmony_ci if (ascot2e_sett[tv_system].agc_sel != ASCOT2E_AUTO) { 3388c2ecf20Sopenharmony_ci /* AGC pin setting from parameter table */ 3398c2ecf20Sopenharmony_ci data[0] |= (u8)( 3408c2ecf20Sopenharmony_ci (ascot2e_sett[tv_system].agc_sel & 0x03) << 3); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci if (ascot2e_sett[tv_system].if_out_sel != ASCOT2E_AUTO) { 3438c2ecf20Sopenharmony_ci /* IFOUT pin setting from parameter table */ 3448c2ecf20Sopenharmony_ci data[0] |= (u8)( 3458c2ecf20Sopenharmony_ci (ascot2e_sett[tv_system].if_out_sel & 0x01) << 2); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci /* Set bit[4:2] only */ 3488c2ecf20Sopenharmony_ci ascot2e_set_reg_bits(priv, 0x05, data[0], 0x1c); 3498c2ecf20Sopenharmony_ci /* 0x06 - 0x0F */ 3508c2ecf20Sopenharmony_ci /* REF_R setting (0x06) */ 3518c2ecf20Sopenharmony_ci if (tv_system == ASCOT2E_DTV_DVBC_6 || 3528c2ecf20Sopenharmony_ci tv_system == ASCOT2E_DTV_DVBC_8) { 3538c2ecf20Sopenharmony_ci /* xtal, xtal*2 */ 3548c2ecf20Sopenharmony_ci data[0] = (frequency > 500000) ? 16 : 32; 3558c2ecf20Sopenharmony_ci } else { 3568c2ecf20Sopenharmony_ci /* xtal/8, xtal/4 */ 3578c2ecf20Sopenharmony_ci data[0] = (frequency > 500000) ? 2 : 4; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci /* XOSC_SEL=100uA */ 3608c2ecf20Sopenharmony_ci data[1] = 0x04; 3618c2ecf20Sopenharmony_ci /* KBW setting (0x08), KC0 setting (0x09), KC1 setting (0x0A) */ 3628c2ecf20Sopenharmony_ci if (tv_system == ASCOT2E_DTV_DVBC_6 || 3638c2ecf20Sopenharmony_ci tv_system == ASCOT2E_DTV_DVBC_8) { 3648c2ecf20Sopenharmony_ci data[2] = 18; 3658c2ecf20Sopenharmony_ci data[3] = 120; 3668c2ecf20Sopenharmony_ci data[4] = 20; 3678c2ecf20Sopenharmony_ci } else { 3688c2ecf20Sopenharmony_ci data[2] = 48; 3698c2ecf20Sopenharmony_ci data[3] = 10; 3708c2ecf20Sopenharmony_ci data[4] = 30; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci /* ORDER/R2_RANGE/R2_BANK/C2_BANK setting (0x0B) */ 3738c2ecf20Sopenharmony_ci if (tv_system == ASCOT2E_DTV_DVBC_6 || 3748c2ecf20Sopenharmony_ci tv_system == ASCOT2E_DTV_DVBC_8) 3758c2ecf20Sopenharmony_ci data[5] = (frequency > 500000) ? 0x08 : 0x0c; 3768c2ecf20Sopenharmony_ci else 3778c2ecf20Sopenharmony_ci data[5] = (frequency > 500000) ? 0x30 : 0x38; 3788c2ecf20Sopenharmony_ci /* Set MIX_OLL (0x0C) value from parameter table */ 3798c2ecf20Sopenharmony_ci data[6] = ascot2e_sett[tv_system].mix_oll; 3808c2ecf20Sopenharmony_ci /* Set RF_GAIN (0x0D) setting from parameter table */ 3818c2ecf20Sopenharmony_ci if (ascot2e_sett[tv_system].rf_gain == ASCOT2E_AUTO) { 3828c2ecf20Sopenharmony_ci /* RF_GAIN auto control enable */ 3838c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x4E, 0x01); 3848c2ecf20Sopenharmony_ci /* RF_GAIN Default value */ 3858c2ecf20Sopenharmony_ci data[7] = 0x00; 3868c2ecf20Sopenharmony_ci } else { 3878c2ecf20Sopenharmony_ci /* RF_GAIN auto control disable */ 3888c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x4E, 0x00); 3898c2ecf20Sopenharmony_ci data[7] = ascot2e_sett[tv_system].rf_gain; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci /* Set IF_BPF_GC/FIF_OFFSET (0x0E) value from parameter table */ 3928c2ecf20Sopenharmony_ci data[8] = (u8)((ascot2e_sett[tv_system].fif_offset << 3) | 3938c2ecf20Sopenharmony_ci (ascot2e_sett[tv_system].if_bpf_gc & 0x07)); 3948c2ecf20Sopenharmony_ci /* Set BW_OFFSET (0x0F) value from parameter table */ 3958c2ecf20Sopenharmony_ci data[9] = ascot2e_sett[tv_system].bw_offset; 3968c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x06, data, 10); 3978c2ecf20Sopenharmony_ci /* 3988c2ecf20Sopenharmony_ci * 0x45 - 0x47 3998c2ecf20Sopenharmony_ci * LNA optimization setting 4008c2ecf20Sopenharmony_ci * RF_LNA_DIST1-5, RF_LNA_CM 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci if (tv_system == ASCOT2E_DTV_DVBC_6 || 4038c2ecf20Sopenharmony_ci tv_system == ASCOT2E_DTV_DVBC_8) { 4048c2ecf20Sopenharmony_ci data[0] = 0x0F; 4058c2ecf20Sopenharmony_ci data[1] = 0x00; 4068c2ecf20Sopenharmony_ci data[2] = 0x01; 4078c2ecf20Sopenharmony_ci } else { 4088c2ecf20Sopenharmony_ci data[0] = 0x0F; 4098c2ecf20Sopenharmony_ci data[1] = 0x00; 4108c2ecf20Sopenharmony_ci data[2] = 0x03; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x45, data, 3); 4138c2ecf20Sopenharmony_ci /* 0x49 - 0x4A 4148c2ecf20Sopenharmony_ci Set RF_OLDET_ENX/RF_OLDET_OLL value from parameter table */ 4158c2ecf20Sopenharmony_ci data[0] = ascot2e_sett[tv_system].rf_oldet; 4168c2ecf20Sopenharmony_ci /* Set IF_BPF_F0 value from parameter table */ 4178c2ecf20Sopenharmony_ci data[1] = ascot2e_sett[tv_system].if_bpf_f0; 4188c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x49, data, 2); 4198c2ecf20Sopenharmony_ci /* 4208c2ecf20Sopenharmony_ci * Tune now 4218c2ecf20Sopenharmony_ci * RFAGC fast mode / RFAGC auto control enable 4228c2ecf20Sopenharmony_ci * (set bit[7], bit[5:4] only) 4238c2ecf20Sopenharmony_ci * vco_cal = 1, set MIX_OL_CPU_EN 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci ascot2e_set_reg_bits(priv, 0x0c, 0x90, 0xb0); 4268c2ecf20Sopenharmony_ci /* Logic wake up, CPU wake up */ 4278c2ecf20Sopenharmony_ci data[0] = 0xc4; 4288c2ecf20Sopenharmony_ci data[1] = 0x40; 4298c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x03, data, 2); 4308c2ecf20Sopenharmony_ci /* 0x10 - 0x14 */ 4318c2ecf20Sopenharmony_ci data[0] = (u8)(frequency & 0xFF); /* 0x10: FRF_L */ 4328c2ecf20Sopenharmony_ci data[1] = (u8)((frequency >> 8) & 0xFF); /* 0x11: FRF_M */ 4338c2ecf20Sopenharmony_ci data[2] = (u8)((frequency >> 16) & 0x0F); /* 0x12: FRF_H (bit[3:0]) */ 4348c2ecf20Sopenharmony_ci /* 0x12: BW (bit[5:4]) */ 4358c2ecf20Sopenharmony_ci data[2] |= (u8)(ascot2e_sett[tv_system].bw << 4); 4368c2ecf20Sopenharmony_ci data[3] = 0xFF; /* 0x13: VCO calibration enable */ 4378c2ecf20Sopenharmony_ci data[4] = 0xFF; /* 0x14: Analog block enable */ 4388c2ecf20Sopenharmony_ci /* Tune (Burst write) */ 4398c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x10, data, 5); 4408c2ecf20Sopenharmony_ci msleep(50); 4418c2ecf20Sopenharmony_ci /* CPU deep sleep */ 4428c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x04, 0x00); 4438c2ecf20Sopenharmony_ci /* Logic sleep */ 4448c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x03, 0xC0); 4458c2ecf20Sopenharmony_ci /* RFAGC normal mode (set bit[5:4] only) */ 4468c2ecf20Sopenharmony_ci ascot2e_set_reg_bits(priv, 0x0C, 0x00, 0x30); 4478c2ecf20Sopenharmony_ci priv->frequency = frequency; 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int ascot2e_get_frequency(struct dvb_frontend *fe, u32 *frequency) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct ascot2e_priv *priv = fe->tuner_priv; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci *frequency = priv->frequency * 1000; 4568c2ecf20Sopenharmony_ci return 0; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops ascot2e_tuner_ops = { 4608c2ecf20Sopenharmony_ci .info = { 4618c2ecf20Sopenharmony_ci .name = "Sony ASCOT2E", 4628c2ecf20Sopenharmony_ci .frequency_min_hz = 1 * MHz, 4638c2ecf20Sopenharmony_ci .frequency_max_hz = 1200 * MHz, 4648c2ecf20Sopenharmony_ci .frequency_step_hz = 25 * kHz, 4658c2ecf20Sopenharmony_ci }, 4668c2ecf20Sopenharmony_ci .init = ascot2e_init, 4678c2ecf20Sopenharmony_ci .release = ascot2e_release, 4688c2ecf20Sopenharmony_ci .sleep = ascot2e_sleep, 4698c2ecf20Sopenharmony_ci .set_params = ascot2e_set_params, 4708c2ecf20Sopenharmony_ci .get_frequency = ascot2e_get_frequency, 4718c2ecf20Sopenharmony_ci}; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistruct dvb_frontend *ascot2e_attach(struct dvb_frontend *fe, 4748c2ecf20Sopenharmony_ci const struct ascot2e_config *config, 4758c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci u8 data[4]; 4788c2ecf20Sopenharmony_ci struct ascot2e_priv *priv = NULL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(struct ascot2e_priv), GFP_KERNEL); 4818c2ecf20Sopenharmony_ci if (priv == NULL) 4828c2ecf20Sopenharmony_ci return NULL; 4838c2ecf20Sopenharmony_ci priv->i2c_address = (config->i2c_address >> 1); 4848c2ecf20Sopenharmony_ci priv->i2c = i2c; 4858c2ecf20Sopenharmony_ci priv->set_tuner_data = config->set_tuner_priv; 4868c2ecf20Sopenharmony_ci priv->set_tuner = config->set_tuner_callback; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 4898c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* 16 MHz xTal frequency */ 4928c2ecf20Sopenharmony_ci data[0] = 16; 4938c2ecf20Sopenharmony_ci /* VCO current setting */ 4948c2ecf20Sopenharmony_ci data[1] = 0x06; 4958c2ecf20Sopenharmony_ci /* Logic wake up, CPU boot */ 4968c2ecf20Sopenharmony_ci data[2] = 0xC4; 4978c2ecf20Sopenharmony_ci data[3] = 0x40; 4988c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x01, data, 4); 4998c2ecf20Sopenharmony_ci /* RFVGA optimization setting (RF_DIST0 - RF_DIST2) */ 5008c2ecf20Sopenharmony_ci data[0] = 0x10; 5018c2ecf20Sopenharmony_ci data[1] = 0x3F; 5028c2ecf20Sopenharmony_ci data[2] = 0x25; 5038c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x22, data, 3); 5048c2ecf20Sopenharmony_ci /* PLL mode setting */ 5058c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x28, 0x1e); 5068c2ecf20Sopenharmony_ci /* RSSI setting */ 5078c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x59, 0x04); 5088c2ecf20Sopenharmony_ci /* TODO check CPU HW error state here */ 5098c2ecf20Sopenharmony_ci msleep(80); 5108c2ecf20Sopenharmony_ci /* Xtal oscillator current control setting */ 5118c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x4c, 0x01); 5128c2ecf20Sopenharmony_ci /* XOSC_SEL=100uA */ 5138c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x07, 0x04); 5148c2ecf20Sopenharmony_ci /* CPU deep sleep */ 5158c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x04, 0x00); 5168c2ecf20Sopenharmony_ci /* Logic sleep */ 5178c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x03, 0xc0); 5188c2ecf20Sopenharmony_ci /* Power save setting */ 5198c2ecf20Sopenharmony_ci data[0] = 0x00; 5208c2ecf20Sopenharmony_ci data[1] = 0x04; 5218c2ecf20Sopenharmony_ci ascot2e_write_regs(priv, 0x14, data, 2); 5228c2ecf20Sopenharmony_ci ascot2e_write_reg(priv, 0x50, 0x01); 5238c2ecf20Sopenharmony_ci priv->state = STATE_SLEEP; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 5268c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &ascot2e_tuner_ops, 5298c2ecf20Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 5308c2ecf20Sopenharmony_ci fe->tuner_priv = priv; 5318c2ecf20Sopenharmony_ci dev_info(&priv->i2c->dev, 5328c2ecf20Sopenharmony_ci "Sony ASCOT2E attached on addr=%x at I2C adapter %p\n", 5338c2ecf20Sopenharmony_ci priv->i2c_address, priv->i2c); 5348c2ecf20Sopenharmony_ci return fe; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ascot2e_attach); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sony ASCOT2E terr/cab tuner driver"); 5398c2ecf20Sopenharmony_ciMODULE_AUTHOR("info@netup.ru"); 5408c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 541