1/*
2 * Static Memory Controller for AT32 chips
3 *
4 * Copyright (C) 2006 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#define DEBUG
11#include <linux/clk.h>
12#include <linux/err.h>
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16
17#include <asm/io.h>
18#include <asm/arch/smc.h>
19
20#include "hsmc.h"
21
22#define NR_CHIP_SELECTS 6
23
24struct hsmc {
25	void __iomem *regs;
26	struct clk *pclk;
27	struct clk *mck;
28};
29
30static struct hsmc *hsmc;
31
32int smc_set_configuration(int cs, const struct smc_config *config)
33{
34	unsigned long mul;
35	unsigned long offset;
36	u32 setup, pulse, cycle, mode;
37
38	if (!hsmc)
39		return -ENODEV;
40	if (cs >= NR_CHIP_SELECTS)
41		return -EINVAL;
42
43	/*
44	 * cycles = x / T = x * f
45	 *   = ((x * 1000000000) * ((f * 65536) / 1000000000)) / 65536
46	 *   = ((x * 1000000000) * (((f / 10000) * 65536) / 100000)) / 65536
47	 */
48	mul = (clk_get_rate(hsmc->mck) / 10000) << 16;
49	mul /= 100000;
50
51#define ns2cyc(x) ((((x) * mul) + 65535) >> 16)
52
53	setup = (HSMC_BF(NWE_SETUP, ns2cyc(config->nwe_setup))
54		 | HSMC_BF(NCS_WR_SETUP, ns2cyc(config->ncs_write_setup))
55		 | HSMC_BF(NRD_SETUP, ns2cyc(config->nrd_setup))
56		 | HSMC_BF(NCS_RD_SETUP, ns2cyc(config->ncs_read_setup)));
57	pulse = (HSMC_BF(NWE_PULSE, ns2cyc(config->nwe_pulse))
58		 | HSMC_BF(NCS_WR_PULSE, ns2cyc(config->ncs_write_pulse))
59		 | HSMC_BF(NRD_PULSE, ns2cyc(config->nrd_pulse))
60		 | HSMC_BF(NCS_RD_PULSE, ns2cyc(config->ncs_read_pulse)));
61	cycle = (HSMC_BF(NWE_CYCLE, ns2cyc(config->write_cycle))
62		 | HSMC_BF(NRD_CYCLE, ns2cyc(config->read_cycle)));
63
64	switch (config->bus_width) {
65	case 1:
66		mode = HSMC_BF(DBW, HSMC_DBW_8_BITS);
67		break;
68	case 2:
69		mode = HSMC_BF(DBW, HSMC_DBW_16_BITS);
70		break;
71	case 4:
72		mode = HSMC_BF(DBW, HSMC_DBW_32_BITS);
73		break;
74	default:
75		return -EINVAL;
76	}
77
78	switch (config->nwait_mode) {
79	case 0:
80		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_DISABLED);
81		break;
82	case 1:
83		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_RESERVED);
84		break;
85	case 2:
86		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_FROZEN);
87		break;
88	case 3:
89		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_READY);
90		break;
91	default:
92		return -EINVAL;
93	}
94
95	if (config->tdf_cycles) {
96		mode |= HSMC_BF(TDF_CYCLES, config->tdf_cycles);
97	}
98
99	if (config->nrd_controlled)
100		mode |= HSMC_BIT(READ_MODE);
101	if (config->nwe_controlled)
102		mode |= HSMC_BIT(WRITE_MODE);
103	if (config->byte_write)
104		mode |= HSMC_BIT(BAT);
105	if (config->tdf_mode)
106		mode |= HSMC_BIT(TDF_MODE);
107
108	pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n",
109		 cs, setup, pulse, cycle, mode);
110
111	offset = cs * 0x10;
112	hsmc_writel(hsmc, SETUP0 + offset, setup);
113	hsmc_writel(hsmc, PULSE0 + offset, pulse);
114	hsmc_writel(hsmc, CYCLE0 + offset, cycle);
115	hsmc_writel(hsmc, MODE0 + offset, mode);
116	hsmc_readl(hsmc, MODE0); /* I/O barrier */
117
118	return 0;
119}
120EXPORT_SYMBOL(smc_set_configuration);
121
122static int hsmc_probe(struct platform_device *pdev)
123{
124	struct resource *regs;
125	struct clk *pclk, *mck;
126	int ret;
127
128	if (hsmc)
129		return -EBUSY;
130
131	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
132	if (!regs)
133		return -ENXIO;
134	pclk = clk_get(&pdev->dev, "pclk");
135	if (IS_ERR(pclk))
136		return PTR_ERR(pclk);
137	mck = clk_get(&pdev->dev, "mck");
138	if (IS_ERR(mck)) {
139		ret = PTR_ERR(mck);
140		goto out_put_pclk;
141	}
142
143	ret = -ENOMEM;
144	hsmc = kzalloc(sizeof(struct hsmc), GFP_KERNEL);
145	if (!hsmc)
146		goto out_put_clocks;
147
148	clk_enable(pclk);
149	clk_enable(mck);
150
151	hsmc->pclk = pclk;
152	hsmc->mck = mck;
153	hsmc->regs = ioremap(regs->start, regs->end - regs->start + 1);
154	if (!hsmc->regs)
155		goto out_disable_clocks;
156
157	dev_info(&pdev->dev, "Atmel Static Memory Controller at 0x%08lx\n",
158		 (unsigned long)regs->start);
159
160	platform_set_drvdata(pdev, hsmc);
161
162	return 0;
163
164out_disable_clocks:
165	clk_disable(mck);
166	clk_disable(pclk);
167	kfree(hsmc);
168out_put_clocks:
169	clk_put(mck);
170out_put_pclk:
171	clk_put(pclk);
172	hsmc = NULL;
173	return ret;
174}
175
176static struct platform_driver hsmc_driver = {
177	.probe		= hsmc_probe,
178	.driver		= {
179		.name	= "smc",
180	},
181};
182
183static int __init hsmc_init(void)
184{
185	return platform_driver_register(&hsmc_driver);
186}
187arch_initcall(hsmc_init);
188