/** * si476x_get_revision_info() * @core: Core device structure * * Get the firmware version number of the device. It is done in * following three steps: * 1. Power-up the device * 2. Send the 'FUNC_INFO' command * 3. Powering the device down. * * The function return zero on success and a negative error code on * failure. */ static int si476x_core_get_revision_info(struct si476x_core *core) { int rval; struct si476x_func_info info; si476x_core_lock(core); rval = si476x_core_set_power_state(core, SI476X_POWER_UP_FULL); if (rval < 0) goto exit; rval = si476x_core_cmd_func_info(core, &info); if (rval < 0) goto power_down; core->revision = si476x_core_fwver_to_revision(core, info.func, info.firmware.major, info.firmware.minor[0], info.firmware.minor[1]); power_down: si476x_core_set_power_state(core, SI476X_POWER_DOWN); exit: si476x_core_unlock(core); return rval; }
/** * si476x_drain_rds_fifo() - RDS buffer drainer. * @work: struct work_struct being ppassed to the function by the * kernel. * * Drain the contents of the RDS FIFO of */ static void si476x_core_drain_rds_fifo(struct work_struct *work) { int err; struct si476x_core *core = container_of(work, struct si476x_core, rds_fifo_drainer); struct si476x_rds_status_report report; si476x_core_lock(core); err = si476x_core_cmd_fm_rds_status(core, true, false, false, &report); if (!err) { int i = report.rdsfifoused; dev_dbg(&core->client->dev, "%d elements in RDS FIFO. Draining.\n", i); for (; i > 0; --i) { err = si476x_core_cmd_fm_rds_status(core, false, false, (i == 1), &report); if (err < 0) goto unlock; kfifo_in(&core->rds_fifo, report.rds, sizeof(report.rds)); dev_dbg(&core->client->dev, "RDS data:\n %*ph\n", (int)sizeof(report.rds), report.rds); } dev_dbg(&core->client->dev, "Drrrrained!\n"); wake_up_interruptible(&core->rds_read_queue); } unlock: si476x_core_unlock(core); si476x_core_report_drainer_stop(core); }
static int si476x_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct si476x_core *core = i2c_mfd_cell_to_core(dai->dev); int rate, width, err; rate = params_rate(params); if (rate < 32000 || rate > 48000) { dev_err(dai->codec->dev, "Rate: %d is not supported\n", rate); return -EINVAL; } switch (params_width(params)) { case 8: width = SI476X_PCM_FORMAT_S8; break; case 16: width = SI476X_PCM_FORMAT_S16_LE; break; case 20: width = SI476X_PCM_FORMAT_S20_3LE; break; case 24: width = SI476X_PCM_FORMAT_S24_LE; break; default: return -EINVAL; } si476x_core_lock(core); err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE, rate); if (err < 0) { dev_err(dai->codec->dev, "Failed to set sample rate\n"); goto out; } err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK, (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)); if (err < 0) { dev_err(dai->codec->dev, "Failed to set output width\n"); goto out; } out: si476x_core_unlock(core); return err; }
static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct si476x_core *core = i2c_mfd_cell_to_core(codec_dai->dev); int err; u16 format = 0; if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) return -EINVAL; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: format |= SI476X_DAUDIO_MODE_DSP_A; break; case SND_SOC_DAIFMT_DSP_B: format |= SI476X_DAUDIO_MODE_DSP_B; break; case SND_SOC_DAIFMT_I2S: format |= SI476X_DAUDIO_MODE_I2S; break; case SND_SOC_DAIFMT_RIGHT_J: format |= SI476X_DAUDIO_MODE_RIGHT_J; break; case SND_SOC_DAIFMT_LEFT_J: format |= SI476X_DAUDIO_MODE_LEFT_J; break; default: return -EINVAL; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_IB_NF: format |= SI476X_DAUDIO_MODE_IB; break; default: return -EINVAL; } break; case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_LEFT_J: switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_IB_IF: format |= SI476X_DAUDIO_MODE_IB | SI476X_DAUDIO_MODE_IF; break; case SND_SOC_DAIFMT_IB_NF: format |= SI476X_DAUDIO_MODE_IB; break; case SND_SOC_DAIFMT_NB_IF: format |= SI476X_DAUDIO_MODE_IF; break; default: return -EINVAL; } break; default: return -EINVAL; } si476x_core_lock(core); err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK, format); si476x_core_unlock(core); if (err < 0) { dev_err(codec_dai->codec->dev, "Failed to set output format\n"); return err; } return 0; }