Commit ca78476e authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Lee Jones
Browse files

mfd: Remove toshiba tmio drivers



Four separate mfd drivers are in the "tmio" family, and all of
them were used in now-removed PXA machines (eseries, tosa, and
hx4700), so the mfd drivers and all its children can be removed
as well.

Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarLee Jones <lee@kernel.org>
Link: https://lore.kernel.org/r/20230105134622.254560-19-arnd@kernel.org
parent 4414a7ab
Loading
Loading
Loading
Loading
+0 −38
Original line number Diff line number Diff line
@@ -301,15 +301,6 @@ config MFD_CS47L92
	help
	  Support for Cirrus Logic CS42L92, CS47L92 and CS47L93 Smart Codecs

config MFD_ASIC3
	bool "Compaq ASIC3"
	depends on GPIOLIB
	depends on ARM || COMPILE_TEST
	select MFD_CORE
	help
	  This driver supports the ASIC3 multifunction chip found on many
	  PDAs (mainly iPAQ and HTC based ones)

config PMIC_DA903X
	bool "Dialog Semiconductor DA9030/DA9034 PMIC Support"
	depends on I2C=y
@@ -1796,35 +1787,6 @@ config MFD_TC3589X
	  additional drivers must be enabled in order to use the
	  functionality of the device.

config MFD_TMIO
	bool
	default n

config MFD_T7L66XB
	bool "Toshiba T7L66XB"
	depends on ARM && HAVE_CLK
	select MFD_CORE
	select MFD_TMIO
	help
	  Support for Toshiba Mobile IO Controller T7L66XB

config MFD_TC6387XB
	bool "Toshiba TC6387XB"
	depends on ARM && HAVE_CLK
	select MFD_CORE
	select MFD_TMIO
	help
	  Support for Toshiba Mobile IO Controller TC6387XB

config MFD_TC6393XB
	bool "Toshiba TC6393XB"
	depends on ARM && HAVE_CLK
	select GPIOLIB
	select MFD_CORE
	select MFD_TMIO
	help
	  Support for Toshiba Mobile IO Controller TC6393XB

config MFD_TQMX86
	tristate "TQ-Systems IO controller TQMX86"
	select MFD_CORE
+0 −4
Original line number Diff line number Diff line
@@ -9,7 +9,6 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o
obj-$(CONFIG_MFD_88PM805)	+= 88pm805.o 88pm80x.o
obj-$(CONFIG_MFD_ACT8945A)	+= act8945a.o
obj-$(CONFIG_MFD_SM501)		+= sm501.o
obj-$(CONFIG_MFD_ASIC3)		+= asic3.o tmio_core.o
obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835-pm.o
obj-$(CONFIG_MFD_BCM590XX)	+= bcm590xx.o
obj-$(CONFIG_MFD_BD9571MWV)	+= bd9571mwv.o
@@ -30,9 +29,6 @@ obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o
obj-$(CONFIG_STMPE_SPI)		+= stmpe-spi.o
obj-$(CONFIG_MFD_SUN6I_PRCM)	+= sun6i-prcm.o
obj-$(CONFIG_MFD_TC3589X)	+= tc3589x.o
obj-$(CONFIG_MFD_T7L66XB)	+= t7l66xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6387XB)	+= tc6387xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6393XB)	+= tc6393xb.o tmio_core.o
obj-$(CONFIG_MFD_TQMX86)	+= tqmx86.o

obj-$(CONFIG_MFD_LOCHNAGAR)	+= lochnagar-i2c.o

drivers/mfd/asic3.c

deleted100644 → 0
+0 −1071

File deleted.

Preview size limit exceeded, changes collapsed.

drivers/mfd/t7l66xb.c

deleted100644 → 0
+0 −427
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 *
 * Toshiba T7L66XB core mfd support
 *
 * Copyright (c) 2005, 2007, 2008 Ian Molton
 * Copyright (c) 2008 Dmitry Baryshkov
 *
 * T7L66 features:
 *
 * Supported in this driver:
 * SD/MMC
 * SM/NAND flash controller
 *
 * As yet not supported
 * GPIO interface (on NAND pins)
 * Serial interface
 * TFT 'interface converter'
 * PCMCIA interface logic
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
#include <linux/mfd/t7l66xb.h>

enum {
	T7L66XB_CELL_NAND,
	T7L66XB_CELL_MMC,
};

static const struct resource t7l66xb_mmc_resources[] = {
	DEFINE_RES_MEM(0x800, 0x200),
	DEFINE_RES_IRQ(IRQ_T7L66XB_MMC)
};

