Skip to content

Commit

Permalink
i2c: New ARM Versatile/Realview bus driver
Browse files Browse the repository at this point in the history
Add support for the I2C bus found on the ARM Versatile and Realview
platforms.  The I2C bus has a RTC and optionally some EEPROMs attached.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
  • Loading branch information
Russell King authored and Jean Delvare committed Dec 10, 2006
1 parent 763d9c0 commit 6b65cd7
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 0 deletions.
13 changes: 13 additions & 0 deletions arch/arm/mach-realview/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,19 @@ struct platform_device realview_smc91x_device = {
.resource = realview_smc91x_resources,
};

static struct resource realview_i2c_resource = {
.start = REALVIEW_I2C_BASE,
.end = REALVIEW_I2C_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
};

struct platform_device realview_i2c_device = {
.name = "versatile-i2c",
.id = -1,
.num_resources = 1,
.resource = &realview_i2c_resource,
};

#define REALVIEW_SYSMCI (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_MCI_OFFSET)

static unsigned int realview_mmc_status(struct device *dev)
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-realview/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ static struct amba_device name##_device = { \

extern struct platform_device realview_flash_device;
extern struct platform_device realview_smc91x_device;
extern struct platform_device realview_i2c_device;
extern struct mmc_platform_data realview_mmc0_plat_data;
extern struct mmc_platform_data realview_mmc1_plat_data;
extern struct clk realview_clcd_clk;
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-realview/realview_eb.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ static void __init realview_eb_init(void)

platform_device_register(&realview_flash_device);
platform_device_register(&realview_smc91x_device);
platform_device_register(&realview_i2c_device);

for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
Expand Down
14 changes: 14 additions & 0 deletions arch/arm/mach-versatile/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,19 @@ static struct platform_device smc91x_device = {
.resource = smc91x_resources,
};

static struct resource versatile_i2c_resource = {
.start = VERSATILE_I2C_BASE,
.end = VERSATILE_I2C_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
};

static struct platform_device versatile_i2c_device = {
.name = "versatile-i2c",
.id = -1,
.num_resources = 1,
.resource = &versatile_i2c_resource,
};

#define VERSATILE_SYSMCI (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET)

unsigned int mmc_status(struct device *dev)
Expand Down Expand Up @@ -775,6 +788,7 @@ void __init versatile_init(void)
clk_register(&versatile_clcd_clk);

platform_device_register(&versatile_flash_device);
platform_device_register(&versatile_i2c_device);
platform_device_register(&smc91x_device);

for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
Expand Down
11 changes: 11 additions & 0 deletions drivers/i2c/busses/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,17 @@ config I2C_STUB

If you don't know what to do here, definitely say N.

config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support"
depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW)
select I2C_ALGOBIT
help
Say yes if you want to support the I2C serial bus on ARMs Versatile
range of platforms.

This driver can also be built as a module. If so, the module
will be called i2c-versatile.

config I2C_VIA
tristate "VIA 82C586B"
depends on I2C && PCI && EXPERIMENTAL
Expand Down
1 change: 1 addition & 0 deletions drivers/i2c/busses/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
Expand Down
153 changes: 153 additions & 0 deletions drivers/i2c/busses/i2c-versatile.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* i2c-versatile.c
*
* Copyright (C) 2006 ARM Ltd.
* written by Russell King, Deep Blue Solutions Ltd.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/init.h>
#include <linux/platform_device.h>

#include <asm/io.h>

#define I2C_CONTROL 0x00
#define I2C_CONTROLS 0x00
#define I2C_CONTROLC 0x04
#define SCL (1 << 0)
#define SDA (1 << 1)

struct i2c_versatile {
struct i2c_adapter adap;
struct i2c_algo_bit_data algo;
void __iomem *base;
};

static void i2c_versatile_setsda(void *data, int state)
{
struct i2c_versatile *i2c = data;

writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
}

static void i2c_versatile_setscl(void *data, int state)
{
struct i2c_versatile *i2c = data;

writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
}

static int i2c_versatile_getsda(void *data)
{
struct i2c_versatile *i2c = data;
return !!(readl(i2c->base + I2C_CONTROL) & SDA);
}

static int i2c_versatile_getscl(void *data)
{
struct i2c_versatile *i2c = data;
return !!(readl(i2c->base + I2C_CONTROL) & SCL);
}

static struct i2c_algo_bit_data i2c_versatile_algo = {
.setsda = i2c_versatile_setsda,
.setscl = i2c_versatile_setscl,
.getsda = i2c_versatile_getsda,
.getscl = i2c_versatile_getscl,
.udelay = 30,
.timeout = HZ,
};

static int i2c_versatile_probe(struct platform_device *dev)
{
struct i2c_versatile *i2c;
struct resource *r;
int ret;

r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!r) {
ret = -EINVAL;
goto err_out;
}

if (!request_mem_region(r->start, r->end - r->start + 1, "versatile-i2c")) {
ret = -EBUSY;
goto err_out;
}

i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL);
if (!i2c) {
ret = -ENOMEM;
goto err_release;
}

i2c->base = ioremap(r->start, r->end - r->start + 1);
if (!i2c->base) {
ret = -ENOMEM;
goto err_free;
}

writel(SCL | SDA, i2c->base + I2C_CONTROLS);

i2c->adap.owner = THIS_MODULE;
strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name));
i2c->adap.algo_data = &i2c->algo;
i2c->adap.dev.parent = &dev->dev;
i2c->algo = i2c_versatile_algo;
i2c->algo.data = i2c;

ret = i2c_bit_add_bus(&i2c->adap);
if (ret >= 0) {
platform_set_drvdata(dev, i2c);
return 0;
}

iounmap(i2c->base);
err_free:
kfree(i2c);
err_release:
release_mem_region(r->start, r->end - r->start + 1);
err_out:
return ret;
}

static int i2c_versatile_remove(struct platform_device *dev)
{
struct i2c_versatile *i2c = platform_get_drvdata(dev);

platform_set_drvdata(dev, NULL);

i2c_del_adapter(&i2c->adap);
return 0;
}

static struct platform_driver i2c_versatile_driver = {
.probe = i2c_versatile_probe,
.remove = i2c_versatile_remove,
.driver = {
.name = "versatile-i2c",
.owner = THIS_MODULE,
},
};

static int __init i2c_versatile_init(void)
{
return platform_driver_register(&i2c_versatile_driver);
}

static void __exit i2c_versatile_exit(void)
{
platform_driver_unregister(&i2c_versatile_driver);
}

module_init(i2c_versatile_init);
module_exit(i2c_versatile_exit);

MODULE_DESCRIPTION("ARM Versatile I2C bus driver");
MODULE_LICENSE("GPL");

0 comments on commit 6b65cd7

Please sign in to comment.