// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Realtek RTL2830 DVB-T demodulator driver
*
* Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
*/
#include "rtl2830_priv.h"
/* Our regmap is bypassing I2C adapter lock, thus we do it! */
static int rtl2830_bulk_write(struct i2c_client *client, unsigned int reg,
const void *val, size_t val_count)
{
struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
return ret;
}
static int rtl2830_update_bits(struct i2c_client *client, unsigned int reg,
unsigned int mask, unsigned int val)
{
struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = regmap_update_bits(dev->regmap, reg, mask, val);
i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
return ret;
}
static int rtl2830_bulk_read(struct i2c_client *client, unsigned int reg,
void *val, size_t val_count)
{
struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
return ret;
}
static int rtl2830_init(struct dvb_frontend *fe)
{
struct i2c_client *client = fe->demodulator_priv;
struct rtl2830_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
int ret, i;
struct rtl2830_reg_val_mask tab[] = {
{0x00d, 0x01, 0x03},
{0x00d, 0x10, 0x10},
{0x104, 0x00, 0x1e},
{0x105, 0x80, 0x80},
{0x110, 0x02, 0x03},
{0x110, 0x08, 0x0c},
{0x17b, 0x00, 0x40},
{0x17d, 0x05, 0x0f},
{0x17d, 0x50, 0xf0},
{0x18c, 0x08, 0x0f},
{0x18d, 0x00, 0xc0},
{0x188, 0x05, 0x0f},
{0x189, 0x00, 0xfc},
{0x2d5, 0x02, 0x02},
{0x2f1, 0x02, 0x06},
{0x2f1, 0x20, 0xf8},
{0x16d, 0x00, 0x01},
{0x1a6, 0x00, 0x80},
{0x106, dev->pdata->vtop, 0x3f},
{0x107, dev->pdata->krf, 0x3f},
{0x112, 0x28, 0xff},
{0x103, dev->pdata->agc_targ_val, 0xff},
{0x00a, 0x02, 0x07},
{0x140, 0x0c, 0x3c},
{0x140, 0x40, 0xc0},
{0x15b, 0x05, 0x07},
{0x15b, 0x28, 0x38},
{0x15c, 0x05, 0x07},
{0x15c, 0x28, 0x38},
{0x115, dev->pdata->spec_inv, 0x01},
{0x16f, 0x01, 0x07},
{0x170, 0x18, 0x38},
{0x172, 0x0f, 0x0f},
{0x173, 0x08, 0x38},
{0x175, 0x01, 0x07},
{0x176, 0x00, 0xc0},
};
for (i = 0; i < ARRAY_SIZE(tab); i++) {
ret = rtl2830_update_bits(client, tab[i].reg, tab[i].mask,
tab[i].val);
if (ret)
goto err;
}
ret = rtl2830_bulk_write(client, 0x18f, "\x28\x00", 2);
if (ret)
goto err;
ret = rtl2830_bulk_write(client, 0x195,
"\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
if (ret)
goto err;
/* TODO: spec init */
/* soft reset */
ret = rtl2830_update_bits(client, 0x101, 0x04, 0x04);
if (ret)
goto err;
ret = rtl2830_update_bits(client, 0x101, 0x04, 0x00);
if (ret)
goto err;
/* init stats here in order signal app which stats are supported */
c->strength.len = 1;
c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->cnr.len = 1;
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_error.len = 1;
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.len = 1;
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
dev->sleeping = false;
return ret;
err:
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2830_sleep(struct dvb_frontend *fe)
{
struct i2c_client *client = fe->demodulator_priv;
struct rtl2830_dev *dev = i2c_get_clientdata(client);
dev->sleeping = true;
dev->fe_status = 0;
return 0;
}
static int rtl2830_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s)
{
s->min_delay_ms = 500;
s->step_size = fe->ops.info.frequency_stepsize_hz * 2;
s->max_drift = (fe->ops.info.frequency_stepsize_hz * 2) + 1;
return 0;
}
static int rtl2830_set_frontend(struct dvb_frontend *fe)
{
struct i2c_client *client = fe->demodulator_priv;
struct rtl2830_dev *dev = i2c_get_clientdata(client);
struct