Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  * Toshiba T7L66XB core mfd support
0005  *
0006  * Copyright (c) 2005, 2007, 2008 Ian Molton
0007  * Copyright (c) 2008 Dmitry Baryshkov
0008  *
0009  * T7L66 features:
0010  *
0011  * Supported in this driver:
0012  * SD/MMC
0013  * SM/NAND flash controller
0014  *
0015  * As yet not supported
0016  * GPIO interface (on NAND pins)
0017  * Serial interface
0018  * TFT 'interface converter'
0019  * PCMCIA interface logic
0020  */
0021 
0022 #include <linux/kernel.h>
0023 #include <linux/module.h>
0024 #include <linux/err.h>
0025 #include <linux/io.h>
0026 #include <linux/slab.h>
0027 #include <linux/irq.h>
0028 #include <linux/clk.h>
0029 #include <linux/platform_device.h>
0030 #include <linux/mfd/core.h>
0031 #include <linux/mfd/tmio.h>
0032 #include <linux/mfd/t7l66xb.h>
0033 
0034 enum {
0035     T7L66XB_CELL_NAND,
0036     T7L66XB_CELL_MMC,
0037 };
0038 
0039 static const struct resource t7l66xb_mmc_resources[] = {
0040     DEFINE_RES_MEM(0x800, 0x200),
0041     DEFINE_RES_IRQ(IRQ_T7L66XB_MMC)
0042 };
0043 
0044 #define SCR_REVID   0x08        /* b Revision ID    */
0045 #define SCR_IMR     0x42        /* b Interrupt Mask */
0046 #define SCR_DEV_CTL 0xe0        /* b Device control */
0047 #define SCR_ISR     0xe1        /* b Interrupt Status   */
0048 #define SCR_GPO_OC  0xf0        /* b GPO output control */
0049 #define SCR_GPO_OS  0xf1        /* b GPO output enable  */
0050 #define SCR_GPI_S   0xf2        /* w GPI status     */
0051 #define SCR_APDC    0xf8        /* b Active pullup down ctrl */
0052 
0053 #define SCR_DEV_CTL_USB     BIT(0)  /* USB enable       */
0054 #define SCR_DEV_CTL_MMC     BIT(1)  /* MMC enable       */
0055 
0056 /*--------------------------------------------------------------------------*/
0057 
0058 struct t7l66xb {
0059     void __iomem        *scr;
0060     /* Lock to protect registers requiring read/modify/write ops. */
0061     raw_spinlock_t      lock;
0062 
0063     struct resource     rscr;
0064     struct clk      *clk48m;
0065     struct clk      *clk32k;
0066     int         irq;
0067     int         irq_base;
0068 };
0069 
0070 /*--------------------------------------------------------------------------*/
0071 
0072 static int t7l66xb_mmc_enable(struct platform_device *mmc)
0073 {
0074     struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
0075     unsigned long flags;
0076     u8 dev_ctl;
0077     int ret;
0078 
0079     ret = clk_prepare_enable(t7l66xb->clk32k);
0080     if (ret)
0081         return ret;
0082 
0083     raw_spin_lock_irqsave(&t7l66xb->lock, flags);
0084 
0085     dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
0086     dev_ctl |= SCR_DEV_CTL_MMC;
0087     tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
0088 
0089     raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
0090 
0091     tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
0092         t7l66xb_mmc_resources[0].start & 0xfffe);
0093 
0094     return 0;
0095 }
0096 
0097 static int t7l66xb_mmc_disable(struct platform_device *mmc)
0098 {
0099     struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
0100     unsigned long flags;
0101     u8 dev_ctl;
0102 
0103     raw_spin_lock_irqsave(&t7l66xb->lock, flags);
0104 
0105     dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
0106     dev_ctl &= ~SCR_DEV_CTL_MMC;
0107     tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
0108 
0109     raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
0110 
0111     clk_disable_unprepare(t7l66xb->clk32k);
0112 
0113     return 0;
0114 }
0115 
0116 static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
0117 {
0118     struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
0119 
0120     tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state);
0121 }
0122 
0123 static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
0124 {
0125     struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
0126 
0127     tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state);
0128 }
0129 
0130 /*--------------------------------------------------------------------------*/
0131 
0132 static struct tmio_mmc_data t7166xb_mmc_data = {
0133     .hclk = 24000000,
0134     .set_pwr = t7l66xb_mmc_pwr,
0135     .set_clk_div = t7l66xb_mmc_clk_div,
0136 };
0137 
0138 static const struct resource t7l66xb_nand_resources[] = {
0139     {
0140         .start  = 0xc00,
0141         .end    = 0xc07,
0142         .flags  = IORESOURCE_MEM,
0143     },
0144     {
0145         .start  = 0x0100,
0146         .end    = 0x01ff,
0147         .flags  = IORESOURCE_MEM,
0148     },
0149     {
0150         .start  = IRQ_T7L66XB_NAND,
0151         .end    = IRQ_T7L66XB_NAND,
0152         .flags  = IORESOURCE_IRQ,
0153     },
0154 };
0155 
0156 static struct mfd_cell t7l66xb_cells[] = {
0157     [T7L66XB_CELL_MMC] = {
0158         .name = "tmio-mmc",
0159         .enable = t7l66xb_mmc_enable,
0160         .disable = t7l66xb_mmc_disable,
0161         .platform_data = &t7166xb_mmc_data,
0162         .pdata_size    = sizeof(t7166xb_mmc_data),
0163         .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
0164         .resources = t7l66xb_mmc_resources,
0165     },
0166     [T7L66XB_CELL_NAND] = {
0167         .name = "tmio-nand",
0168         .num_resources = ARRAY_SIZE(t7l66xb_nand_resources),
0169         .resources = t7l66xb_nand_resources,
0170     },
0171 };
0172 
0173 /*--------------------------------------------------------------------------*/
0174 
0175 /* Handle the T7L66XB interrupt mux */
0176 static void t7l66xb_irq(struct irq_desc *desc)
0177 {
0178     struct t7l66xb *t7l66xb = irq_desc_get_handler_data(desc);
0179     unsigned int isr;
0180     unsigned int i, irq_base;
0181 
0182     irq_base = t7l66xb->irq_base;
0183 
0184     while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) &
0185                 ~tmio_ioread8(t7l66xb->scr + SCR_IMR)))
0186         for (i = 0; i < T7L66XB_NR_IRQS; i++)
0187             if (isr & (1 << i))
0188                 generic_handle_irq(irq_base + i);
0189 }
0190 
0191 static void t7l66xb_irq_mask(struct irq_data *data)
0192 {
0193     struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
0194     unsigned long           flags;
0195     u8 imr;
0196 
0197     raw_spin_lock_irqsave(&t7l66xb->lock, flags);
0198     imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
0199     imr |= 1 << (data->irq - t7l66xb->irq_base);
0200     tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
0201     raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
0202 }
0203 
0204 static void t7l66xb_irq_unmask(struct irq_data *data)
0205 {
0206     struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
0207     unsigned long flags;
0208     u8 imr;
0209 
0210     raw_spin_lock_irqsave(&t7l66xb->lock, flags);
0211     imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
0212     imr &= ~(1 << (data->irq - t7l66xb->irq_base));
0213     tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
0214     raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
0215 }
0216 
0217 static struct irq_chip t7l66xb_chip = {
0218     .name       = "t7l66xb",
0219     .irq_ack    = t7l66xb_irq_mask,
0220     .irq_mask   = t7l66xb_irq_mask,
0221     .irq_unmask = t7l66xb_irq_unmask,
0222 };
0223 
0224 /*--------------------------------------------------------------------------*/
0225 
0226 /* Install the IRQ handler */
0227 static void t7l66xb_attach_irq(struct platform_device *dev)
0228 {
0229     struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
0230     unsigned int irq, irq_base;
0231 
0232     irq_base = t7l66xb->irq_base;
0233 
0234     for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) {
0235         irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq);
0236         irq_set_chip_data(irq, t7l66xb);
0237     }
0238 
0239     irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING);
0240     irq_set_chained_handler_and_data(t7l66xb->irq, t7l66xb_irq, t7l66xb);
0241 }
0242 
0243 static void t7l66xb_detach_irq(struct platform_device *dev)
0244 {
0245     struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
0246     unsigned int irq, irq_base;
0247 
0248     irq_base = t7l66xb->irq_base;
0249 
0250     irq_set_chained_handler_and_data(t7l66xb->irq, NULL, NULL);
0251 
0252     for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) {
0253         irq_set_chip(irq, NULL);
0254         irq_set_chip_data(irq, NULL);
0255     }
0256 }
0257 
0258 /*--------------------------------------------------------------------------*/
0259 
0260 #ifdef CONFIG_PM
0261 static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
0262 {
0263     struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
0264     struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
0265 
0266     if (pdata && pdata->suspend)
0267         pdata->suspend(dev);
0268     clk_disable_unprepare(t7l66xb->clk48m);
0269 
0270     return 0;
0271 }
0272 
0273 static int t7l66xb_resume(struct platform_device *dev)
0274 {
0275     struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
0276     struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
0277     int ret;
0278 
0279     ret = clk_prepare_enable(t7l66xb->clk48m);
0280     if (ret)
0281         return ret;
0282 
0283     if (pdata && pdata->resume)
0284         pdata->resume(dev);
0285 
0286     tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
0287         t7l66xb_mmc_resources[0].start & 0xfffe);
0288 
0289     return 0;
0290 }
0291 #else
0292 #define t7l66xb_suspend NULL
0293 #define t7l66xb_resume  NULL
0294 #endif
0295 
0296 /*--------------------------------------------------------------------------*/
0297 
0298 static int t7l66xb_probe(struct platform_device *dev)
0299 {
0300     struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
0301     struct t7l66xb *t7l66xb;
0302     struct resource *iomem, *rscr;
0303     int ret;
0304 
0305     if (!pdata)
0306         return -EINVAL;
0307 
0308     iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
0309     if (!iomem)
0310         return -EINVAL;
0311 
0312     t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL);
0313     if (!t7l66xb)
0314         return -ENOMEM;
0315 
0316     raw_spin_lock_init(&t7l66xb->lock);
0317 
0318     platform_set_drvdata(dev, t7l66xb);
0319 
0320     ret = platform_get_irq(dev, 0);
0321     if (ret >= 0)
0322         t7l66xb->irq = ret;
0323     else
0324         goto err_noirq;
0325 
0326     t7l66xb->irq_base = pdata->irq_base;
0327 
0328     t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K");
0329     if (IS_ERR(t7l66xb->clk32k)) {
0330         ret = PTR_ERR(t7l66xb->clk32k);
0331         goto err_clk32k_get;
0332     }
0333 
0334     t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M");
0335     if (IS_ERR(t7l66xb->clk48m)) {
0336         ret = PTR_ERR(t7l66xb->clk48m);
0337         goto err_clk48m_get;
0338     }
0339 
0340     rscr = &t7l66xb->rscr;
0341     rscr->name = "t7l66xb-core";
0342     rscr->start = iomem->start;
0343     rscr->end = iomem->start + 0xff;
0344     rscr->flags = IORESOURCE_MEM;
0345 
0346     ret = request_resource(iomem, rscr);
0347     if (ret)
0348         goto err_request_scr;
0349 
0350     t7l66xb->scr = ioremap(rscr->start, resource_size(rscr));
0351     if (!t7l66xb->scr) {
0352         ret = -ENOMEM;
0353         goto err_ioremap;
0354     }
0355 
0356     ret = clk_prepare_enable(t7l66xb->clk48m);
0357     if (ret)
0358         goto err_clk_enable;
0359 
0360     if (pdata->enable)
0361         pdata->enable(dev);
0362 
0363     /* Mask all interrupts */
0364     tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR);
0365 
0366     printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n",
0367         dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID),
0368         (unsigned long)iomem->start, t7l66xb->irq);
0369 
0370     t7l66xb_attach_irq(dev);
0371 
0372     t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data;
0373     t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data);
0374 
0375     ret = mfd_add_devices(&dev->dev, dev->id,
0376                   t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
0377                   iomem, t7l66xb->irq_base, NULL);
0378 
0379     if (!ret)
0380         return 0;
0381 
0382     t7l66xb_detach_irq(dev);
0383     clk_disable_unprepare(t7l66xb->clk48m);
0384 err_clk_enable:
0385     iounmap(t7l66xb->scr);
0386 err_ioremap:
0387     release_resource(&t7l66xb->rscr);
0388 err_request_scr:
0389     clk_put(t7l66xb->clk48m);
0390 err_clk48m_get:
0391     clk_put(t7l66xb->clk32k);
0392 err_clk32k_get:
0393 err_noirq:
0394     kfree(t7l66xb);
0395     return ret;
0396 }
0397 
0398 static int t7l66xb_remove(struct platform_device *dev)
0399 {
0400     struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
0401 
0402     clk_disable_unprepare(t7l66xb->clk48m);
0403     clk_put(t7l66xb->clk48m);
0404     clk_disable_unprepare(t7l66xb->clk32k);
0405     clk_put(t7l66xb->clk32k);
0406     t7l66xb_detach_irq(dev);
0407     iounmap(t7l66xb->scr);
0408     release_resource(&t7l66xb->rscr);
0409     mfd_remove_devices(&dev->dev);
0410     kfree(t7l66xb);
0411 
0412     return 0;
0413 }
0414 
0415 static struct platform_driver t7l66xb_platform_driver = {
0416     .driver = {
0417         .name   = "t7l66xb",
0418     },
0419     .suspend    = t7l66xb_suspend,
0420     .resume     = t7l66xb_resume,
0421     .probe      = t7l66xb_probe,
0422     .remove     = t7l66xb_remove,
0423 };
0424 
0425 /*--------------------------------------------------------------------------*/
0426 
0427 module_platform_driver(t7l66xb_platform_driver);
0428 
0429 MODULE_DESCRIPTION("Toshiba T7L66XB core driver");
0430 MODULE_LICENSE("GPL v2");
0431 MODULE_AUTHOR("Ian Molton");
0432 MODULE_ALIAS("platform:t7l66xb");