/* * Values for audio compression release time (sorted by second column) * device release * value time (us)
*/ staticunsignedlong acomp_rtimes[] = {
0, 100000,
1, 200000,
2, 350000,
3, 525000,
4, 1000000,
};
/* * Values for preemphasis (sorted by second column) * device preemphasis * value value (v4l2)
*/ staticunsignedlong preemphasis_values[] = {
FMPE_DISABLED, V4L2_PREEMPHASIS_DISABLED,
FMPE_EU, V4L2_PREEMPHASIS_50_uS,
FMPE_USA, V4L2_PREEMPHASIS_75_uS,
};
staticint usecs_to_dev(unsignedlong usecs, unsignedlongconst array[], int size)
{ int i; int rval = -EINVAL;
for (i = 0; i < size / 2; i++) if (array[(i * 2) + 1] >= usecs) {
rval = array[i * 2]; break;
}
return rval;
}
/* si4713_handler: IRQ handler, just complete work */ static irqreturn_t si4713_handler(int irq, void *dev)
{ struct si4713_device *sdev = dev;
v4l2_dbg(2, debug, &sdev->sd, "%s: sending signal to completion work.\n", __func__);
complete(&sdev->work);
return IRQ_HANDLED;
}
/* * si4713_send_command - sends a command to si4713 and waits its response * @sdev: si4713_device structure for the device we are communicating * @command: command id * @args: command arguments we are sending (up to 7) * @argn: actual size of @args * @response: buffer to place the expected response from the device (up to 15) * @respn: actual size of @response * @usecs: amount of time to wait before reading the response (in usecs)
*/ staticint si4713_send_command(struct si4713_device *sdev, const u8 command, const u8 args[], constint argn,
u8 response[], constint respn, constint usecs)
{ struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); unsignedlong until_jiffies;
u8 data1[MAX_ARGS + 1]; int err;
if (!client->adapter) return -ENODEV;
/* First send the command and its arguments */
data1[0] = command;
memcpy(data1 + 1, args, argn);
DBG_BUFFER(&sdev->sd, "Parameters", data1, argn + 1);
/* Wait response from interrupt */ if (client->irq) { if (!wait_for_completion_timeout(&sdev->work,
usecs_to_jiffies(usecs) + 1))
v4l2_warn(&sdev->sd, "(%s) Device took too much time to answer.\n",
__func__);
}
do {
err = i2c_master_recv(client, response, respn); if (err != respn) {
v4l2_err(&sdev->sd, "Error %d while reading response for command 0x%02x\n",
err, command); return err < 0 ? err : -EIO;
}
DBG_BUFFER(&sdev->sd, "Response", response, respn); if (!check_command_failed(response[0])) return 0;
if (client->irq) return -EBUSY; if (usecs <= 1000)
usleep_range(usecs, 1000); else
usleep_range(1000, 2000);
} while (time_is_after_jiffies(until_jiffies));
return -EBUSY;
}
/* * si4713_read_property - reads a si4713 property * @sdev: si4713_device structure for the device we are communicating * @prop: property identification number * @pv: property value to be returned on success
*/ staticint si4713_read_property(struct si4713_device *sdev, u16 prop, u32 *pv)
{ int err;
u8 val[SI4713_GET_PROP_NRESP]; /* * .First byte = 0 * .Second byte = property's MSB * .Third byte = property's LSB
*/ const u8 args[SI4713_GET_PROP_NARGS] = {
0x00,
msb(prop),
lsb(prop),
};
/* * As there is no command response for SET_PROPERTY, * wait Tcomp time to finish before proceed, in order * to have property properly set.
*/
msleep(TIMEOUT_SET_PROPERTY);
return rval;
}
/* * si4713_powerup - Powers the device up * @sdev: si4713_device structure for the device we are communicating
*/ staticint si4713_powerup(struct si4713_device *sdev)
{ struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); int err;
u8 resp[SI4713_PWUP_NRESP]; /* * .First byte = Enabled interrupts and boot function * .Second byte = Input operation mode
*/
u8 args[SI4713_PWUP_NARGS] = {
SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX,
SI4713_PWUP_OPMOD_ANALOG,
};
if (sdev->power_state) return 0;
if (sdev->vdd) {
err = regulator_enable(sdev->vdd); if (err) {
v4l2_err(&sdev->sd, "Failed to enable vdd: %d\n", err); return err;
}
}
if (sdev->vio) {
err = regulator_enable(sdev->vio); if (err) {
v4l2_err(&sdev->sd, "Failed to enable vio: %d\n", err); return err;
}
}
if (sdev->gpio_reset) {
udelay(50);
gpiod_set_value(sdev->gpio_reset, 1);
}
if (sdev->vdd) {
err = regulator_disable(sdev->vdd); if (err)
v4l2_err(&sdev->sd, "Failed to disable vdd: %d\n", err);
}
if (sdev->vio) {
err = regulator_disable(sdev->vio); if (err)
v4l2_err(&sdev->sd, "Failed to disable vio: %d\n", err);
}
return err;
}
/* * si4713_powerdown - Powers the device down * @sdev: si4713_device structure for the device we are communicating
*/ staticint si4713_powerdown(struct si4713_device *sdev)
{ int err;
u8 resp[SI4713_PWDN_NRESP];
if (!err) {
v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n",
resp[0]);
v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n"); if (sdev->gpio_reset)
gpiod_set_value(sdev->gpio_reset, 0);
if (sdev->vdd) {
err = regulator_disable(sdev->vdd); if (err) {
v4l2_err(&sdev->sd, "Failed to disable vdd: %d\n", err);
}
}
if (sdev->vio) {
err = regulator_disable(sdev->vio); if (err) {
v4l2_err(&sdev->sd, "Failed to disable vio: %d\n", err);
}
}
sdev->power_state = POWER_OFF;
}
return err;
}
/* * si4713_checkrev - Checks if we are treating a device with the correct rev. * @sdev: si4713_device structure for the device we are communicating
*/ staticint si4713_checkrev(struct si4713_device *sdev)
{ struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); int rval;
u8 resp[SI4713_GETREV_NRESP];
/* * si4713_wait_stc - Waits STC interrupt and clears status bits. Useful * for TX_TUNE_POWER, TX_TUNE_FREQ and TX_TUNE_MEAS * @sdev: si4713_device structure for the device we are communicating * @usecs: timeout to wait for STC interrupt signal
*/ staticint si4713_wait_stc(struct si4713_device *sdev, constint usecs)
{ struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd);
u8 resp[SI4713_GET_STATUS_NRESP]; unsignedlong start_jiffies = jiffies; int err;
if (client->irq &&
!wait_for_completion_timeout(&sdev->work, usecs_to_jiffies(usecs) + 1))
v4l2_warn(&sdev->sd, "(%s) Device took too much time to answer.\n", __func__);
for (;;) { /* Clear status bits */
err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS,
NULL, 0,
resp, ARRAY_SIZE(resp),
DEFAULT_TIMEOUT); /* The USB device returns errors when it waits for the
* STC bit to be set. Hence polling */ if (err >= 0) {
v4l2_dbg(1, debug, &sdev->sd, "%s: status bits: 0x%02x\n", __func__, resp[0]);
if (resp[0] & SI4713_STC_INT) return 0;
} if (jiffies_to_usecs(jiffies - start_jiffies) > usecs) return err < 0 ? err : -EIO; /* We sleep here for 3-4 ms in order to avoid flooding the device * with USB requests. The si4713 USB driver was developed * by reverse engineering the Windows USB driver. The windows
* driver also has a ~2.5 ms delay between responses. */
usleep_range(3000, 4000);
}
}
/* * si4713_tx_tune_freq - Sets the state of the RF carrier and sets the tuning * frequency between 76 and 108 MHz in 10 kHz units and * steps of 50 kHz. * @sdev: si4713_device structure for the device we are communicating * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz)
*/ staticint si4713_tx_tune_freq(struct si4713_device *sdev, u16 frequency)
{ int err;
u8 val[SI4713_TXFREQ_NRESP]; /* * .First byte = 0 * .Second byte = frequency's MSB * .Third byte = frequency's LSB
*/ const u8 args[SI4713_TXFREQ_NARGS] = {
0x00,
msb(frequency),
lsb(frequency),
};
err = si4713_wait_stc(sdev, TIMEOUT_TX_TUNE); if (err < 0) return err;
return compose_u16(args[1], args[2]);
}
/* * si4713_tx_tune_power - Sets the RF voltage level between 88 and 120 dBuV in * 1 dB units. A value of 0x00 indicates off. The command * also sets the antenna tuning capacitance. A value of 0 * indicates autotuning, and a value of 1 - 191 indicates * a manual override, which results in a tuning * capacitance of 0.25 pF x @antcap. * @sdev: si4713_device structure for the device we are communicating * @power: tuning power (88 - 120 dBuV, unit/step 1 dB) * @antcap: value of antenna tuning capacitor (0 - 191)
*/ staticint si4713_tx_tune_power(struct si4713_device *sdev, u8 power,
u8 antcap)
{ int err;
u8 val[SI4713_TXPWR_NRESP]; /* * .First byte = 0 * .Second byte = 0 * .Third byte = power * .Fourth byte = antcap
*/
u8 args[SI4713_TXPWR_NARGS] = {
0x00,
0x00,
power,
antcap,
};
/* Map power values 1-87 to MIN_POWER (88) */ if (power > 0 && power < SI4713_MIN_POWER)
args[2] = power = SI4713_MIN_POWER;
/* * si4713_tx_tune_measure - Enters receive mode and measures the received noise * level in units of dBuV on the selected frequency. * The Frequency must be between 76 and 108 MHz in 10 kHz * units and steps of 50 kHz. The command also sets the * antenna tuning capacitance. A value of 0 means * autotuning, and a value of 1 to 191 indicates manual * override. * @sdev: si4713_device structure for the device we are communicating * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz) * @antcap: value of antenna tuning capacitor (0 - 191)
*/ staticint si4713_tx_tune_measure(struct si4713_device *sdev, u16 frequency,
u8 antcap)
{ int err;
u8 val[SI4713_TXMEA_NRESP]; /* * .First byte = 0 * .Second byte = frequency's MSB * .Third byte = frequency's LSB * .Fourth byte = antcap
*/ const u8 args[SI4713_TXMEA_NARGS] = {
0x00,
msb(frequency),
lsb(frequency),
antcap,
};
/* * si4713_tx_tune_status- Returns the status of the tx_tune_freq, tx_tune_mea or * tx_tune_power commands. This command return the current * frequency, output voltage in dBuV, the antenna tunning * capacitance value and the received noise level. The * command also clears the stcint interrupt bit when the * first bit of its arguments is high. * @sdev: si4713_device structure for the device we are communicating * @intack: 0x01 to clear the seek/tune complete interrupt status indicator. * @frequency: returned frequency * @power: returned power * @antcap: returned antenna capacitance * @noise: returned noise level
*/ staticint si4713_tx_tune_status(struct si4713_device *sdev, u8 intack,
u16 *frequency, u8 *power,
u8 *antcap, u8 *noise)
{ int err;
u8 val[SI4713_TXSTATUS_NRESP]; /* * .First byte = intack bit
*/ const u8 args[SI4713_TXSTATUS_NARGS] = {
intack & SI4713_INTACK_MASK,
};
/* * si4713_tx_rds_buff - Loads the RDS group buffer FIFO or circular buffer. * @sdev: si4713_device structure for the device we are communicating * @mode: the buffer operation mode. * @rdsb: RDS Block B * @rdsc: RDS Block C * @rdsd: RDS Block D * @cbleft: returns the number of available circular buffer blocks minus the * number of used circular buffer blocks.
*/ staticint si4713_tx_rds_buff(struct si4713_device *sdev, u8 mode, u16 rdsb,
u16 rdsc, u16 rdsd, s8 *cbleft)
{ int err;
u8 val[SI4713_RDSBUFF_NRESP];
/* * si4713_tx_rds_ps - Loads the program service buffer. * @sdev: si4713_device structure for the device we are communicating * @psid: program service id to be loaded. * @pschar: assumed 4 size char array to be loaded into the program service
*/ staticint si4713_tx_rds_ps(struct si4713_device *sdev, u8 psid, unsignedchar *pschar)
{ int err;
u8 val[SI4713_RDSPS_NRESP];
if (sdev->power_state)
rval = si4713_write_property(sdev,
SI4713_TX_LINE_INPUT_MUTE, mute);
return rval;
}
staticint si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name)
{ int rval = 0, i;
u8 len = 0;
/* We want to clear the whole thing */ if (!strlen(ps_name))
memset(ps_name, 0, MAX_RDS_PS_NAME + 1);
if (sdev->power_state) { /* Write the new ps name and clear the padding */ for (i = 0; i < MAX_RDS_PS_NAME; i += (RDS_BLOCK / 2)) {
rval = si4713_tx_rds_ps(sdev, (i / (RDS_BLOCK / 2)),
ps_name + i); if (rval < 0) return rval;
}
/* Setup the size to be sent */ if (strlen(ps_name))
len = strlen(ps_name) - 1; else
len = 1;
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)) { for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) { if (!rt[t_index + i] ||
rt[t_index + i] == RDS_CARRIAGE_RETURN) {
rt = cr;
cr_inserted = 1; break;
}
}
}
/* * 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
*/ staticint si4713_update_tune_status(struct si4713_device *sdev)
{ int rval;
u16 f = 0;
u8 p = 0, a = 0, n = 0;
/* 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;
staticint si4713_s_frequency(struct v4l2_subdev *sd, conststruct v4l2_frequency *f); staticint si4713_s_modulator(struct v4l2_subdev *sd, conststruct v4l2_modulator *); /* * si4713_setup - Sets the device up with current configuration. * @sdev: si4713_device structure for the device we are communicating
*/ staticint si4713_setup(struct si4713_device *sdev)
{ struct v4l2_frequency f; struct v4l2_modulator vm; int rval;
/* Device procedure needs to set frequency first */
f.tuner = 0;
f.frequency = sdev->frequency ? sdev->frequency : DEFAULT_FREQUENCY;
f.frequency = si4713_to_v4l2(f.frequency);
rval = si4713_s_frequency(&sdev->sd, &f);
vm.index = 0; if (sdev->stereo)
vm.txsubchans = V4L2_TUNER_SUB_STEREO; else
vm.txsubchans = V4L2_TUNER_SUB_MONO; if (sdev->rds_enabled)
vm.txsubchans |= V4L2_TUNER_SUB_RDS;
si4713_s_modulator(&sdev->sd, &vm);
return rval;
}
/* * si4713_initialize - Sets the device up with default configuration. * @sdev: si4713_device structure for the device we are communicating
*/ staticint si4713_initialize(struct si4713_device *sdev)
{ int rval;
rval = si4713_set_power_state(sdev, POWER_ON); if (rval < 0) return rval;
rval = si4713_checkrev(sdev); if (rval < 0) return rval;
rval = si4713_set_power_state(sdev, POWER_OFF); if (rval < 0) return rval;
/* si4713_s_ctrl - set the value of a control */ staticint si4713_s_ctrl(struct v4l2_ctrl *ctrl)
{ 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; unsignedlong *table = NULL; int size = 0; bool force = false; int c; int ret = 0;
if (ctrl->id != V4L2_CID_AUDIO_MUTE) return -EINVAL; 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;
for (c = 1; !ret && c < ctrl->ncontrols; c++) {
ctrl = ctrl->cluster[c];
if (!force && !ctrl->is_new) continue;
switch (ctrl->id) { case V4L2_CID_RDS_TX_PS_NAME:
ret = si4713_set_rds_ps_name(sdev, ctrl->p_new.p_char); break;
case V4L2_CID_RDS_TX_RADIO_TEXT:
ret = si4713_set_rds_radio_text(sdev, ctrl->p_new.p_char); break;
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;
fallthrough; case V4L2_CID_TUNE_POWER_LEVEL:
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;
case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE: case V4L2_CID_RDS_TX_ALT_FREQS: if (sdev->rds_alt_freqs_enable->val) {
val = sdev->rds_alt_freqs->p_new.p_u32[0];
val = val / 100 - 876 + 0xe101;
} else {
val = 0xe0e0;
}
ret = si4713_write_property(sdev, SI4713_TX_RDS_PS_AF, val); break;
default:
ret = si4713_choose_econtrol_action(sdev, ctrl->id, &bit,
&mask, &property, &mul, &table, &size); if (ret < 0) break;
val = ctrl->val; if (mul) {
val = val / mul;
} elseif (table) {
ret = usecs_to_dev(val, table, size); if (ret < 0) break;
val = ret;
ret = 0;
}
if (mask) {
ret = si4713_read_property(sdev, property, &val); if (ret < 0) break;
val = set_bits(val, ctrl->val, bit, mask);
}
ret = si4713_write_property(sdev, property, val); if (ret < 0) break; if (mask)
val = ctrl->val; break;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.