tc6387xb.c 5.7 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
#include <linux/err.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
#include <linux/mfd/tc6387xb.h>
20
#include <linux/slab.h>
21

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

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
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,
	},
};

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

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

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

	return 0;
}

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

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

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

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

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

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
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);
}


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

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

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

	return 0;
}

static int tc6387xb_mmc_disable(struct platform_device *mmc)
{
	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 119 120

	return 0;
}

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

127
/*--------------------------------------------------------------------------*/
128 129

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

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

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

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

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

163 164 165
	clk32k = clk_get(&dev->dev, "CLK_CK32K");
	if (IS_ERR(clk32k)) {
		ret = PTR_ERR(clk32k);
166 167 168 169 170 171 172 173 174 175 176
		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)
177
		goto err_resource;
178 179 180 181 182

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

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

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

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

I
Ian Molton 已提交
193 194 195 196 197
	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]);

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

	if (!ret)
		return 0;

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

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

218 219 220 221
	mfd_remove_devices(&dev->dev);
	clk_disable(clk32k);
	clk_put(clk32k);
	platform_set_drvdata(dev, NULL);
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 254

	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");
255