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