コード例 #1
0
static void omap_init_mcspi(void)
{
	platform_device_register(&omap2_mcspi1);
	platform_device_register(&omap2_mcspi2);
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
	if (cpu_is_omap2430() || cpu_is_omap343x())
		platform_device_register(&omap2_mcspi3);
#endif
#ifdef CONFIG_ARCH_OMAP3
	if (cpu_is_omap343x())
		platform_device_register(&omap2_mcspi4);
#endif
}
コード例 #2
0
static void omap_init_mcspi(void)
{
	if (cpu_is_omap44xx())
		omap4_mcspi_fixup();

	platform_device_register(&omap2_mcspi1);
	platform_device_register(&omap2_mcspi2);

	if (cpu_is_omap2430() || cpu_is_omap343x() || cpu_is_omap44xx())
		omap2_mcspi3_init();

	if (cpu_is_omap343x() || cpu_is_omap44xx())
		omap2_mcspi4_init();
}
コード例 #3
0
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
				  struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
	struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
	int err = 0;

	if (cpu_is_omap343x() && mcbsp_data->bus_id == 1) {
		/*
		 * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer.
		 * Set constraint for minimum buffer size to the same than FIFO
		 * size in order to avoid underruns in playback startup because
		 * HW is keeping the DMA request active until FIFO is filled.
		 */
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
			snd_pcm_hw_constraint_minmax(substream->runtime,
			SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4096, UINT_MAX);
		else
			snd_pcm_hw_constraint_minmax(substream->runtime,
			SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 1024, UINT_MAX);
	}

	if (!cpu_dai->active) {
		err = omap_mcbsp_request(mcbsp_data->bus_id);
		cpu_dai->active = 1;
	}

	return err;
}
コード例 #4
0
/* Smartreflex Class3 init API to be called from board file */
static int __init sr_class3_init(void)
{
	/* Enable this class only for OMAP343x and OMAP443x */
	if (!cpu_is_omap343x() && !cpu_is_omap443x())
		return -EINVAL;

	pr_info("SmartReflex Class3 initialized\n");
	return sr_register_class(&class3_data);
}
コード例 #5
0
static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
				       int clk_id)
{
	int sel_bit;
	u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;

	if (cpu_class_is_omap1()) {
		/* OMAP1's can use only external source clock */
		if (unlikely(clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK))
			return -EINVAL;
		else
			return 0;
	}

	if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
		return -EINVAL;

	if (cpu_is_omap343x())
		reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;

	switch (mcbsp_data->bus_id) {
	case 0:
		reg = OMAP2_CONTROL_DEVCONF0;
		sel_bit = 2;
		break;
	case 1:
		reg = OMAP2_CONTROL_DEVCONF0;
		sel_bit = 6;
		break;
	case 2:
		reg = reg_devconf1;
		sel_bit = 0;
		break;
	case 3:
		reg = reg_devconf1;
		sel_bit = 2;
		break;
	case 4:
		reg = reg_devconf1;
		sel_bit = 4;
		break;
	default:
		return -EINVAL;
	}

	if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
		omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
	else
		omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);

	return 0;
}
コード例 #6
0
ファイル: devices.c プロジェクト: gzdaoke/linux2.6.32_kernel
static void omap_init_mcspi(void)
{
	if (cpu_is_omap44xx()) {
		omap2_mcspi1_resources[0].start	= OMAP4_MCSPI1_BASE;
		omap2_mcspi1_resources[0].end	= OMAP4_MCSPI1_BASE + 0xff;
		omap2_mcspi2_resources[0].start	= OMAP4_MCSPI2_BASE;
		omap2_mcspi2_resources[0].end	= OMAP4_MCSPI2_BASE + 0xff;
		omap2_mcspi3_resources[0].start	= OMAP4_MCSPI3_BASE;
		omap2_mcspi3_resources[0].end	= OMAP4_MCSPI3_BASE + 0xff;
		omap2_mcspi4_resources[0].start	= OMAP4_MCSPI4_BASE;
		omap2_mcspi4_resources[0].end	= OMAP4_MCSPI4_BASE + 0xff;
	}
	platform_device_register(&omap2_mcspi1);
	platform_device_register(&omap2_mcspi2);
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
	defined(CONFIG_ARCH_OMAP4)
	if (cpu_is_omap2430() || cpu_is_omap343x() || cpu_is_omap44xx())
		platform_device_register(&omap2_mcspi3);
#endif
#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
	if (cpu_is_omap343x() || cpu_is_omap44xx())
		platform_device_register(&omap2_mcspi4);
#endif
}
コード例 #7
0
ファイル: clock.c プロジェクト: 383530895/linux
/**
 * ti_clk_init_features - init clock features struct for the SoC
 *
 * Initializes the clock features struct based on the SoC type.
 */
void __init ti_clk_init_features(void)
{
	/* Fint setup for DPLLs */
	if (cpu_is_omap3430()) {
		ti_clk_features.fint_min = OMAP3430_DPLL_FINT_BAND1_MIN;
		ti_clk_features.fint_max = OMAP3430_DPLL_FINT_BAND2_MAX;
		ti_clk_features.fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX;
		ti_clk_features.fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN;
	} else {
		ti_clk_features.fint_min = OMAP3PLUS_DPLL_FINT_MIN;
		ti_clk_features.fint_max = OMAP3PLUS_DPLL_FINT_MAX;
	}

	/* Bypass value setup for DPLLs */
	if (cpu_is_omap24xx()) {
		ti_clk_features.dpll_bypass_vals |=
			(1 << OMAP2XXX_EN_DPLL_LPBYPASS) |
			(1 << OMAP2XXX_EN_DPLL_FRBYPASS);
	} else if (cpu_is_omap34xx()) {
		ti_clk_features.dpll_bypass_vals |=
			(1 << OMAP3XXX_EN_DPLL_LPBYPASS) |
			(1 << OMAP3XXX_EN_DPLL_FRBYPASS);
	} else if (soc_is_am33xx() || cpu_is_omap44xx() || soc_is_am43xx() ||
		   soc_is_omap54xx() || soc_is_dra7xx()) {
		ti_clk_features.dpll_bypass_vals |=
			(1 << OMAP4XXX_EN_DPLL_LPBYPASS) |
			(1 << OMAP4XXX_EN_DPLL_FRBYPASS) |
			(1 << OMAP4XXX_EN_DPLL_MNBYPASS);
	}

	/* Jitter correction only available on OMAP343X */
	if (cpu_is_omap343x())
		ti_clk_features.flags |= TI_CLK_DPLL_HAS_FREQSEL;

	/* Idlest value for interface clocks.
	 * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
	 * 34xx reverses this, just to keep us on our toes
	 * AM35xx uses both, depending on the module.
	 */
	if (cpu_is_omap24xx())
		ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
	else if (cpu_is_omap34xx())
		ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL;

	/* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */
	if (omap_rev() == OMAP3430_REV_ES1_0)
		ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
}
コード例 #8
0
static void omap_init_wdt(void)
{
	if (cpu_is_omap16xx())
		wdt_resources[0].start = 0xfffeb000;
	else if (cpu_is_omap2420())
		wdt_resources[0].start = 0x48022000; /* WDT2 */
	else if (cpu_is_omap2430())
		wdt_resources[0].start = 0x49016000; /* WDT2 */
	else if (cpu_is_omap343x())
		wdt_resources[0].start = 0x48314000; /* WDT2 */
	else
		return;

	wdt_resources[0].end = wdt_resources[0].start + 0x4f;

	(void) platform_device_register(&omap_wdt_device);
}
コード例 #9
0
ファイル: omap-mcbsp.c プロジェクト: AbheekG/XIA-for-Linux
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *cpu_dai)
{
    struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
    int bus_id = mcbsp_data->bus_id;
    int err = 0;

    if (!cpu_dai->active)
        err = omap_mcbsp_request(bus_id);

    /*
     * OMAP3 McBSP FIFO is word structured.
     * McBSP2 has 1024 + 256 = 1280 word long buffer,
     * McBSP1,3,4,5 has 128 word long buffer
     * This means that the size of the FIFO depends on the sample format.
     * For example on McBSP3:
     * 16bit samples: size is 128 * 2 = 256 bytes
     * 32bit samples: size is 128 * 4 = 512 bytes
     * It is simpler to place constraint for buffer and period based on
     * channels.
     * McBSP3 as example again (16 or 32 bit samples):
     * 1 channel (mono): size is 128 frames (128 words)
     * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
     * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
     */
    if (cpu_is_omap343x() || cpu_is_omap44xx()) {
        /*
        * Rule for the buffer size. We should not allow
        * smaller buffer than the FIFO size to avoid underruns
        */
        snd_pcm_hw_rule_add(substream->runtime, 0,
                            SNDRV_PCM_HW_PARAM_CHANNELS,
                            omap_mcbsp_hwrule_min_buffersize,
                            mcbsp_data,
                            SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);

        /* Make sure, that the period size is always even */
        snd_pcm_hw_constraint_step(substream->runtime, 0,
                                   SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
    }

    return err;
}
コード例 #10
0
static int sr_dev_init(struct omap_hwmod *oh, void *user)
{
	struct omap_sr_data *sr_data;
	struct omap_sr_dev_data *sr_dev_data;
	struct omap_device *od;
	char *name = "smartreflex";
	static int i;

	sr_data = kzalloc(sizeof(struct omap_sr_data), GFP_KERNEL);
	if (!sr_data) {
		pr_err("%s: Unable to allocate memory for %s sr_data.Error!\n",
			__func__, oh->name);
		return -ENOMEM;
	}

	sr_dev_data = (struct omap_sr_dev_data *)oh->dev_attr;
	if (unlikely(!sr_dev_data)) {
		pr_err("%s: dev atrribute is NULL\n", __func__);
		kfree(sr_data);
		goto exit;
	}

	/*
	 * OMAP3430 ES3.1 chips by default come with Efuse burnt
	 * with parameters required for full functionality of
	 * smartreflex AVS feature like ntarget values , sennenable
	 * and senpenable. So enable the SR AVS feature during boot up
	 * itself if it is a OMAP3430 ES3.1 chip.
	 */
	if (cpu_is_omap343x()) {
		if (omap_rev() == OMAP3430_REV_ES3_1)
			sr_data->enable_on_init = true;
		else
			sr_data->enable_on_init = false;
	} else {
		sr_data->enable_on_init = false;
	}
	sr_data->device_enable = omap_device_enable;
	sr_data->device_shutdown = omap_device_shutdown;
	sr_data->device_idle = omap_device_idle;
	sr_data->voltdm = omap_voltage_domain_get(sr_dev_data->vdd_name);
	if (IS_ERR(sr_data->voltdm)) {
		pr_err("%s: Unable to get voltage domain pointer for VDD %s\n",
			__func__, sr_dev_data->vdd_name);
		kfree(sr_data);
		goto exit;
	}
	sr_dev_data->volts_supported = omap_voltage_get_volttable(
			sr_data->voltdm, &sr_dev_data->volt_data);
	if (!sr_dev_data->volts_supported) {
		pr_warning("%s: No Voltage table registerd fo VDD%d."
			"Something really wrong\n\n", __func__, i + 1);
		kfree(sr_data);
		goto exit;
	}
	sr_set_nvalues(sr_dev_data, sr_data);
	od = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data),
			       omap_sr_latency,
			       ARRAY_SIZE(omap_sr_latency), 0);
	if (IS_ERR(od)) {
		pr_warning("%s: Could not build omap_device for %s: %s.\n\n",
			__func__, name, oh->name);
		kfree(sr_data);
	}
exit:
	i++;
	return 0;
}
コード例 #11
0
static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
				    struct snd_pcm_hw_params *params,
				    struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
	struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
	struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
	int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
	int uninitialized_var(wlen);
	int uninitialized_var(channels);
	int uninitialized_var(wpf);
	unsigned long uninitialized_var(port);
	unsigned int uninitialized_var(format);
	int xfer_size = 0;

	if (cpu_class_is_omap1()) {
		dma = omap1_dma_reqs[bus_id][substream->stream];
		port = omap1_mcbsp_port[bus_id][substream->stream];
	} else if (cpu_is_omap2420()) {
		dma = omap24xx_dma_reqs[bus_id][substream->stream];
		port = omap2420_mcbsp_port[bus_id][substream->stream];
	} else if (cpu_is_omap2430()) {
		dma = omap24xx_dma_reqs[bus_id][substream->stream];
		port = omap2430_mcbsp_port[bus_id][substream->stream];
	} else if (cpu_is_omap343x()) {
		dma = omap24xx_dma_reqs[bus_id][substream->stream];
		port = omap34xx_mcbsp_port[bus_id][substream->stream];
		xfer_size = omap34xx_mcbsp_thresholds[bus_id]
					[substream->stream];
		/* reset the xfer_size to the integral multiple of
		the buffer size. This is for DMA packet mode transfer */
		if (xfer_size) {
			int buffer_size = params_buffer_size(params);
			if (xfer_size > buffer_size) {
				printk(KERN_DEBUG "buffer_size is %d \n",
					buffer_size);
				xfer_size = 0;
			} else if (params_channels(params) == 1) {
				/* Mono needs 16 bits DMA, no FIFO */
				xfer_size = 1;
			} else {
				int temp =  buffer_size / xfer_size;
				while (buffer_size % xfer_size) {
					temp++;
					xfer_size = buffer_size / (temp);
				}
			}
		}
	} else {
		return -ENODEV;
	}
	omap_mcbsp_dai_dma_params[id][substream->stream].name =
		substream->stream ? "Audio Capture" : "Audio Playback";
	omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
	omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
	omap_mcbsp_dai_dma_params[id][substream->stream].xfer_size = xfer_size;
	cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];

	if (mcbsp_data->configured) {
		/* McBSP already configured by another stream */
		return 0;
	}

	format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
	wpf = channels = params_channels(params);

	if (format == SND_SOC_DAIFMT_SPDIF) {
		regs->xcr2	&= ~(XPHASE);
		regs->rcr2	&= ~(RPHASE);
		/* Don't care about channels number and frame
			length 2. Set 4 frames (frame length 1) */
		regs->xcr1	|= XFRLEN1(4 - 1);
		regs->rcr1	|= RFRLEN1(1 - 1);
	} else {
		switch (channels) {
		case 2:
			if (format == SND_SOC_DAIFMT_I2S) {
				/* Use dual-phase frames */
				regs->rcr2	|= RPHASE;
				regs->xcr2	|= XPHASE;
				/* Set 1 word per (McBSP) frame for phase1 and phase2 */
				wpf--;
				regs->rcr2	|= RFRLEN2(wpf - 1);
				regs->xcr2	|= XFRLEN2(wpf - 1);
			} else if (format == SND_SOC_DAIFMT_I2S_1PHASE || format == SND_SOC_DAIFMT_DSP_A_1PHASE) {
				printk(KERN_DEBUG "Configure McBSP for 1 phase\n");
				regs->xcr2	&= ~(XPHASE);
				regs->rcr2	&= ~(RPHASE);
				wpf--;
			}
		case 1:
		case 4:
			/* Set word per (McBSP) frame for phase1 */
			regs->rcr1	|= RFRLEN1(wpf - 1);
			regs->xcr1	|= XFRLEN1(wpf - 1);
			break;
		default:
			/* Unsupported number of channels */
			return -EINVAL;
		}
	}

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		/* Set word lengths */
		wlen = 16;
		if (format == SND_SOC_DAIFMT_SPDIF ||
		   (channels != 1 && (format == SND_SOC_DAIFMT_I2S_1PHASE ||
		   format == SND_SOC_DAIFMT_DSP_A_1PHASE))) {
			regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_32);
			regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_32);
			omap_mcbsp_dai_dma_params[id]
			[SNDRV_PCM_STREAM_PLAYBACK].dma_word_size = 32;
			omap_mcbsp_dai_dma_params[id]
			[SNDRV_PCM_STREAM_CAPTURE].dma_word_size = 32;
		} else {
			regs->rcr2	|= RWDLEN2(OMAP_MCBSP_WORD_16);
			regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_16);
			regs->xcr2	|= XWDLEN2(OMAP_MCBSP_WORD_16);
			regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_16);
			omap_mcbsp_dai_dma_params[id]
			[substream->stream].dma_word_size = 16;
		}
		break;
	case SNDRV_PCM_FORMAT_S8:
		/* Set word lengths */
		wlen = 8;
		if (format == SND_SOC_DAIFMT_SPDIF ||
		   (channels != 1 && (format == SND_SOC_DAIFMT_I2S_1PHASE ||
		   format == SND_SOC_DAIFMT_DSP_A_1PHASE))) {
			regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_16);
			regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_16);
			omap_mcbsp_dai_dma_params[id]
			[SNDRV_PCM_STREAM_PLAYBACK].dma_word_size = 16;
			omap_mcbsp_dai_dma_params[id]
			[SNDRV_PCM_STREAM_CAPTURE].dma_word_size = 16;
		} else {
			regs->rcr2	|= RWDLEN2(OMAP_MCBSP_WORD_8);
			regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_8);
			regs->xcr2	|= XWDLEN2(OMAP_MCBSP_WORD_8);
			regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_8);
			omap_mcbsp_dai_dma_params[id]
			[substream->stream].dma_word_size = 8;
		}
		break;
	default:
		/* Unsupported PCM format */
		return -EINVAL;
	}

	/* Set FS period and length in terms of bit clock periods */
	switch (format) {
	case SND_SOC_DAIFMT_I2S:
	case SND_SOC_DAIFMT_I2S_1PHASE:
		regs->srgr2	|= FPER(wlen * channels - 1);
		regs->srgr1	|= FWID(wlen - 1);
		break;
	case SND_SOC_DAIFMT_DSP_A_1PHASE:
	case SND_SOC_DAIFMT_DSP_A:
	case SND_SOC_DAIFMT_DSP_B:
		regs->srgr2	|= FPER(wlen * channels - 1);
		regs->srgr1	|= FWID(0);
		break;
	case SND_SOC_DAIFMT_SPDIF:
		regs->srgr2	|= FPER(4 * 32 - 1);
		regs->srgr1	|= FWID(0);
		break;
	}

	regs->xccr |= XDMAEN;
	regs->wken = XRDYEN;
	regs->rccr |= RDMAEN;

	omap_mcbsp_config(bus_id, &mcbsp_data->regs);

	if ((bus_id == 1) && (xfer_size != 0)) {
		printk(KERN_DEBUG "Configure McBSP TX FIFO threshold to %d\n",
			xfer_size);
		omap_mcbsp_set_tx_threshold(bus_id, xfer_size);
	}

	/* We want to be able to change stuff 
		(like channels number) dynamically */ 
	//mcbsp_data->configured = 1;

	return 0;
}
コード例 #12
0
/**
 * omap3_noncore_dpll_set_rate - set non-core DPLL rate
 * @clk: struct clk * of DPLL to set
 * @rate: rounded target rate
 *
 * Set the DPLL CLKOUT to the target rate.  If the DPLL can enter
 * low-power bypass, and the target rate is the bypass source clock
 * rate, then configure the DPLL for bypass.  Otherwise, round the
 * target rate if it hasn't been done already, then program and lock
 * the DPLL.  Returns -EINVAL upon error, or 0 upon success.
 */
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
					unsigned long parent_rate)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
	struct clk *new_parent = NULL;
	unsigned long rrate;
	u16 freqsel = 0;
	struct dpll_data *dd;
	int ret;

	if (!hw || !rate)
		return -EINVAL;

	dd = clk->dpll_data;
	if (!dd)
		return -EINVAL;

	if (__clk_get_rate(dd->clk_bypass) == rate &&
	    (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
		pr_debug("%s: %s: set rate: entering bypass.\n",
			 __func__, __clk_get_name(hw->clk));

		__clk_prepare(dd->clk_bypass);
		clk_enable(dd->clk_bypass);
		ret = _omap3_noncore_dpll_bypass(clk);
		if (!ret)
			new_parent = dd->clk_bypass;
		clk_disable(dd->clk_bypass);
		__clk_unprepare(dd->clk_bypass);
	} else {
		__clk_prepare(dd->clk_ref);
		clk_enable(dd->clk_ref);

		if (dd->last_rounded_rate != rate) {
			rrate = __clk_round_rate(hw->clk, rate);
			if (rrate != rate) {
				pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
					__func__, __clk_get_name(hw->clk),
					rrate, rate);
				rate = rrate;
			}
		}

		if (dd->last_rounded_rate == 0)
			return -EINVAL;

		/* Freqsel is available only on OMAP343X devices */
		if (cpu_is_omap343x()) {
			freqsel = _omap3_dpll_compute_freqsel(clk,
						dd->last_rounded_n);
			WARN_ON(!freqsel);
		}

		pr_debug("%s: %s: set rate: locking rate to %lu.\n",
			 __func__, __clk_get_name(hw->clk), rate);

		ret = omap3_noncore_dpll_program(clk, freqsel);
		if (!ret)
			new_parent = dd->clk_ref;
		clk_disable(dd->clk_ref);
		__clk_unprepare(dd->clk_ref);
	}
	/*
	* FIXME - this is all wrong.  common code handles reparenting and
	* migrating prepare/enable counts.  dplls should be a multiplexer
	* clock and this should be a set_parent operation so that all of that
	* stuff is inherited for free
	*/

	if (!ret && clk_get_parent(hw->clk) != new_parent)
		__clk_reparent(hw->clk, new_parent);

	return 0;
}
コード例 #13
0
/*
 * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly
 * @clk:	struct clk * of DPLL to set
 * @freqsel:	FREQSEL value to set
 *
 * Program the DPLL with the last M, N values calculated, and wait for
 * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success.
 */
static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
{
	struct dpll_data *dd = clk->dpll_data;
	u8 dco, sd_div;
	u32 v;

	/* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
	_omap3_noncore_dpll_bypass(clk);

	if (dd->sink_clkdm)
		clkdm_clk_enable(dd->sink_clkdm, clk->hw.clk);

	/*
	 * Set jitter correction. Jitter correction applicable for OMAP343X
	 * only since freqsel field is no longer present on other devices.
	 */
	if (cpu_is_omap343x()) {
		v = omap2_clk_readl(clk, dd->control_reg);
		v &= ~dd->freqsel_mask;
		v |= freqsel << __ffs(dd->freqsel_mask);
		omap2_clk_writel(v, clk, dd->control_reg);
	}

	/* Set DPLL multiplier, divider */
	v = omap2_clk_readl(clk, dd->mult_div1_reg);

	/* Handle Duty Cycle Correction */
	if (dd->dcc_mask) {
		if (dd->last_rounded_rate >= dd->dcc_rate)
			v |= dd->dcc_mask; /* Enable DCC */
		else
			v &= ~dd->dcc_mask; /* Disable DCC */
	}

	v &= ~(dd->mult_mask | dd->div1_mask);
	v |= dd->last_rounded_m << __ffs(dd->mult_mask);
	v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);

	/* Configure dco and sd_div for dplls that have these fields */
	if (dd->dco_mask) {
		_lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n);
		v &= ~(dd->dco_mask);
		v |= dco << __ffs(dd->dco_mask);
	}
	if (dd->sddiv_mask) {
		_lookup_sddiv(clk, &sd_div, dd->last_rounded_m,
			      dd->last_rounded_n);
		v &= ~(dd->sddiv_mask);
		v |= sd_div << __ffs(dd->sddiv_mask);
	}

	omap2_clk_writel(v, clk, dd->mult_div1_reg);

	/* Set 4X multiplier and low-power mode */
	if (dd->m4xen_mask || dd->lpmode_mask) {
		v = omap2_clk_readl(clk, dd->control_reg);

		if (dd->m4xen_mask) {
			if (dd->last_rounded_m4xen)
				v |= dd->m4xen_mask;
			else
				v &= ~dd->m4xen_mask;
		}

		if (dd->lpmode_mask) {
			if (dd->last_rounded_lpmode)
				v |= dd->lpmode_mask;
			else
				v &= ~dd->lpmode_mask;
		}

		omap2_clk_writel(v, clk, dd->control_reg);
	}

	/* We let the clock framework set the other output dividers later */

	/* REVISIT: Set ramp-up delay? */

	_omap3_noncore_dpll_lock(clk);

	if (dd->sink_clkdm)
		clkdm_clk_disable(dd->sink_clkdm, clk->hw.clk);

	return 0;
}
コード例 #14
0
ファイル: omap-mcbsp.c プロジェクト: AbheekG/XIA-for-Linux
static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params,
                                    struct snd_soc_dai *cpu_dai)
{
    struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
    struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
    struct omap_pcm_dma_data *dma_data;
    int dma, bus_id = mcbsp_data->bus_id;
    int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
    int pkt_size = 0;
    unsigned long port;
    unsigned int format, div, framesize, master;

    dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream];

    dma = omap_mcbsp_dma_ch_params(bus_id, substream->stream);
    port = omap_mcbsp_dma_reg_params(bus_id, substream->stream);

    switch (params_format(params)) {
    case SNDRV_PCM_FORMAT_S16_LE:
        dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
        wlen = 16;
        break;
    case SNDRV_PCM_FORMAT_S32_LE:
        dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;
        wlen = 32;
        break;
    default:
        return -EINVAL;
    }
    if (cpu_is_omap343x()) {
        dma_data->set_threshold = omap_mcbsp_set_threshold;
        /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
        if (omap_mcbsp_get_dma_op_mode(bus_id) ==
                MCBSP_DMA_MODE_THRESHOLD) {
            int period_words, max_thrsh;

            period_words = params_period_bytes(params) / (wlen / 8);
            if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                max_thrsh = omap_mcbsp_get_max_tx_threshold(
                                mcbsp_data->bus_id);
            else
                max_thrsh = omap_mcbsp_get_max_rx_threshold(
                                mcbsp_data->bus_id);
            /*
             * If the period contains less or equal number of words,
             * we are using the original threshold mode setup:
             * McBSP threshold = sDMA frame size = period_size
             * Otherwise we switch to sDMA packet mode:
             * McBSP threshold = sDMA packet size
             * sDMA frame size = period size
             */
            if (period_words > max_thrsh) {
                int divider = 0;

                /*
                 * Look for the biggest threshold value, which
                 * divides the period size evenly.
                 */
                divider = period_words / max_thrsh;
                if (period_words % max_thrsh)
                    divider++;
                while (period_words % divider &&
                        divider < period_words)
                    divider++;
                if (divider == period_words)
                    return -EINVAL;

                pkt_size = period_words / divider;
                sync_mode = OMAP_DMA_SYNC_PACKET;
            } else {
                sync_mode = OMAP_DMA_SYNC_FRAME;
            }
        }
    }

    dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback";
    dma_data->dma_req = dma;
    dma_data->port_addr = port;
    dma_data->sync_mode = sync_mode;
    dma_data->packet_size = pkt_size;

    snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);

    if (mcbsp_data->configured) {
        /* McBSP already configured by another stream */
        return 0;
    }

    format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
    wpf = channels = params_channels(params);
    if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
                          format == SND_SOC_DAIFMT_LEFT_J)) {
        /* Use dual-phase frames */
        regs->rcr2	|= RPHASE;
        regs->xcr2	|= XPHASE;
        /* Set 1 word per (McBSP) frame for phase1 and phase2 */
        wpf--;
        regs->rcr2	|= RFRLEN2(wpf - 1);
        regs->xcr2	|= XFRLEN2(wpf - 1);
    }

    regs->rcr1	|= RFRLEN1(wpf - 1);
    regs->xcr1	|= XFRLEN1(wpf - 1);

    switch (params_format(params)) {
    case SNDRV_PCM_FORMAT_S16_LE:
        /* Set word lengths */
        regs->rcr2	|= RWDLEN2(OMAP_MCBSP_WORD_16);
        regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_16);
        regs->xcr2	|= XWDLEN2(OMAP_MCBSP_WORD_16);
        regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_16);
        break;
    case SNDRV_PCM_FORMAT_S32_LE:
        /* Set word lengths */
        regs->rcr2	|= RWDLEN2(OMAP_MCBSP_WORD_32);
        regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_32);
        regs->xcr2	|= XWDLEN2(OMAP_MCBSP_WORD_32);
        regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_32);
        break;
    default:
        /* Unsupported PCM format */
        return -EINVAL;
    }

    /* In McBSP master modes, FRAME (i.e. sample rate) is generated
     * by _counting_ BCLKs. Calculate frame size in BCLKs */
    master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK;
    if (master ==	SND_SOC_DAIFMT_CBS_CFS) {
        div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1;
        framesize = (mcbsp_data->in_freq / div) / params_rate(params);

        if (framesize < wlen * channels) {
            printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
                   "channels\n", __func__);
            return -EINVAL;
        }
    } else
        framesize = wlen * channels;

    /* Set FS period and length in terms of bit clock periods */
    switch (format) {
    case SND_SOC_DAIFMT_I2S:
    case SND_SOC_DAIFMT_LEFT_J:
        regs->srgr2	|= FPER(framesize - 1);
        regs->srgr1	|= FWID((framesize >> 1) - 1);
        break;
    case SND_SOC_DAIFMT_DSP_A:
    case SND_SOC_DAIFMT_DSP_B:
        regs->srgr2	|= FPER(framesize - 1);
        regs->srgr1	|= FWID(0);
        break;
    }

    omap_mcbsp_config(bus_id, &mcbsp_data->regs);
    mcbsp_data->wlen = wlen;
    mcbsp_data->configured = 1;

    return 0;
}