^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) Copyright (C) 2008 Sirius International (Hong Kong) Limited
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) Timothy Lee <timothy.lee@siriushk.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <media/dvb_frontend.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "lgs8gl5.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define REG_RESET 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define REG_RESET_OFF 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define REG_03 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define REG_04 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define REG_07 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define REG_09 0x09
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define REG_0A 0x0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define REG_0B 0x0b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define REG_0C 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define REG_37 0x37
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define REG_STRENGTH 0x4b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define REG_STRENGTH_MASK 0x7f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define REG_STRENGTH_CARRIER 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define REG_INVERSION 0x7c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define REG_INVERSION_ON 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define REG_7D 0x7d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define REG_7E 0x7e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define REG_A2 0xa2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define REG_STATUS 0xa4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define REG_STATUS_SYNC 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define REG_STATUS_LOCK 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct lgs8gl5_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct i2c_adapter *i2c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) const struct lgs8gl5_config *config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct dvb_frontend frontend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static int debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define dprintk(args...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (debug) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) printk(KERN_DEBUG "lgs8gl5: " args); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* Writes into demod's register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u8 buf[] = {reg, data};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct i2c_msg msg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .addr = state->config->demod_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .buf = buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) .len = 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) ret = i2c_transfer(state->i2c, &msg, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (ret != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) __func__, reg, data, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return (ret != 1) ? -1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* Reads from demod's register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u8 b0[] = {reg};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) u8 b1[] = {0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct i2c_msg msg[2] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .addr = state->config->demod_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) .buf = b0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .len = 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .addr = state->config->demod_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .flags = I2C_M_RD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .buf = b1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .len = 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ret = i2c_transfer(state->i2c, msg, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (ret != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return b1[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) lgs8gl5_read_reg(state, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) lgs8gl5_write_reg(state, reg, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /* Writes into alternate device's register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* TODO: Find out what that device is for! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) u8 b0[] = {reg};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) u8 b1[] = {0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) u8 b2[] = {reg, data};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct i2c_msg msg[3] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .addr = state->config->demod_address + 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .buf = b0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .len = 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .addr = state->config->demod_address + 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .flags = I2C_M_RD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .buf = b1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .len = 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .addr = state->config->demod_address + 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .buf = b2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .len = 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) ret = i2c_transfer(state->i2c, msg, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return (ret != 3) ? -1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) lgs8gl5_soft_reset(struct lgs8gl5_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) u8 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) dprintk("%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) val = lgs8gl5_read_reg(state, REG_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) msleep(5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /* Starts demodulation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) lgs8gl5_start_demod(struct lgs8gl5_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) u8 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) int n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) dprintk("%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) lgs8gl5_soft_reset(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) lgs8gl5_update_reg(state, REG_07, 0x10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) lgs8gl5_update_reg(state, REG_07, 0x10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) lgs8gl5_write_reg(state, REG_09, 0x0e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) lgs8gl5_write_reg(state, REG_0A, 0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) lgs8gl5_write_reg(state, REG_0B, 0x35);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) lgs8gl5_write_reg(state, REG_0C, 0x30);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) lgs8gl5_update_reg(state, REG_03, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) lgs8gl5_update_reg(state, REG_7E, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) lgs8gl5_update_reg(state, REG_04, 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) lgs8gl5_update_reg(state, REG_37, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) lgs8gl5_soft_reset(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /* Wait for carrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) for (n = 0; n < 10; n++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) val = lgs8gl5_read_reg(state, REG_STRENGTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (val & REG_STRENGTH_CARRIER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) msleep(4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (!(val & REG_STRENGTH_CARRIER))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /* Wait for lock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) for (n = 0; n < 20; n++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) val = lgs8gl5_read_reg(state, REG_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) dprintk("Wait for lock[%d] 0x%02X\n", n, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (val & REG_STATUS_LOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) msleep(12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (!(val & REG_STATUS_LOCK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) lgs8gl5_soft_reset(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) lgs8gl5_init(struct dvb_frontend *fe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) struct lgs8gl5_state *state = fe->demodulator_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) dprintk("%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) lgs8gl5_soft_reset(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) lgs8gl5_update_reg(state, REG_07, 0x10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) lgs8gl5_update_reg(state, REG_07, 0x10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) lgs8gl5_write_reg(state, REG_09, 0x0e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) lgs8gl5_write_reg(state, REG_0A, 0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) lgs8gl5_write_reg(state, REG_0B, 0x35);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) lgs8gl5_write_reg(state, REG_0C, 0x30);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) lgs8gl5_read_status(struct dvb_frontend *fe, enum fe_status *status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct lgs8gl5_state *state = fe->demodulator_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) *status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if ((level & REG_STRENGTH_MASK) > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) *status |= FE_HAS_SIGNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (level & REG_STRENGTH_CARRIER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) *status |= FE_HAS_CARRIER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (flags & REG_STATUS_SYNC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) *status |= FE_HAS_SYNC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (flags & REG_STATUS_LOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) *status |= FE_HAS_LOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) *ber = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct lgs8gl5_state *state = fe->demodulator_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) *signal_strength = (level & REG_STRENGTH_MASK) << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) struct lgs8gl5_state *state = fe->demodulator_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) *snr = (level & REG_STRENGTH_MASK) << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) *ucblocks = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) lgs8gl5_set_frontend(struct dvb_frontend *fe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) struct dtv_frontend_properties *p = &fe->dtv_property_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) struct lgs8gl5_state *state = fe->demodulator_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) dprintk("%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (p->bandwidth_hz != 8000000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (fe->ops.tuner_ops.set_params) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) fe->ops.tuner_ops.set_params(fe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (fe->ops.i2c_gate_ctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) fe->ops.i2c_gate_ctrl(fe, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) /* lgs8gl5_set_inversion(state, p->inversion); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) lgs8gl5_start_demod(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) lgs8gl5_get_frontend(struct dvb_frontend *fe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) struct dtv_frontend_properties *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) struct lgs8gl5_state *state = fe->demodulator_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) p->code_rate_HP = FEC_1_2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) p->code_rate_LP = FEC_7_8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) p->guard_interval = GUARD_INTERVAL_1_32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) p->transmission_mode = TRANSMISSION_MODE_2K;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) p->modulation = QAM_64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) p->hierarchy = HIERARCHY_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) p->bandwidth_hz = 8000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) lgs8gl5_get_tune_settings(struct dvb_frontend *fe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct dvb_frontend_tune_settings *fesettings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) fesettings->min_delay_ms = 240;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) fesettings->step_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) fesettings->max_drift = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) lgs8gl5_release(struct dvb_frontend *fe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) struct lgs8gl5_state *state = fe->demodulator_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) kfree(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static const struct dvb_frontend_ops lgs8gl5_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) struct dvb_frontend*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) struct lgs8gl5_state *state = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) dprintk("%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) /* Allocate memory for the internal state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) state = kzalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (state == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /* Setup the state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) state->config = config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) state->i2c = i2c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /* Check if the demod is there */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (lgs8gl5_read_reg(state, REG_RESET) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /* Create dvb_frontend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) memcpy(&state->frontend.ops, &lgs8gl5_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) sizeof(struct dvb_frontend_ops));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) state->frontend.demodulator_priv = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return &state->frontend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) kfree(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) EXPORT_SYMBOL(lgs8gl5_attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) static const struct dvb_frontend_ops lgs8gl5_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) .delsys = { SYS_DTMB },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) .info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) .name = "Legend Silicon LGS-8GL5 DMB-TH",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) .frequency_min_hz = 474 * MHz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) .frequency_max_hz = 858 * MHz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) .frequency_stepsize_hz = 10 * kHz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) .caps = FE_CAN_FEC_AUTO |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) FE_CAN_TRANSMISSION_MODE_AUTO |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) FE_CAN_BANDWIDTH_AUTO |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) FE_CAN_GUARD_INTERVAL_AUTO |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) FE_CAN_HIERARCHY_AUTO |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) FE_CAN_RECOVER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) .release = lgs8gl5_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) .init = lgs8gl5_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) .set_frontend = lgs8gl5_set_frontend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) .get_frontend = lgs8gl5_get_frontend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) .get_tune_settings = lgs8gl5_get_tune_settings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .read_status = lgs8gl5_read_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) .read_ber = lgs8gl5_read_ber,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) .read_signal_strength = lgs8gl5_read_signal_strength,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) .read_snr = lgs8gl5_read_snr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) .read_ucblocks = lgs8gl5_read_ucblocks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) module_param(debug, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) MODULE_AUTHOR("Timothy Lee");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) MODULE_LICENSE("GPL");