summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/socfpga/clk.c163
-rw-r--r--drivers/gpio/gpio-tegra.c21
-rw-r--r--drivers/mmc/host/davinci_mmc.c88
3 files changed, 244 insertions, 28 deletions
diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c
index 2c855a6394ff..bd11315cf5ab 100644
--- a/drivers/clk/socfpga/clk.c
+++ b/drivers/clk/socfpga/clk.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2012 Altera Corporation <www.altera.com>
+ * Copyright 2011-2012 Calxeda, Inc.
+ * Copyright (C) 2012-2013 Altera Corporation <www.altera.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -11,41 +12,161 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
+ * Based from clk-highbank.c
+ *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
-#define SOCFPGA_OSC1_CLK 10000000
-#define SOCFPGA_MPU_CLK 800000000
-#define SOCFPGA_MAIN_QSPI_CLK 432000000
-#define SOCFPGA_MAIN_NAND_SDMMC_CLK 250000000
-#define SOCFPGA_S2F_USR_CLK 125000000
+/* Clock Manager offsets */
+#define CLKMGR_CTRL 0x0
+#define CLKMGR_BYPASS 0x4
-void __init socfpga_init_clocks(void)
+/* Clock bypass bits */
+#define MAINPLL_BYPASS (1<<0)
+#define SDRAMPLL_BYPASS (1<<1)
+#define SDRAMPLL_SRC_BYPASS (1<<2)
+#define PERPLL_BYPASS (1<<3)
+#define PERPLL_SRC_BYPASS (1<<4)
+
+#define SOCFPGA_PLL_BG_PWRDWN 0
+#define SOCFPGA_PLL_EXT_ENA 1
+#define SOCFPGA_PLL_PWR_DOWN 2
+#define SOCFPGA_PLL_DIVF_MASK 0x0000FFF8
+#define SOCFPGA_PLL_DIVF_SHIFT 3
+#define SOCFPGA_PLL_DIVQ_MASK 0x003F0000
+#define SOCFPGA_PLL_DIVQ_SHIFT 16
+
+extern void __iomem *clk_mgr_base_addr;
+
+struct socfpga_clk {
+ struct clk_gate hw;
+ char *parent_name;
+ char *clk_name;
+ u32 fixed_div;
+};
+#define to_socfpga_clk(p) container_of(p, struct socfpga_clk, hw.hw)
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
{
+ struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
+ unsigned long divf, divq, vco_freq, reg;
+ unsigned long bypass;
+
+ reg = readl(socfpgaclk->hw.reg);
+ bypass = readl(clk_mgr_base_addr + CLKMGR_BYPASS);
+ if (bypass & MAINPLL_BYPASS)
+ return parent_rate;
+
+ divf = (reg & SOCFPGA_PLL_DIVF_MASK) >> SOCFPGA_PLL_DIVF_SHIFT;
+ divq = (reg & SOCFPGA_PLL_DIVQ_MASK) >> SOCFPGA_PLL_DIVQ_SHIFT;
+ vco_freq = parent_rate * (divf + 1);
+ return vco_freq / (1 + divq);
+}
+
+
+static struct clk_ops clk_pll_ops = {
+ .recalc_rate = clk_pll_recalc_rate,
+};
+
+static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
+ u32 div;
+
+ if (socfpgaclk->fixed_div)
+ div = socfpgaclk->fixed_div;
+ else
+ div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
+
+ return parent_rate / div;
+}
+
+static const struct clk_ops periclk_ops = {
+ .recalc_rate = clk_periclk_recalc_rate,
+};
+
+static __init struct clk *socfpga_clk_init(struct device_node *node,
+ const struct clk_ops *ops)
+{
+ u32 reg;
struct clk *clk;
+ struct socfpga_clk *socfpga_clk;
+ const char *clk_name = node->name;
+ const char *parent_name;
+ struct clk_init_data init;
+ int rc;
+ u32 fixed_div;
+
+ rc = of_property_read_u32(node, "reg", &reg);
+ if (WARN_ON(rc))
+ return NULL;
+
+ socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
+ if (WARN_ON(!socfpga_clk))
+ return NULL;
+
+ socfpga_clk->hw.reg = clk_mgr_base_addr + reg;
+
+ rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
+ if (rc)
+ socfpga_clk->fixed_div = 0;
+ else
+ socfpga_clk->fixed_div = fixed_div;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ init.name = clk_name;
+ init.ops = ops;
+ init.flags = 0;
+ parent_name = of_clk_get_parent_name(node, 0);
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
- clk = clk_register_fixed_rate(NULL, "osc1_clk", NULL, CLK_IS_ROOT, SOCFPGA_OSC1_CLK);
- clk_register_clkdev(clk, "osc1_clk", NULL);
+ socfpga_clk->hw.hw.init = &init;
- clk = clk_register_fixed_rate(NULL, "mpu_clk", NULL, CLK_IS_ROOT, SOCFPGA_MPU_CLK);
- clk_register_clkdev(clk, "mpu_clk", NULL);
+ if (strcmp(clk_name, "main_pll") || strcmp(clk_name, "periph_pll") ||
+ strcmp(clk_name, "sdram_pll")) {
+ socfpga_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
+ clk_pll_ops.enable = clk_gate_ops.enable;
+ clk_pll_ops.disable = clk_gate_ops.disable;
+ }
- clk = clk_register_fixed_rate(NULL, "main_clk", NULL, CLK_IS_ROOT, SOCFPGA_MPU_CLK/2);
- clk_register_clkdev(clk, "main_clk", NULL);
+ clk = clk_register(NULL, &socfpga_clk->hw.hw);
+ if (WARN_ON(IS_ERR(clk))) {
+ kfree(socfpga_clk);
+ return NULL;
+ }
+ rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ return clk;
+}
- clk = clk_register_fixed_rate(NULL, "dbg_base_clk", NULL, CLK_IS_ROOT, SOCFPGA_MPU_CLK/2);
- clk_register_clkdev(clk, "dbg_base_clk", NULL);
+static void __init socfpga_pll_init(struct device_node *node)
+{
+ socfpga_clk_init(node, &clk_pll_ops);
+}
+CLK_OF_DECLARE(socfpga_pll, "altr,socfpga-pll-clock", socfpga_pll_init);
- clk = clk_register_fixed_rate(NULL, "main_qspi_clk", NULL, CLK_IS_ROOT, SOCFPGA_MAIN_QSPI_CLK);
- clk_register_clkdev(clk, "main_qspi_clk", NULL);
+static void __init socfpga_periph_init(struct device_node *node)
+{
+ socfpga_clk_init(node, &periclk_ops);
+}
+CLK_OF_DECLARE(socfpga_periph, "altr,socfpga-perip-clk", socfpga_periph_init);
- clk = clk_register_fixed_rate(NULL, "main_nand_sdmmc_clk", NULL, CLK_IS_ROOT, SOCFPGA_MAIN_NAND_SDMMC_CLK);
- clk_register_clkdev(clk, "main_nand_sdmmc_clk", NULL);
+void __init socfpga_init_clocks(void)
+{
+ struct clk *clk;
+ int ret;
- clk = clk_register_fixed_rate(NULL, "s2f_usr_clk", NULL, CLK_IS_ROOT, SOCFPGA_S2F_USR_CLK);
- clk_register_clkdev(clk, "s2f_usr_clk", NULL);
+ clk = clk_register_fixed_factor(NULL, "smp_twd", "mpuclk", 0, 1, 4);
+ ret = clk_register_clkdev(clk, NULL, "smp_twd");
+ if (ret)
+ pr_err("smp_twd alias not registered\n");
}
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 8e2155548888..dde0656ea951 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -71,6 +71,7 @@ struct tegra_gpio_bank {
u32 oe[4];
u32 int_enb[4];
u32 int_lvl[4];
+ u32 wake_enb[4];
#endif
};
@@ -332,15 +333,31 @@ static int tegra_gpio_suspend(struct device *dev)
bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio));
bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio));
bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio));
+
+ /* Enable gpio irq for wake up source */
+ tegra_gpio_writel(bank->wake_enb[p],
+ GPIO_INT_ENB(gpio));
}
}
local_irq_restore(flags);
return 0;
}
-static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable)
+static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
{
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ int gpio = d->hwirq;
+ u32 port, bit, mask;
+
+ port = GPIO_PORT(gpio);
+ bit = GPIO_BIT(gpio);
+ mask = BIT(bit);
+
+ if (enable)
+ bank->wake_enb[port] |= mask;
+ else
+ bank->wake_enb[port] &= ~mask;
+
return irq_set_irq_wake(bank->irq, enable);
}
#endif
@@ -352,7 +369,7 @@ static struct irq_chip tegra_gpio_irq_chip = {
.irq_unmask = tegra_gpio_irq_unmask,
.irq_set_type = tegra_gpio_irq_set_type,
#ifdef CONFIG_PM_SLEEP
- .irq_set_wake = tegra_gpio_wake_enable,
+ .irq_set_wake = tegra_gpio_irq_set_wake,
#endif
};
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 20636772c09b..f8a96d652e9e 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -34,6 +34,8 @@
#include <linux/dma-mapping.h>
#include <linux/edma.h>
#include <linux/mmc/mmc.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_data/mmc-davinci.h>
@@ -522,14 +524,16 @@ static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
dma_cap_set(DMA_SLAVE, mask);
host->dma_tx =
- dma_request_channel(mask, edma_filter_fn, &host->txdma);
+ dma_request_slave_channel_compat(mask, edma_filter_fn,
+ &host->txdma, mmc_dev(host->mmc), "tx");
if (!host->dma_tx) {
dev_err(mmc_dev(host->mmc), "Can't get dma_tx channel\n");
return -ENODEV;
}
host->dma_rx =
- dma_request_channel(mask, edma_filter_fn, &host->rxdma);
+ dma_request_slave_channel_compat(mask, edma_filter_fn,
+ &host->rxdma, mmc_dev(host->mmc), "rx");
if (!host->dma_rx) {
dev_err(mmc_dev(host->mmc), "Can't get dma_rx channel\n");
r = -ENODEV;
@@ -1157,16 +1161,86 @@ static void __init init_mmcsd_host(struct mmc_davinci_host *host)
mmc_davinci_reset_ctrl(host, 0);
}
-static int __init davinci_mmcsd_probe(struct platform_device *pdev)
+static struct platform_device_id davinci_mmc_devtype[] = {
+ {
+ .name = "dm6441-mmc",
+ .driver_data = MMC_CTLR_VERSION_1,
+ }, {
+ .name = "da830-mmc",
+ .driver_data = MMC_CTLR_VERSION_2,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, davinci_mmc_devtype);
+
+static const struct of_device_id davinci_mmc_dt_ids[] = {
+ {
+ .compatible = "ti,dm6441-mmc",
+ .data = &davinci_mmc_devtype[MMC_CTLR_VERSION_1],
+ },
+ {
+ .compatible = "ti,da830-mmc",
+ .data = &davinci_mmc_devtype[MMC_CTLR_VERSION_2],
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, davinci_mmc_dt_ids);
+
+static struct davinci_mmc_config
+ *mmc_parse_pdata(struct platform_device *pdev)
{
+ struct device_node *np;
struct davinci_mmc_config *pdata = pdev->dev.platform_data;
+ const struct of_device_id *match =
+ of_match_device(of_match_ptr(davinci_mmc_dt_ids), &pdev->dev);
+ u32 data;
+
+ np = pdev->dev.of_node;
+ if (!np)
+ return pdata;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Failed to allocate memory for struct davinci_mmc_config\n");
+ goto nodata;
+ }
+
+ if (match)
+ pdev->id_entry = match->data;
+
+ if (of_property_read_u32(np, "max-frequency", &pdata->max_freq))
+ dev_info(&pdev->dev, "'max-frequency' property not specified, defaulting to 25MHz\n");
+
+ of_property_read_u32(np, "bus-width", &data);
+ switch (data) {
+ case 1:
+ case 4:
+ case 8:
+ pdata->wires = data;
+ break;
+ default:
+ pdata->wires = 1;
+ dev_info(&pdev->dev, "Unsupported buswidth, defaulting to 1 bit\n");
+ }
+nodata:
+ return pdata;
+}
+
+static int __init davinci_mmcsd_probe(struct platform_device *pdev)
+{
+ struct davinci_mmc_config *pdata = NULL;
struct mmc_davinci_host *host = NULL;
struct mmc_host *mmc = NULL;
struct resource *r, *mem = NULL;
int ret = 0, irq = 0;
size_t mem_size;
+ const struct platform_device_id *id_entry;
- /* REVISIT: when we're fully converted, fail if pdata is NULL */
+ pdata = mmc_parse_pdata(pdev);
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "Couldn't get platform data\n");
+ return -ENOENT;
+ }
ret = -ENODEV;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1237,7 +1311,9 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
if (pdata && (pdata->wires == 8))
mmc->caps |= (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA);
- host->version = pdata->version;
+ id_entry = platform_get_device_id(pdev);
+ if (id_entry)
+ host->version = id_entry->driver_data;
mmc->ops = &mmc_davinci_ops;
mmc->f_min = 312500;
@@ -1406,8 +1482,10 @@ static struct platform_driver davinci_mmcsd_driver = {
.name = "davinci_mmc",
.owner = THIS_MODULE,
.pm = davinci_mmcsd_pm_ops,
+ .of_match_table = of_match_ptr(davinci_mmc_dt_ids),
},
.remove = __exit_p(davinci_mmcsd_remove),
+ .id_table = davinci_mmc_devtype,
};
static int __init davinci_mmcsd_init(void)