1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *
4  * Toshiba T7L66XB core mfd support
5  *
6  * Copyright (c) 2005, 2007, 2008 Ian Molton
7  * Copyright (c) 2008 Dmitry Baryshkov
8  *
9  * T7L66 features:
10  *
11  * Supported in this driver:
12  * SD/MMC
13  * SM/NAND flash controller
14  *
15  * As yet not supported
16  * GPIO interface (on NAND pins)
17  * Serial interface
18  * TFT 'interface converter'
19  * PCMCIA interface logic
20  */
21 
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/err.h>
25 #include <linux/io.h>
26 #include <linux/slab.h>
27 #include <linux/irq.h>
28 #include <linux/clk.h>
29 #include <linux/platform_device.h>
30 #include <linux/mfd/core.h>
31 #include <linux/mfd/tmio.h>
32 #include <linux/mfd/t7l66xb.h>
33 
34 enum {
35 	T7L66XB_CELL_NAND,
36 	T7L66XB_CELL_MMC,
37 };
38 
39 static const struct resource t7l66xb_mmc_resources[] = {
40 	DEFINE_RES_MEM(0x800, 0x200),
41 	DEFINE_RES_IRQ(IRQ_T7L66XB_MMC)
42 };
43 
44 #define SCR_REVID	0x08		/* b Revision ID	*/
45 #define SCR_IMR		0x42		/* b Interrupt Mask	*/
46 #define SCR_DEV_CTL	0xe0		/* b Device control	*/
47 #define SCR_ISR		0xe1		/* b Interrupt Status	*/
48 #define SCR_GPO_OC	0xf0		/* b GPO output control	*/
49 #define SCR_GPO_OS	0xf1		/* b GPO output enable	*/
50 #define SCR_GPI_S	0xf2		/* w GPI status		*/
51 #define SCR_APDC	0xf8		/* b Active pullup down ctrl */
52 
53 #define SCR_DEV_CTL_USB		BIT(0)	/* USB enable		*/
54 #define SCR_DEV_CTL_MMC		BIT(1)	/* MMC enable		*/
55 
56 /*--------------------------------------------------------------------------*/
57 
58 struct t7l66xb {
59 	void __iomem		*scr;
60 	/* Lock to protect registers requiring read/modify/write ops. */
61 	raw_spinlock_t		lock;
62 
63 	struct resource		rscr;
64 	struct clk		*clk48m;
65 	struct clk		*clk32k;
66 	int			irq;
67 	int			irq_base;
68 };
69 
70 /*--------------------------------------------------------------------------*/
71 
t7l66xb_mmc_enable(struct platform_device * mmc)72 static int t7l66xb_mmc_enable(struct platform_device *mmc)
73 {
74 	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
75 	unsigned long flags;
76 	u8 dev_ctl;
77 	int ret;
78 
79 	ret = clk_prepare_enable(t7l66xb->clk32k);
80 	if (ret)
81 		return ret;
82 
83 	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
84 
85 	dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
86 	dev_ctl |= SCR_DEV_CTL_MMC;
87 	tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
88 
89 	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
90 
91 	tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
92 		t7l66xb_mmc_resources[0].start & 0xfffe);
93 
94 	return 0;
95 }
96 
t7l66xb_mmc_disable(struct platform_device * mmc)97 static int t7l66xb_mmc_disable(struct platform_device *mmc)
98 {
99 	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
100 	unsigned long flags;
101 	u8 dev_ctl;
102 
103 	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
104 
105 	dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
106 	dev_ctl &= ~SCR_DEV_CTL_MMC;
107 	tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
108 
109 	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
110 
111 	clk_disable_unprepare(t7l66xb->clk32k);
112 
113 	return 0;
114 }
115 
t7l66xb_mmc_pwr(struct platform_device * mmc,int state)116 static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
117 {
118 	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
119 
120 	tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state);
121 }
122 
t7l66xb_mmc_clk_div(struct platform_device * mmc,int state)123 static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
124 {
125 	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
126 
127 	tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state);
128 }
129 
130 /*--------------------------------------------------------------------------*/
131 
132 static struct tmio_mmc_data t7166xb_mmc_data = {
133 	.hclk = 24000000,
134 	.set_pwr = t7l66xb_mmc_pwr,
135 	.set_clk_div = t7l66xb_mmc_clk_div,
136 };
137 
138 static const struct resource t7l66xb_nand_resources[] = {
139 	{
140 		.start	= 0xc00,
141 		.end	= 0xc07,
142 		.flags	= IORESOURCE_MEM,
143 	},
144 	{
145 		.start	= 0x0100,
146 		.end	= 0x01ff,
147 		.flags	= IORESOURCE_MEM,
148 	},
149 	{
150 		.start	= IRQ_T7L66XB_NAND,
151 		.end	= IRQ_T7L66XB_NAND,
152 		.flags	= IORESOURCE_IRQ,
153 	},
154 };
155 
156 static struct mfd_cell t7l66xb_cells[] = {
157 	[T7L66XB_CELL_MMC] = {
158 		.name = "tmio-mmc",
159 		.enable = t7l66xb_mmc_enable,
160 		.disable = t7l66xb_mmc_disable,
161 		.platform_data = &t7166xb_mmc_data,
162 		.pdata_size    = sizeof(t7166xb_mmc_data),
163 		.num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
164 		.resources = t7l66xb_mmc_resources,
165 	},
166 	[T7L66XB_CELL_NAND] = {
167 		.name = "tmio-nand",
168 		.num_resources = ARRAY_SIZE(t7l66xb_nand_resources),
169 		.resources = t7l66xb_nand_resources,
170 	},
171 };
172 
173 /*--------------------------------------------------------------------------*/
174 
175 /* Handle the T7L66XB interrupt mux */
t7l66xb_irq(struct irq_desc * desc)176 static void t7l66xb_irq(struct irq_desc *desc)
177 {
178 	struct t7l66xb *t7l66xb = irq_desc_get_handler_data(desc);
179 	unsigned int isr;
180 	unsigned int i, irq_base;
181 
182 	irq_base = t7l66xb->irq_base;
183 
184 	while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) &
185 				~tmio_ioread8(t7l66xb->scr + SCR_IMR)))
186 		for (i = 0; i < T7L66XB_NR_IRQS; i++)
187 			if (isr & (1 << i))
188 				generic_handle_irq(irq_base + i);
189 }
190 
t7l66xb_irq_mask(struct irq_data * data)191 static void t7l66xb_irq_mask(struct irq_data *data)
192 {
193 	struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
194 	unsigned long			flags;
195 	u8 imr;
196 
197 	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
198 	imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
199 	imr |= 1 << (data->irq - t7l66xb->irq_base);
200 	tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
201 	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
202 }
203 
t7l66xb_irq_unmask(struct irq_data * data)204 static void t7l66xb_irq_unmask(struct irq_data *data)
205 {
206 	struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
207 	unsigned long flags;
208 	u8 imr;
209 
210 	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
211 	imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
212 	imr &= ~(1 << (data->irq - t7l66xb->irq_base));
213 	tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
214 	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
215 }
216 
217 static struct irq_chip t7l66xb_chip = {
218 	.name		= "t7l66xb",
219 	.irq_ack	= t7l66xb_irq_mask,
220 	.irq_mask	= t7l66xb_irq_mask,
221 	.irq_unmask	= t7l66xb_irq_unmask,
222 };
223 
224 /*--------------------------------------------------------------------------*/
225 
226 /* Install the IRQ handler */
t7l66xb_attach_irq(struct platform_device * dev)227 static void t7l66xb_attach_irq(struct platform_device *dev)
228 {
229 	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
230 	unsigned int irq, irq_base;
231 
232 	irq_base = t7l66xb->irq_base;
233 
234 	for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) {
235 		irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq);
236 		irq_set_chip_data(irq, t7l66xb);
237 	}
238 
239 	irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING);
240 	irq_set_chained_handler_and_data(t7l66xb->irq, t7l66xb_irq, t7l66xb);
241 }
242 
t7l66xb_detach_irq(struct platform_device * dev)243 static void t7l66xb_detach_irq(struct platform_device *dev)
244 {
245 	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
246 	unsigned int irq, irq_base;
247 
248 	irq_base = t7l66xb->irq_base;
249 
250 	irq_set_chained_handler_and_data(t7l66xb->irq, NULL, NULL);
251 
252 	for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) {
253 		irq_set_chip(irq, NULL);
254 		irq_set_chip_data(irq, NULL);
255 	}
256 }
257 
258 /*--------------------------------------------------------------------------*/
259 
260 #ifdef CONFIG_PM
t7l66xb_suspend(struct platform_device * dev,pm_message_t state)261 static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
262 {
263 	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
264 	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
265 
266 	if (pdata && pdata->suspend)
267 		pdata->suspend(dev);
268 	clk_disable_unprepare(t7l66xb->clk48m);
269 
270 	return 0;
271 }
272 
t7l66xb_resume(struct platform_device * dev)273 static int t7l66xb_resume(struct platform_device *dev)
274 {
275 	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
276 	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
277 	int ret;
278 
279 	ret = clk_prepare_enable(t7l66xb->clk48m);
280 	if (ret)
281 		return ret;
282 
283 	if (pdata && pdata->resume)
284 		pdata->resume(dev);
285 
286 	tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
287 		t7l66xb_mmc_resources[0].start & 0xfffe);
288 
289 	return 0;
290 }
291 #else
292 #define t7l66xb_suspend NULL
293 #define t7l66xb_resume	NULL
294 #endif
295 
296 /*--------------------------------------------------------------------------*/
297 
t7l66xb_probe(struct platform_device * dev)298 static int t7l66xb_probe(struct platform_device *dev)
299 {
300 	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
301 	struct t7l66xb *t7l66xb;
302 	struct resource *iomem, *rscr;
303 	int ret;
304 
305 	if (!pdata)
306 		return -EINVAL;
307 
308 	iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
309 	if (!iomem)
310 		return -EINVAL;
311 
312 	t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL);
313 	if (!t7l66xb)
314 		return -ENOMEM;
315 
316 	raw_spin_lock_init(&t7l66xb->lock);
317 
318 	platform_set_drvdata(dev, t7l66xb);
319 
320 	ret = platform_get_irq(dev, 0);
321 	if (ret >= 0)
322 		t7l66xb->irq = ret;
323 	else
324 		goto err_noirq;
325 
326 	t7l66xb->irq_base = pdata->irq_base;
327 
328 	t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K");
329 	if (IS_ERR(t7l66xb->clk32k)) {
330 		ret = PTR_ERR(t7l66xb->clk32k);
331 		goto err_clk32k_get;
332 	}
333 
334 	t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M");
335 	if (IS_ERR(t7l66xb->clk48m)) {
336 		ret = PTR_ERR(t7l66xb->clk48m);
337 		goto err_clk48m_get;
338 	}
339 
340 	rscr = &t7l66xb->rscr;
341 	rscr->name = "t7l66xb-core";
342 	rscr->start = iomem->start;
343 	rscr->end = iomem->start + 0xff;
344 	rscr->flags = IORESOURCE_MEM;
345 
346 	ret = request_resource(iomem, rscr);
347 	if (ret)
348 		goto err_request_scr;
349 
350 	t7l66xb->scr = ioremap(rscr->start, resource_size(rscr));
351 	if (!t7l66xb->scr) {
352 		ret = -ENOMEM;
353 		goto err_ioremap;
354 	}
355 
356 	ret = clk_prepare_enable(t7l66xb->clk48m);
357 	if (ret)
358 		goto err_clk_enable;
359 
360 	if (pdata->enable)
361 		pdata->enable(dev);
362 
363 	/* Mask all interrupts */
364 	tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR);
365 
366 	printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n",
367 		dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID),
368 		(unsigned long)iomem->start, t7l66xb->irq);
369 
370 	t7l66xb_attach_irq(dev);
371 
372 	t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data;
373 	t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data);
374 
375 	ret = mfd_add_devices(&dev->dev, dev->id,
376 			      t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
377 			      iomem, t7l66xb->irq_base, NULL);
378 
379 	if (!ret)
380 		return 0;
381 
382 	t7l66xb_detach_irq(dev);
383 	clk_disable_unprepare(t7l66xb->clk48m);
384 err_clk_enable:
385 	iounmap(t7l66xb->scr);
386 err_ioremap:
387 	release_resource(&t7l66xb->rscr);
388 err_request_scr:
389 	clk_put(t7l66xb->clk48m);
390 err_clk48m_get:
391 	clk_put(t7l66xb->clk32k);
392 err_clk32k_get:
393 err_noirq:
394 	kfree(t7l66xb);
395 	return ret;
396 }
397 
t7l66xb_remove(struct platform_device * dev)398 static int t7l66xb_remove(struct platform_device *dev)
399 {
400 	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
401 	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
402 	int ret;
403 
404 	ret = pdata->disable(dev);
405 	clk_disable_unprepare(t7l66xb->clk48m);
406 	clk_put(t7l66xb->clk48m);
407 	clk_disable_unprepare(t7l66xb->clk32k);
408 	clk_put(t7l66xb->clk32k);
409 	t7l66xb_detach_irq(dev);
410 	iounmap(t7l66xb->scr);
411 	release_resource(&t7l66xb->rscr);
412 	mfd_remove_devices(&dev->dev);
413 	kfree(t7l66xb);
414 
415 	return ret;
416 
417 }
418 
419 static struct platform_driver t7l66xb_platform_driver = {
420 	.driver = {
421 		.name	= "t7l66xb",
422 	},
423 	.suspend	= t7l66xb_suspend,
424 	.resume		= t7l66xb_resume,
425 	.probe		= t7l66xb_probe,
426 	.remove		= t7l66xb_remove,
427 };
428 
429 /*--------------------------------------------------------------------------*/
430 
431 module_platform_driver(t7l66xb_platform_driver);
432 
433 MODULE_DESCRIPTION("Toshiba T7L66XB core driver");
434 MODULE_LICENSE("GPL v2");
435 MODULE_AUTHOR("Ian Molton");
436 MODULE_ALIAS("platform:t7l66xb");
437