#define SCR_REVID	0x08		/* b Revision ID	*/
#define SCR_IMR		0x42		/* b Interrupt Mask	*/
#define SCR_DEV_CTL	0xe0		/* b Device control	*/
#define SCR_ISR		0xe1		/* b Interrupt Status	*/
#define SCR_GPO_OC	0xf0		/* b GPO output control	*/
#define SCR_GPO_OS	0xf1		/* b GPO output enable	*/
#define SCR_GPI_S	0xf2		/* w GPI status		*/
#define SCR_APDC	0xf8		/* b Active pullup down ctrl */

#define SCR_DEV_CTL_USB		BIT(0)	/* USB enable		*/
#define SCR_DEV_CTL_MMC		BIT(1)	/* MMC enable		*/

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

struct t7l66xb {
	void __iomem		*scr;
	/* Lock to protect registers requiring read/modify/write ops. */
	raw_spinlock_t		lock;

	struct resource		rscr;
	struct clk		*clk48m;
	struct clk		*clk32k;
	int			irq;
	int			irq_base;
};

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

static int t7l66xb_mmc_enable(struct platform_device *mmc)
{
	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
	unsigned long flags;
	u8 dev_ctl;
	int ret;

	ret = clk_prepare_enable(t7l66xb->clk32k);
	if (ret)
		return ret;

	raw_spin_lock_irqsave(&t7l66xb->lock, flags);

	dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
	dev_ctl |= SCR_DEV_CTL_MMC;
	tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);

	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);

	tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
		t7l66xb_mmc_resources[0].start & 0xfffe);

	return 0;
}

static int t7l66xb_mmc_disable(struct platform_device *mmc)
{
	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
	unsigned long flags;
	u8 dev_ctl;

	raw_spin_lock_irqsave(&t7l66xb->lock, flags);

	dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
	dev_ctl &= ~SCR_DEV_CTL_MMC;
	tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);

	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);

	clk_disable_unprepare(t7l66xb->clk32k);

	return 0;
}

static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
{
	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);

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

static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
{
	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);

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

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

static struct tmio_mmc_data t7166xb_mmc_data = {
	.hclk = 24000000,
	.set_pwr = t7l66xb_mmc_pwr,
	.set_clk_div = t7l66xb_mmc_clk_div,
};

static const struct resource t7l66xb_nand_resources[] = {
	{
		.start	= 0xc00,
		.end	= 0xc07,
		.flags	= IORESOURCE_MEM,
	},
	{
		.start	= 0x0100,
		.end	= 0x01ff,
		.flags	= IORESOURCE_MEM,
	},
	{
		.start	= IRQ_T7L66XB_NAND,
		.end	= IRQ_T7L66XB_NAND,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct mfd_cell t7l66xb_cells[] = {
	[T7L66XB_CELL_MMC] = {
		.name = "tmio-mmc",
		.enable = t7l66xb_mmc_enable,
		.disable = t7l66xb_mmc_disable,
		.platform_data = &t7166xb_mmc_data,
		.pdata_size    = sizeof(t7166xb_mmc_data),
		.num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
		.resources = t7l66xb_mmc_resources,
	},
	[T7L66XB_CELL_NAND] = {
		.name = "tmio-nand",
		.num_resources = ARRAY_SIZE(t7l66xb_nand_resources),
		.resources = t7l66xb_nand_resources,
	},
};

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

/* Handle the T7L66XB interrupt mux */
static void t7l66xb_irq(struct irq_desc *desc)
{
	struct t7l66xb *t7l66xb = irq_desc_get_handler_data(desc);
	unsigned int isr;
	unsigned int i, irq_base;

	irq_base = t7l66xb->irq_base;

	while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) &
				~tmio_ioread8(t7l66xb->scr + SCR_IMR)))
		for (i = 0; i < T7L66XB_NR_IRQS; i++)
			if (isr & (1 << i))
				generic_handle_irq(irq_base + i);
}

static void t7l66xb_irq_mask(struct irq_data *data)
{
	struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
	unsigned long			flags;
	u8 imr;

	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
	imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
	imr |= 1 << (data->irq - t7l66xb->irq_base);
	tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
}

static void t7l66xb_irq_unmask(struct irq_data *data)
{
	struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
	unsigned long flags;
	u8 imr;

	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
	imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
	imr &= ~(1 << (data->irq - t7l66xb->irq_base));
	tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
}

