diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt index eafcaddf0bc67..36896d2af98a2 100644 --- a/Documentation/devicetree/bindings/arm/omap/omap.txt +++ b/Documentation/devicetree/bindings/arm/omap/omap.txt @@ -24,6 +24,9 @@ Optional properties: - ti,no-reset-on-init: When present, the module should not be reset at init - ti,no-idle-on-init: When present, the module should not be idled at init - ti,no-idle: When present, the module is never allowed to idle. +- ti,deassert-hard-reset: list of hwmod and hardware reset line name pairs + (ascii strings) to be deasserted upon device instantiation. + Example: diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index 2f2eb2a193684..74fdb78a24bc6 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c @@ -128,8 +128,8 @@ static int omap_device_build_from_dt(struct platform_device *pdev) struct omap_device *od; struct omap_hwmod *oh; struct device_node *node = pdev->dev.of_node; - const char *oh_name; - int oh_cnt, i, ret = 0; + const char *oh_name, *rst_name; + int oh_cnt, dstr_cnt, i, ret = 0; bool device_active = false; oh_cnt = of_property_count_strings(node, "ti,hwmods"); @@ -180,6 +180,26 @@ static int omap_device_build_from_dt(struct platform_device *pdev) omap_device_enable(pdev); pm_runtime_set_active(&pdev->dev); } + dstr_cnt = + of_property_count_strings(node, "ti,deassert-hard-reset"); + if (dstr_cnt > 0) { + for (i = 0; i < dstr_cnt; i += 2) { + of_property_read_string_index( + node, "ti,deassert-hard-reset", i, + &oh_name); + of_property_read_string_index( + node, "ti,deassert-hard-reset", i+1, + &rst_name); + oh = omap_hwmod_lookup(oh_name); + if (!oh) { + dev_warn(&pdev->dev, + "Cannot parse deassert property for '%s'\n", + oh_name); + break; + } + omap_hwmod_deassert_hardreset(oh, rst_name); + } + } odbfd_exit1: kfree(hwmods); diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 8a15c323c030f..01d921c3aa945 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -126,10 +126,10 @@ config UIO_FSL_ELBC_GPCM_NETX5152 config UIO_PRUSS tristate "Texas Instruments PRUSS driver" - depends on ARCH_DAVINCI_DA850 + depends on ARCH_DAVINCI_DA850 || SOC_AM33XX select GENERIC_ALLOCATOR help - PRUSS driver for OMAPL138/DA850/AM18XX devices + PRUSS driver for OMAPL138/DA850/AM18XX and AM33XX devices PRUSS driver requires user space components, examples and user space driver is available from below SVN repo - you may use anonymous login diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index 818735bb8c3a7..e235e45cf098a 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,11 @@ #include #include #include +#include +#include +#include +#include +#include #define DRV_NAME "pruss_uio" #define DRV_VERSION "1.0" @@ -105,10 +111,12 @@ static void pruss_cleanup(struct device *dev, struct uio_pruss_dev *gdev) dma_free_coherent(dev, extram_pool_sz, gdev->ddr_vaddr, gdev->ddr_paddr); } +#ifdef CONFIG_ARCH_DAVINCI_DA850 if (gdev->sram_vaddr) gen_pool_free(gdev->sram_pool, gdev->sram_vaddr, sram_pool_sz); +#endif kfree(gdev->info); clk_put(gdev->pruss_clk); kfree(gdev); @@ -119,9 +127,15 @@ static int pruss_probe(struct platform_device *pdev) struct uio_info *p; struct uio_pruss_dev *gdev; struct resource *regs_prussio; + struct resource res; struct device *dev = &pdev->dev; int ret = -ENODEV, cnt = 0, len; struct uio_pruss_pdata *pdata = dev_get_platdata(dev); + struct pinctrl *pinctrl; + + int count; + struct device_node *child; + const char *pin_name; gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL); if (!gdev) @@ -132,7 +146,7 @@ static int pruss_probe(struct platform_device *pdev) kfree(gdev); return -ENOMEM; } - +#ifdef CONFIG_ARCH_DAVINCI_DA850 /* Power on PRU in case its not done as part of boot-loader */ gdev->pruss_clk = clk_get(dev, "pruss"); if (IS_ERR(gdev->pruss_clk)) { @@ -144,8 +158,25 @@ static int pruss_probe(struct platform_device *pdev) } else { clk_enable(gdev->pruss_clk); } +#endif + + if (pdev->dev.of_node) { + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (IS_ERR_VALUE(ret)) { + dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); + return ret; + } - regs_prussio = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ret = of_address_to_resource(pdev->dev.of_node, 0, &res); + if (IS_ERR_VALUE(ret)) { + dev_err(&pdev->dev, "failed to parse DT reg\n"); + return ret; + } + regs_prussio = &res; + } + else + regs_prussio = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs_prussio) { dev_err(dev, "No PRUSS I/O resource specified\n"); goto out_free; @@ -156,7 +187,47 @@ static int pruss_probe(struct platform_device *pdev) goto out_free; } - if (pdata->sram_pool) { + + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, + "pins are not configured from the driver\n"); + else{ + count = of_get_child_count(pdev->dev.of_node); + if (!count){ + dev_info(&pdev->dev, "No children\n"); + return -ENODEV; + } + // Run through all children. They have lables for easy reference. + for_each_child_of_node(pdev->dev.of_node, child){ + enum of_gpio_flags flags; + unsigned gpio; + + count = of_gpio_count(child); + + ret = of_property_count_strings(child, "pin-names"); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get pin-names\n"); + continue; + } + if(count != ret){ + dev_err(&pdev->dev, "The number of gpios (%d) does not match"\ + " the number of pin names (%d)\n", count, ret); + continue; + } + + dev_err(&pdev->dev, "Child has %u gpios\n", count); + for(cnt=0; cntdev, "Error on pin-name #%d\n", cnt); + gpio = of_get_gpio_flags(child, cnt, &flags); + ret = devm_gpio_request_one(&pdev->dev, gpio, flags, pin_name); + } + } + } + if (pdata && pdata->sram_pool) { gdev->sram_pool = pdata->sram_pool; gdev->sram_vaddr = (unsigned long)gen_pool_dma_alloc(gdev->sram_pool, @@ -181,7 +252,17 @@ static int pruss_probe(struct platform_device *pdev) goto out_free; } - gdev->pintc_base = pdata->pintc_base; + if (pdev->dev.of_node) { + ret = of_property_read_u32(pdev->dev.of_node, + "ti,pintc-offset", + &gdev->pintc_base); + if (ret < 0) { + dev_err(&pdev->dev, + "Can't parse ti,pintc-offset property\n"); + goto out_free; + } + } else + gdev->pintc_base = pdata->pintc_base; gdev->hostirq_start = platform_get_irq(pdev, 0); for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++) { @@ -189,6 +270,7 @@ static int pruss_probe(struct platform_device *pdev) p->mem[0].size = resource_size(regs_prussio); p->mem[0].memtype = UIO_MEM_PHYS; +#ifdef CONFIG_ARCH_DAVINCI_DA850 p->mem[1].addr = gdev->sram_paddr; p->mem[1].size = sram_pool_sz; p->mem[1].memtype = UIO_MEM_PHYS; @@ -196,7 +278,11 @@ static int pruss_probe(struct platform_device *pdev) p->mem[2].addr = gdev->ddr_paddr; p->mem[2].size = extram_pool_sz; p->mem[2].memtype = UIO_MEM_PHYS; - +#else + p->mem[1].addr = gdev->ddr_paddr; + p->mem[1].size = extram_pool_sz; + p->mem[1].memtype = UIO_MEM_PHYS; +#endif p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", cnt); p->version = DRV_VERSION; @@ -226,11 +312,20 @@ static int pruss_remove(struct platform_device *dev) return 0; } +static const struct of_device_id pruss_dt_ids[] = { + { .compatible = "ti,pruss-v1", .data = NULL, }, + { .compatible = "ti,pruss-v2", .data = NULL, }, + {}, +}; +MODULE_DEVICE_TABLE(of, pruss_dt_ids); + + static struct platform_driver pruss_driver = { .probe = pruss_probe, .remove = pruss_remove, .driver = { .name = DRV_NAME, + .of_match_table = pruss_dt_ids, }, };