forked from Minki/linux
ARM: OMAP2+: gpmc: minimal driver support
Create a minimal driver out of gpmc code. Responsibilities handled by earlier gpmc initialization is now achieved in probe. Signed-off-by: Afzal Mohammed <afzal@ti.com> Reviewed-by: Jon Hunter <jon-hunter@ti.com> [paul@pwsan.com: fixed some checkpatch messages] Signed-off-by: Paul Walmsley <paul@pwsan.com>
This commit is contained in:
parent
4be48fd53b
commit
da49687397
@ -24,6 +24,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <plat/gpmc.h>
|
||||
@ -86,6 +87,12 @@
|
||||
#define ENABLE_PREFETCH (0x1 << 7)
|
||||
#define DMA_MPU_MODE 2
|
||||
|
||||
#define GPMC_REVISION_MAJOR(l) ((l >> 4) & 0xf)
|
||||
#define GPMC_REVISION_MINOR(l) (l & 0xf)
|
||||
|
||||
#define GPMC_HAS_WR_ACCESS 0x1
|
||||
#define GPMC_HAS_WR_DATA_MUX_BUS 0x2
|
||||
|
||||
/* XXX: Only NAND irq has been considered,currently these are the only ones used
|
||||
*/
|
||||
#define GPMC_NR_IRQ 2
|
||||
@ -131,7 +138,10 @@ static struct resource gpmc_cs_mem[GPMC_CS_NUM];
|
||||
static DEFINE_SPINLOCK(gpmc_mem_lock);
|
||||
static unsigned int gpmc_cs_map; /* flag for cs which are initialized */
|
||||
static int gpmc_ecc_used = -EINVAL; /* cs using ecc engine */
|
||||
|
||||
static struct device *gpmc_dev;
|
||||
static int gpmc_irq;
|
||||
static resource_size_t phys_base, mem_size;
|
||||
static unsigned gpmc_capability;
|
||||
static void __iomem *gpmc_base;
|
||||
|
||||
static struct clk *gpmc_l3_clk;
|
||||
@ -321,10 +331,10 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
|
||||
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
|
||||
|
||||
if (cpu_is_omap34xx()) {
|
||||
if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
|
||||
if (gpmc_capability & GPMC_HAS_WR_ACCESS)
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
|
||||
}
|
||||
|
||||
/* caller is expected to have initialized CONFIG1 to cover
|
||||
* at least sync vs async
|
||||
@ -434,6 +444,20 @@ static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int gpmc_cs_delete_mem(int cs)
|
||||
{
|
||||
struct resource *res = &gpmc_cs_mem[cs];
|
||||
int r;
|
||||
|
||||
spin_lock(&gpmc_mem_lock);
|
||||
r = release_resource(&gpmc_cs_mem[cs]);
|
||||
res->start = 0;
|
||||
res->end = 0;
|
||||
spin_unlock(&gpmc_mem_lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
|
||||
{
|
||||
struct resource *res = &gpmc_cs_mem[cs];
|
||||
@ -770,7 +794,7 @@ static void gpmc_irq_noop(struct irq_data *data) { }
|
||||
|
||||
static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
|
||||
|
||||
static int gpmc_setup_irq(int gpmc_irq)
|
||||
static int gpmc_setup_irq(void)
|
||||
{
|
||||
int i;
|
||||
u32 regval;
|
||||
@ -814,7 +838,37 @@ static int gpmc_setup_irq(int gpmc_irq)
|
||||
return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
|
||||
}
|
||||
|
||||
static void __init gpmc_mem_init(void)
|
||||
static __exit int gpmc_free_irq(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (gpmc_irq)
|
||||
free_irq(gpmc_irq, NULL);
|
||||
|
||||
for (i = 0; i < GPMC_NR_IRQ; i++) {
|
||||
irq_set_handler(gpmc_client_irq[i].irq, NULL);
|
||||
irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
|
||||
irq_modify_status(gpmc_client_irq[i].irq, 0, 0);
|
||||
}
|
||||
|
||||
irq_free_descs(gpmc_irq_start, GPMC_NR_IRQ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit gpmc_mem_exit(void)
|
||||
{
|
||||
int cs;
|
||||
|
||||
for (cs = 0; cs < GPMC_CS_NUM; cs++) {
|
||||
if (!gpmc_cs_mem_enabled(cs))
|
||||
continue;
|
||||
gpmc_cs_delete_mem(cs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void __devinit gpmc_mem_init(void)
|
||||
{
|
||||
int cs;
|
||||
unsigned long boot_rom_space = 0;
|
||||
@ -841,65 +895,85 @@ static void __init gpmc_mem_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int __init gpmc_init(void)
|
||||
static __devinit int gpmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 l;
|
||||
int ret = -EINVAL;
|
||||
int gpmc_irq;
|
||||
char *ck = NULL;
|
||||
struct resource *res;
|
||||
|
||||
if (cpu_is_omap24xx()) {
|
||||
ck = "core_l3_ck";
|
||||
if (cpu_is_omap2420())
|
||||
l = OMAP2420_GPMC_BASE;
|
||||
else
|
||||
l = OMAP34XX_GPMC_BASE;
|
||||
gpmc_irq = 20 + OMAP_INTC_START;
|
||||
} else if (cpu_is_omap34xx()) {
|
||||
ck = "gpmc_fck";
|
||||
l = OMAP34XX_GPMC_BASE;
|
||||
gpmc_irq = 20 + OMAP_INTC_START;
|
||||
} else if (cpu_is_omap44xx() || soc_is_omap54xx()) {
|
||||
/* Base address and irq number are same for OMAP4/5 */
|
||||
ck = "gpmc_ck";
|
||||
l = OMAP44XX_GPMC_BASE;
|
||||
gpmc_irq = 20 + OMAP44XX_IRQ_GIC_START;
|
||||
}
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (WARN_ON(!ck))
|
||||
return ret;
|
||||
phys_base = res->start;
|
||||
mem_size = resource_size(res);
|
||||
|
||||
gpmc_l3_clk = clk_get(NULL, ck);
|
||||
if (IS_ERR(gpmc_l3_clk)) {
|
||||
printk(KERN_ERR "Could not get GPMC clock %s\n", ck);
|
||||
BUG();
|
||||
}
|
||||
|
||||
gpmc_base = ioremap(l, SZ_4K);
|
||||
gpmc_base = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!gpmc_base) {
|
||||
clk_put(gpmc_l3_clk);
|
||||
printk(KERN_ERR "Could not get GPMC register memory\n");
|
||||
BUG();
|
||||
dev_err(&pdev->dev, "error: request memory / ioremap\n");
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (res == NULL)
|
||||
dev_warn(&pdev->dev, "Failed to get resource: irq\n");
|
||||
else
|
||||
gpmc_irq = res->start;
|
||||
|
||||
gpmc_l3_clk = clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(gpmc_l3_clk)) {
|
||||
dev_err(&pdev->dev, "error: clk_get\n");
|
||||
gpmc_irq = 0;
|
||||
return PTR_ERR(gpmc_l3_clk);
|
||||
}
|
||||
|
||||
clk_prepare_enable(gpmc_l3_clk);
|
||||
|
||||
gpmc_dev = &pdev->dev;
|
||||
|
||||
l = gpmc_read_reg(GPMC_REVISION);
|
||||
printk(KERN_INFO "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
|
||||
/* Set smart idle mode and automatic L3 clock gating */
|
||||
l = gpmc_read_reg(GPMC_SYSCONFIG);
|
||||
l &= 0x03 << 3;
|
||||
l |= (0x02 << 3) | (1 << 0);
|
||||
gpmc_write_reg(GPMC_SYSCONFIG, l);
|
||||
if (GPMC_REVISION_MAJOR(l) > 0x4)
|
||||
gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
|
||||
dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
|
||||
GPMC_REVISION_MINOR(l));
|
||||
|
||||
gpmc_mem_init();
|
||||
|
||||
ret = gpmc_setup_irq(gpmc_irq);
|
||||
if (ret)
|
||||
pr_err("gpmc: irq-%d could not claim: err %d\n",
|
||||
gpmc_irq, ret);
|
||||
return ret;
|
||||
if (IS_ERR_VALUE(gpmc_setup_irq()))
|
||||
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __exit int gpmc_remove(struct platform_device *pdev)
|
||||
{
|
||||
gpmc_free_irq();
|
||||
gpmc_mem_exit();
|
||||
gpmc_dev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpmc_driver = {
|
||||
.probe = gpmc_probe,
|
||||
.remove = __devexit_p(gpmc_remove),
|
||||
.driver = {
|
||||
.name = DEVICE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static __init int gpmc_init(void)
|
||||
{
|
||||
return platform_driver_register(&gpmc_driver);
|
||||
}
|
||||
|
||||
static __exit void gpmc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&gpmc_driver);
|
||||
|
||||
}
|
||||
|
||||
postcore_initcall(gpmc_init);
|
||||
module_exit(gpmc_exit);
|
||||
|
||||
static int __init omap_gpmc_init(void)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user