static struct irq_chip t7l66xb_chip = {
	.name		= "t7l66xb",
	.irq_ack	= t7l66xb_irq_mask,
	.irq_mask	= t7l66xb_irq_mask,
	.irq_unmask	= t7l66xb_irq_unmask,
};

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

/* Install the IRQ handler */
static void t7l66xb_attach_irq(struct platform_device *dev)
{
	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
	unsigned int irq, irq_base;

	irq_base = t7l66xb->irq_base;

	for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) {
		irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq);
		irq_set_chip_data(irq, t7l66xb);
	}

	irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING);
	irq_set_chained_handler_and_data(t7l66xb->irq, t7l66xb_irq, t7l66xb);
}

static void t7l66xb_detach_irq(struct platform_device *dev)
{
	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
	unsigned int irq, irq_base;

	irq_base = t7l66xb->irq_base;

	irq_set_chained_handler_and_data(t7l66xb->irq, NULL, NULL);

	for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) {
		irq_set_chip(irq, NULL);
		irq_set_chip_data(irq, NULL);
	}
}

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

static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
{
	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);

	if (pdata && pdata->suspend)
		pdata->suspend(dev);
	clk_disable_unprepare(t7l66xb->clk48m);

	return 0;
}

static int t7l66xb_resume(struct platform_device *dev)
{
	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
	int ret;

	ret = clk_prepare_enable(t7l66xb->clk48m);
	if (ret)
		return ret;

	if (pdata && pdata->resume)
		pdata->resume(dev);

	tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
		t7l66xb_mmc_resources[0].start & 0xfffe);

	return 0;
}

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

static int t7l66xb_probe(struct platform_device *dev)
{
	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
	struct t7l66xb *t7l66xb;
	struct resource *iomem, *rscr;
	int ret;

	if (!pdata)
		return -EINVAL;

	iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
	if (!iomem)
		return -EINVAL;

	t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL);
	if (!t7l66xb)
		return -ENOMEM;

	raw_spin_lock_init(&t7l66xb->lock);

	platform_set_drvdata(dev, t7l66xb);

	ret = platform_get_irq(dev, 0);
	if (ret >= 0)
		t7l66xb->irq = ret;
	else
		goto err_noirq;

	t7l66xb->irq_base = pdata->irq_base;

	t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K");
	if (IS_ERR(t7l66xb->clk32k)) {
		ret = PTR_ERR(t7l66xb->clk32k);
		goto err_clk32k_get;
	}

	t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M");
	if (IS_ERR(t7l66xb->clk48m)) {
		ret = PTR_ERR(t7l66xb->clk48m);
		goto err_clk48m_get;
	}

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

	ret = request_resource(iomem, rscr);
	if (ret)
		goto err_request_scr;

	t7l66xb->scr = ioremap(rscr->start, resource_size(rscr));
	if (!t7l66xb->scr) {
		ret = -ENOMEM;
		goto err_ioremap;
	}

	ret = clk_prepare_enable(t7l66xb->clk48m);
	if (ret)
		goto err_clk_enable;

	if (pdata->enable)
		pdata->enable(dev);

	/* Mask all interrupts */
	tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR);

	printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n",
		dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID),
		(unsigned long)iomem->start, t7l66xb->irq);

	t7l66xb_attach_irq(dev);

	t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data;
	t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data);

	ret = mfd_add_devices(&dev->dev, dev->id,
			      t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
			      iomem, t7l66xb->irq_base, NULL);

	if (!ret)
		return 0;

	t7l66xb_detach_irq(dev);
	clk_disable_unprepare(t7l66xb->clk48m);
err_clk_enable:
	iounmap(t7l66xb->scr);
err_ioremap:
	release_resource(&t7l66xb->rscr);
err_request_scr:
	clk_put(t7l66xb->clk48m);
err_clk48m_get:
	clk_put(t7l66xb->clk32k);
err_clk32k_get:
err_noirq:
	kfree(t7l66xb);
	return ret;
}

static int t7l66xb_remove(struct platform_device *dev)
{
	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);

	clk_disable_unprepare(t7l66xb->clk48m);
	clk_put(t7l66xb->clk48m);
	clk_disable_unprepare(t7l66xb->clk32k);
	clk_put(t7l66xb->clk32k);
	t7l66xb_detach_irq(dev);
	iounmap(t7l66xb->scr);
	release_resource(&t7l66xb->rscr);
	mfd_remove_devices(&dev->dev);
	kfree(t7l66xb);

	return 0;
}

