tc6387xb.c 5.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Toshiba TC6387XB support
 * Copyright (c) 2005 Ian Molton
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This file contains TC6387XB base support.
 *
 */

#include <linux/module.h>
#include <linux/platform_device.h>
15
#include <linux/clk.h>
16 17 18 19 20
#include <linux/err.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
#include <linux/mfd/tc6387xb.h>

I
Ian Molton 已提交
21 22 23 24
enum {
	TC6387XB_CELL_MMC,
};

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
struct tc6387xb {
	void __iomem *scr;
	struct clk *clk32k;
	struct resource rscr;
};

static struct resource tc6387xb_mmc_resources[] = {
	{
		.start = 0x800,
		.end   = 0x9ff,
		.flags = IORESOURCE_MEM,
	},
	{
		.start = 0,
		.end   = 0,
		.flags = IORESOURCE_IRQ,
	},
};

/*--------------------------------------------------------------------------*/

46 47 48
#ifdef CONFIG_PM
static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
{
49
	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
50
	struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
51 52 53

	if (pdata && pdata->suspend)
		pdata->suspend(dev);
54
	clk_disable(tc6387xb->clk32k);
55 56 57 58 59 60

	return 0;
}

static int tc6387xb_resume(struct platform_device *dev)
{
61
	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
62
	struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
63

64
	clk_enable(tc6387xb->clk32k);
65 66 67
	if (pdata && pdata->resume)
		pdata->resume(dev);

68 69 70
	tmio_core_mmc_resume(tc6387xb->scr + 0x200, 0,
		tc6387xb_mmc_resources[0].start & 0xfffe);

71 72 73 74 75 76 77 78 79
	return 0;
}
#else
#define tc6387xb_suspend  NULL
#define tc6387xb_resume   NULL
#endif

/*--------------------------------------------------------------------------*/

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state)
{
	struct platform_device *dev = to_platform_device(mmc->dev.parent);
	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);

	tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state);
}

static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
{
	struct platform_device *dev = to_platform_device(mmc->dev.parent);
	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);

	tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state);
}


97 98 99
static int tc6387xb_mmc_enable(struct platform_device *mmc)
{
	struct platform_device *dev      = to_platform_device(mmc->dev.parent);
100
	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
101

102 103 104 105
	clk_enable(tc6387xb->clk32k);

	tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0,
		tc6387xb_mmc_resources[0].start & 0xfffe);
106 107 108 109 110 111 112

	return 0;
}

static int tc6387xb_mmc_disable(struct platform_device *mmc)
{
	struct platform_device *dev      = to_platform_device(mmc->dev.parent);
113
	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
114

115
	clk_disable(tc6387xb->clk32k);
116 117 118 119

	return 0;
}

S
Samuel Ortiz 已提交
120
static struct tmio_mmc_data tc6387xb_mmc_data = {
121
	.hclk = 24000000,
122 123
	.set_pwr = tc6387xb_mmc_pwr,
	.set_clk_div = tc6387xb_mmc_clk_div,
124 125
};

126
/*--------------------------------------------------------------------------*/
127 128

static struct mfd_cell tc6387xb_cells[] = {
I
Ian Molton 已提交
129
	[TC6387XB_CELL_MMC] = {
130 131 132
		.name = "tmio-mmc",
		.enable = tc6387xb_mmc_enable,
		.disable = tc6387xb_mmc_disable,
133
		.driver_data = &tc6387xb_mmc_data,
134 135 136 137 138 139 140
		.num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
		.resources = tc6387xb_mmc_resources,
	},
};

static int tc6387xb_probe(struct platform_device *dev)
{
141
	struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
142
	struct resource *iomem, *rscr;
143
	struct clk *clk32k;
144
	struct tc6387xb *tc6387xb;
145 146 147 148
	int irq, ret;

	iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
	if (!iomem) {
149
		return -EINVAL;
150 151
	}

152 153 154 155
	tc6387xb = kzalloc(sizeof *tc6387xb, GFP_KERNEL);
	if (!tc6387xb)
		return -ENOMEM;

156 157 158 159
	ret  = platform_get_irq(dev, 0);
	if (ret >= 0)
		irq = ret;
	else
160
		goto err_no_irq;
161

162 163 164
	clk32k = clk_get(&dev->dev, "CLK_CK32K");
	if (IS_ERR(clk32k)) {
		ret = PTR_ERR(clk32k);
165 166 167 168 169 170 171 172 173 174 175
		goto err_no_clk;
	}

	rscr = &tc6387xb->rscr;
	rscr->name = "tc6387xb-core";
	rscr->start = iomem->start;
	rscr->end = iomem->start + 0xff;
	rscr->flags = IORESOURCE_MEM;

	ret = request_resource(iomem, rscr);
	if (ret)
176
		goto err_resource;
177 178 179 180 181

	tc6387xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1);
	if (!tc6387xb->scr) {
		ret = -ENOMEM;
		goto err_ioremap;
182
	}
183 184 185

	tc6387xb->clk32k = clk32k;
	platform_set_drvdata(dev, tc6387xb);
186 187 188

	if (pdata && pdata->enable)
		pdata->enable(dev);
189 190 191

	printk(KERN_INFO "Toshiba tc6387xb initialised\n");

I
Ian Molton 已提交
192 193 194 195 196
	tc6387xb_cells[TC6387XB_CELL_MMC].platform_data =
		&tc6387xb_cells[TC6387XB_CELL_MMC];
	tc6387xb_cells[TC6387XB_CELL_MMC].data_size =
		sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]);

197 198
	ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells,
			      ARRAY_SIZE(tc6387xb_cells), iomem, irq);
199 200 201 202

	if (!ret)
		return 0;

203 204
err_ioremap:
	release_resource(&tc6387xb->rscr);
205
err_resource:
206 207 208 209
	clk_put(clk32k);
err_no_clk:
err_no_irq:
	kfree(tc6387xb);
210 211 212 213 214
	return ret;
}

static int tc6387xb_remove(struct platform_device *dev)
{
215
	struct clk *clk32k = platform_get_drvdata(dev);
216

217 218 219 220
	mfd_remove_devices(&dev->dev);
	clk_disable(clk32k);
	clk_put(clk32k);
	platform_set_drvdata(dev, NULL);
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253

	return 0;
}


static struct platform_driver tc6387xb_platform_driver = {
	.driver = {
		.name		= "tc6387xb",
	},
	.probe		= tc6387xb_probe,
	.remove		= tc6387xb_remove,
	.suspend        = tc6387xb_suspend,
	.resume         = tc6387xb_resume,
};


static int __init tc6387xb_init(void)
{
	return platform_driver_register(&tc6387xb_platform_driver);
}

static void __exit tc6387xb_exit(void)
{
	platform_driver_unregister(&tc6387xb_platform_driver);
}

module_init(tc6387xb_init);
module_exit(tc6387xb_exit);

MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Molton");
MODULE_ALIAS("platform:tc6387xb");
254