Commit 03aa1bcd authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] radio-si4713: convert to the control framework

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Acked-by: default avatarEduardo Valentin <edubezval@gmail.com>
Tested-by: default avatarEduardo Valentin <edubezval@gmail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent b387754d
......@@ -76,61 +76,6 @@ static int radio_si4713_querycap(struct file *file, void *priv,
return 0;
}
/* radio_si4713_queryctrl - enumerate control items */
static int radio_si4713_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
/* Must be sorted from low to high control ID! */
static const u32 user_ctrls[] = {
V4L2_CID_USER_CLASS,
V4L2_CID_AUDIO_MUTE,
0
};
/* Must be sorted from low to high control ID! */
static const u32 fmtx_ctrls[] = {
V4L2_CID_FM_TX_CLASS,
V4L2_CID_RDS_TX_DEVIATION,
V4L2_CID_RDS_TX_PI,
V4L2_CID_RDS_TX_PTY,
V4L2_CID_RDS_TX_PS_NAME,
V4L2_CID_RDS_TX_RADIO_TEXT,
V4L2_CID_AUDIO_LIMITER_ENABLED,
V4L2_CID_AUDIO_LIMITER_RELEASE_TIME,
V4L2_CID_AUDIO_LIMITER_DEVIATION,
V4L2_CID_AUDIO_COMPRESSION_ENABLED,
V4L2_CID_AUDIO_COMPRESSION_GAIN,
V4L2_CID_AUDIO_COMPRESSION_THRESHOLD,
V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME,
V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME,
V4L2_CID_PILOT_TONE_ENABLED,
V4L2_CID_PILOT_TONE_DEVIATION,
V4L2_CID_PILOT_TONE_FREQUENCY,
V4L2_CID_TUNE_PREEMPHASIS,
V4L2_CID_TUNE_POWER_LEVEL,
V4L2_CID_TUNE_ANTENNA_CAPACITOR,
0
};
static const u32 *ctrl_classes[] = {
user_ctrls,
fmtx_ctrls,
NULL
};
struct radio_si4713_device *rsdev;
rsdev = video_get_drvdata(video_devdata(file));
qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
if (qc->id == 0)
return -EINVAL;
if (qc->id == V4L2_CID_USER_CLASS || qc->id == V4L2_CID_FM_TX_CLASS)
return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0);
return v4l2_device_call_until_err(&rsdev->v4l2_dev, 0, core,
queryctrl, qc);
}
/*
* v4l2 ioctl call backs.
* we are just a wrapper for v4l2_sub_devs.
......@@ -140,34 +85,6 @@ static inline struct v4l2_device *get_v4l2_dev(struct file *file)
return &((struct radio_si4713_device *)video_drvdata(file))->v4l2_dev;
}
static int radio_si4713_g_ext_ctrls(struct file *file, void *p,
struct v4l2_ext_controls *vecs)
{
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
g_ext_ctrls, vecs);
}
static int radio_si4713_s_ext_ctrls(struct file *file, void *p,
struct v4l2_ext_controls *vecs)
{
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
s_ext_ctrls, vecs);
}
static int radio_si4713_g_ctrl(struct file *file, void *p,
struct v4l2_control *vc)
{
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
g_ctrl, vc);
}
static int radio_si4713_s_ctrl(struct file *file, void *p,
struct v4l2_control *vc)
{
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
s_ctrl, vc);
}
static int radio_si4713_g_modulator(struct file *file, void *p,
struct v4l2_modulator *vm)
{
......@@ -205,11 +122,6 @@ static long radio_si4713_default(struct file *file, void *p,
static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = {
.vidioc_querycap = radio_si4713_querycap,
.vidioc_queryctrl = radio_si4713_queryctrl,
.vidioc_g_ext_ctrls = radio_si4713_g_ext_ctrls,
.vidioc_s_ext_ctrls = radio_si4713_s_ext_ctrls,
.vidioc_g_ctrl = radio_si4713_g_ctrl,
.vidioc_s_ctrl = radio_si4713_s_ctrl,
.vidioc_g_modulator = radio_si4713_g_modulator,
.vidioc_s_modulator = radio_si4713_s_modulator,
.vidioc_g_frequency = radio_si4713_g_frequency,
......@@ -274,6 +186,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
rsdev->radio_dev = radio_si4713_vdev_template;
rsdev->radio_dev.v4l2_dev = &rsdev->v4l2_dev;
rsdev->radio_dev.ctrl_handler = sd->ctrl_handler;
/* Serialize all access to the si4713 */
rsdev->radio_dev.lock = &rsdev->lock;
video_set_drvdata(&rsdev->radio_dev, rsdev);
......
......@@ -52,8 +52,6 @@ static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = {
#define DEFAULT_RDS_PI 0x00
#define DEFAULT_RDS_PTY 0x00
#define DEFAULT_RDS_PS_NAME ""
#define DEFAULT_RDS_RADIO_TEXT DEFAULT_RDS_PS_NAME
#define DEFAULT_RDS_DEVIATION 0x00C8
#define DEFAULT_RDS_PS_REPEAT_COUNT 0x0003
#define DEFAULT_LIMITER_RTIME 0x1392
......@@ -107,7 +105,6 @@ static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = {
(status & SI4713_ERR))
/* mute definition */
#define set_mute(p) ((p & 1) | ((p & 1) << 1));
#define get_mute(p) (p & 0x01)
#ifdef DEBUG
#define DBG_BUFFER(device, message, buffer, size) \
......@@ -189,21 +186,6 @@ static int usecs_to_dev(unsigned long usecs, unsigned long const array[],
return rval;
}
static unsigned long dev_to_usecs(int value, unsigned long const array[],
int size)
{
int i;
int rval = -EINVAL;
for (i = 0; i < size / 2; i++)
if (array[i * 2] == value) {
rval = array[(i * 2) + 1];
break;
}
return rval;
}
/* si4713_handler: IRQ handler, just complete work */
static irqreturn_t si4713_handler(int irq, void *dev)
{
......@@ -787,9 +769,6 @@ static int si4713_set_mute(struct si4713_device *sdev, u16 mute)
rval = si4713_write_property(sdev,
SI4713_TX_LINE_INPUT_MUTE, mute);
if (rval >= 0)
sdev->mute = get_mute(mute);
return rval;
}
......@@ -830,7 +809,6 @@ static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name)
return rval;
}
strncpy(sdev->rds_info.ps_name, ps_name, MAX_RDS_PS_NAME);
return rval;
}
......@@ -842,24 +820,23 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt)
s8 left;
if (!sdev->power_state)
goto copy;
return rval;
rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_CLEAR, 0, 0, 0, &left);
if (rval < 0)
return rval;
if (!strlen(rt))
goto copy;
return rval;
do {
/* RDS spec says that if the last block isn't used,
* then apply a carriage return
*/
if (t_index < (RDS_RADIOTEXT_INDEX_MAX *
RDS_RADIOTEXT_BLK_SIZE)) {
if (t_index < (RDS_RADIOTEXT_INDEX_MAX * RDS_RADIOTEXT_BLK_SIZE)) {
for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) {
if (!rt[t_index + i] || rt[t_index + i] ==
RDS_CARRIAGE_RETURN) {
if (!rt[t_index + i] ||
rt[t_index + i] == RDS_CARRIAGE_RETURN) {
rt[t_index + i] = RDS_CARRIAGE_RETURN;
cr_inserted = 1;
break;
......@@ -881,13 +858,38 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt)
break;
} while (left > 0);
copy:
strncpy(sdev->rds_info.radio_text, rt, MAX_RDS_RADIO_TEXT);
return rval;
}
/*
* si4713_update_tune_status - update properties from tx_tune_status
* command. Must be called with sdev->mutex held.
* @sdev: si4713_device structure for the device we are communicating
*/
static int si4713_update_tune_status(struct si4713_device *sdev)
{
int rval;
u16 f = 0;
u8 p = 0, a = 0, n = 0;
rval = si4713_tx_tune_status(sdev, 0x00, &f, &p, &a, &n);
if (rval < 0)
goto exit;
/* TODO: check that power_level and antenna_capacitor really are not
changed by the hardware. If they are, then these controls should become
volatiles.
sdev->power_level = p;
sdev->antenna_capacitor = a;*/
sdev->tune_rnl = n;
exit:
return rval;
}
static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id,
u32 **shadow, s32 *bit, s32 *mask, u16 *property, int *mul,
s32 *bit, s32 *mask, u16 *property, int *mul,
unsigned long **table, int *size)
{
s32 rval = 0;
......@@ -897,157 +899,71 @@ static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id,
case V4L2_CID_RDS_TX_PI:
*property = SI4713_TX_RDS_PI;
*mul = 1;
*shadow = &sdev->rds_info.pi;
break;
case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
*property = SI4713_TX_ACOMP_THRESHOLD;
*mul = 1;
*shadow = &sdev->acomp_info.threshold;
break;
case V4L2_CID_AUDIO_COMPRESSION_GAIN:
*property = SI4713_TX_ACOMP_GAIN;
*mul = 1;
*shadow = &sdev->acomp_info.gain;
break;
case V4L2_CID_PILOT_TONE_FREQUENCY:
*property = SI4713_TX_PILOT_FREQUENCY;
*mul = 1;
*shadow = &sdev->pilot_info.frequency;
break;
case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
*property = SI4713_TX_ACOMP_ATTACK_TIME;
*mul = ATTACK_TIME_UNIT;
*shadow = &sdev->acomp_info.attack_time;
break;
case V4L2_CID_PILOT_TONE_DEVIATION:
*property = SI4713_TX_PILOT_DEVIATION;
*mul = 10;
*shadow = &sdev->pilot_info.deviation;
break;
case V4L2_CID_AUDIO_LIMITER_DEVIATION:
*property = SI4713_TX_AUDIO_DEVIATION;
*mul = 10;
*shadow = &sdev->limiter_info.deviation;
break;
case V4L2_CID_RDS_TX_DEVIATION:
*property = SI4713_TX_RDS_DEVIATION;
*mul = 1;
*shadow = &sdev->rds_info.deviation;
break;
case V4L2_CID_RDS_TX_PTY:
*property = SI4713_TX_RDS_PS_MISC;
*bit = 5;
*mask = 0x1F << 5;
*shadow = &sdev->rds_info.pty;
break;
case V4L2_CID_AUDIO_LIMITER_ENABLED:
*property = SI4713_TX_ACOMP_ENABLE;
*bit = 1;
*mask = 1 << 1;
*shadow = &sdev->limiter_info.enabled;
break;
case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
*property = SI4713_TX_ACOMP_ENABLE;
*bit = 0;
*mask = 1 << 0;
*shadow = &sdev->acomp_info.enabled;
break;
case V4L2_CID_PILOT_TONE_ENABLED:
*property = SI4713_TX_COMPONENT_ENABLE;
*bit = 0;
*mask = 1 << 0;
*shadow = &sdev->pilot_info.enabled;
break;
case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
*property = SI4713_TX_LIMITER_RELEASE_TIME;
*table = limiter_times;
*size = ARRAY_SIZE(limiter_times);
*shadow = &sdev->limiter_info.release_time;
break;
case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
*property = SI4713_TX_ACOMP_RELEASE_TIME;
*table = acomp_rtimes;
*size = ARRAY_SIZE(acomp_rtimes);
*shadow = &sdev->acomp_info.release_time;
break;
case V4L2_CID_TUNE_PREEMPHASIS:
*property = SI4713_TX_PREEMPHASIS;
*table = preemphasis_values;
*size = ARRAY_SIZE(preemphasis_values);
*shadow = &sdev->preemphasis;
break;
default:
rval = -EINVAL;
}
return rval;
}
static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
/* write string property */
static int si4713_write_econtrol_string(struct si4713_device *sdev,
struct v4l2_ext_control *control)
{
struct v4l2_queryctrl vqc;
int len;
s32 rval = 0;
vqc.id = control->id;
rval = si4713_queryctrl(&sdev->sd, &vqc);
if (rval < 0)
goto exit;
switch (control->id) {
case V4L2_CID_RDS_TX_PS_NAME: {
char ps_name[MAX_RDS_PS_NAME + 1];
len = control->size - 1;
if (len < 0 || len > MAX_RDS_PS_NAME) {
rval = -ERANGE;
goto exit;
}
rval = copy_from_user(ps_name, control->string, len);
if (rval) {
rval = -EFAULT;
goto exit;
}
ps_name[len] = '\0';
if (strlen(ps_name) % vqc.step) {
rval = -ERANGE;
goto exit;
}
rval = si4713_set_rds_ps_name(sdev, ps_name);
}
break;
case V4L2_CID_RDS_TX_RADIO_TEXT: {
char radio_text[MAX_RDS_RADIO_TEXT + 1];
len = control->size - 1;
if (len < 0 || len > MAX_RDS_RADIO_TEXT) {
rval = -ERANGE;
goto exit;
}
rval = copy_from_user(radio_text, control->string, len);
if (rval) {
rval = -EFAULT;
goto exit;
}
radio_text[len] = '\0';
if (strlen(radio_text) % vqc.step) {
rval = -ERANGE;
goto exit;
}
rval = si4713_set_rds_radio_text(sdev, radio_text);
}
break;
default:
......@@ -1055,121 +971,6 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev,
break;
}
exit:
return rval;
}
static int validate_range(struct v4l2_subdev *sd,
struct v4l2_ext_control *control)
{
struct v4l2_queryctrl vqc;
int rval;
vqc.id = control->id;
rval = si4713_queryctrl(sd, &vqc);
if (rval < 0)
goto exit;
if (control->value < vqc.minimum || control->value > vqc.maximum)
rval = -ERANGE;
exit:
return rval;
}
/* properties which use tx_tune_power*/
static int si4713_write_econtrol_tune(struct si4713_device *sdev,
struct v4l2_ext_control *control)
{
s32 rval = 0;
u8 power, antcap;
rval = validate_range(&sdev->sd, control);
if (rval < 0)
return rval;
switch (control->id) {
case V4L2_CID_TUNE_POWER_LEVEL:
power = control->value;
antcap = sdev->antenna_capacitor;
break;
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
power = sdev->power_level;
antcap = control->value;
break;
default:
return -EINVAL;
}
if (sdev->power_state)
rval = si4713_tx_tune_power(sdev, power, antcap);
if (rval == 0) {
sdev->power_level = power;
sdev->antenna_capacitor = antcap;
}
return rval;
}
static int si4713_write_econtrol_integers(struct si4713_device *sdev,
struct v4l2_ext_control *control)
{
s32 rval;
u32 *shadow = NULL, val = 0;
s32 bit = 0, mask = 0;
u16 property = 0;
int mul = 0;
unsigned long *table = NULL;
int size = 0;
rval = validate_range(&sdev->sd, control);
if (rval < 0)
return rval;
rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit,
&mask, &property, &mul, &table, &size);
if (rval < 0)
return rval;
val = control->value;
if (mul) {
val = control->value / mul;
} else if (table) {
rval = usecs_to_dev(control->value, table, size);
if (rval < 0)
return rval;
val = rval;
rval = 0;
}
if (sdev->power_state) {
if (mask) {
rval = si4713_read_property(sdev, property, &val);
if (rval < 0)
return rval;
val = set_bits(val, control->value, bit, mask);
}
rval = si4713_write_property(sdev, property, val);
if (rval < 0)
return rval;
if (mask)
val = control->value;
}
if (mul) {
*shadow = val * mul;
} else if (table) {
rval = dev_to_usecs(val, table, size);
if (rval < 0)
return rval;
*shadow = rval;
rval = 0;
} else {
*shadow = val;
}
return rval;
}
......@@ -1181,110 +982,25 @@ static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulato
*/
static int si4713_setup(struct si4713_device *sdev)
{
struct v4l2_ext_control ctrl;
struct v4l2_frequency f;
struct v4l2_modulator vm;
struct si4713_device *tmp;
int rval = 0;
tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
/* Get a local copy to avoid race */
memcpy(tmp, sdev, sizeof(*sdev));
ctrl.id = V4L2_CID_RDS_TX_PI;
ctrl.value = tmp->rds_info.pi;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_AUDIO_COMPRESSION_THRESHOLD;
ctrl.value = tmp->acomp_info.threshold;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_AUDIO_COMPRESSION_GAIN;
ctrl.value = tmp->acomp_info.gain;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_PILOT_TONE_FREQUENCY;
ctrl.value = tmp->pilot_info.frequency;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME;
ctrl.value = tmp->acomp_info.attack_time;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_PILOT_TONE_DEVIATION;
ctrl.value = tmp->pilot_info.deviation;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_AUDIO_LIMITER_DEVIATION;
ctrl.value = tmp->limiter_info.deviation;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_RDS_TX_DEVIATION;
ctrl.value = tmp->rds_info.deviation;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_RDS_TX_PTY;
ctrl.value = tmp->rds_info.pty;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_AUDIO_LIMITER_ENABLED;
ctrl.value = tmp->limiter_info.enabled;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ENABLED;
ctrl.value = tmp->acomp_info.enabled;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_PILOT_TONE_ENABLED;
ctrl.value = tmp->pilot_info.enabled;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_AUDIO_LIMITER_RELEASE_TIME;
ctrl.value = tmp->limiter_info.release_time;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME;
ctrl.value = tmp->acomp_info.release_time;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_TUNE_PREEMPHASIS;
ctrl.value = tmp->preemphasis;
rval |= si4713_write_econtrol_integers(sdev, &ctrl);
ctrl.id = V4L2_CID_RDS_TX_PS_NAME;
rval |= si4713_set_rds_ps_name(sdev, tmp->rds_info.ps_name);
ctrl.id = V4L2_CID_RDS_TX_RADIO_TEXT;
rval |= si4713_set_rds_radio_text(sdev, tmp->rds_info.radio_text);
int rval;
/* Device procedure needs to set frequency first */
f.tuner = 0;
f.frequency = tmp->frequency ? tmp->frequency : DEFAULT_FREQUENCY;
f.frequency = sdev->frequency ? sdev->frequency : DEFAULT_FREQUENCY;
f.frequency = si4713_to_v4l2(f.frequency);
rval |= si4713_s_frequency(&sdev->sd, &f);
ctrl.id = V4L2_CID_TUNE_POWER_LEVEL;
ctrl.value = tmp->power_level;
rval |= si4713_write_econtrol_tune(sdev, &ctrl);
ctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR;
ctrl.value = tmp->antenna_capacitor;
rval |= si4713_write_econtrol_tune(sdev, &ctrl);
rval = si4713_s_frequency(&sdev->sd, &f);
vm.index = 0;
if (tmp->stereo)
if (sdev->stereo)
vm.txsubchans = V4L2_TUNER_SUB_STEREO;
else
vm.txsubchans = V4L2_TUNER_SUB_MONO;
if (tmp->rds_info.enabled)
if (sdev->rds_enabled)
vm.txsubchans |= V4L2_TUNER_SUB_RDS;
si4713_s_modulator(&sdev->sd, &vm);
kfree(tmp);
return rval;
}
......@@ -1308,406 +1024,116 @@ static int si4713_initialize(struct si4713_device *sdev)
if (rval < 0)
return rval;
sdev->rds_info.pi = DEFAULT_RDS_PI;
sdev->rds_info.pty = DEFAULT_RDS_PTY;
sdev->rds_info.deviation = DEFAULT_RDS_DEVIATION;
strlcpy(sdev->rds_info.ps_name, DEFAULT_RDS_PS_NAME, MAX_RDS_PS_NAME);
strlcpy(sdev->rds_info.radio_text, DEFAULT_RDS_RADIO_TEXT,
MAX_RDS_RADIO_TEXT);
sdev->rds_info.enabled = 1;
sdev->limiter_info.release_time = DEFAULT_LIMITER_RTIME;
sdev->limiter_info.deviation = DEFAULT_LIMITER_DEV;
sdev->limiter_info.enabled = 1;
sdev->pilot_info.deviation = DEFAULT_PILOT_DEVIATION;
sdev->pilot_info.frequency = DEFAULT_PILOT_FREQUENCY;
sdev->pilot_info.enabled = 1;
sdev->acomp_info.release_time = DEFAULT_ACOMP_RTIME;
sdev->acomp_info.attack_time = DEFAULT_ACOMP_ATIME;
sdev->acomp_info.threshold = DEFAULT_ACOMP_THRESHOLD;
sdev->acomp_info.gain = DEFAULT_ACOMP_GAIN;
sdev->acomp_info.enabled = 1;
sdev->frequency = DEFAULT_FREQUENCY;
sdev->preemphasis = DEFAULT_PREEMPHASIS;
sdev->mute = DEFAULT_MUTE;
sdev->power_level = DEFAULT_POWER_LEVEL;
sdev->antenna_capacitor = 0;
sdev->stereo = 1;
sdev->tune_rnl = DEFAULT_TUNE_RNL;
return rval;
}
/* read string property */
static int si4713_read_econtrol_string(struct si4713_device *sdev,
struct v4l2_ext_control *control)
{
s32 rval = 0;
switch (control->id) {
case V4L2_CID_RDS_TX_PS_NAME:
if (strlen(sdev->rds_info.ps_name) + 1 > control->size) {
control->size = MAX_RDS_PS_NAME + 1;
rval = -ENOSPC;
goto exit;
}
rval = copy_to_user(control->string, sdev->rds_info.ps_name,
strlen(sdev->rds_info.ps_name) + 1);
if (rval)
rval = -EFAULT;
break;
case V4L2_CID_RDS_TX_RADIO_TEXT:
if (strlen(sdev->rds_info.radio_text) + 1 > control->size) {
control->size = MAX_RDS_RADIO_TEXT + 1;
rval = -ENOSPC;
goto exit;
}
rval = copy_to_user(control->string, sdev->rds_info.radio_text,
strlen(sdev->rds_info.radio_text) + 1);
if (rval)
rval = -EFAULT;
break;
default:
rval = -EINVAL;
break;
}
exit:
return rval;
}
/*
* si4713_update_tune_status - update properties from tx_tune_status
* command.
* @sdev: si4713_device structure for the device we are communicating
*/
static int si4713_update_tune_status(struct si4713_device *sdev)
{
int rval;
u16 f = 0;
u8 p = 0, a = 0, n = 0;
rval = si4713_tx_tune_status(sdev, 0x00, &f, &p, &a, &n);
if (rval < 0)
goto exit;
sdev->power_level = p;
sdev->antenna_capacitor = a;
sdev->tune_rnl = n;
exit:
return rval;
}
/* properties which use tx_tune_status */
static int si4713_read_econtrol_tune(struct si4713_device *sdev,
struct v4l2_ext_control *control)
{
s32 rval = 0;
if (sdev->power_state) {
rval = si4713_update_tune_status(sdev);
if (rval < 0)
return rval;
}
switch (control->id) {
case V4L2_CID_TUNE_POWER_LEVEL:
control->value = sdev->power_level;
break;
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
control->value = sdev->antenna_capacitor;
break;
default:
return -EINVAL;
}
return rval;
return 0;
}
static int si4713_read_econtrol_integers(struct si4713_device *sdev,
struct v4l2_ext_control *control)
/* si4713_s_ctrl - set the value of a control */
static int si4713_s_ctrl(struct v4l2_ctrl *ctrl)
{
s32 rval;
u32 *shadow = NULL, val = 0;
struct si4713_device *sdev =
container_of(ctrl->handler, struct si4713_device, ctrl_handler);
u32 val = 0;
s32 bit = 0, mask = 0;
u16 property = 0;
int mul = 0;
unsigned long *table = NULL;
int size = 0;
bool force = false;
int c;
int ret = 0;
rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit,
&mask, &property, &mul, &table, &size);
if (rval < 0)
return rval;
if (sdev->power_state) {
rval = si4713_read_property(sdev, property, &val);
if (rval < 0)
return rval;
/* Keep negative values for threshold */
if (control->id == V4L2_CID_AUDIO_COMPRESSION_THRESHOLD)
*shadow = (s16)val;
else if (mask)
*shadow = get_status_bit(val, bit, mask);
else if (mul)
*shadow = val * mul;
else
*shadow = dev_to_usecs(val, table, size);
}
control->value = *shadow;
return rval;
}
/*
* Video4Linux Subdev Interface
*/
/* si4713_s_ext_ctrls - set extended controls value */
static int si4713_s_ext_ctrls(struct v4l2_subdev *sd,
struct v4l2_ext_controls *ctrls)
{
struct si4713_device *sdev = to_si4713_device(sd);
int i;
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
if (ctrl->id != V4L2_CID_AUDIO_MUTE)
return -EINVAL;
for (i = 0; i < ctrls->count; i++) {
int err;
switch ((ctrls->controls + i)->id) {
case V4L2_CID_RDS_TX_PS_NAME:
case V4L2_CID_RDS_TX_RADIO_TEXT:
err = si4713_write_econtrol_string(sdev,
ctrls->controls + i);
break;
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
case V4L2_CID_TUNE_POWER_LEVEL:
err = si4713_write_econtrol_tune(sdev,
ctrls->controls + i);
break;
default:
err = si4713_write_econtrol_integers(sdev,
ctrls->controls + i);
}
if (err < 0) {
ctrls->error_idx = i;
return err;
if (ctrl->is_new) {
if (ctrl->val) {
ret = si4713_set_mute(sdev, ctrl->val);
if (!ret)
ret = si4713_set_power_state(sdev, POWER_DOWN);
return ret;
}
ret = si4713_set_power_state(sdev, POWER_UP);
if (!ret)
ret = si4713_set_mute(sdev, ctrl->val);
if (!ret)
ret = si4713_setup(sdev);
if (ret)
return ret;
force = true;
}
if (!sdev->power_state)
return 0;
}
/* si4713_g_ext_ctrls - get extended controls value */
static int si4713_g_ext_ctrls(struct v4l2_subdev *sd,
struct v4l2_ext_controls *ctrls)
{
struct si4713_device *sdev = to_si4713_device(sd);
int i;
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
return -EINVAL;
for (c = 1; !ret && c < ctrl->ncontrols; c++) {
ctrl = ctrl->cluster[c];
for (i = 0; i < ctrls->count; i++) {
int err;
if (!force && !ctrl->is_new)
continue;
switch ((ctrls->controls + i)->id) {
switch (ctrl->id) {
case V4L2_CID_RDS_TX_PS_NAME:
case V4L2_CID_RDS_TX_RADIO_TEXT:
err = si4713_read_econtrol_string(sdev,
ctrls->controls + i);
ret = si4713_set_rds_ps_name(sdev, ctrl->string);
break;
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
case V4L2_CID_TUNE_POWER_LEVEL:
err = si4713_read_econtrol_tune(sdev,
ctrls->controls + i);
break;
default:
err = si4713_read_econtrol_integers(sdev,
ctrls->controls + i);
}
if (err < 0) {
ctrls->error_idx = i;
return err;
}
}
return 0;
}
/* si4713_queryctrl - enumerate control items */
static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
int rval = 0;
switch (qc->id) {
/* User class controls */
case V4L2_CID_AUDIO_MUTE:
rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, DEFAULT_MUTE);
break;
/* FM_TX class controls */
case V4L2_CID_RDS_TX_PI:
rval = v4l2_ctrl_query_fill(qc, 0, 0xFFFF, 1, DEFAULT_RDS_PI);
break;
case V4L2_CID_RDS_TX_PTY:
rval = v4l2_ctrl_query_fill(qc, 0, 31, 1, DEFAULT_RDS_PTY);
break;
case V4L2_CID_RDS_TX_DEVIATION:
rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_DEVIATION,
10, DEFAULT_RDS_DEVIATION);
break;
case V4L2_CID_RDS_TX_PS_NAME:
/*
* Report step as 8. From RDS spec, psname
* should be 8. But there are receivers which scroll strings
* sized as 8xN.
*/
rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_PS_NAME, 8, 0);
break;
case V4L2_CID_RDS_TX_RADIO_TEXT:
/*
* Report step as 32 (2A block). From RDS spec,
* radio text should be 32 for 2A block. But there are receivers
* which scroll strings sized as 32xN. Setting default to 32.
*/
rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_RADIO_TEXT, 32, 0);
ret = si4713_set_rds_radio_text(sdev, ctrl->string);
break;
case V4L2_CID_AUDIO_LIMITER_ENABLED:
rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
break;
case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
rval = v4l2_ctrl_query_fill(qc, 250, MAX_LIMITER_RELEASE_TIME,
50, DEFAULT_LIMITER_RTIME);
break;
case V4L2_CID_AUDIO_LIMITER_DEVIATION:
rval = v4l2_ctrl_query_fill(qc, 0, MAX_LIMITER_DEVIATION,
10, DEFAULT_LIMITER_DEV);
break;
case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
break;
case V4L2_CID_AUDIO_COMPRESSION_GAIN:
rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_GAIN, 1,
DEFAULT_ACOMP_GAIN);
break;
case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
rval = v4l2_ctrl_query_fill(qc, MIN_ACOMP_THRESHOLD,
MAX_ACOMP_THRESHOLD, 1,
DEFAULT_ACOMP_THRESHOLD);
break;
case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_ATTACK_TIME,
500, DEFAULT_ACOMP_ATIME);
break;
case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
rval = v4l2_ctrl_query_fill(qc, 100000, MAX_ACOMP_RELEASE_TIME,
100000, DEFAULT_ACOMP_RTIME);
break;
case V4L2_CID_PILOT_TONE_ENABLED:
rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
break;
case V4L2_CID_PILOT_TONE_DEVIATION:
rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_DEVIATION,
10, DEFAULT_PILOT_DEVIATION);
break;
case V4L2_CID_PILOT_TONE_FREQUENCY:
rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_FREQUENCY,
1, DEFAULT_PILOT_FREQUENCY);
break;
case V4L2_CID_TUNE_PREEMPHASIS:
rval = v4l2_ctrl_query_fill(qc, V4L2_PREEMPHASIS_DISABLED,
V4L2_PREEMPHASIS_75_uS, 1,
V4L2_PREEMPHASIS_50_uS);
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
/* don't handle this control if we force setting all
* controls since in that case it will be handled by
* V4L2_CID_TUNE_POWER_LEVEL. */
if (force)
break;
/* fall through */
case V4L2_CID_TUNE_POWER_LEVEL:
rval = v4l2_ctrl_query_fill(qc, 0, 120, 1, DEFAULT_POWER_LEVEL);
break;
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
rval = v4l2_ctrl_query_fill(qc, 0, 191, 1, 0);
ret = si4713_tx_tune_power(sdev,
sdev->tune_pwr_level->val, sdev->tune_ant_cap->val);
if (!ret) {
/* Make sure we don't set this twice */
sdev->tune_ant_cap->is_new = false;
sdev->tune_pwr_level->is_new = false;
}
break;
default:
rval = -EINVAL;
ret = si4713_choose_econtrol_action(sdev, ctrl->id, &bit,
&mask, &property, &mul, &table, &size);
if (ret < 0)
break;
}
return rval;
}
/* si4713_g_ctrl - get the value of a control */
static int si4713_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct si4713_device *sdev = to_si4713_device(sd);
int rval = 0;
if (!sdev)
return -ENODEV;
if (sdev->power_state) {
rval = si4713_read_property(sdev, SI4713_TX_LINE_INPUT_MUTE,
&sdev->mute);
if (rval < 0)
return rval;
val = ctrl->val;
if (mul) {
val = val / mul;
} else if (table) {
ret = usecs_to_dev(val, table, size);
if (ret < 0)
break;
val = ret;
ret = 0;
}
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
ctrl->value = get_mute(sdev->mute);
if (mask) {
ret = si4713_read_property(sdev, property, &val);
if (ret < 0)
break;
val = set_bits(val, ctrl->val, bit, mask);
}
return rval;
}
/* si4713_s_ctrl - set the value of a control */
static int si4713_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct si4713_device *sdev = to_si4713_device(sd);
int rval = 0;
if (!sdev)
return -ENODEV;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
if (ctrl->value) {
rval = si4713_set_mute(sdev, ctrl->value);
if (rval < 0)
goto exit;
rval = si4713_set_power_state(sdev, POWER_DOWN);
} else {
rval = si4713_set_power_state(sdev, POWER_UP);
if (rval < 0)
goto exit;
rval = si4713_setup(sdev);
if (rval < 0)
goto exit;
rval = si4713_set_mute(sdev, ctrl->value);
}
ret = si4713_write_property(sdev, property, val);
if (ret < 0)
break;
if (mask)
val = ctrl->val;
break;
}
}
exit:
return rval;
return ret;
}
/* si4713_ioctl - deal with private ioctls (only rnl for now) */
......@@ -1746,15 +1172,6 @@ static long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
return rval;
}
static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = {
.queryctrl = si4713_queryctrl,
.g_ext_ctrls = si4713_g_ext_ctrls,
.s_ext_ctrls = si4713_s_ext_ctrls,
.g_ctrl = si4713_g_ctrl,
.s_ctrl = si4713_s_ctrl,
.ioctl = si4713_ioctl,
};
/* si4713_g_modulator - get modulator attributes */
static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
{
......@@ -1784,7 +1201,6 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
return rval;
sdev->stereo = get_status_bit(comp_en, 1, 1 << 1);
sdev->rds_info.enabled = get_status_bit(comp_en, 2, 1 << 2);
}
/* Report current audio mode: mono or stereo */
......@@ -1794,7 +1210,7 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
vm->txsubchans = V4L2_TUNER_SUB_MONO;
/* Report rds feature status */
if (sdev->rds_info.enabled)
if (sdev->rds_enabled)
vm->txsubchans |= V4L2_TUNER_SUB_RDS;
else
vm->txsubchans &= ~V4L2_TUNER_SUB_RDS;
......@@ -1842,7 +1258,7 @@ static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulato
}
sdev->stereo = stereo;
sdev->rds_info.enabled = rds;
sdev->rds_enabled = rds;
return rval;
}
......@@ -1897,6 +1313,14 @@ static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequenc
return rval;
}
static const struct v4l2_ctrl_ops si4713_ctrl_ops = {
.s_ctrl = si4713_s_ctrl,
};
static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = {
.ioctl = si4713_ioctl,
};
static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = {
.g_frequency = si4713_g_frequency,
.s_frequency = si4713_s_frequency,
......@@ -1918,6 +1342,7 @@ static int si4713_probe(struct i2c_client *client,
{
struct si4713_device *sdev;
struct si4713_platform_data *pdata = client->dev.platform_data;
struct v4l2_ctrl_handler *hdl;
int rval, i;
sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
......@@ -1953,6 +1378,82 @@ static int si4713_probe(struct i2c_client *client,
init_completion(&sdev->work);
hdl = &sdev->ctrl_handler;
v4l2_ctrl_handler_init(hdl, 20);
sdev->mute = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_AUDIO_MUTE, 0, 1, 1, DEFAULT_MUTE);
sdev->rds_pi = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, DEFAULT_RDS_PI);
sdev->rds_pty = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_RDS_TX_PTY, 0, 31, 1, DEFAULT_RDS_PTY);
sdev->rds_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_RDS_TX_DEVIATION, 0, MAX_RDS_DEVIATION,
10, DEFAULT_RDS_DEVIATION);
/*
* Report step as 8. From RDS spec, psname
* should be 8. But there are receivers which scroll strings
* sized as 8xN.
*/
sdev->rds_ps_name = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_RDS_TX_PS_NAME, 0, MAX_RDS_PS_NAME, 8, 0);
/*
* Report step as 32 (2A block). From RDS spec,
* radio text should be 32 for 2A block. But there are receivers
* which scroll strings sized as 32xN. Setting default to 32.
*/
sdev->rds_radio_text = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_RDS_TX_RADIO_TEXT, 0, MAX_RDS_RADIO_TEXT, 32, 0);
sdev->limiter_enabled = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_AUDIO_LIMITER_ENABLED, 0, 1, 1, 1);
sdev->limiter_release_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_AUDIO_LIMITER_RELEASE_TIME, 250,
MAX_LIMITER_RELEASE_TIME, 10, DEFAULT_LIMITER_RTIME);
sdev->limiter_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_AUDIO_LIMITER_DEVIATION, 0,
MAX_LIMITER_DEVIATION, 10, DEFAULT_LIMITER_DEV);
sdev->compression_enabled = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_AUDIO_COMPRESSION_ENABLED, 0, 1, 1, 1);
sdev->compression_gain = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_AUDIO_COMPRESSION_GAIN, 0, MAX_ACOMP_GAIN, 1,
DEFAULT_ACOMP_GAIN);
sdev->compression_threshold = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, MIN_ACOMP_THRESHOLD,
MAX_ACOMP_THRESHOLD, 1,
DEFAULT_ACOMP_THRESHOLD);
sdev->compression_attack_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, 0,
MAX_ACOMP_ATTACK_TIME, 500, DEFAULT_ACOMP_ATIME);
sdev->compression_release_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME, 100000,
MAX_ACOMP_RELEASE_TIME, 100000, DEFAULT_ACOMP_RTIME);
sdev->pilot_tone_enabled = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_PILOT_TONE_ENABLED, 0, 1, 1, 1);
sdev->pilot_tone_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_PILOT_TONE_DEVIATION, 0, MAX_PILOT_DEVIATION,
10, DEFAULT_PILOT_DEVIATION);
sdev->pilot_tone_freq = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_PILOT_TONE_FREQUENCY, 0, MAX_PILOT_FREQUENCY,
1, DEFAULT_PILOT_FREQUENCY);
sdev->tune_preemphasis = v4l2_ctrl_new_std_menu(hdl, &si4713_ctrl_ops,
V4L2_CID_TUNE_PREEMPHASIS,
V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS);
sdev->tune_pwr_level = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_TUNE_POWER_LEVEL, 0, 120, 1, DEFAULT_POWER_LEVEL);
sdev->tune_ant_cap = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, 191, 1, 0);
if (hdl->error) {
rval = hdl->error;
goto free_ctrls;
}
v4l2_ctrl_cluster(20, &sdev->mute);
sdev->sd.ctrl_handler = hdl;
if (client->irq) {
rval = request_irq(client->irq,
si4713_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED,
......@@ -1977,6 +1478,8 @@ static int si4713_probe(struct i2c_client *client,
free_irq:
if (client->irq)
free_irq(client->irq, sdev);
free_ctrls:
v4l2_ctrl_handler_free(hdl);
put_reg:
regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
free_gpio:
......@@ -2001,6 +1504,7 @@ static int si4713_remove(struct i2c_client *client)
free_irq(client->irq, sdev);
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(sd->ctrl_handler);
regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
if (gpio_is_valid(sdev->gpio_reset))
gpio_free(sdev->gpio_reset);
......
......@@ -16,6 +16,7 @@
#define SI4713_I2C_H
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include <media/si4713.h>
#define SI4713_PRODUCT_NUMBER 0x0D
......@@ -160,56 +161,33 @@
#define POWER_UP 0x01
#define POWER_DOWN 0x00
struct rds_info {
u32 pi;
#define MAX_RDS_PTY 31
u32 pty;
#define MAX_RDS_DEVIATION 90000
u32 deviation;
/*
* PSNAME is known to be defined as 8 character sized (RDS Spec).
* However, there is receivers which scroll PSNAME 8xN sized.
*/
#define MAX_RDS_PS_NAME 96
u8 ps_name[MAX_RDS_PS_NAME + 1];
/*
* MAX_RDS_RADIO_TEXT is known to be defined as 32 (2A group) or 64 (2B group)
* character sized (RDS Spec).
* However, there is receivers which scroll them as well.
*/
#define MAX_RDS_RADIO_TEXT 384
u8 radio_text[MAX_RDS_RADIO_TEXT + 1];
u32 enabled;
};
struct limiter_info {
#define MAX_LIMITER_RELEASE_TIME 102390
u32 release_time;
#define MAX_LIMITER_DEVIATION 90000
u32 deviation;
u32 enabled;
};
struct pilot_info {
#define MAX_PILOT_DEVIATION 90000
u32 deviation;
#define MAX_PILOT_FREQUENCY 19000
u32 frequency;
u32 enabled;
};
struct acomp_info {
#define MAX_ACOMP_RELEASE_TIME 1000000
u32 release_time;
#define MAX_ACOMP_ATTACK_TIME 5000
u32 attack_time;
#define MAX_ACOMP_THRESHOLD 0
#define MIN_ACOMP_THRESHOLD (-40)
s32 threshold;
#define MAX_ACOMP_GAIN 20
u32 gain;
u32 enabled;
};
#define SI4713_NUM_SUPPLIES 2
......@@ -219,20 +197,41 @@ struct acomp_info {
struct si4713_device {
/* v4l2_subdev and i2c reference (v4l2_subdev priv data) */
struct v4l2_subdev sd;
struct v4l2_ctrl_handler ctrl_handler;
/* private data structures */
struct { /* si4713 control cluster */
/* This is one big cluster since the mute control
* powers off the device and after unmuting again all
* controls need to be set at once. The only way of doing
* that is by making it one big cluster. */
struct v4l2_ctrl *mute;
struct v4l2_ctrl *rds_ps_name;
struct v4l2_ctrl *rds_radio_text;
struct v4l2_ctrl *rds_pi;
struct v4l2_ctrl *rds_deviation;
struct v4l2_ctrl *rds_pty;
struct v4l2_ctrl *compression_enabled;
struct v4l2_ctrl *compression_threshold;
struct v4l2_ctrl *compression_gain;
struct v4l2_ctrl *compression_attack_time;
struct v4l2_ctrl *compression_release_time;
struct v4l2_ctrl *pilot_tone_enabled;
struct v4l2_ctrl *pilot_tone_freq;
struct v4l2_ctrl *pilot_tone_deviation;
struct v4l2_ctrl *limiter_enabled;
struct v4l2_ctrl *limiter_deviation;
struct v4l2_ctrl *limiter_release_time;
struct v4l2_ctrl *tune_preemphasis;
struct v4l2_ctrl *tune_pwr_level;
struct v4l2_ctrl *tune_ant_cap;
};
struct completion work;
struct rds_info rds_info;
struct limiter_info limiter_info;
struct pilot_info pilot_info;
struct acomp_info acomp_info;
struct regulator_bulk_data supplies[SI4713_NUM_SUPPLIES];
int gpio_reset;
u32 power_state;
u32 rds_enabled;
u32 frequency;
u32 preemphasis;
u32 mute;
u32 power_level;
u32 power_state;
u32 antenna_capacitor;
u32 stereo;
u32 tune_rnl;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment