select ARCH_REQUIRE_GPIOLIB
select CLKDEV_LOOKUP
select CLKSRC_MMIO
+ select HAVE_CLK_PREPARE
help
Support for Freescale MXS-based family of processors
*/
clk_set_parent(&ssp_clk, &ref_io_clk);
- clk_enable(&cpu_clk);
- clk_enable(&hbus_clk);
- clk_enable(&xbus_clk);
- clk_enable(&emi_clk);
- clk_enable(&uart_clk);
+ clk_prepare_enable(&cpu_clk);
+ clk_prepare_enable(&hbus_clk);
+ clk_prepare_enable(&xbus_clk);
+ clk_prepare_enable(&emi_clk);
+ clk_prepare_enable(&uart_clk);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
clk_set_parent(&ssp0_clk, &ref_io0_clk);
clk_set_parent(&ssp1_clk, &ref_io0_clk);
- clk_enable(&cpu_clk);
- clk_enable(&hbus_clk);
- clk_enable(&xbus_clk);
- clk_enable(&emi_clk);
- clk_enable(&uart_clk);
+ clk_prepare_enable(&cpu_clk);
+ clk_prepare_enable(&hbus_clk);
+ clk_prepare_enable(&xbus_clk);
+ clk_prepare_enable(&emi_clk);
+ clk_prepare_enable(&uart_clk);
clk_set_parent(&lcdif_clk, &ref_pix_clk);
clk_set_parent(&saif0_clk, &pll0_clk);
return 0;
}
-/* This function increments the reference count on the clock and enables the
- * clock if not already enabled. The parent clock tree is recursively enabled
+/*
+ * The clk_enable/clk_disable could be called by drivers in atomic context,
+ * so they should not really hold mutex. Instead, clk_prepare/clk_unprepare
+ * can hold a mutex, as the pair will only be called in non-atomic context.
+ * Before migrating to common clk framework, we can have __clk_enable and
+ * __clk_disable called in clk_prepare/clk_unprepare with mutex held and
+ * leave clk_enable/clk_disable as the dummy functions.
*/
-int clk_enable(struct clk *clk)
+int clk_prepare(struct clk *clk)
{
int ret = 0;
return ret;
}
-EXPORT_SYMBOL(clk_enable);
+EXPORT_SYMBOL(clk_prepare);
-/* This function decrements the reference count on the clock and disables
- * the clock when reference count is 0. The parent clock tree is
- * recursively disabled
- */
-void clk_disable(struct clk *clk)
+void clk_unprepare(struct clk *clk)
{
if (clk == NULL || IS_ERR(clk))
return;
__clk_disable(clk);
mutex_unlock(&clocks_mutex);
}
+EXPORT_SYMBOL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ /* nothing to do */
+}
EXPORT_SYMBOL(clk_disable);
/* Retrieve the *current* clock rate. If the clock itself
return ret;
if (clk->usecount)
- clk_enable(parent);
+ clk_prepare_enable(parent);
mutex_lock(&clocks_mutex);
ret = clk->set_parent(clk, parent);
/* Enable fec phy clock */
clk = clk_get_sys("pll2", NULL);
if (!IS_ERR(clk))
- clk_enable(clk);
+ clk_prepare_enable(clk);
/* Power up fec phy */
ret = gpio_request(MX28EVK_FEC_PHY_POWER, "fec-phy-power");
clk = clk_get_sys("rtc", NULL);
if (!IS_ERR(clk))
- clk_enable(clk);
+ clk_prepare_enable(clk);
return 0;
}
void __init mxs_timer_init(struct clk *timer_clk, int irq)
{
- clk_enable(timer_clk);
+ clk_prepare_enable(timer_clk);
/*
* Initialize timers to a known state
bool
select HAVE_CLK
+config HAVE_CLK_PREPARE
+ bool
+
config HAVE_MACH_CLKDEV
bool
goto err_irq;
}
- ret = clk_enable(mxs_dma->clk);
+ ret = clk_prepare_enable(mxs_dma->clk);
if (ret)
goto err_clk;
dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
mxs_chan->ccw, mxs_chan->ccw_phys);
- clk_disable(mxs_dma->clk);
+ clk_disable_unprepare(mxs_dma->clk);
}
static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
{
int ret;
- ret = clk_enable(mxs_dma->clk);
+ ret = clk_prepare_enable(mxs_dma->clk);
if (ret)
goto err_out;
writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS,
mxs_dma->base + HW_APBHX_CTRL1 + MXS_SET_ADDR);
- clk_disable(mxs_dma->clk);
+ clk_disable_unprepare(mxs_dma->clk);
return 0;
ret = PTR_ERR(host->clk);
goto out_iounmap;
}
- clk_enable(host->clk);
+ clk_prepare_enable(host->clk);
mxs_mmc_reset(host);
if (host->dmach)
dma_release_channel(host->dmach);
out_clk_put:
- clk_disable(host->clk);
+ clk_disable_unprepare(host->clk);
clk_put(host->clk);
out_iounmap:
iounmap(host->base);
if (host->dmach)
dma_release_channel(host->dmach);
- clk_disable(host->clk);
+ clk_disable_unprepare(host->clk);
clk_put(host->clk);
iounmap(host->base);
ret = mmc_suspend_host(mmc);
- clk_disable(host->clk);
+ clk_disable_unprepare(host->clk);
return ret;
}
struct mxs_mmc_host *host = mmc_priv(mmc);
int ret = 0;
- clk_enable(host->clk);
+ clk_prepare_enable(host->clk);
ret = mmc_resume_host(mmc);
struct resources *r = &this->resources;
int ret;
- ret = clk_enable(r->clock);
+ ret = clk_prepare_enable(r->clock);
if (ret)
goto err_out;
ret = gpmi_reset_block(r->gpmi_regs, false);
/* Select BCH ECC. */
writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
- clk_disable(r->clock);
+ clk_disable_unprepare(r->clock);
return 0;
err_out:
return ret;
ecc_strength = bch_geo->ecc_strength >> 1;
page_size = bch_geo->page_size;
- ret = clk_enable(r->clock);
+ ret = clk_prepare_enable(r->clock);
if (ret)
goto err_out;
writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
r->bch_regs + HW_BCH_CTRL_SET);
- clk_disable(r->clock);
+ clk_disable_unprepare(r->clock);
return 0;
err_out:
return ret;
int ret;
/* Enable the clock. */
- ret = clk_enable(r->clock);
+ ret = clk_prepare_enable(r->clock);
if (ret) {
pr_err("We failed in enable the clk\n");
goto err_out;
void gpmi_end(struct gpmi_nand_data *this)
{
struct resources *r = &this->resources;
- clk_disable(r->clock);
+ clk_disable_unprepare(r->clock);
}
/* Clears a BCH interrupt. */
struct flexcan_priv *priv = netdev_priv(dev);
int err;
- clk_enable(priv->clk);
+ clk_prepare_enable(priv->clk);
err = open_candev(dev);
if (err)
out_close:
close_candev(dev);
out:
- clk_disable(priv->clk);
+ clk_disable_unprepare(priv->clk);
return err;
}
flexcan_chip_stop(dev);
free_irq(dev->irq, dev);
- clk_disable(priv->clk);
+ clk_disable_unprepare(priv->clk);
close_candev(dev);
struct flexcan_regs __iomem *regs = priv->base;
u32 reg, err;
- clk_enable(priv->clk);
+ clk_prepare_enable(priv->clk);
/* select "bus clock", chip must be disabled */
flexcan_chip_disable(priv);
out:
/* disable core and turn off clocks */
flexcan_chip_disable(priv);
- clk_disable(priv->clk);
+ clk_disable_unprepare(priv->clk);
return err;
}
ret = PTR_ERR(fep->clk);
goto failed_clk;
}
- clk_enable(fep->clk);
+ clk_prepare_enable(fep->clk);
ret = fec_enet_init(ndev);
if (ret)
fec_enet_mii_remove(fep);
failed_mii_init:
failed_init:
- clk_disable(fep->clk);
+ clk_disable_unprepare(fep->clk);
clk_put(fep->clk);
failed_clk:
for (i = 0; i < FEC_IRQ_NUM; i++) {
fec_stop(ndev);
fec_enet_mii_remove(fep);
- clk_disable(fep->clk);
+ clk_disable_unprepare(fep->clk);
clk_put(fep->clk);
iounmap(fep->hwp);
unregister_netdev(ndev);
fec_stop(ndev);
netif_device_detach(ndev);
}
- clk_disable(fep->clk);
+ clk_disable_unprepare(fep->clk);
return 0;
}
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
- clk_enable(fep->clk);
+ clk_prepare_enable(fep->clk);
if (netif_running(ndev)) {
fec_restart(ndev, fep->full_duplex);
netif_device_attach(ndev);
{
struct mxs_auart_port *s = to_auart_port(u);
- clk_enable(s->clk);
+ clk_prepare_enable(s->clk);
writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
u->membase + AUART_INTR_CLR);
- clk_disable(s->clk);
+ clk_disable_unprepare(s->clk);
}
static unsigned int mxs_auart_tx_empty(struct uart_port *u)
if (!s)
return -ENODEV;
- clk_enable(s->clk);
+ clk_prepare_enable(s->clk);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
ret = uart_set_options(&s->port, co, baud, parity, bits, flow);
- clk_disable(s->clk);
+ clk_disable_unprepare(s->clk);
return ret;
}
dev_dbg(&host->pdev->dev, "%s\n", __func__);
- clk_enable(host->clk);
+ clk_prepare_enable(host->clk);
clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
/* if it was disabled, re-enable the mode again */
writel(VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4 + REG_CLR);
- clk_disable(host->clk);
+ clk_disable_unprepare(host->clk);
host->enabled = 0;
}
line_count = fb_info->fix.smem_len / fb_info->fix.line_length;
fb_info->fix.ypanstep = 1;
- clk_enable(host->clk);
+ clk_prepare_enable(host->clk);
host->enabled = 1;
return 0;
error_register:
if (host->enabled)
- clk_disable(host->clk);
+ clk_disable_unprepare(host->clk);
fb_destroy_modelist(&fb_info->modelist);
error_init_fb:
kfree(fb_info->pseudo_palette);
}
#endif
+/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
+static inline int clk_prepare_enable(struct clk *clk)
+{
+ int ret;
+
+ ret = clk_prepare(clk);
+ if (ret)
+ return ret;
+ ret = clk_enable(clk);
+ if (ret)
+ clk_unprepare(clk);
+
+ return ret;
+}
+
+/* clk_disable_unprepare helps cases using clk_disable in non-atomic context. */
+static inline void clk_disable_unprepare(struct clk *clk)
+{
+ clk_disable(clk);
+ clk_unprepare(clk);
+}
+
/**
* clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
* This is only valid once the clock source has been enabled.
return -EBUSY;
}
- clk_disable(saif->clk);
+ clk_disable_unprepare(saif->clk);
/* disable MCLK output */
__raw_writel(BM_SAIF_CTRL_CLKGATE,
if (ret)
return ret;
- ret = clk_enable(saif->clk);
+ ret = clk_prepare_enable(saif->clk);
if (ret)
return ret;