162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci Mantis VP-2033 driver 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci Copyright (C) Manu Abraham (abraham.manu@gmail.com) 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci*/ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/signal.h> 1062306a36Sopenharmony_ci#include <linux/sched.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <media/dmxdev.h> 1462306a36Sopenharmony_ci#include <media/dvbdev.h> 1562306a36Sopenharmony_ci#include <media/dvb_demux.h> 1662306a36Sopenharmony_ci#include <media/dvb_frontend.h> 1762306a36Sopenharmony_ci#include <media/dvb_net.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "tda1002x.h" 2062306a36Sopenharmony_ci#include "mantis_common.h" 2162306a36Sopenharmony_ci#include "mantis_ioc.h" 2262306a36Sopenharmony_ci#include "mantis_dvb.h" 2362306a36Sopenharmony_ci#include "mantis_vp2033.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define MANTIS_MODEL_NAME "VP-2033" 2662306a36Sopenharmony_ci#define MANTIS_DEV_TYPE "DVB-C" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic struct tda1002x_config vp2033_tda1002x_cu1216_config = { 2962306a36Sopenharmony_ci .demod_address = 0x18 >> 1, 3062306a36Sopenharmony_ci .invert = 1, 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic struct tda10023_config vp2033_tda10023_cu1216_config = { 3462306a36Sopenharmony_ci .demod_address = 0x18 >> 1, 3562306a36Sopenharmony_ci .invert = 1, 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic u8 read_pwm(struct mantis_pci *mantis) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct i2c_adapter *adapter = &mantis->adapter; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci u8 b = 0xff; 4362306a36Sopenharmony_ci u8 pwm; 4462306a36Sopenharmony_ci struct i2c_msg msg[] = { 4562306a36Sopenharmony_ci {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, 4662306a36Sopenharmony_ci {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} 4762306a36Sopenharmony_ci }; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if ((i2c_transfer(adapter, msg, 2) != 2) 5062306a36Sopenharmony_ci || (pwm == 0xff)) 5162306a36Sopenharmony_ci pwm = 0x48; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return pwm; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 5962306a36Sopenharmony_ci struct mantis_pci *mantis = fe->dvb->priv; 6062306a36Sopenharmony_ci struct i2c_adapter *adapter = &mantis->adapter; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci u8 buf[6]; 6362306a36Sopenharmony_ci struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; 6462306a36Sopenharmony_ci int i; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define CU1216_IF 36125000 6762306a36Sopenharmony_ci#define TUNER_MUL 62500 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci buf[0] = (div >> 8) & 0x7f; 7262306a36Sopenharmony_ci buf[1] = div & 0xff; 7362306a36Sopenharmony_ci buf[2] = 0xce; 7462306a36Sopenharmony_ci buf[3] = (p->frequency < 150000000 ? 0x01 : 7562306a36Sopenharmony_ci p->frequency < 445000000 ? 0x02 : 0x04); 7662306a36Sopenharmony_ci buf[4] = 0xde; 7762306a36Sopenharmony_ci buf[5] = 0x20; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 8062306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (i2c_transfer(adapter, &msg, 1) != 1) 8362306a36Sopenharmony_ci return -EIO; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* wait for the pll lock */ 8662306a36Sopenharmony_ci msg.flags = I2C_M_RD; 8762306a36Sopenharmony_ci msg.len = 1; 8862306a36Sopenharmony_ci for (i = 0; i < 20; i++) { 8962306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 9062306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci msleep(10); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* switch the charge pump to the lower current */ 9962306a36Sopenharmony_ci msg.flags = 0; 10062306a36Sopenharmony_ci msg.len = 2; 10162306a36Sopenharmony_ci msg.buf = &buf[2]; 10262306a36Sopenharmony_ci buf[2] &= ~0x40; 10362306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 10462306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (i2c_transfer(adapter, &msg, 1) != 1) 10762306a36Sopenharmony_ci return -EIO; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct i2c_adapter *adapter = &mantis->adapter; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci int err = 0; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci err = mantis_frontend_power(mantis, POWER_ON); 11962306a36Sopenharmony_ci if (err == 0) { 12062306a36Sopenharmony_ci mantis_frontend_soft_reset(mantis); 12162306a36Sopenharmony_ci msleep(250); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); 12462306a36Sopenharmony_ci fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config, 12562306a36Sopenharmony_ci adapter, 12662306a36Sopenharmony_ci read_pwm(mantis)); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (fe) { 12962306a36Sopenharmony_ci dprintk(MANTIS_ERROR, 1, 13062306a36Sopenharmony_ci "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", 13162306a36Sopenharmony_ci vp2033_tda1002x_cu1216_config.demod_address); 13262306a36Sopenharmony_ci } else { 13362306a36Sopenharmony_ci fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config, 13462306a36Sopenharmony_ci adapter, 13562306a36Sopenharmony_ci read_pwm(mantis)); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (fe) { 13862306a36Sopenharmony_ci dprintk(MANTIS_ERROR, 1, 13962306a36Sopenharmony_ci "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", 14062306a36Sopenharmony_ci vp2033_tda1002x_cu1216_config.demod_address); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (fe) { 14562306a36Sopenharmony_ci fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; 14662306a36Sopenharmony_ci dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); 14762306a36Sopenharmony_ci } else { 14862306a36Sopenharmony_ci return -1; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } else { 15162306a36Sopenharmony_ci dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", 15262306a36Sopenharmony_ci adapter->name, 15362306a36Sopenharmony_ci err); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return -EIO; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci mantis->fe = fe; 15962306a36Sopenharmony_ci dprintk(MANTIS_DEBUG, 1, "Done!"); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistruct mantis_hwconfig vp2033_config = { 16562306a36Sopenharmony_ci .model_name = MANTIS_MODEL_NAME, 16662306a36Sopenharmony_ci .dev_type = MANTIS_DEV_TYPE, 16762306a36Sopenharmony_ci .ts_size = MANTIS_TS_204, 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci .baud_rate = MANTIS_BAUD_9600, 17062306a36Sopenharmony_ci .parity = MANTIS_PARITY_NONE, 17162306a36Sopenharmony_ci .bytes = 0, 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci .frontend_init = vp2033_frontend_init, 17462306a36Sopenharmony_ci .power = GPIF_A12, 17562306a36Sopenharmony_ci .reset = GPIF_A13, 17662306a36Sopenharmony_ci}; 177