linux/drivers/mfd/tc6387xb.c
<<
>>
Prefs
   1/*
   2 * Toshiba TC6387XB support
   3 * Copyright (c) 2005 Ian Molton
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 *
   9 * This file contains TC6387XB base support.
  10 *
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/platform_device.h>
  15#include <linux/clk.h>
  16#include <linux/err.h>
  17#include <linux/mfd/core.h>
  18#include <linux/mfd/tmio.h>
  19#include <linux/mfd/tc6387xb.h>
  20#include <linux/slab.h>
  21
  22enum {
  23        TC6387XB_CELL_MMC,
  24};
  25
  26struct tc6387xb {
  27        void __iomem *scr;
  28        struct clk *clk32k;
  29        struct resource rscr;
  30};
  31
  32static struct resource tc6387xb_mmc_resources[] = {
  33        {
  34                .start = 0x800,
  35                .end   = 0x9ff,
  36                .flags = IORESOURCE_MEM,
  37        },
  38        {
  39                .start = 0,
  40                .end   = 0,
  41                .flags = IORESOURCE_IRQ,
  42        },
  43};
  44
  45/*--------------------------------------------------------------------------*/
  46
  47#ifdef CONFIG_PM
  48static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
  49{
  50        struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
  51        struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
  52
  53        if (pdata && pdata->suspend)
  54                pdata->suspend(dev);
  55        clk_disable(tc6387xb->clk32k);
  56
  57        return 0;
  58}
  59
  60static int tc6387xb_resume(struct platform_device *dev)
  61{
  62        struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
  63        struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
  64
  65        clk_enable(tc6387xb->clk32k);
  66        if (pdata && pdata->resume)
  67                pdata->resume(dev);
  68
  69        tmio_core_mmc_resume(tc6387xb->scr + 0x200, 0,
  70                tc6387xb_mmc_resources[0].start & 0xfffe);
  71
  72        return 0;
  73}
  74#else
  75#define tc6387xb_suspend  NULL
  76#define tc6387xb_resume   NULL
  77#endif
  78
  79/*--------------------------------------------------------------------------*/
  80
  81static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state)
  82{
  83        struct platform_device *dev = to_platform_device(mmc->dev.parent);
  84        struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
  85
  86        tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state);
  87}
  88
  89static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
  90{
  91        struct platform_device *dev = to_platform_device(mmc->dev.parent);
  92        struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
  93
  94        tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state);
  95}
  96
  97
  98static int tc6387xb_mmc_enable(struct platform_device *mmc)
  99{
 100        struct platform_device *dev      = to_platform_device(mmc->dev.parent);
 101        struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
 102
 103        clk_enable(tc6387xb->clk32k);
 104
 105        tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0,
 106                tc6387xb_mmc_resources[0].start & 0xfffe);
 107
 108        return 0;
 109}
 110
 111static int tc6387xb_mmc_disable(struct platform_device *mmc)
 112{
 113        struct platform_device *dev      = to_platform_device(mmc->dev.parent);
 114        struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
 115
 116        clk_disable(tc6387xb->clk32k);
 117
 118        return 0;
 119}
 120
 121static struct tmio_mmc_data tc6387xb_mmc_data = {
 122        .hclk = 24000000,
 123        .set_pwr = tc6387xb_mmc_pwr,
 124        .set_clk_div = tc6387xb_mmc_clk_div,
 125};
 126
 127/*--------------------------------------------------------------------------*/
 128
 129static struct mfd_cell tc6387xb_cells[] = {
 130        [TC6387XB_CELL_MMC] = {
 131                .name = "tmio-mmc",
 132                .enable = tc6387xb_mmc_enable,
 133                .disable = tc6387xb_mmc_disable,
 134                .platform_data = &tc6387xb_mmc_data,
 135                .pdata_size    = sizeof(tc6387xb_mmc_data),
 136                .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
 137                .resources = tc6387xb_mmc_resources,
 138        },
 139};
 140
 141static int tc6387xb_probe(struct platform_device *dev)
 142{
 143        struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
 144        struct resource *iomem, *rscr;
 145        struct clk *clk32k;
 146        struct tc6387xb *tc6387xb;
 147        int irq, ret;
 148
 149        iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 150        if (!iomem) {
 151                return -EINVAL;
 152        }
 153
 154        tc6387xb = kzalloc(sizeof *tc6387xb, GFP_KERNEL);
 155        if (!tc6387xb)
 156                return -ENOMEM;
 157
 158        ret  = platform_get_irq(dev, 0);
 159        if (ret >= 0)
 160                irq = ret;
 161        else
 162                goto err_no_irq;
 163
 164        clk32k = clk_get(&dev->dev, "CLK_CK32K");
 165        if (IS_ERR(clk32k)) {
 166                ret = PTR_ERR(clk32k);
 167                goto err_no_clk;
 168        }
 169
 170        rscr = &tc6387xb->rscr;
 171        rscr->name = "tc6387xb-core";
 172        rscr->start = iomem->start;
 173        rscr->end = iomem->start + 0xff;
 174        rscr->flags = IORESOURCE_MEM;
 175
 176        ret = request_resource(iomem, rscr);
 177        if (ret)
 178                goto err_resource;
 179
 180        tc6387xb->scr = ioremap(rscr->start, resource_size(rscr));
 181        if (!tc6387xb->scr) {
 182                ret = -ENOMEM;
 183                goto err_ioremap;
 184        }
 185
 186        tc6387xb->clk32k = clk32k;
 187        platform_set_drvdata(dev, tc6387xb);
 188
 189        if (pdata && pdata->enable)
 190                pdata->enable(dev);
 191
 192        printk(KERN_INFO "Toshiba tc6387xb initialised\n");
 193
 194        ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells,
 195                              ARRAY_SIZE(tc6387xb_cells), iomem, irq, NULL);
 196
 197        if (!ret)
 198                return 0;
 199
 200        iounmap(tc6387xb->scr);
 201err_ioremap:
 202        release_resource(&tc6387xb->rscr);
 203err_resource:
 204        clk_put(clk32k);
 205err_no_clk:
 206err_no_irq:
 207        kfree(tc6387xb);
 208        return ret;
 209}
 210
 211static int tc6387xb_remove(struct platform_device *dev)
 212{
 213        struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
 214
 215        mfd_remove_devices(&dev->dev);
 216        iounmap(tc6387xb->scr);
 217        release_resource(&tc6387xb->rscr);
 218        clk_disable(tc6387xb->clk32k);
 219        clk_put(tc6387xb->clk32k);
 220        kfree(tc6387xb);
 221
 222        return 0;
 223}
 224
 225
 226static struct platform_driver tc6387xb_platform_driver = {
 227        .driver = {
 228                .name           = "tc6387xb",
 229        },
 230        .probe          = tc6387xb_probe,
 231        .remove         = tc6387xb_remove,
 232        .suspend        = tc6387xb_suspend,
 233        .resume         = tc6387xb_resume,
 234};
 235
 236module_platform_driver(tc6387xb_platform_driver);
 237
 238MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
 239MODULE_LICENSE("GPL v2");
 240MODULE_AUTHOR("Ian Molton");
 241MODULE_ALIAS("platform:tc6387xb");
 242
 243
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.