Example #1
0
/**
 * 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;
}
Example #2
0
/**
 * 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);
}
Example #3
0
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;
}
Example #4
0
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;
}