static struct platform_driver t7l66xb_platform_driver = {
	.driver = {
		.name	= "t7l66xb",
	},
	.suspend	= pm_sleep_ptr(t7l66xb_suspend),
	.resume		= pm_sleep_ptr(t7l66xb_resume),
	.probe		= t7l66xb_probe,
	.remove		= t7l66xb_remove,
};

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

module_platform_driver(t7l66xb_platform_driver);

MODULE_DESCRIPTION("Toshiba T7L66XB core driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Molton");
MODULE_ALIAS("platform:t7l66xb");

drivers/mfd/tc6387xb.c

deleted100644 → 0
+0 −228
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Toshiba TC6387XB support
 * Copyright (c) 2005 Ian Molton
 *
 * This file contains TC6387XB base support.
 */

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
#include <linux/mfd/tc6387xb.h>
#include <linux/slab.h>

enum {
	TC6387XB_CELL_MMC,
};

struct tc6387xb {
	void __iomem *scr;
	struct clk *clk32k;
	struct resource rscr;
};

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

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

static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
{
	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
	struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);

	if (pdata && pdata->suspend)
		pdata->suspend(dev);
	clk_disable_unprepare(tc6387xb->clk32k);

	return 0;
}

static int tc6387xb_resume(struct platform_device *dev)
{
	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
	struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);

	clk_prepare_enable(tc6387xb->clk32k);
	if (pdata && pdata->resume)
		pdata->resume(dev);

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

	return 0;
}

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

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

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

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

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


static int tc6387xb_mmc_enable(struct platform_device *mmc)
{
	struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);

	clk_prepare_enable(tc6387xb->clk32k);

	tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0,
		tc6387xb_mmc_resources[0].start & 0xfffe);

	return 0;
}

static int tc6387xb_mmc_disable(struct platform_device *mmc)
{
	struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);

	clk_disable_unprepare(tc6387xb->clk32k);

	return 0;
}

static struct tmio_mmc_data tc6387xb_mmc_data = {
	.hclk = 24000000,
	.set_pwr = tc6387xb_mmc_pwr,
	.set_clk_div = tc6387xb_mmc_clk_div,
};

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

static const struct mfd_cell tc6387xb_cells[] = {
	[TC6387XB_CELL_MMC] = {
		.name = "tmio-mmc",
		.enable = tc6387xb_mmc_enable,
		.disable = tc6387xb_mmc_disable,
		.platform_data = &tc6387xb_mmc_data,
		.pdata_size    = sizeof(tc6387xb_mmc_data),
		.num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
		.resources = tc6387xb_mmc_resources,
	},
};

static int tc6387xb_probe(struct platform_device *dev)
{
	struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
	struct resource *iomem, *rscr;
	struct clk *clk32k;
	struct tc6387xb *tc6387xb;
	int irq, ret;

	iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
	if (!iomem)
		return -EINVAL;

	tc6387xb = kzalloc(sizeof(*tc6387xb), GFP_KERNEL);
	if (!tc6387xb)
		return -ENOMEM;

	ret  = platform_get_irq(dev, 0);
	if (ret >= 0)
		irq = ret;
	else
		goto err_no_irq;

	clk32k = clk_get(&dev->dev, "CLK_CK32K");
	if (IS_ERR(clk32k)) {
		ret = PTR_ERR(clk32k);
		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)
		goto err_resource;

	tc6387xb->scr = ioremap(rscr->start, resource_size(rscr));
	if (!tc6387xb->scr) {
		ret = -ENOMEM;
		goto err_ioremap;
	}

	tc6387xb->clk32k = clk32k;
	platform_set_drvdata(dev, tc6387xb);

	if (pdata && pdata->enable)
		pdata->enable(dev);

	dev_info(&dev->dev, "Toshiba tc6387xb initialised\n");

	ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells,
			      ARRAY_SIZE(tc6387xb_cells), iomem, irq, NULL);

	if (!ret)
		return 0;

	iounmap(tc6387xb->scr);
err_ioremap:
	release_resource(&tc6387xb->rscr);
err_resource:
	clk_put(clk32k);
err_no_clk:
err_no_irq:
	kfree(tc6387xb);
	return ret;
}

static int tc6387xb_remove(struct platform_device *dev)
{
	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);

	mfd_remove_devices(&dev->dev);
	iounmap(tc6387xb->scr);
	release_resource(&tc6387xb->rscr);
	clk_disable_unprepare(tc6387xb->clk32k);
	clk_put(tc6387xb->clk32k);
	kfree(tc6387xb);

	return 0;
}


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

module_platform_driver(tc6387xb_platform_driver);

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