/** * si476x_core_send_command() - sends a command to si476x and waits its * response * @core: si476x_device structure for the device we are * communicating with * @command: command id * @args: command arguments we are sending * @argn: actual size of @args * @resp: buffer to place the expected response from the device * @respn: actual size of @resp * @usecs: amount of time to wait before reading the response (in * usecs) * * Function returns 0 on success and negative error code on * failure
*/ staticint si476x_core_send_command(struct si476x_core *core, const u8 command, const u8 args[], constint argn,
u8 resp[], constint respn, constint usecs)
{ struct i2c_client *client = core->client; int err;
u8 data[CMD_MAX_ARGS_COUNT + 1];
if (argn > CMD_MAX_ARGS_COUNT) {
err = -ENOMEM; gotoexit;
}
if (!client->adapter) {
err = -ENODEV; gotoexit;
}
/* First send the command and its arguments */
data[0] = command;
memcpy(&data[1], args, argn);
dev_dbg(&client->dev, "Command:\n %*ph\n", argn + 1, data);
err = si476x_core_i2c_xfer(core, SI476X_I2C_SEND,
(char *) data, argn + 1); if (err != argn + 1) {
dev_err(&core->client->dev, "Error while sending command 0x%02x\n",
command);
err = (err >= 0) ? -EIO : err; gotoexit;
} /* Set CTS to zero only after the command is send to avoid
* possible racing conditions when working in polling mode */
atomic_set(&core->cts, 0);
/* if (unlikely(command == CMD_POWER_DOWN) */ if (!wait_event_timeout(core->command,
atomic_read(&core->cts),
usecs_to_jiffies(usecs) + 1))
dev_warn(&core->client->dev, "(%s) [CMD 0x%02x] Answer timeout.\n",
__func__, command);
/* When working in polling mode, for some reason the tuner will report CTS bit as being set in the first status byte read, but all the consequtive ones will return zeros until the tuner is actually completed the POWER_UP command. To workaround that we wait for second CTS to be reported
*/ if (unlikely(!core->client->irq && command == CMD_POWER_UP)) { if (!wait_event_timeout(core->command,
atomic_read(&core->cts),
usecs_to_jiffies(usecs) + 1))
dev_warn(&core->client->dev, "(%s) Power up took too much time.\n",
__func__);
}
/* Then get the response */
err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, resp, respn); if (err != respn) {
dev_err(&core->client->dev, "Error while reading response for command 0x%02x\n",
command);
err = (err >= 0) ? -EIO : err; gotoexit;
}
dev_dbg(&client->dev, "Response:\n %*ph\n", respn, resp);
err = 0;
if (resp[0] & SI476X_ERR) {
dev_err(&core->client->dev, "[CMD 0x%02x] Chip set error flag\n", command);
err = si476x_core_parse_and_nag_about_error(core); gotoexit;
}
/** * si476x_core_cmd_func_info() - send 'FUNC_INFO' command to the device * @core: device to send the command to * @info: struct si476x_func_info to fill all the information * returned by the command * * The command requests the firmware and patch version for currently * loaded firmware (dependent on the function of the device FM/AM/WB) * * Function returns 0 on success and negative error code on * failure
*/ int si476x_core_cmd_func_info(struct si476x_core *core, struct si476x_func_info *info)
{ int err;
u8 resp[CMD_FUNC_INFO_NRESP];
/** * si476x_core_cmd_get_property() - send 'GET_PROPERTY' command to the device * @core: device to send the command to * @property: property address * * Function return the value of property as u16 on success or a * negative error on failure
*/ int si476x_core_cmd_get_property(struct si476x_core *core, u16 property)
{ int err;
u8 resp[CMD_GET_PROPERTY_NRESP]; const u8 args[CMD_GET_PROPERTY_NARGS] = {
0x00,
msb(property),
lsb(property),
};
/** * si476x_core_cmd_dig_audio_pin_cfg() - send 'DIG_AUDIO_PIN_CFG' command to * the device * @core: device to send the command to * @dclk: DCLK pin function configuration: * #SI476X_DCLK_NOOP - do not modify the behaviour * #SI476X_DCLK_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * #SI476X_DCLK_DAUDIO - set the pin to be a part of digital * audio interface * @dfs: DFS pin function configuration: * #SI476X_DFS_NOOP - do not modify the behaviour * #SI476X_DFS_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_DFS_DAUDIO - set the pin to be a part of digital * audio interface * @dout: - DOUT pin function configuration: * SI476X_DOUT_NOOP - do not modify the behaviour * SI476X_DOUT_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_DOUT_I2S_OUTPUT - set this pin to be digital out on I2S * port 1 * SI476X_DOUT_I2S_INPUT - set this pin to be digital in on I2S * port 1 * @xout: - XOUT pin function configuration: * SI476X_XOUT_NOOP - do not modify the behaviour * SI476X_XOUT_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_XOUT_I2S_INPUT - set this pin to be digital in on I2S * port 1 * SI476X_XOUT_MODE_SELECT - set this pin to be the input that * selects the mode of the I2S audio * combiner (analog or HD) * [SI4761/63/65/67 Only] * * Function returns 0 on success and negative error code on failure
*/ int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *core, enum si476x_dclk_config dclk, enum si476x_dfs_config dfs, enum si476x_dout_config dout, enum si476x_xout_config xout)
{
u8 resp[CMD_DIG_AUDIO_PIN_CFG_NRESP]; const u8 args[CMD_DIG_AUDIO_PIN_CFG_NARGS] = {
PIN_CFG_BYTE(dclk),
PIN_CFG_BYTE(dfs),
PIN_CFG_BYTE(dout),
PIN_CFG_BYTE(xout),
};
/** * si476x_core_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND' * @core: - device to send the command to * @iqclk: - IQCL pin function configuration: * SI476X_IQCLK_NOOP - do not modify the behaviour * SI476X_IQCLK_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_IQCLK_IQ - set pin to be a part of I/Q interface * in master mode * @iqfs: - IQFS pin function configuration: * SI476X_IQFS_NOOP - do not modify the behaviour * SI476X_IQFS_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_IQFS_IQ - set pin to be a part of I/Q interface * in master mode * @iout: - IOUT pin function configuration: * SI476X_IOUT_NOOP - do not modify the behaviour * SI476X_IOUT_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_IOUT_OUTPUT - set pin to be I out * @qout: - QOUT pin function configuration: * SI476X_QOUT_NOOP - do not modify the behaviour * SI476X_QOUT_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_QOUT_OUTPUT - set pin to be Q out * * Function returns 0 on success and negative error code on failure
*/ int si476x_core_cmd_zif_pin_cfg(struct si476x_core *core, enum si476x_iqclk_config iqclk, enum si476x_iqfs_config iqfs, enum si476x_iout_config iout, enum si476x_qout_config qout)
{
u8 resp[CMD_ZIF_PIN_CFG_NRESP]; const u8 args[CMD_ZIF_PIN_CFG_NARGS] = {
PIN_CFG_BYTE(iqclk),
PIN_CFG_BYTE(iqfs),
PIN_CFG_BYTE(iout),
PIN_CFG_BYTE(qout),
};
/** * si476x_core_cmd_ic_link_gpo_ctl_pin_cfg - send * 'IC_LINK_GPIO_CTL_PIN_CFG' command to the device * @core: - device to send the command to * @icin: - ICIN pin function configuration: * SI476X_ICIN_NOOP - do not modify the behaviour * SI476X_ICIN_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_ICIN_GPO1_HIGH - set pin to be an output, drive it high * SI476X_ICIN_GPO1_LOW - set pin to be an output, drive it low * SI476X_ICIN_IC_LINK - set the pin to be a part of Inter-Chip link * @icip: - ICIP pin function configuration: * SI476X_ICIP_NOOP - do not modify the behaviour * SI476X_ICIP_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_ICIP_GPO1_HIGH - set pin to be an output, drive it high * SI476X_ICIP_GPO1_LOW - set pin to be an output, drive it low * SI476X_ICIP_IC_LINK - set the pin to be a part of Inter-Chip link * @icon: - ICON pin function configuration: * SI476X_ICON_NOOP - do not modify the behaviour * SI476X_ICON_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_ICON_I2S - set the pin to be a part of audio * interface in slave mode (DCLK) * SI476X_ICON_IC_LINK - set the pin to be a part of Inter-Chip link * @icop: - ICOP pin function configuration: * SI476X_ICOP_NOOP - do not modify the behaviour * SI476X_ICOP_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_ICOP_I2S - set the pin to be a part of audio * interface in slave mode (DOUT) * [Si4761/63/65/67 Only] * SI476X_ICOP_IC_LINK - set the pin to be a part of Inter-Chip link * * Function returns 0 on success and negative error code on failure
*/ int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *core, enum si476x_icin_config icin, enum si476x_icip_config icip, enum si476x_icon_config icon, enum si476x_icop_config icop)
{
u8 resp[CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP]; const u8 args[CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS] = {
PIN_CFG_BYTE(icin),
PIN_CFG_BYTE(icip),
PIN_CFG_BYTE(icon),
PIN_CFG_BYTE(icop),
};
/** * si476x_core_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the * device * @core: - device to send the command to * @lrout: - LROUT pin function configuration: * SI476X_LROUT_NOOP - do not modify the behaviour * SI476X_LROUT_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_LROUT_AUDIO - set pin to be audio output * SI476X_LROUT_MPX - set pin to be MPX output * * Function returns 0 on success and negative error code on failure
*/ int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *core, enum si476x_lrout_config lrout)
{
u8 resp[CMD_ANA_AUDIO_PIN_CFG_NRESP]; const u8 args[CMD_ANA_AUDIO_PIN_CFG_NARGS] = {
PIN_CFG_BYTE(lrout),
};
/** * si476x_core_cmd_intb_pin_cfg_a10 - send 'INTB_PIN_CFG' command to the device * @core: - device to send the command to * @intb: - INTB pin function configuration: * SI476X_INTB_NOOP - do not modify the behaviour * SI476X_INTB_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_INTB_DAUDIO - set pin to be a part of digital * audio interface in slave mode * SI476X_INTB_IRQ - set pin to be an interrupt request line * @a1: - A1 pin function configuration: * SI476X_A1_NOOP - do not modify the behaviour * SI476X_A1_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown * SI476X_A1_IRQ - set pin to be an interrupt request line * * Function returns 0 on success and negative error code on failure
*/ staticint si476x_core_cmd_intb_pin_cfg_a10(struct si476x_core *core, enum si476x_intb_config intb, enum si476x_a1_config a1)
{
u8 resp[CMD_INTB_PIN_CFG_A10_NRESP]; const u8 args[CMD_INTB_PIN_CFG_NARGS] = {
PIN_CFG_BYTE(intb),
PIN_CFG_BYTE(a1),
};
/** * si476x_core_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the * device * @core: - device to send the command to * @rsqargs: - pointer to a structure containing a group of sub-args * relevant to sending the RSQ status command * @report: - all signal quality information returned by the command * (if NULL then the output of the command is ignored) * * Function returns 0 on success and negative error code on failure
*/ int si476x_core_cmd_am_rsq_status(struct si476x_core *core, struct si476x_rsq_status_args *rsqargs, struct si476x_rsq_status_report *report)
{ int err;
u8 resp[CMD_AM_RSQ_STATUS_NRESP]; const u8 args[CMD_AM_RSQ_STATUS_NARGS] = {
rsqargs->rsqack << 3 | rsqargs->attune << 2 |
rsqargs->cancel << 1 | rsqargs->stcack,
};
err = si476x_core_send_command(core, CMD_AM_RSQ_STATUS,
args, ARRAY_SIZE(args),
resp, ARRAY_SIZE(resp),
SI476X_DEFAULT_TIMEOUT); /* * Besides getting received signal quality information this * command can be used to just acknowledge different interrupt * flags in those cases it is useless to copy and parse * received data so user can pass NULL, and thus avoid * unnecessary copying.
*/ if (!report) return err;
/** * si476x_core_cmd_fm_seek_start - send 'FM_SEEK_START' command to the * device * @core: - device to send the command to * @seekup: - if set the direction of the search is 'up' * @wrap: - if set seek wraps when hitting band limit * * This function begins search for a valid station. The station is * considered valid when 'FM_VALID_SNR_THRESHOLD' and * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria * are met. } * * Function returns 0 on success and negative error code on failure
*/ int si476x_core_cmd_fm_seek_start(struct si476x_core *core, bool seekup, bool wrap)
{
u8 resp[CMD_FM_SEEK_START_NRESP]; const u8 args[CMD_FM_SEEK_START_NARGS] = {
seekup << 3 | wrap << 2,
};
/** * si476x_core_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the * device * @core: - device to send the command to * @status_only: - if set the data is not removed from RDSFIFO, * RDSFIFOUSED is not decremented and data in all the * rest RDS data contains the last valid info received * @mtfifo: if set the command clears RDS receive FIFO * @intack: if set the command clards the RDSINT bit. * @report: - all signal quality information returned by the command * (if NULL then the output of the command is ignored) * * Function returns 0 on success and negative error code on failure
*/ int si476x_core_cmd_fm_rds_status(struct si476x_core *core, bool status_only, bool mtfifo, bool intack, struct si476x_rds_status_report *report)
{ int err;
u8 resp[CMD_FM_RDS_STATUS_NRESP]; const u8 args[CMD_FM_RDS_STATUS_NARGS] = {
status_only << 2 | mtfifo << 1 | intack,
};
err = si476x_core_send_command(core, CMD_FM_RDS_STATUS,
args, ARRAY_SIZE(args),
resp, ARRAY_SIZE(resp),
SI476X_DEFAULT_TIMEOUT); /* * Besides getting RDS status information this command can be * used to just acknowledge different interrupt flags in those * cases it is useless to copy and parse received data so user * can pass NULL, and thus avoid unnecessary copying.
*/ if (err < 0 || report == NULL) return err;
return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY,
args, ARRAY_SIZE(args),
resp, ARRAY_SIZE(resp),
SI476X_DEFAULT_TIMEOUT);
}
EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity); /** * si476x_core_cmd_fm_phase_div_status() - get the phase diversity * status * * @core: si476x device * * NOTE caller must hold core lock * * Function returns the value of the status bit in case of success and * negative error code in case of failure.
*/ int si476x_core_cmd_fm_phase_div_status(struct si476x_core *core)
{ int err;
u8 resp[CMD_FM_PHASE_DIV_STATUS_NRESP];
/** * si476x_core_cmd_am_seek_start - send 'FM_SEEK_START' command to the * device * @core: - device to send the command to * @seekup: - if set the direction of the search is 'up' * @wrap: - if set seek wraps when hitting band limit * * This function begins search for a valid station. The station is * considered valid when 'FM_VALID_SNR_THRESHOLD' and * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria * are met. * * Function returns 0 on success and negative error code on failure
*/ int si476x_core_cmd_am_seek_start(struct si476x_core *core, bool seekup, bool wrap)
{
u8 resp[CMD_AM_SEEK_START_NRESP]; const u8 args[CMD_AM_SEEK_START_NARGS] = {
seekup << 3 | wrap << 2,
};
err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS,
args, ARRAY_SIZE(args),
resp, ARRAY_SIZE(resp),
SI476X_DEFAULT_TIMEOUT); /* * Besides getting received signal quality information this * command can be used to just acknowledge different interrupt * flags in those cases it is useless to copy and parse * received data so user can pass NULL, and thus avoid * unnecessary copying.
*/ if (err < 0 || report == NULL) return err;
err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS,
args, ARRAY_SIZE(args),
resp, ARRAY_SIZE(resp),
SI476X_DEFAULT_TIMEOUT); /* * Besides getting received signal quality information this * command can be used to just acknowledge different interrupt * flags in those cases it is useless to copy and parse * received data so user can pass NULL, and thus avoid * unnecessary copying.
*/ if (err < 0 || report == NULL) return err;
err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS,
args, ARRAY_SIZE(args),
resp, ARRAY_SIZE(resp),
SI476X_DEFAULT_TIMEOUT); /* * Besides getting received signal quality information this * command can be used to just acknowledge different interrupt * flags in those cases it is useless to copy and parse * received data so user can pass NULL, and thus avoid * unnecessary copying.
*/ if (err < 0 || report == NULL) return err;
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.