18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ZyDAS ZD1301 driver (demodulator) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Antti Palosaari <crope@iki.fi> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "zd1301_demod.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistatic u8 zd1301_demod_gain = 0x38; 118c2ecf20Sopenharmony_cimodule_param_named(gain, zd1301_demod_gain, byte, 0644); 128c2ecf20Sopenharmony_ciMODULE_PARM_DESC(gain, "gain (value: 0x00 - 0x70, default: 0x38)"); 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistruct zd1301_demod_dev { 158c2ecf20Sopenharmony_ci struct platform_device *pdev; 168c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 178c2ecf20Sopenharmony_ci struct i2c_adapter adapter; 188c2ecf20Sopenharmony_ci u8 gain; 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int zd1301_demod_wreg(struct zd1301_demod_dev *dev, u16 reg, u8 val) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct platform_device *pdev = dev->pdev; 248c2ecf20Sopenharmony_ci struct zd1301_demod_platform_data *pdata = pdev->dev.platform_data; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci return pdata->reg_write(pdata->reg_priv, reg, val); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int zd1301_demod_rreg(struct zd1301_demod_dev *dev, u16 reg, u8 *val) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct platform_device *pdev = dev->pdev; 328c2ecf20Sopenharmony_ci struct zd1301_demod_platform_data *pdata = pdev->dev.platform_data; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci return pdata->reg_read(pdata->reg_priv, reg, val); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int zd1301_demod_set_frontend(struct dvb_frontend *fe) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev = fe->demodulator_priv; 408c2ecf20Sopenharmony_ci struct platform_device *pdev = dev->pdev; 418c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 428c2ecf20Sopenharmony_ci int ret; 438c2ecf20Sopenharmony_ci u32 if_frequency; 448c2ecf20Sopenharmony_ci u8 r6a50_val; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "frequency=%u bandwidth_hz=%u\n", 478c2ecf20Sopenharmony_ci c->frequency, c->bandwidth_hz); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Program tuner */ 508c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params && 518c2ecf20Sopenharmony_ci fe->ops.tuner_ops.get_if_frequency) { 528c2ecf20Sopenharmony_ci ret = fe->ops.tuner_ops.set_params(fe); 538c2ecf20Sopenharmony_ci if (ret) 548c2ecf20Sopenharmony_ci goto err; 558c2ecf20Sopenharmony_ci ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); 568c2ecf20Sopenharmony_ci if (ret) 578c2ecf20Sopenharmony_ci goto err; 588c2ecf20Sopenharmony_ci } else { 598c2ecf20Sopenharmony_ci ret = -EINVAL; 608c2ecf20Sopenharmony_ci goto err; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "if_frequency=%u\n", if_frequency); 648c2ecf20Sopenharmony_ci if (if_frequency != 36150000) { 658c2ecf20Sopenharmony_ci ret = -EINVAL; 668c2ecf20Sopenharmony_ci goto err; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci switch (c->bandwidth_hz) { 708c2ecf20Sopenharmony_ci case 6000000: 718c2ecf20Sopenharmony_ci r6a50_val = 0x78; 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci case 7000000: 748c2ecf20Sopenharmony_ci r6a50_val = 0x68; 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci case 8000000: 778c2ecf20Sopenharmony_ci r6a50_val = 0x58; 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci default: 808c2ecf20Sopenharmony_ci ret = -EINVAL; 818c2ecf20Sopenharmony_ci goto err; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a60, 0x11); 858c2ecf20Sopenharmony_ci if (ret) 868c2ecf20Sopenharmony_ci goto err; 878c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a47, 0x46); 888c2ecf20Sopenharmony_ci if (ret) 898c2ecf20Sopenharmony_ci goto err; 908c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a48, 0x46); 918c2ecf20Sopenharmony_ci if (ret) 928c2ecf20Sopenharmony_ci goto err; 938c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a4a, 0x15); 948c2ecf20Sopenharmony_ci if (ret) 958c2ecf20Sopenharmony_ci goto err; 968c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a4b, 0x63); 978c2ecf20Sopenharmony_ci if (ret) 988c2ecf20Sopenharmony_ci goto err; 998c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a5b, 0x99); 1008c2ecf20Sopenharmony_ci if (ret) 1018c2ecf20Sopenharmony_ci goto err; 1028c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a3b, 0x10); 1038c2ecf20Sopenharmony_ci if (ret) 1048c2ecf20Sopenharmony_ci goto err; 1058c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6806, 0x01); 1068c2ecf20Sopenharmony_ci if (ret) 1078c2ecf20Sopenharmony_ci goto err; 1088c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a41, 0x08); 1098c2ecf20Sopenharmony_ci if (ret) 1108c2ecf20Sopenharmony_ci goto err; 1118c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a42, 0x46); 1128c2ecf20Sopenharmony_ci if (ret) 1138c2ecf20Sopenharmony_ci goto err; 1148c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a44, 0x14); 1158c2ecf20Sopenharmony_ci if (ret) 1168c2ecf20Sopenharmony_ci goto err; 1178c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a45, 0x67); 1188c2ecf20Sopenharmony_ci if (ret) 1198c2ecf20Sopenharmony_ci goto err; 1208c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a38, 0x00); 1218c2ecf20Sopenharmony_ci if (ret) 1228c2ecf20Sopenharmony_ci goto err; 1238c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a4c, 0x52); 1248c2ecf20Sopenharmony_ci if (ret) 1258c2ecf20Sopenharmony_ci goto err; 1268c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a49, 0x2a); 1278c2ecf20Sopenharmony_ci if (ret) 1288c2ecf20Sopenharmony_ci goto err; 1298c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6840, 0x2e); 1308c2ecf20Sopenharmony_ci if (ret) 1318c2ecf20Sopenharmony_ci goto err; 1328c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a50, r6a50_val); 1338c2ecf20Sopenharmony_ci if (ret) 1348c2ecf20Sopenharmony_ci goto err; 1358c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a38, 0x07); 1368c2ecf20Sopenharmony_ci if (ret) 1378c2ecf20Sopenharmony_ci goto err; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_cierr: 1418c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "failed=%d\n", ret); 1428c2ecf20Sopenharmony_ci return ret; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int zd1301_demod_sleep(struct dvb_frontend *fe) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev = fe->demodulator_priv; 1488c2ecf20Sopenharmony_ci struct platform_device *pdev = dev->pdev; 1498c2ecf20Sopenharmony_ci int ret; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "\n"); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a43, 0x70); 1548c2ecf20Sopenharmony_ci if (ret) 1558c2ecf20Sopenharmony_ci goto err; 1568c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x684e, 0x00); 1578c2ecf20Sopenharmony_ci if (ret) 1588c2ecf20Sopenharmony_ci goto err; 1598c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6849, 0x00); 1608c2ecf20Sopenharmony_ci if (ret) 1618c2ecf20Sopenharmony_ci goto err; 1628c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x68e2, 0xd7); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci goto err; 1658c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x68e0, 0x39); 1668c2ecf20Sopenharmony_ci if (ret) 1678c2ecf20Sopenharmony_ci goto err; 1688c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6840, 0x21); 1698c2ecf20Sopenharmony_ci if (ret) 1708c2ecf20Sopenharmony_ci goto err; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_cierr: 1748c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "failed=%d\n", ret); 1758c2ecf20Sopenharmony_ci return ret; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int zd1301_demod_init(struct dvb_frontend *fe) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev = fe->demodulator_priv; 1818c2ecf20Sopenharmony_ci struct platform_device *pdev = dev->pdev; 1828c2ecf20Sopenharmony_ci int ret; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "\n"); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6840, 0x26); 1878c2ecf20Sopenharmony_ci if (ret) 1888c2ecf20Sopenharmony_ci goto err; 1898c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x68e0, 0xff); 1908c2ecf20Sopenharmony_ci if (ret) 1918c2ecf20Sopenharmony_ci goto err; 1928c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x68e2, 0xd8); 1938c2ecf20Sopenharmony_ci if (ret) 1948c2ecf20Sopenharmony_ci goto err; 1958c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6849, 0x4e); 1968c2ecf20Sopenharmony_ci if (ret) 1978c2ecf20Sopenharmony_ci goto err; 1988c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x684e, 0x01); 1998c2ecf20Sopenharmony_ci if (ret) 2008c2ecf20Sopenharmony_ci goto err; 2018c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a43, zd1301_demod_gain); 2028c2ecf20Sopenharmony_ci if (ret) 2038c2ecf20Sopenharmony_ci goto err; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_cierr: 2078c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "failed=%d\n", ret); 2088c2ecf20Sopenharmony_ci return ret; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int zd1301_demod_get_tune_settings(struct dvb_frontend *fe, 2128c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings *settings) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev = fe->demodulator_priv; 2158c2ecf20Sopenharmony_ci struct platform_device *pdev = dev->pdev; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "\n"); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* ~180ms seems to be enough */ 2208c2ecf20Sopenharmony_ci settings->min_delay_ms = 400; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int zd1301_demod_read_status(struct dvb_frontend *fe, 2268c2ecf20Sopenharmony_ci enum fe_status *status) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev = fe->demodulator_priv; 2298c2ecf20Sopenharmony_ci struct platform_device *pdev = dev->pdev; 2308c2ecf20Sopenharmony_ci int ret; 2318c2ecf20Sopenharmony_ci u8 u8tmp; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci ret = zd1301_demod_rreg(dev, 0x6a24, &u8tmp); 2348c2ecf20Sopenharmony_ci if (ret) 2358c2ecf20Sopenharmony_ci goto err; 2368c2ecf20Sopenharmony_ci if (u8tmp > 0x00 && u8tmp < 0x20) 2378c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | 2388c2ecf20Sopenharmony_ci FE_HAS_SYNC | FE_HAS_LOCK; 2398c2ecf20Sopenharmony_ci else 2408c2ecf20Sopenharmony_ci *status = 0; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "lock byte=%02x\n", u8tmp); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 2458c2ecf20Sopenharmony_ci * Interesting registers here are: 2468c2ecf20Sopenharmony_ci * 0x6a05: get some gain value 2478c2ecf20Sopenharmony_ci * 0x6a06: get about same gain value than set to 0x6a43 2488c2ecf20Sopenharmony_ci * 0x6a07: get some gain value 2498c2ecf20Sopenharmony_ci * 0x6a43: set gain value by driver 2508c2ecf20Sopenharmony_ci * 0x6a24: get demod lock bits (FSM stage?) 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * Driver should implement some kind of algorithm to calculate suitable 2538c2ecf20Sopenharmony_ci * value for register 0x6a43, based likely values from register 0x6a05 2548c2ecf20Sopenharmony_ci * and 0x6a07. Looks like gain register 0x6a43 value could be from 2558c2ecf20Sopenharmony_ci * range 0x00 - 0x70. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (dev->gain != zd1301_demod_gain) { 2598c2ecf20Sopenharmony_ci dev->gain = zd1301_demod_gain; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a43, dev->gain); 2628c2ecf20Sopenharmony_ci if (ret) 2638c2ecf20Sopenharmony_ci goto err; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_cierr: 2688c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "failed=%d\n", ret); 2698c2ecf20Sopenharmony_ci return ret; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops zd1301_demod_ops = { 2738c2ecf20Sopenharmony_ci .delsys = {SYS_DVBT}, 2748c2ecf20Sopenharmony_ci .info = { 2758c2ecf20Sopenharmony_ci .name = "ZyDAS ZD1301", 2768c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | 2778c2ecf20Sopenharmony_ci FE_CAN_FEC_2_3 | 2788c2ecf20Sopenharmony_ci FE_CAN_FEC_3_4 | 2798c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | 2808c2ecf20Sopenharmony_ci FE_CAN_FEC_7_8 | 2818c2ecf20Sopenharmony_ci FE_CAN_FEC_AUTO | 2828c2ecf20Sopenharmony_ci FE_CAN_QPSK | 2838c2ecf20Sopenharmony_ci FE_CAN_QAM_16 | 2848c2ecf20Sopenharmony_ci FE_CAN_QAM_64 | 2858c2ecf20Sopenharmony_ci FE_CAN_QAM_AUTO | 2868c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | 2878c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | 2888c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO | 2898c2ecf20Sopenharmony_ci FE_CAN_MUTE_TS 2908c2ecf20Sopenharmony_ci }, 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci .sleep = zd1301_demod_sleep, 2938c2ecf20Sopenharmony_ci .init = zd1301_demod_init, 2948c2ecf20Sopenharmony_ci .set_frontend = zd1301_demod_set_frontend, 2958c2ecf20Sopenharmony_ci .get_tune_settings = zd1301_demod_get_tune_settings, 2968c2ecf20Sopenharmony_ci .read_status = zd1301_demod_read_status, 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistruct dvb_frontend *zd1301_demod_get_dvb_frontend(struct platform_device *pdev) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev = platform_get_drvdata(pdev); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "\n"); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return &dev->frontend; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zd1301_demod_get_dvb_frontend); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int zd1301_demod_i2c_master_xfer(struct i2c_adapter *adapter, 3108c2ecf20Sopenharmony_ci struct i2c_msg msg[], int num) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev = i2c_get_adapdata(adapter); 3138c2ecf20Sopenharmony_ci struct platform_device *pdev = dev->pdev; 3148c2ecf20Sopenharmony_ci int ret, i; 3158c2ecf20Sopenharmony_ci unsigned long timeout; 3168c2ecf20Sopenharmony_ci u8 u8tmp; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci #define I2C_XFER_TIMEOUT 5 3198c2ecf20Sopenharmony_ci #define ZD1301_IS_I2C_XFER_WRITE_READ(_msg, _num) \ 3208c2ecf20Sopenharmony_ci (_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD)) 3218c2ecf20Sopenharmony_ci #define ZD1301_IS_I2C_XFER_WRITE(_msg, _num) \ 3228c2ecf20Sopenharmony_ci (_num == 1 && !(_msg[0].flags & I2C_M_RD)) 3238c2ecf20Sopenharmony_ci #define ZD1301_IS_I2C_XFER_READ(_msg, _num) \ 3248c2ecf20Sopenharmony_ci (_num == 1 && (_msg[0].flags & I2C_M_RD)) 3258c2ecf20Sopenharmony_ci if (ZD1301_IS_I2C_XFER_WRITE_READ(msg, num)) { 3268c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "write&read msg[0].len=%u msg[1].len=%u\n", 3278c2ecf20Sopenharmony_ci msg[0].len, msg[1].len); 3288c2ecf20Sopenharmony_ci if (msg[0].len > 1 || msg[1].len > 8) { 3298c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 3308c2ecf20Sopenharmony_ci goto err; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6811, 0x80); 3348c2ecf20Sopenharmony_ci if (ret) 3358c2ecf20Sopenharmony_ci goto err; 3368c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6812, 0x05); 3378c2ecf20Sopenharmony_ci if (ret) 3388c2ecf20Sopenharmony_ci goto err; 3398c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6813, msg[1].addr << 1); 3408c2ecf20Sopenharmony_ci if (ret) 3418c2ecf20Sopenharmony_ci goto err; 3428c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6801, msg[0].buf[0]); 3438c2ecf20Sopenharmony_ci if (ret) 3448c2ecf20Sopenharmony_ci goto err; 3458c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6802, 0x00); 3468c2ecf20Sopenharmony_ci if (ret) 3478c2ecf20Sopenharmony_ci goto err; 3488c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6803, 0x06); 3498c2ecf20Sopenharmony_ci if (ret) 3508c2ecf20Sopenharmony_ci goto err; 3518c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6805, 0x00); 3528c2ecf20Sopenharmony_ci if (ret) 3538c2ecf20Sopenharmony_ci goto err; 3548c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6804, msg[1].len); 3558c2ecf20Sopenharmony_ci if (ret) 3568c2ecf20Sopenharmony_ci goto err; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Poll xfer ready */ 3598c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(I2C_XFER_TIMEOUT); 3608c2ecf20Sopenharmony_ci for (u8tmp = 1; !time_after(jiffies, timeout) && u8tmp;) { 3618c2ecf20Sopenharmony_ci usleep_range(500, 800); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci ret = zd1301_demod_rreg(dev, 0x6804, &u8tmp); 3648c2ecf20Sopenharmony_ci if (ret) 3658c2ecf20Sopenharmony_ci goto err; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci for (i = 0; i < msg[1].len; i++) { 3698c2ecf20Sopenharmony_ci ret = zd1301_demod_rreg(dev, 0x0600 + i, &msg[1].buf[i]); 3708c2ecf20Sopenharmony_ci if (ret) 3718c2ecf20Sopenharmony_ci goto err; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } else if (ZD1301_IS_I2C_XFER_WRITE(msg, num)) { 3748c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "write msg[0].len=%u\n", msg[0].len); 3758c2ecf20Sopenharmony_ci if (msg[0].len > 1 + 8) { 3768c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 3778c2ecf20Sopenharmony_ci goto err; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6811, 0x80); 3818c2ecf20Sopenharmony_ci if (ret) 3828c2ecf20Sopenharmony_ci goto err; 3838c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6812, 0x01); 3848c2ecf20Sopenharmony_ci if (ret) 3858c2ecf20Sopenharmony_ci goto err; 3868c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6813, msg[0].addr << 1); 3878c2ecf20Sopenharmony_ci if (ret) 3888c2ecf20Sopenharmony_ci goto err; 3898c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6800, msg[0].buf[0]); 3908c2ecf20Sopenharmony_ci if (ret) 3918c2ecf20Sopenharmony_ci goto err; 3928c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6802, 0x00); 3938c2ecf20Sopenharmony_ci if (ret) 3948c2ecf20Sopenharmony_ci goto err; 3958c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6803, 0x06); 3968c2ecf20Sopenharmony_ci if (ret) 3978c2ecf20Sopenharmony_ci goto err; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci for (i = 0; i < msg[0].len - 1; i++) { 4008c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x0600 + i, msg[0].buf[1 + i]); 4018c2ecf20Sopenharmony_ci if (ret) 4028c2ecf20Sopenharmony_ci goto err; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6805, 0x80); 4068c2ecf20Sopenharmony_ci if (ret) 4078c2ecf20Sopenharmony_ci goto err; 4088c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6804, msg[0].len - 1); 4098c2ecf20Sopenharmony_ci if (ret) 4108c2ecf20Sopenharmony_ci goto err; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Poll xfer ready */ 4138c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(I2C_XFER_TIMEOUT); 4148c2ecf20Sopenharmony_ci for (u8tmp = 1; !time_after(jiffies, timeout) && u8tmp;) { 4158c2ecf20Sopenharmony_ci usleep_range(500, 800); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci ret = zd1301_demod_rreg(dev, 0x6804, &u8tmp); 4188c2ecf20Sopenharmony_ci if (ret) 4198c2ecf20Sopenharmony_ci goto err; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } else { 4228c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "unknown msg[0].len=%u\n", msg[0].len); 4238c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 4248c2ecf20Sopenharmony_ci goto err; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return num; 4288c2ecf20Sopenharmony_cierr: 4298c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "failed=%d\n", ret); 4308c2ecf20Sopenharmony_ci return ret; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic u32 zd1301_demod_i2c_functionality(struct i2c_adapter *adapter) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci return I2C_FUNC_I2C; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic const struct i2c_algorithm zd1301_demod_i2c_algorithm = { 4398c2ecf20Sopenharmony_ci .master_xfer = zd1301_demod_i2c_master_xfer, 4408c2ecf20Sopenharmony_ci .functionality = zd1301_demod_i2c_functionality, 4418c2ecf20Sopenharmony_ci}; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistruct i2c_adapter *zd1301_demod_get_i2c_adapter(struct platform_device *pdev) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev = platform_get_drvdata(pdev); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "\n"); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return &dev->adapter; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zd1301_demod_get_i2c_adapter); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/* Platform driver interface */ 4548c2ecf20Sopenharmony_cistatic int zd1301_demod_probe(struct platform_device *pdev) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev; 4578c2ecf20Sopenharmony_ci struct zd1301_demod_platform_data *pdata = pdev->dev.platform_data; 4588c2ecf20Sopenharmony_ci int ret; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "\n"); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (!pdata) { 4638c2ecf20Sopenharmony_ci ret = -EINVAL; 4648c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot proceed without platform data\n"); 4658c2ecf20Sopenharmony_ci goto err; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci if (!pdev->dev.parent->driver) { 4688c2ecf20Sopenharmony_ci ret = -EINVAL; 4698c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "no parent device\n"); 4708c2ecf20Sopenharmony_ci goto err; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 4748c2ecf20Sopenharmony_ci if (!dev) { 4758c2ecf20Sopenharmony_ci ret = -ENOMEM; 4768c2ecf20Sopenharmony_ci goto err; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* Setup the state */ 4808c2ecf20Sopenharmony_ci dev->pdev = pdev; 4818c2ecf20Sopenharmony_ci dev->gain = zd1301_demod_gain; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* Sleep */ 4848c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6840, 0x21); 4858c2ecf20Sopenharmony_ci if (ret) 4868c2ecf20Sopenharmony_ci goto err_kfree; 4878c2ecf20Sopenharmony_ci ret = zd1301_demod_wreg(dev, 0x6a38, 0x07); 4888c2ecf20Sopenharmony_ci if (ret) 4898c2ecf20Sopenharmony_ci goto err_kfree; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Create I2C adapter */ 4928c2ecf20Sopenharmony_ci strscpy(dev->adapter.name, "ZyDAS ZD1301 demod", 4938c2ecf20Sopenharmony_ci sizeof(dev->adapter.name)); 4948c2ecf20Sopenharmony_ci dev->adapter.algo = &zd1301_demod_i2c_algorithm; 4958c2ecf20Sopenharmony_ci dev->adapter.algo_data = NULL; 4968c2ecf20Sopenharmony_ci dev->adapter.dev.parent = pdev->dev.parent; 4978c2ecf20Sopenharmony_ci i2c_set_adapdata(&dev->adapter, dev); 4988c2ecf20Sopenharmony_ci ret = i2c_add_adapter(&dev->adapter); 4998c2ecf20Sopenharmony_ci if (ret) { 5008c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "I2C adapter add failed %d\n", ret); 5018c2ecf20Sopenharmony_ci goto err_kfree; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Create dvb frontend */ 5058c2ecf20Sopenharmony_ci memcpy(&dev->frontend.ops, &zd1301_demod_ops, sizeof(dev->frontend.ops)); 5068c2ecf20Sopenharmony_ci dev->frontend.demodulator_priv = dev; 5078c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 5088c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "ZyDAS ZD1301 demod attached\n"); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci return 0; 5118c2ecf20Sopenharmony_cierr_kfree: 5128c2ecf20Sopenharmony_ci kfree(dev); 5138c2ecf20Sopenharmony_cierr: 5148c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "failed=%d\n", ret); 5158c2ecf20Sopenharmony_ci return ret; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int zd1301_demod_remove(struct platform_device *pdev) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct zd1301_demod_dev *dev = platform_get_drvdata(pdev); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "\n"); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci i2c_del_adapter(&dev->adapter); 5258c2ecf20Sopenharmony_ci kfree(dev); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic struct platform_driver zd1301_demod_driver = { 5318c2ecf20Sopenharmony_ci .driver = { 5328c2ecf20Sopenharmony_ci .name = "zd1301_demod", 5338c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 5348c2ecf20Sopenharmony_ci }, 5358c2ecf20Sopenharmony_ci .probe = zd1301_demod_probe, 5368c2ecf20Sopenharmony_ci .remove = zd1301_demod_remove, 5378c2ecf20Sopenharmony_ci}; 5388c2ecf20Sopenharmony_cimodule_platform_driver(zd1301_demod_driver); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 5418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ZyDAS ZD1301 demodulator driver"); 5428c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 543