* [PATCH3/7] i2c: OF helpers for the i2c API
From: Jochen Friedrich @ 2008-04-11 14:09 UTC (permalink / raw)
To: Kumar Gala
Cc: linuxppc-dev list, Kernel, Linux, Scott Wood, Jean Delvare,
Linux I2C
This patch implements various helpers to support OF bindings for
the i2c API.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
---
drivers/of/Kconfig | 6 +++
drivers/of/Makefile | 1 +
drivers/of/i2c.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_i2c.h | 24 ++++++++++
4 files changed, 146 insertions(+), 0 deletions(-)
create mode 100644 drivers/of/i2c.c
create mode 100644 include/linux/of_i2c.h
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index c03072b..3cff449 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -1,3 +1,9 @@
config OF_DEVICE
def_bool y
depends on OF && (SPARC || PPC_OF)
+
+config OF_I2C
+ def_bool y
+ depends on OF && PPC_OF && I2C
+ help
+ OpenFirmware I2C accessors
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index ab9be5d..655b982 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,2 +1,3 @@
obj-y = base.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
+obj-$(CONFIG_OF_I2C) += i2c.o
diff --git a/drivers/of/i2c.c b/drivers/of/i2c.c
new file mode 100644
index 0000000..6316891
--- /dev/null
+++ b/drivers/of/i2c.c
@@ -0,0 +1,115 @@
+/*
+ * OF helpers for the I2C API
+ *
+ * Copyright (c) 2008 Jochen Friedrich <jochen@scram.de>
+ *
+ * Based on a previous patch from Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/of.h>
+
+struct i2c_driver_device {
+ char *of_device;
+ char *i2c_type;
+};
+
+static struct i2c_driver_device i2c_devices[] = {
+ { "dallas,ds1374", "rtc-ds1374" },
+};
+
+static int of_find_i2c_driver(struct device_node *node,
+ struct i2c_board_info *info)
+{
+ int i, cplen;
+ const char *compatible;
+ const char *p;
+
+ /* 1. search for exception list entry */
+ for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
+ if (!of_device_is_compatible(node, i2c_devices[i].of_device))
+ continue;
+ if (strlcpy(info->type, i2c_devices[i].i2c_type,
+ I2C_NAME_SIZE) >= I2C_NAME_SIZE)
+ return -ENOMEM;
+
+ return 0;
+ }
+
+ compatible = of_get_property(node, "compatible", &cplen);
+ if (!compatible)
+ return -ENODEV;
+
+ /* 2. search for linux,<i2c-type> entry */
+ p = compatible;
+ while (cplen > 0) {
+ if (!strncmp(p, "linux,", 6)) {
+ p += 6;
+ if (strlcpy(info->type, p,
+ I2C_NAME_SIZE) >= I2C_NAME_SIZE)
+ return -ENOMEM;
+ return 0;
+ }
+
+ i = strlen(p) + 1;
+ p += i;
+ cplen -= i;
+ }
+
+ /* 3. take fist compatible entry and strip manufacturer */
+ p = strchr(compatible, ',');
+ if (!p)
+ return -ENODEV;
+ p++;
+ if (strlcpy(info->type, p, I2C_NAME_SIZE) >= I2C_NAME_SIZE)
+ return -ENOMEM;
+ return 0;
+}
+
+void of_register_i2c_devices(struct i2c_adapter *adap,
+ struct device_node *adap_node)
+{
+ void *result;
+ struct device_node *node;
+
+ for_each_child_of_node(adap_node, node) {
+ struct i2c_board_info info = {};
+ const u32 *addr;
+ int len;
+
+ addr = of_get_property(node, "reg", &len);
+ if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
+ printk(KERN_ERR
+ "of-i2c: invalid i2c device entry\n");
+ continue;
+ }
+
+ info.irq = irq_of_parse_and_map(node, 0);
+ if (info.irq == NO_IRQ)
+ info.irq = -1;
+
+ if (of_find_i2c_driver(node, &info) < 0) {
+ irq_dispose_mapping(info.irq);
+ continue;
+ }
+
+ info.addr = *addr;
+
+ request_module(info.type);
+
+ result = i2c_new_device(adap, &info);
+ if (result == NULL) {
+ printk(KERN_ERR
+ "of-i2c: Failed to load driver for %s\n",
+ info.type);
+ irq_dispose_mapping(info.irq);
+ continue;
+ }
+ }
+}
+EXPORT_SYMBOL(of_register_i2c_devices);
diff --git a/include/linux/of_i2c.h b/include/linux/of_i2c.h
new file mode 100644
index 0000000..2e5a967
--- /dev/null
+++ b/include/linux/of_i2c.h
@@ -0,0 +1,24 @@
+/*
+ * Generic I2C API implementation for PowerPC.
+ *
+ * Copyright (c) 2008 Jochen Friedrich <jochen@scram.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_OF_I2C_H
+#define __LINUX_OF_I2C_H
+
+#include <linux/i2c.h>
+
+#ifdef CONFIG_OF_I2C
+
+void of_register_i2c_devices(struct i2c_adapter *adap,
+ struct device_node *adap_node);
+
+#endif /* CONFIG_OF_I2C */
+
+#endif /* __LINUX_OF_I2C_H */
--
1.5.4.5
^ permalink raw reply related
* Re: [PATCH 2/8] [POWERPC] fsl_lbc: implement few routines to manage FSL UPMs
From: Kumar Gala @ 2008-04-11 14:09 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev
In-Reply-To: <20080311172408.GB7727@localhost.localdomain>
On Mar 11, 2008, at 12:24 PM, Anton Vorontsov wrote:
> These will be used by the FSL UPM NAND driver.
can this be a bit more descriptive. What exactly are these functions
trying to accomplish.
>
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
> arch/powerpc/Kconfig | 5 ++
> arch/powerpc/sysdev/Makefile | 1 +
> arch/powerpc/sysdev/fsl_lbc.c | 99 ++++++++++++++++++++++++++++++++
> +++++++++
> include/asm-powerpc/fsl_lbc.h | 63 ++++++++++++++++++++++++++
> 4 files changed, 168 insertions(+), 0 deletions(-)
> create mode 100644 arch/powerpc/sysdev/fsl_lbc.c
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index ef12db0..9c68592 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -491,6 +491,11 @@ config FSL_PCI
> bool
> select PPC_INDIRECT_PCI
>
> +config FSL_LBC
> + bool
> + help
> + Freescale Localbus support
> +
> # Yes MCA RS/6000s exist but Linux-PPC does not currently support any
> config MCA
> bool
> diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/
> Makefile
> index 15f3e85..62b6ef0 100644
> --- a/arch/powerpc/sysdev/Makefile
> +++ b/arch/powerpc/sysdev/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_U3_DART) += dart_iommu.o
> obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
> obj-$(CONFIG_FSL_SOC) += fsl_soc.o
> obj-$(CONFIG_FSL_PCI) += fsl_pci.o
> +obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
> obj-$(CONFIG_RAPIDIO) += fsl_rio.o
> obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
> obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
> diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/
> fsl_lbc.c
> new file mode 100644
> index 0000000..b59f2f4
> --- /dev/null
> +++ b/arch/powerpc/sysdev/fsl_lbc.c
> @@ -0,0 +1,99 @@
> +/*
> + * Freescale UPM routines.
> + *
> + * Copyright (c) 2007-2008 MontaVista Software, Inc.
> + *
> + * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> + *
> + * This program is free software; you can redistribute it and/or
> modify
> + * it under the terms of the GNU General Public License as
> published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <asm/fsl_lbc.h>
> +
> +spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
> +
> +struct fsl_lbc_regs __iomem *fsl_lbc_regs;
> +EXPORT_SYMBOL(fsl_lbc_regs);
> +
> +static char __initdata *compat_lbc[] = {
> + "fsl,pq2-localbus",
> + "fsl,pq2pro-localbus",
> + "fsl,pq3-localbus",
> + "fsl,elbc",
> +};
> +
> +static int __init fsl_lbc_init(void)
> +{
> + struct device_node *lbus;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
> + lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
> + if (lbus)
> + goto found;
> + }
> + return -ENODEV;
> +
> +found:
> + fsl_lbc_regs = of_iomap(lbus, 0);
> + of_node_put(lbus);
> + if (!fsl_lbc_regs)
> + return -ENOMEM;
> + return 0;
> +}
> +arch_initcall(fsl_lbc_init);
> +
> +int fsl_upm_find(u32 base, struct fsl_upm *upm)
what is base?
>
> +{
> + int i;
> + __be32 br;
> + __be32 or;
> +
> + if (!fsl_lbc_regs)
> + return -ENODEV;
> +
> + for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
> + br = in_be32(&fsl_lbc_regs->bank[i].br);
> + or = in_be32(&fsl_lbc_regs->bank[i].or);
> +
> + if (br & BR_V && (br & or & BR_BA) == base)
> + goto found;
> + }
> +
> + return -ENOENT;
> +found:
> + switch (br & BR_MSEL) {
> + case BR_MS_UPMA:
> + upm->mxmr = &fsl_lbc_regs->mamr;
> + break;
> + case BR_MS_UPMB:
> + upm->mxmr = &fsl_lbc_regs->mbmr;
> + break;
> + case BR_MS_UPMC:
> + upm->mxmr = &fsl_lbc_regs->mcmr;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + switch (br & BR_PS) {
> + case BR_PS_8:
> + upm->width = 8;
> + break;
> + case BR_PS_16:
> + upm->width = 16;
> + break;
> + case BR_PS_32:
> + upm->width = 32;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
^ permalink raw reply
* [PATCH4/7] i2c: Convert PowerPC MPC i2c to of_platform_driver from platform_driver
From: Jochen Friedrich @ 2008-04-11 14:10 UTC (permalink / raw)
To: Kumar Gala
Cc: linuxppc-dev list, Kernel, Linux, Scott Wood, Jean Delvare,
Linux I2C
Based on earlier work by Jon Smirl.
Changed common name from powerpc_ to of_ per Olof's suggestion.
Convert MPC i2c driver from a platform_driver to a of_platform_driver. Add the ability to dynamically load i2c drivers based on device tree names. Routine names were changed from fsl_ to mpc_ to make them match the file name. Common code moved to of-common.* Orginal ppc driver left intact for deletion when ppc arch is removed.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
Cc: Jon Smirl <jonsmirl@gmail.com>
---
arch/powerpc/sysdev/fsl_soc.c | 123 ---------------------------------
drivers/i2c/busses/i2c-mpc.c | 150 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 144 insertions(+), 129 deletions(-)
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 2cd4ef9..6f68969 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -386,129 +386,6 @@ err:
arch_initcall(gfar_of_init);
-#ifdef CONFIG_I2C_BOARDINFO
-#include <linux/i2c.h>
-struct i2c_driver_device {
- char *of_device;
- char *i2c_type;
-};
-
-static struct i2c_driver_device i2c_devices[] __initdata = {
- {"ricoh,rs5c372a", "rs5c372a",},
- {"ricoh,rs5c372b", "rs5c372b",},
- {"ricoh,rv5c386", "rv5c386",},
- {"ricoh,rv5c387a", "rv5c387a",},
- {"dallas,ds1307", "ds1307",},
- {"dallas,ds1337", "ds1337",},
- {"dallas,ds1338", "ds1338",},
- {"dallas,ds1339", "ds1339",},
- {"dallas,ds1340", "ds1340",},
- {"stm,m41t00", "m41t00"},
- {"dallas,ds1374", "rtc-ds1374",},
-};
-
-static int __init of_find_i2c_driver(struct device_node *node,
- struct i2c_board_info *info)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
- if (!of_device_is_compatible(node, i2c_devices[i].of_device))
- continue;
- if (strlcpy(info->type, i2c_devices[i].i2c_type,
- I2C_NAME_SIZE) >= I2C_NAME_SIZE)
- return -ENOMEM;
- return 0;
- }
- return -ENODEV;
-}
-
-static void __init of_register_i2c_devices(struct device_node *adap_node,
- int bus_num)
-{
- struct device_node *node = NULL;
-
- while ((node = of_get_next_child(adap_node, node))) {
- struct i2c_board_info info = {};
- const u32 *addr;
- int len;
-
- addr = of_get_property(node, "reg", &len);
- if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
- printk(KERN_WARNING "fsl_soc.c: invalid i2c device entry\n");
- continue;
- }
-
- info.irq = irq_of_parse_and_map(node, 0);
- if (info.irq == NO_IRQ)
- info.irq = -1;
-
- if (of_find_i2c_driver(node, &info) < 0)
- continue;
-
- info.addr = *addr;
-
- i2c_register_board_info(bus_num, &info, 1);
- }
-}
-
-static int __init fsl_i2c_of_init(void)
-{
- struct device_node *np;
- unsigned int i = 0;
- struct platform_device *i2c_dev;
- int ret;
-
- for_each_compatible_node(np, NULL, "fsl-i2c") {
- struct resource r[2];
- struct fsl_i2c_platform_data i2c_data;
- const unsigned char *flags = NULL;
-
- memset(&r, 0, sizeof(r));
- memset(&i2c_data, 0, sizeof(i2c_data));
-
- ret = of_address_to_resource(np, 0, &r[0]);
- if (ret)
- goto err;
-
- of_irq_to_resource(np, 0, &r[1]);
-
- i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2);
- if (IS_ERR(i2c_dev)) {
- ret = PTR_ERR(i2c_dev);
- goto err;
- }
-
- i2c_data.device_flags = 0;
- flags = of_get_property(np, "dfsrr", NULL);
- if (flags)
- i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
-
- flags = of_get_property(np, "fsl5200-clocking", NULL);
- if (flags)
- i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
-
- ret =
- platform_device_add_data(i2c_dev, &i2c_data,
- sizeof(struct
- fsl_i2c_platform_data));
- if (ret)
- goto unreg;
-
- of_register_i2c_devices(np, i++);
- }
-
- return 0;
-
-unreg:
- platform_device_unregister(i2c_dev);
-err:
- return ret;
-}
-
-arch_initcall(fsl_i2c_of_init);
-#endif
-
#ifdef CONFIG_PPC_83xx
static int __init mpc83xx_wdt_init(void)
{
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index bbe787b..fdc4f67 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -18,20 +18,24 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/platform_device.h>
-
#include <asm/io.h>
#include <linux/fsl_devices.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#define MPC_I2C_ADDR 0x00
+#ifdef CONFIG_PPC_MERGE
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h"
+#endif
+
+#define DRV_NAME "mpc-i2c"
+
#define MPC_I2C_FDR 0x04
#define MPC_I2C_CR 0x08
#define MPC_I2C_SR 0x0c
#define MPC_I2C_DR 0x10
#define MPC_I2C_DFSRR 0x14
-#define MPC_I2C_REGION 0x20
#define CCR_MEN 0x80
#define CCR_MIEN 0x40
@@ -57,7 +61,7 @@ struct mpc_i2c {
u32 flags;
};
-static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x)
+static inline void writeccr(struct mpc_i2c *i2c, u32 x)
{
writeb(x, i2c->base + MPC_I2C_CR);
}
@@ -178,7 +182,7 @@ static void mpc_i2c_stop(struct mpc_i2c *i2c)
}
static int mpc_write(struct mpc_i2c *i2c, int target,
- const u8 * data, int length, int restart)
+ const u8 *data, int length, int restart)
{
int i, result;
unsigned timeout = i2c->adap.timeout;
@@ -209,7 +213,7 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
}
static int mpc_read(struct mpc_i2c *i2c, int target,
- u8 * data, int length, int restart)
+ u8 *data, int length, int restart)
{
unsigned timeout = i2c->adap.timeout;
int i, result;
@@ -315,6 +319,138 @@ static struct i2c_adapter mpc_ops = {
.timeout = 1,
};
+#ifdef CONFIG_PPC_MERGE
+
+struct i2c_driver_device {
+ char *of_device;
+ char *i2c_driver;
+ char *i2c_type;
+};
+
+static int mpc_i2c_probe(struct of_device *op, const struct of_device_id *match)
+{
+ int result = 0;
+ struct mpc_i2c *i2c;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (of_get_property(op->node, "dfsrr", NULL))
+ i2c->flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
+
+ if (of_device_is_compatible(op->node, "mpc5200-i2c"))
+ i2c->flags |= FSL_I2C_DEV_CLOCK_5200;
+
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->base = of_iomap(op->node, 0);
+ if (!i2c->base) {
+ printk(KERN_ERR "i2c-mpc - failed to map controller\n");
+ result = -ENOMEM;
+ goto fail_map;
+ }
+
+ i2c->irq = irq_of_parse_and_map(op->node, 0);
+ if (i2c->irq == NO_IRQ) {
+ result = -ENXIO;
+ goto fail_irq;
+ }
+
+ result = request_irq(i2c->irq, mpc_i2c_isr,
+ IRQF_SHARED, "i2c-mpc", i2c);
+ if (result < 0) {
+ printk(KERN_ERR "i2c-mpc - failed to attach interrupt\n");
+ goto fail_request;
+ }
+
+ mpc_i2c_setclock(i2c);
+
+ dev_set_drvdata(&op->dev, i2c);
+
+ i2c->adap = mpc_ops;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &op->dev;
+
+ result = i2c_add_adapter(&i2c->adap);
+ if (result < 0) {
+ printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
+ goto fail_add;
+ }
+
+ of_register_i2c_devices(&i2c->adap, op->node);
+
+ return result;
+
+ fail_add:
+ dev_set_drvdata(&op->dev, NULL);
+ free_irq(i2c->irq, i2c);
+ fail_request:
+ irq_dispose_mapping(i2c->irq);
+ fail_irq:
+ iounmap(i2c->base);
+ fail_map:
+ kfree(i2c);
+ return result;
+};
+
+static int mpc_i2c_remove(struct of_device *op)
+{
+ struct mpc_i2c *i2c = dev_get_drvdata(&op->dev);
+
+ i2c_del_adapter(&i2c->adap);
+ dev_set_drvdata(&op->dev, NULL);
+
+ if (i2c->irq != NO_IRQ)
+ free_irq(i2c->irq, i2c);
+
+ irq_dispose_mapping(i2c->irq);
+ iounmap(i2c->base);
+ kfree(i2c);
+ return 0;
+};
+
+static const struct of_device_id mpc_i2c_of_match[] = {
+ {
+ .compatible = "fsl-i2c",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
+
+
+/* Structure for a device driver */
+static struct of_platform_driver mpc_i2c_driver = {
+ .match_table = mpc_i2c_of_match,
+ .probe = mpc_i2c_probe,
+ .remove = __devexit_p(mpc_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init mpc_i2c_init(void)
+{
+ int rv;
+
+ rv = of_register_platform_driver(&mpc_i2c_driver);
+ if (rv)
+ printk(KERN_ERR DRV_NAME
+ " of_register_platform_driver failed (%i)\n", rv);
+ return rv;
+}
+
+static void __exit mpc_i2c_exit(void)
+{
+ of_unregister_platform_driver(&mpc_i2c_driver);
+}
+
+module_init(mpc_i2c_init);
+module_exit(mpc_i2c_exit);
+
+#else
+
static int fsl_i2c_probe(struct platform_device *pdev)
{
int result = 0;
@@ -415,6 +551,8 @@ static void __exit fsl_i2c_exit(void)
module_init(fsl_i2c_init);
module_exit(fsl_i2c_exit);
+#endif
+
MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
MODULE_DESCRIPTION
("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");
--
1.5.4.5
^ permalink raw reply related
* [PATCH5/7] i2c: Kill the old driver matching scheme
From: Jochen Friedrich @ 2008-04-11 14:11 UTC (permalink / raw)
To: Kumar Gala
Cc: linuxppc-dev list, Kernel, Linux, Scott Wood, Jean Delvare,
Linux I2C
Based on earlier work by Jon Smirl and Jean Delvare.
Remove the old driver_name/type scheme for i2c driver matching. Only the
standard aliasing model will be used from now on.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
Cc: Jean Delvare <khali@linux-fr.org>
Cc: Jon Smirl <jonsmirl@gmail.com>
---
drivers/i2c/i2c-core.c | 35 +++++++++++++----------------------
include/linux/i2c.h | 9 ++-------
2 files changed, 15 insertions(+), 29 deletions(-)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 8879acb..874638e 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -74,10 +74,7 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
- /* new style drivers use the same kind of driver matching policy
- * as platform devices or SPI: compare device and driver IDs.
- */
- return strcmp(client->driver_name, drv->name) == 0;
+ return 0;
}
#ifdef CONFIG_HOTPLUG
@@ -91,14 +88,9 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
if (dev->driver)
return 0;
- if (client->driver_name[0]) {
- if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
- return -ENOMEM;
- } else {
- if (add_uevent_var(env, "MODALIAS=%s%s",
- I2C_MODULE_PREFIX, client->name))
- return -ENOMEM;
- }
+ if (add_uevent_var(env, "MODALIAS=%s%s",
+ I2C_MODULE_PREFIX, client->name))
+ return -ENOMEM;
dev_dbg(dev, "uevent\n");
return 0;
}
@@ -206,9 +198,7 @@ static ssize_t show_client_name(struct device *dev, struct device_attribute *att
static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
- return client->driver_name[0]
- ? sprintf(buf, "%s\n", client->driver_name)
- : sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
+ return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
}
static struct device_attribute i2c_dev_attrs[] = {
@@ -282,8 +272,6 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->addr = info->addr;
client->irq = info->irq;
- strlcpy(client->driver_name, info->driver_name,
- sizeof(client->driver_name));
strlcpy(client->name, info->type, sizeof(client->name));
/* a new style driver may be bound to this device when we
@@ -326,6 +314,11 @@ void i2c_unregister_device(struct i2c_client *client)
}
EXPORT_SYMBOL_GPL(i2c_unregister_device);
+static const struct i2c_device_id dummy_id[] = {
+ { "dummy", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, dummy_id);
static int dummy_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -342,13 +335,13 @@ static struct i2c_driver dummy_driver = {
.driver.name = "dummy",
.probe = dummy_probe,
.remove = dummy_remove,
+ .id_table = dummy_id,
};
/**
* i2c_new_dummy - return a new i2c device bound to a dummy driver
* @adapter: the adapter managing the device
* @address: seven bit address to be used
- * @type: optional label used for i2c_client.name
* Context: can sleep
*
* This returns an I2C client bound to the "dummy" driver, intended for use
@@ -364,15 +357,13 @@ static struct i2c_driver dummy_driver = {
* i2c_unregister_device(); or NULL to indicate an error.
*/
struct i2c_client *
-i2c_new_dummy(struct i2c_adapter *adapter, u16 address, const char *type)
+i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
{
struct i2c_board_info info = {
- .driver_name = "dummy",
+ .type = "dummy",
.addr = address,
};
- if (type)
- strlcpy(info.type, type, sizeof info.type);
return i2c_new_device(adapter, &info);
}
EXPORT_SYMBOL_GPL(i2c_new_dummy);
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 01ad5db..4eec279 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -155,8 +155,6 @@ struct i2c_driver {
* @driver: device's driver, hence pointer to access routines
* @dev: Driver model device node for the slave.
* @irq: indicates the IRQ generated by this device (if any)
- * @driver_name: Identifies new-style driver used with this device; also
- * used as the module name for hotplug/coldplug modprobe support.
* @list: list of active/busy clients (DEPRECATED)
* @released: used to synchronize client releases & detaches and references
*
@@ -174,7 +172,6 @@ struct i2c_client {
struct i2c_driver *driver; /* and our access routines */
struct device dev; /* the device structure */
int irq; /* irq issued by device (or -1) */
- char driver_name[KOBJ_NAME_LEN];
struct list_head list; /* DEPRECATED */
struct completion released;
};
@@ -200,8 +197,7 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
/**
* struct i2c_board_info - template for device creation
- * @driver_name: identifies the driver to be bound to the device
- * @type: optional chip type information, to initialize i2c_client.name
+ * @type: chip type, to initialize i2c_client.name
* @flags: to initialize i2c_client.flags
* @addr: stored in i2c_client.addr
* @platform_data: stored in i2c_client.dev.platform_data
@@ -220,7 +216,6 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
* with the adapter already known.
*/
struct i2c_board_info {
- char driver_name[KOBJ_NAME_LEN];
char type[I2C_NAME_SIZE];
unsigned short flags;
unsigned short addr;
@@ -262,7 +257,7 @@ i2c_new_probed_device(struct i2c_adapter *adap,
* client handles for the extra addresses.
*/
extern struct i2c_client *
-i2c_new_dummy(struct i2c_adapter *adap, u16 address, const char *type);
+i2c_new_dummy(struct i2c_adapter *adap, u16 address);
extern void i2c_unregister_device(struct i2c_client *);
--
1.5.4.5
^ permalink raw reply related
* [PATCH6/7] i2c: adds support for i2c bus on Freescale CPM1/CPM2 controllers
From: Jochen Friedrich @ 2008-04-11 14:11 UTC (permalink / raw)
To: Kumar Gala
Cc: linuxppc-dev list, Kernel, Linux, Scott Wood, Jean Delvare,
Linux I2C
This driver uses the port of 2.4 code from Vitaly Bordug
<vitb@kernel.crashing.org> and the actual algorithm used by the i2c
driver of the DBox code on cvs.tuxboc.org from Felix Domke
(tmbinc@gmx.net) and Gillem (htoa@gmx.net) converted to an
of_platform_driver. Tested on CPM1 (MPC823 on dbox2 hardware) and
CPM2 (MPC8272).
Signed-off-by: Jochen Friedrich <jochen@scram.de>
---
drivers/i2c/busses/Kconfig | 10 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-cpm.c | 728 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 739 insertions(+), 0 deletions(-)
create mode 100644 drivers/i2c/busses/i2c-cpm.c
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 5fa9c3c..5c4f270 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -114,6 +114,16 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
help
The unit of the TWI clock is kHz.
+config I2C_CPM
+ tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
+ depends on (CPM1 || CPM2) && PPC_OF
+ help
+ This supports the use of the I2C interface on Freescale
+ processors with CPM1 or CPM2.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-cpm.
+
config I2C_DAVINCI
tristate "DaVinci I2C driver"
depends on ARCH_DAVINCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ea7068f..1291e2b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
new file mode 100644
index 0000000..e6e8317
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -0,0 +1,728 @@
+/*
+ * Freescale CPM1/CPM2 I2C interface.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * moved into proper i2c interface;
+ * Brad Parker (brad@heeltoe.com)
+ *
+ * (C) 2007 Montavista Software, Inc.
+ * Vitaly Bordug <vitb@kernel.crashing.org>
+ *
+ * Parts from dbox2_i2c.c (cvs.tuxbox.org)
+ * (C) 2000-2001 Felix Domke (tmbinc@gmx.net), Gillem (htoa@gmx.net)
+ *
+ * Converted to of_platform_device. Renamed to i2c-cpm.c.
+ * (C) 2007,2008 Jochen Friedrich <jochen@scram.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/stddef.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/cpm.h>
+
+/* Try to define this if you have an older CPU (earlier than rev D4) */
+/* However, better use a GPIO based bitbang driver in this case :/ */
+#undef I2C_CHIP_ERRATA
+
+#define CPM_MAX_READ 513
+#define CPM_MAXBD 4
+
+#define CPM_CR_INIT_TRX (0x00)
+#define CPM_CR_CLOSE_RX_BD (0x07)
+
+#define I2C_EB (0x10) /* Big endian mode */
+#define I2C_EB_CPM2 (0x30) /* Big endian mode, memory snoop */
+
+#define DPRAM_BASE ((u8 __iomem __force *)cpm_muram_addr(0))
+
+/* I2C parameter RAM. */
+struct i2c_ram {
+ ushort rbase; /* Rx Buffer descriptor base address */
+ ushort tbase; /* Tx Buffer descriptor base address */
+ u_char rfcr; /* Rx function code */
+ u_char tfcr; /* Tx function code */
+ ushort mrblr; /* Max receive buffer length */
+ uint rstate; /* Internal */
+ uint rdp; /* Internal */
+ ushort rbptr; /* Rx Buffer descriptor pointer */
+ ushort rbc; /* Internal */
+ uint rxtmp; /* Internal */
+ uint tstate; /* Internal */
+ uint tdp; /* Internal */
+ ushort tbptr; /* Tx Buffer descriptor pointer */
+ ushort tbc; /* Internal */
+ uint txtmp; /* Internal */
+ char res1[4]; /* Reserved */
+ ushort rpbase; /* Relocation pointer */
+ char res2[2]; /* Reserved */
+};
+
+/* I2C Registers */
+struct i2c_reg {
+ u8 i2mod;
+ u8 res1[3];
+ u8 i2add;
+ u8 res2[3];
+ u8 i2brg;
+ u8 res3[3];
+ u8 i2com;
+ u8 res4[3];
+ u8 i2cer;
+ u8 res5[3];
+ u8 i2cmr;
+};
+
+struct cpm_i2c {
+ char *base;
+ struct of_device *ofdev;
+ struct i2c_adapter adap;
+ uint dp_addr;
+ int version; /* CPM1=1, CPM2=2 */
+ int irq;
+ int cp_command;
+ struct i2c_reg __iomem *i2c_reg;
+ struct i2c_ram __iomem *i2c_ram;
+ u16 i2c_addr;
+ wait_queue_head_t i2c_wait;
+ struct mutex i2c_mutex; /* Protects struct i2c_ram */
+ cbd_t __iomem *tbase;
+ cbd_t __iomem *rbase;
+ u_char *txbuf[CPM_MAXBD];
+ u_char *rxbuf[CPM_MAXBD];
+ u32 txdma[CPM_MAXBD];
+ u32 rxdma[CPM_MAXBD];
+};
+
+static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id)
+{
+ struct cpm_i2c *cpm;
+ struct i2c_reg __iomem *i2c_reg;
+ struct i2c_adapter *adap = dev_id;
+ int i;
+
+ cpm = i2c_get_adapdata(dev_id);
+ i2c_reg = cpm->i2c_reg;
+
+ /* Clear interrupt. */
+ i = in_8(&i2c_reg->i2cer);
+ out_8(&i2c_reg->i2cer, i);
+
+ dev_dbg(&adap->dev, "Interrupt: %x\n", i);
+
+ /* Get me going again. */
+ wake_up_interruptible(&cpm->i2c_wait);
+
+ return i ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void cpm_reset_i2c_params(struct cpm_i2c *cpm)
+{
+ struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
+
+ /* Set up the IIC parameters in the parameter ram. */
+ out_be16(&i2c_ram->tbase, (u8 __iomem *)cpm->tbase - DPRAM_BASE);
+ out_be16(&i2c_ram->rbase, (u8 __iomem *)cpm->rbase - DPRAM_BASE);
+
+ if (cpm->version == 1) {
+ out_8(&i2c_ram->tfcr, I2C_EB);
+ out_8(&i2c_ram->rfcr, I2C_EB);
+ } else {
+ out_8(&i2c_ram->tfcr, I2C_EB_CPM2);
+ out_8(&i2c_ram->rfcr, I2C_EB_CPM2);
+ }
+
+ out_be16(&i2c_ram->mrblr, CPM_MAX_READ);
+
+ out_be32(&i2c_ram->rstate, 0);
+ out_be32(&i2c_ram->rdp, 0);
+ out_be16(&i2c_ram->rbptr, 0);
+ out_be16(&i2c_ram->rbc, 0);
+ out_be32(&i2c_ram->rxtmp, 0);
+ out_be32(&i2c_ram->tstate, 0);
+ out_be32(&i2c_ram->tdp, 0);
+ out_be16(&i2c_ram->tbptr, 0);
+ out_be16(&i2c_ram->tbc, 0);
+ out_be32(&i2c_ram->txtmp, 0);
+}
+
+static void cpm_i2c_force_close(struct i2c_adapter *adap)
+{
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+ struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
+
+ dev_dbg(&adap->dev, "cpm_i2c_force_close()\n");
+
+ cpm_command(cpm->cp_command, CPM_CR_CLOSE_RX_BD);
+
+ out_8(&i2c_reg->i2cmr, 0x00); /* Disable all interrupts */
+ out_8(&i2c_reg->i2cer, 0xff);
+}
+
+static void cpm_i2c_parse_message(struct i2c_adapter *adap,
+ struct i2c_msg *pmsg, int num, int tx, int rx)
+{
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+ u_char addr;
+ u_char *tb;
+ u_char *rb;
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+
+ tbdf = cpm->tbase + tx;
+ rbdf = cpm->rbase + rx;
+
+ addr = pmsg->addr << 1;
+ if (pmsg->flags & I2C_M_RD)
+ addr |= 1;
+
+ tb = cpm->txbuf[tx];
+ rb = cpm->rxbuf[rx];
+
+ /* Align read buffer */
+ rb = (u_char *) (((ulong) rb + 1) & ~1);
+
+ tb[0] = addr; /* Device address byte w/rw flag */
+
+ out_be16(&tbdf->cbd_datlen, pmsg->len + 1);
+ out_be16(&tbdf->cbd_sc, 0);
+
+ if (!(pmsg->flags & I2C_M_NOSTART))
+ setbits16(&tbdf->cbd_sc, BD_I2C_START);
+
+ if (tx + 1 == num)
+ setbits16(&tbdf->cbd_sc, BD_SC_LAST | BD_SC_WRAP);
+
+ if (pmsg->flags & I2C_M_RD) {
+ /*
+ * To read, we need an empty buffer of the proper length.
+ * All that is used is the first byte for address, the remainder
+ * is just used for timing (and doesn't really have to exist).
+ */
+
+ dev_dbg(&adap->dev, "cpm_i2c_read(abyte=0x%x)\n", addr);
+
+ out_be16(&rbdf->cbd_datlen, 0);
+ out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
+
+ if (rx + 1 == CPM_MAXBD)
+ setbits16(&rbdf->cbd_sc, BD_SC_WRAP);
+
+ eieio();
+ setbits16(&tbdf->cbd_sc, BD_SC_READY);
+ } else {
+ dev_dbg(&adap->dev, "cpm_iic_write(abyte=0x%x)\n", addr);
+
+ memcpy(tb+1, pmsg->buf, pmsg->len);
+
+ eieio();
+ setbits16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_INTRPT);
+ }
+}
+
+static int cpm_i2c_check_message(struct i2c_adapter *adap,
+ struct i2c_msg *pmsg, int tx, int rx)
+{
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+ u_char *tb;
+ u_char *rb;
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+
+ tbdf = cpm->tbase + tx;
+ rbdf = cpm->rbase + rx;
+
+ tb = cpm->txbuf[tx];
+ rb = cpm->rxbuf[rx];
+
+ /* Align read buffer */
+ rb = (u_char *) (((uint) rb + 1) & ~1);
+
+ eieio();
+ if (pmsg->flags & I2C_M_RD) {
+ dev_dbg(&adap->dev, "tx sc 0x%04x, rx sc 0x%04x\n",
+ in_be16(&tbdf->cbd_sc), in_be16(&rbdf->cbd_sc));
+
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
+ dev_err(&adap->dev, "IIC read; No ack\n");
+ return -EIO;
+ }
+ if (in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY) {
+ dev_err(&adap->dev,
+ "IIC read; complete but rbuf empty\n");
+ return -EREMOTEIO;
+ }
+ if (in_be16(&rbdf->cbd_sc) & BD_SC_OV) {
+ dev_err(&adap->dev, "IIC read; Overrun\n");
+ return -EREMOTEIO;
+ }
+ memcpy(pmsg->buf, rb, pmsg->len);
+ } else {
+ dev_dbg(&adap->dev, "tx sc %d 0x%04x\n", tx,
+ in_be16(&tbdf->cbd_sc));
+
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
+ dev_err(&adap->dev, "IIC write; No ack\n");
+ return -EIO;
+ }
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_UN) {
+ dev_err(&adap->dev, "IIC write; Underrun\n");
+ return -EIO;
+ }
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) {
+ dev_err(&adap->dev, "IIC write; Collision\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+ struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
+ struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
+ struct i2c_msg *pmsg;
+ int ret, i;
+ int tptr;
+ int rptr;
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+
+ if (num > CPM_MAXBD)
+ return -EINVAL;
+
+ /* Check if we have any oversized READ requests */
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ if (pmsg->len >= CPM_MAX_READ)
+ return -EINVAL;
+ }
+
+ mutex_lock(&cpm->i2c_mutex);
+
+ /* Reset to use first buffer */
+ out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
+ out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
+
+ tbdf = cpm->tbase;
+ rbdf = cpm->rbase;
+
+ tptr = 0;
+ rptr = 0;
+
+ while (tptr < num) {
+ pmsg = &msgs[tptr];
+ dev_dbg(&adap->dev, "R: %d T: %d\n", rptr, tptr);
+
+ cpm_i2c_parse_message(adap, pmsg, num, tptr, rptr);
+ if (pmsg->flags & I2C_M_RD)
+ rptr++;
+ tptr++;
+ }
+ /* Start transfer now */
+ /* Chip bug, set enable here */
+ out_8(&i2c_reg->i2cmr, 0x13); /* Enable RX/TX/Error interupts */
+ out_8(&i2c_reg->i2cer, 0xff); /* Clear interrupt status */
+ setbits8(&i2c_reg->i2mod, 1); /* Enable */
+ /* Begin transmission */
+ setbits8(&i2c_reg->i2com, 0x80);
+
+ tptr = 0;
+ rptr = 0;
+
+ while (tptr < num) {
+ /* Check for outstanding messages */
+ dev_dbg(&adap->dev, "test ready.\n");
+ pmsg = &msgs[tptr];
+ if (pmsg->flags & I2C_M_RD)
+ ret = wait_event_interruptible_timeout(cpm->i2c_wait,
+ !(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY),
+ 1 * HZ);
+ else
+ ret = wait_event_interruptible_timeout(cpm->i2c_wait,
+ !(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_READY),
+ 1 * HZ);
+ if (ret == 0) {
+ ret = -EREMOTEIO;
+ dev_dbg(&adap->dev, "I2C read: timeout!\n");
+ goto out_err;
+ }
+ if (ret > 0) {
+ dev_dbg(&adap->dev, "ready.\n");
+ ret = cpm_i2c_check_message(adap, pmsg, tptr, rptr);
+ tptr++;
+ if (pmsg->flags & I2C_M_RD)
+ rptr++;
+ if (ret)
+ goto out_err;
+ }
+ }
+#ifdef I2C_CHIP_ERRATA
+ /*
+ * Chip errata, clear enable. This is not needed on rev D4 CPUs.
+ * Disabling I2C too early may cause too short stop condition
+ */
+ udelay(4);
+ clrbits8(&i2c_reg->i2mod, 1);
+#endif
+ mutex_unlock(&cpm->i2c_mutex);
+ return (num);
+
+out_err:
+ cpm_i2c_force_close(adap);
+#ifdef I2C_CHIP_ERRATA
+ /*
+ * Chip errata, clear enable. This is not needed on rev D4 CPUs.
+ */
+ clrbits8(&i2c_reg->i2mod, 1);
+#endif
+ mutex_unlock(&cpm->i2c_mutex);
+ return ret;
+}
+
+static u32 cpm_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static const struct i2c_algorithm cpm_i2c_algo = {
+ .master_xfer = cpm_i2c_xfer,
+ .functionality = cpm_i2c_func,
+};
+
+static const struct i2c_adapter cpm_ops = {
+ .owner = THIS_MODULE,
+ .name = "i2c-cpm",
+ .algo = &cpm_i2c_algo,
+ .class = I2C_CLASS_HWMON,
+};
+
+static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
+{
+ struct of_device *ofdev = cpm->ofdev;
+ const u32 *data;
+ int len, ret, i;
+ void __iomem *i2c_base;
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+ unsigned char brg;
+
+ dev_dbg(&cpm->ofdev->dev, "cpm_i2c_setup()\n");
+
+ init_waitqueue_head(&cpm->i2c_wait);
+ mutex_init(&cpm->i2c_mutex);
+
+ cpm->irq = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (cpm->irq == NO_IRQ)
+ return -EINVAL;
+
+ /* Install interrupt handler. */
+ ret = request_irq(cpm->irq, cpm_i2c_interrupt, 0, "cpm_i2c",
+ &cpm->adap);
+ if (ret)
+ goto out_irq;
+
+ /* IIC parameter RAM */
+ i2c_base = of_iomap(ofdev->node, 1);
+ if (i2c_base == NULL) {
+ ret = -EINVAL;
+ goto out_irq;
+ }
+
+ if (of_device_is_compatible(ofdev->node, "fsl,cpm1-i2c")) {
+
+ /* Check for and use a microcode relocation patch. */
+ cpm->i2c_ram = i2c_base;
+ cpm->i2c_addr = in_be16(&cpm->i2c_ram->rpbase);
+
+ /*
+ * Maybe should use cpm_muram_alloc instead of hardcoding
+ * this in micropatch.c
+ */
+ if (cpm->i2c_addr) {
+ cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
+ iounmap(i2c_base);
+ }
+
+ cpm->version = 1;
+
+ } else if (of_device_is_compatible(ofdev->node, "fsl,cpm2-i2c")) {
+ cpm->i2c_addr = cpm_muram_alloc(sizeof(struct i2c_ram), 64);
+ cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
+ out_be16(i2c_base, cpm->i2c_addr);
+ iounmap(i2c_base);
+
+ cpm->version = 2;
+
+ } else {
+ iounmap(i2c_base);
+ ret = -EINVAL;
+ goto out_irq;
+ }
+
+ /* I2C control/status registers */
+ cpm->i2c_reg = of_iomap(ofdev->node, 0);
+ if (cpm->i2c_reg == NULL) {
+ ret = -EINVAL;
+ goto out_ram;
+ }
+
+ data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
+ if (!data || len != 4) {
+ ret = -EINVAL;
+ goto out_reg;
+ }
+ cpm->cp_command = *data;
+
+ data = of_get_property(ofdev->node, "linux,i2c-class", &len);
+ if (data && len == 4)
+ cpm->adap.class = *data;
+
+ /*
+ * Allocate space for CPM_MAXBD transmit and receive buffer
+ * descriptors in the DP ram.
+ */
+ cpm->dp_addr = cpm_muram_alloc(sizeof(cbd_t) * 2 * CPM_MAXBD, 8);
+ if (!cpm->dp_addr) {
+ ret = -ENOMEM;
+ goto out_reg;
+ }
+
+ cpm->tbase = cpm_muram_addr(cpm->dp_addr);
+ cpm->rbase = cpm_muram_addr(cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD);
+
+ /* Allocate TX and RX buffers */
+
+ tbdf = cpm->tbase;
+ rbdf = cpm->rbase;
+
+ for (i = 0; i < CPM_MAXBD; i++) {
+ cpm->rxbuf[i] = dma_alloc_coherent(
+ NULL, CPM_MAX_READ + 1, &cpm->rxdma[i], GFP_KERNEL);
+ if (!cpm->rxbuf[i]) {
+ ret = -ENOMEM;
+ goto out_muram;
+ }
+ out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1));
+
+ cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(
+ NULL, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL);
+ if (!cpm->txbuf[i]) {
+ ret = -ENOMEM;
+ goto out_muram;
+ }
+ out_be32(&tbdf[i].cbd_bufaddr, cpm->txdma[i]);
+ }
+
+ /* Initialize Tx/Rx parameters. */
+
+ cpm_reset_i2c_params(cpm);
+
+ dev_dbg(&cpm->ofdev->dev, "i2c_ram %p, i2c_addr 0x%04x\n",
+ cpm->i2c_ram, cpm->i2c_addr);
+ dev_dbg(&cpm->ofdev->dev, "tbase 0x%04x, rbase 0x%04x\n",
+ (u8 __iomem *)cpm->tbase - DPRAM_BASE,
+ (u8 __iomem *)cpm->rbase - DPRAM_BASE);
+
+ cpm_command(cpm->cp_command, CPM_CR_INIT_TRX);
+
+ /*
+ * Select an invalid address. Just make sure we don't use loopback mode
+ */
+ out_8(&cpm->i2c_reg->i2add, 0xfe);
+
+ /* Make clock run at 60 kHz. */
+
+ brg = get_brgfreq() / (32 * 2 * 60000) - 3;
+ out_8(&cpm->i2c_reg->i2brg, brg);
+
+ out_8(&cpm->i2c_reg->i2mod, 0x00);
+ out_8(&cpm->i2c_reg->i2com, 0x01); /* Master mode */
+
+ /* Disable interrupts. */
+ out_8(&cpm->i2c_reg->i2cmr, 0);
+ out_8(&cpm->i2c_reg->i2cer, 0xff);
+
+ return 0;
+
+out_muram:
+ for (i = 0; i < CPM_MAXBD; i++) {
+ if (cpm->rxbuf[i])
+ dma_free_coherent(NULL, CPM_MAX_READ + 1,
+ cpm->rxbuf[i], cpm->rxdma[i]);
+ if (cpm->txbuf[i])
+ dma_free_coherent(NULL, CPM_MAX_READ + 1,
+ cpm->txbuf[i], cpm->txdma[i]);
+ }
+ cpm_muram_free(cpm->dp_addr);
+out_reg:
+ iounmap(cpm->i2c_reg);
+out_ram:
+ if ((cpm->version == 1) && (!cpm->i2c_addr))
+ iounmap(cpm->i2c_ram);
+ if (cpm->version == 2)
+ cpm_muram_free(cpm->i2c_addr);
+out_irq:
+ free_irq(cpm->irq, &cpm->adap);
+ return ret;
+}
+
+static void cpm_i2c_shutdown(struct cpm_i2c *cpm)
+{
+ int i;
+
+ /* Shut down I2C. */
+ clrbits8(&cpm->i2c_reg->i2mod, 1);
+
+ /* Disable interrupts */
+ out_8(&cpm->i2c_reg->i2cmr, 0);
+ out_8(&cpm->i2c_reg->i2cer, 0xff);
+
+ free_irq(cpm->irq, &cpm->adap);
+
+ /* Free all memory */
+ for (i = 0; i < CPM_MAXBD; i++) {
+ dma_free_coherent(NULL, CPM_MAX_READ + 1,
+ cpm->rxbuf[i], cpm->rxdma[i]);
+ dma_free_coherent(NULL, CPM_MAX_READ + 1,
+ cpm->txbuf[i], cpm->txdma[i]);
+ }
+
+ cpm_muram_free(cpm->dp_addr);
+ iounmap(cpm->i2c_reg);
+
+ if ((cpm->version == 1) && (!cpm->i2c_addr))
+ iounmap(cpm->i2c_ram);
+ if (cpm->version == 2)
+ cpm_muram_free(cpm->i2c_addr);
+
+ return;
+}
+
+static int __devinit cpm_i2c_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ int result;
+ struct cpm_i2c *cpm;
+
+ cpm = kzalloc(sizeof(struct cpm_i2c), GFP_KERNEL);
+ if (!cpm)
+ return -ENOMEM;
+
+ cpm->ofdev = ofdev;
+
+ dev_set_drvdata(&ofdev->dev, cpm);
+
+ cpm->adap = cpm_ops;
+ i2c_set_adapdata(&cpm->adap, cpm);
+ cpm->adap.dev.parent = &ofdev->dev;
+
+ result = cpm_i2c_setup(cpm);
+ if (result) {
+ dev_err(&ofdev->dev, "Unable to init hardware\n");
+ goto out_free;
+ }
+
+ /* register new adapter to i2c module... */
+
+ result = i2c_add_adapter(&cpm->adap);
+ if (result < 0) {
+ dev_err(&ofdev->dev, "Unable to register with I2C\n");
+ goto out_shut;
+ }
+
+ dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
+ cpm->adap.name);
+
+ /*
+ * register OF I2C devices
+ */
+ of_register_i2c_devices(&cpm->adap, ofdev->node);
+
+ return 0;
+out_shut:
+ cpm_i2c_shutdown(cpm);
+out_free:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(cpm);
+
+ return result;
+}
+
+static int __devexit cpm_i2c_remove(struct of_device *ofdev)
+{
+ struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev);
+
+ i2c_del_adapter(&cpm->adap);
+
+ cpm_i2c_shutdown(cpm);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(cpm);
+
+ return 0;
+}
+
+static const struct of_device_id cpm_i2c_match[] = {
+ {
+ .compatible = "fsl,cpm-i2c",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, cpm_i2c_match);
+
+static struct of_platform_driver cpm_i2c_driver = {
+ .match_table = cpm_i2c_match,
+ .probe = cpm_i2c_probe,
+ .remove = __devexit_p(cpm_i2c_remove),
+ .driver = {
+ .name = "fsl-i2c-cpm",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init cpm_i2c_init(void)
+{
+ return of_register_platform_driver(&cpm_i2c_driver);
+}
+
+static void __exit cpm_i2c_exit(void)
+{
+ of_unregister_platform_driver(&cpm_i2c_driver);
+}
+
+module_init(cpm_i2c_init);
+module_exit(cpm_i2c_exit);
+
+MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards");
+MODULE_LICENSE("GPL");
--
1.5.4.5
^ permalink raw reply related
* [PATCH7/7] [POWERPC] Add i2c pins to dts and board setup
From: Jochen Friedrich @ 2008-04-11 14:12 UTC (permalink / raw)
To: Kumar Gala
Cc: linuxppc-dev list, Kernel, Linux, Scott Wood, Jean Delvare,
Linux I2C
Initialize I2C pins on boards with CPM1/CPM2 controllers.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
---
arch/powerpc/boot/dts/mpc8272ads.dts | 10 ++++++++++
arch/powerpc/boot/dts/mpc866ads.dts | 10 ++++++++++
arch/powerpc/boot/dts/mpc885ads.dts | 10 ++++++++++
arch/powerpc/platforms/82xx/mpc8272_ads.c | 4 ++++
arch/powerpc/platforms/8xx/mpc86xads_setup.c | 4 ++++
arch/powerpc/platforms/8xx/mpc885ads_setup.c | 3 +++
6 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 7285ca1..7273996 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -215,6 +215,16 @@
linux,network-index = <1>;
fsl,cpm-command = <16200300>;
};
+
+ i2c@11860 {
+ compatible = "fsl,mpc8248-i2c",
+ "fsl,cpm2-i2c",
+ "fsl,cpm-i2c";
+ reg = <11860 20 8afc 2>;
+ interrupts = <1 8>;
+ interrupt-parent = <&PIC>;
+ fsl,cpm-command = <29600000>;
+ };
};
PIC: interrupt-controller@10c00 {
diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts
index daf9433..d669049 100644
--- a/arch/powerpc/boot/dts/mpc866ads.dts
+++ b/arch/powerpc/boot/dts/mpc866ads.dts
@@ -169,6 +169,16 @@
fsl,cpm-command = <0000>;
linux,network-index = <1>;
};
+
+ i2c@860 {
+ compatible = "fsl,mpc866-i2c",
+ "fsl,cpm1-i2c",
+ "fsl,cpm-i2c";
+ reg = <860 20 3c80 30>;
+ interrupts = <10>;
+ interrupt-parent = <&CPM_PIC>;
+ fsl,cpm-command = <0010>;
+ };
};
};
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index d84a012..d3ddda7 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -214,6 +214,16 @@
fsl,cpm-command = <0080>;
linux,network-index = <2>;
};
+
+ i2c@860 {
+ compatible = "fsl,mpc885-i2c",
+ "fsl,cpm1-i2c",
+ "fsl,cpm-i2c";
+ reg = <860 20 3c80 30>;
+ interrupts = <10>;
+ interrupt-parent = <&CPM_PIC>;
+ fsl,cpm-command = <0010>;
+ };
};
};
diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c
index 7d30187..8054c68 100644
--- a/arch/powerpc/platforms/82xx/mpc8272_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c
@@ -96,6 +96,10 @@ static struct cpm_pin mpc8272_ads_pins[] = {
{1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
{2, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
{2, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+
+ /* I2C */
+ {3, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
+ {3, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
};
static void __init init_ioports(void)
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
index c028a5b..caaec29 100644
--- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
@@ -65,6 +65,10 @@ static struct cpm_pin mpc866ads_pins[] = {
{CPM_PORTD, 13, CPM_PIN_OUTPUT},
{CPM_PORTD, 14, CPM_PIN_OUTPUT},
{CPM_PORTD, 15, CPM_PIN_OUTPUT},
+
+ /* I2C */
+ {CPM_PORTB, 26, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN},
+ {CPM_PORTB, 27, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN},
};
static void __init init_ioports(void)
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index 6e7ded0..45ed6cd 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -158,6 +158,9 @@ static struct cpm_pin mpc885ads_pins[] = {
{CPM_PORTE, 28, CPM_PIN_OUTPUT},
{CPM_PORTE, 29, CPM_PIN_OUTPUT},
#endif
+ /* I2C */
+ {CPM_PORTB, 26, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN},
+ {CPM_PORTB, 27, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN},
};
static void __init init_ioports(void)
--
1.5.4.5
^ permalink raw reply related
* Re: [PATCH 2/2] [POWERPC] UCC nodes cleanup
From: Kumar Gala @ 2008-04-11 14:13 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev
In-Reply-To: <20080311171045.GB4684@localhost.localdomain>
On Mar 11, 2008, at 12:10 PM, Anton Vorontsov wrote:
> - get rid of `model = "UCC"' in the ucc nodes
> It isn't used anywhere, so remove it. If we'll ever need something
> like this, we'll use compatible property instead.
> - replace cell-index and device-id properties by fsl,ucc.
>
> Drivers are modified for backward compatibility's sake.
I'd prefer we use cell-index and not introduce "fsl,ucc". I'm ok with
dropping device-id and model (its implied in the compatiable).
- k
^ permalink raw reply
* Re: [PATCH 2/2] [POWERPC] Implement support for the GPIO LIB API
From: Grant Likely @ 2008-04-11 14:16 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev, Paul Mackerras, David Miller
In-Reply-To: <20080411130636.GA12655@polina.dev.rtsoft.ru>
On Fri, Apr 11, 2008 at 7:06 AM, Anton Vorontsov
<avorontsov@ru.mvista.com> wrote:
> This patch implements support for the GPIO LIB API. Two calls
> unimplemented though: irq_to_gpio and gpio_to_irq.
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
I like it
Acked-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> Documentation/powerpc/booting-without-of.txt | 52 ++++++++++++++++++++++++
> arch/powerpc/Kconfig | 5 ++
> include/asm-powerpc/gpio.h | 56 ++++++++++++++++++++++++++
> 3 files changed, 113 insertions(+), 0 deletions(-)
> create mode 100644 include/asm-powerpc/gpio.h
>
> diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
> index b506245..e9e0c2f 100644
> --- a/Documentation/powerpc/booting-without-of.txt
> +++ b/Documentation/powerpc/booting-without-of.txt
> @@ -66,6 +66,10 @@ Table of Contents
> 3) OpenPIC Interrupt Controllers
> 4) ISA Interrupt Controllers
>
> + VIII - Specifying GPIO information for devices
> + 1) gpios property
> + 2) gpio-controller nodes
> +
> Appendix A - Sample SOC node for MPC8540
>
>
> @@ -2925,6 +2929,54 @@ encodings listed below:
> 2 = high to low edge sensitive type enabled
> 3 = low to high edge sensitive type enabled
>
> +VIII - Specifying GPIO information for devices
> +==============================================
> +
> +1) gpios property
> +-----------------
> +
> +Nodes that makes use of GPIOs should define them using `gpios' property,
> +format of which is: <&gpio-controller1-phandle gpio1-specifier
> + &gpio-controller2-phandle gpio2-specifier
> + 0 /* holes are permitted, means no GPIO 3 */
> + &gpio-controller4-phandle gpio4-specifier
> + ...>;
> +
> +Note that gpio-specifier length is controller dependent.
> +
> +gpio-specifier may encode: bank, pin position inside the bank,
> +whether pin is open-drain and whether pin is logically inverted.
> +
> +Example of the node using GPIOs:
> +
> + node {
> + gpios = <&qe_pio_e 18 0>;
> + };
> +
> +In this example gpio-specifier is "18 0" and encodes GPIO pin number,
> +and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
> +
> +2) gpio-controller nodes
> +------------------------
> +
> +Every GPIO controller node must have #gpio-cells property defined,
> +this information will be used to translate gpio-specifiers.
> +
> +Example of two SOC GPIO banks defined as gpio-controller nodes:
> +
> + qe_pio_a: gpio-controller@1400 {
> + #gpio-cells = <2>;
> + compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
> + reg = <0x1400 0x18>;
> + gpio-controller;
> + };
> +
> + qe_pio_e: gpio-controller@1460 {
> + #gpio-cells = <2>;
> + compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
> + reg = <0x1460 0x18>;
> + gpio-controller;
> + };
>
> Appendix A - Sample SOC node for MPC8540
> ========================================
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 0b27cbd..f328509 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -81,6 +81,11 @@ config GENERIC_FIND_NEXT_BIT
> bool
> default y
>
> +config GENERIC_GPIO
> + bool
> + help
> + Generic GPIO API support
> +
> config ARCH_NO_VIRT_TO_BUS
> def_bool PPC64
>
> diff --git a/include/asm-powerpc/gpio.h b/include/asm-powerpc/gpio.h
> new file mode 100644
> index 0000000..77ad3a8
> --- /dev/null
> +++ b/include/asm-powerpc/gpio.h
> @@ -0,0 +1,56 @@
> +/*
> + * Generic GPIO API implementation for PowerPC.
> + *
> + * Copyright (c) 2007-2008 MontaVista Software, Inc.
> + *
> + * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef __ASM_POWERPC_GPIO_H
> +#define __ASM_POWERPC_GPIO_H
> +
> +#include <linux/errno.h>
> +#include <asm-generic/gpio.h>
> +
> +#ifdef CONFIG_HAVE_GPIO_LIB
> +
> +/*
> + * We don't (yet) implement inlined/rapid versions for on-chip gpios.
> + * Just call gpiolib.
> + */
> +static inline int gpio_get_value(unsigned int gpio)
> +{
> + return __gpio_get_value(gpio);
> +}
> +
> +static inline void gpio_set_value(unsigned int gpio, int value)
> +{
> + __gpio_set_value(gpio, value);
> +}
> +
> +static inline int gpio_cansleep(unsigned int gpio)
> +{
> + return __gpio_cansleep(gpio);
> +}
> +
> +/*
> + * Not implemented, yet.
> + */
> +static inline int gpio_to_irq(unsigned int gpio)
> +{
> + return -ENOSYS;
> +}
> +
> +static inline int irq_to_gpio(unsigned int irq)
> +{
> + return -EINVAL;
> +}
> +
> +#endif /* CONFIG_HAVE_GPIO_LIB */
> +
> +#endif /* __ASM_POWERPC_GPIO_H */
> --
> 1.5.4.5
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 1/2] ibm_newemac: PowerPC 440GX EMAC PHY clock workaround
From: Josh Boyer @ 2008-04-11 14:24 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linuxppc-dev, netdev
In-Reply-To: <47EDA6F1.9080206@garzik.org>
On Fri, 28 Mar 2008 22:18:25 -0400
Jeff Garzik <jeff@garzik.org> wrote:
> Valentine Barshak wrote:
> > The PowerPC 440GX Taishan board fails to reset EMAC3 (reset timeout error)
> > if there's no link. Because of that it fails to find PHY chip. The older ibm_emac
> > driver had a workaround for that: the EMAC_CLK_INTERNAL/EMAC_CLK_EXTERNAL macros,
> > which toggle the Ethernet Clock Select bit in the SDR0_MFR register. This patch
> > does the same for "ibm,emac-440gx" compatible chips. The workaround forces
> > clock on -all- EMACs, so we select clock under global emac_phy_map_lock.
> >
> > Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
> > ---
> > drivers/net/ibm_newemac/core.c | 16 +++++++++++++++-
> > drivers/net/ibm_newemac/core.h | 8 ++++++--
> > 2 files changed, 21 insertions(+), 3 deletions(-)
>
> is this for 2.6.25-rc?
Jeff, can I get an ack from you on this patch, and patch 2 in this
set? They depend on a patch in my tree and I'd like to include them in
my next push to Paul for 2.6.26.
josh
^ permalink raw reply
* Re: [PATCH 2/2] [POWERPC] UCC nodes cleanup
From: Timur Tabi @ 2008-04-11 14:26 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev
In-Reply-To: <82E8E38A-C159-4C23-BDE8-086D4429F366@kernel.crashing.org>
Kumar Gala wrote:
> I'd prefer we use cell-index and not introduce "fsl,ucc".
Yeah, me too. cell-index is the right property for the UCC number.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: [PATCH 1/2] OF helpers for the GPIO API
From: Grant Likely @ 2008-04-11 14:28 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev, Paul Mackerras, David Miller
In-Reply-To: <20080411130645.GB12655@polina.dev.rtsoft.ru>
On Fri, Apr 11, 2008 at 7:06 AM, Anton Vorontsov
<avorontsov@ru.mvista.com> wrote:
> This patch implements various helpers to support OF bindings for
> the GPIO LIB API.
>
> Previously this was PowerPC specific, but it seems this code
> isn't arch-dependent anyhow, so let's place it into of/.
>
> SPARC will not see this addition yet, real hardware seem to not use
> GPIOs at all. But this might change:
>
> http://www.leox.org/docs/faq_MLleon.html
>
> "16-bit I/O port" sounds promising. :-)
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Looks pretty sane to me. Only nitpick; the documentation should be part of this
patch, not the next one; but I have no complaints if they both get
picked up at the same time.
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH] CPM: Always use new binding.
From: Scott Wood @ 2008-04-11 14:46 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <E26DEDA5-96A7-40C1-A06A-5D8503453715@kernel.crashing.org>
On Thu, Apr 10, 2008 at 06:44:24PM -0500, Kumar Gala wrote:
>
> On Apr 10, 2008, at 3:45 PM, Scott Wood wrote:
>> The kconfig entry can go away once arch/ppc and references to the
>> config in
>> drivers are removed.
>
> just to be clear. arch/powerpc will always just use the new binding and
> arch/ppc uses the old (or has the option)?
Yes, CONFIG_PPC_NEW_BINDING is effectively an alias for CONFIG_PPC_MERGE
after this patch (but I figure there's no point changing the drivers to use
the latter, just to make another change in a couple months when arch/ppc
dies).
-Scott
^ permalink raw reply
* Re: State of the MPC5200 PSC AC97 driver
From: Marian Balakowicz @ 2008-04-11 14:53 UTC (permalink / raw)
To: Grant Likely; +Cc: Sven Luther, spitzauer_77, linuxppc-dev
In-Reply-To: <fa686aa40804110650h2a215290h5269ce74ff6e33c5@mail.gmail.com>
Grant Likely wrote:
> On Fri, Apr 11, 2008 at 3:23 AM, Marian Balakowicz <m8@semihalf.com> wrote:
>> All,
>>
>> Thanks for the input and comments.
>>
>> I am also having a look at the I2S driver. There were attempts some
>> time ago and I found few pieces of code floating on net but couldn't
>> find anything cleaned up. Did anyone tried to put the results of those
>> attempts together?
>
> I'm actually working on the I2S driver now and I'll probably have
> something to post about a month from now. This is funded development,
> so I'll actually have lots of time to spend on it when I get back from
> ELC.
Nice, I'll most probably work on it quite soon as well. It would be
good to coordinate efforts, will ping you when I am about to start.
Cheers,
m.
^ permalink raw reply
* Re: [PATCH7/7] [POWERPC] Add i2c pins to dts and board setup
From: Scott Wood @ 2008-04-11 15:02 UTC (permalink / raw)
To: Jochen Friedrich
Cc: Kernel, Linux, linuxppc-dev list, Jean Delvare, Linux I2C
In-Reply-To: <47FF71B1.9070907@scram.de>
Jochen Friedrich wrote:
> diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
> index 7285ca1..7273996 100644
> --- a/arch/powerpc/boot/dts/mpc8272ads.dts
> +++ b/arch/powerpc/boot/dts/mpc8272ads.dts
> @@ -215,6 +215,16 @@
> linux,network-index = <1>;
> fsl,cpm-command = <16200300>;
> };
> +
> + i2c@11860 {
> + compatible = "fsl,mpc8248-i2c",
mpc8272-i2c
-Scott
^ permalink raw reply
* Flash on LocalBus @ MPC8343
From: Andre Schwarz @ 2008-04-11 15:13 UTC (permalink / raw)
To: linux-ppc list
Hi all,
I've been trying hard to make the mtd-partitions available via device
tree on my MPC8343 local bus.
No success so far ...
Everything works fine on my MPC5200B based system - flash layout
definition is quite simple ....
To me it looks like there's a problem regarding the local bus in general.
Am I missing a "compatible" or anything else ? "reg" or "ranges" ?
The other boards use static map files or provide partition over command
line args .... so suitable dts available.
Flash is 8MB size in 16-Bit configuration and should reside on
0xFF800000 at cs0.
Any hints ?
regards,
Andre Schwarz
Matrix Vision
dts syntax :
<snip>
localbus@e0005000 {
#address-cells = <2>;
#size-cells = <1>;
compatible = "fsl,mpc8343-localbus", "fsl,pq2pro-localbus";
ranges = <0x0 0x0 0xff800000 0x00800000>;
flash@0,0 {
compatible = "amd,s29gl64", "cfi-flash";
reg = <0 0 800000>;
#address-cells = <1>;
#size-cells = <1>;
bank-width = <2>;
device-width = <2>;
ppcboot_env@0 {
reg = <0x0 0x2000>;
};
<snip>
MATRIX VISION GmbH, Talstraße 16, DE-71570 Oppenweiler - Registergericht: Amtsgericht Stuttgart, HRB 271090
Geschäftsführer: Gerhard Thullner, Werner Armingeon, Uwe Furtner
^ permalink raw reply
* Re: Flash on LocalBus @ MPC8343
From: Laurent Pinchart @ 2008-04-11 15:20 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Andre Schwarz
In-Reply-To: <47FF802B.5020708@matrix-vision.de>
[-- Attachment #1: Type: text/plain, Size: 1707 bytes --]
On Friday 11 April 2008 17:13, Andre Schwarz wrote:
> Hi all,
>
> I've been trying hard to make the mtd-partitions available via device
> tree on my MPC8343 local bus.
> No success so far ...
>
> Everything works fine on my MPC5200B based system - flash layout
> definition is quite simple ....
>
> To me it looks like there's a problem regarding the local bus in general.
>
> Am I missing a "compatible" or anything else ? "reg" or "ranges" ?
>
> The other boards use static map files or provide partition over command
> line args .... so suitable dts available.
>
> Flash is 8MB size in 16-Bit configuration and should reside on
> 0xFF800000 at cs0.
>
>
> Any hints ?
>
>
> regards,
> Andre Schwarz
> Matrix Vision
>
>
> dts syntax :
>
> <snip>
>
> localbus@e0005000 {
> #address-cells = <2>;
> #size-cells = <1>;
> compatible = "fsl,mpc8343-localbus", "fsl,pq2pro-localbus";
>
> ranges = <0x0 0x0 0xff800000 0x00800000>;
>
> flash@0,0 {
> compatible = "amd,s29gl64", "cfi-flash";
> reg = <0 0 800000>;
reg should be <0 0 0x800000>.
> #address-cells = <1>;
> #size-cells = <1>;
> bank-width = <2>;
> device-width = <2>;
>
> ppcboot_env@0 {
> reg = <0x0 0x2000>;
> };
--
Laurent Pinchart
CSE Semaphore Belgium
Chaussee de Bruxelles, 732A
B-1410 Waterloo
Belgium
T +32 (2) 387 42 59
F +32 (2) 387 42 75
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH v2.6.26] gianfar: Determine TBIPA value dynamically
From: Scott Wood @ 2008-04-11 15:31 UTC (permalink / raw)
To: Andy Fleming; +Cc: linuxppc-dev, netdev, paul.gortmaker
In-Reply-To: <1207870471-3601-1-git-send-email-afleming@freescale.com>
On Thu, Apr 10, 2008 at 06:34:31PM -0500, Andy Fleming wrote:
>
> + /*
> + * This is mildly evil, but so is our hardware for doing this.
> + * Also, we have to cast back to struct gfar_mii because of
> + * definition weirdness done in gianfar.h.
> + */
> + enet_regs = (struct gfar __iomem *)
> + ((char *)regs - offsetof(struct gfar, gfar_mii_regs));
Can we use to_container() here?
-Scott
^ permalink raw reply
* Re: Flash on LocalBus @ MPC8343
From: Scott Wood @ 2008-04-11 15:38 UTC (permalink / raw)
To: Andre Schwarz; +Cc: linux-ppc list
In-Reply-To: <47FF802B.5020708@matrix-vision.de>
On Fri, Apr 11, 2008 at 05:13:47PM +0200, Andre Schwarz wrote:
> To me it looks like there's a problem regarding the local bus in general.
>
> Am I missing a "compatible" or anything else ? "reg" or "ranges" ?
Do you have an of_bus_ids[] entry that covers the localbus?
-Scott
^ permalink raw reply
* Re: [PATCH v2.6.26] gianfar: Determine TBIPA value dynamically
From: Paul Gortmaker @ 2008-04-11 15:49 UTC (permalink / raw)
To: Andy Fleming; +Cc: netdev, linuxppc-dev
In-Reply-To: <1207870471-3601-1-git-send-email-afleming@freescale.com>
In message: [PATCH v2.6.26] gianfar: Determine TBIPA value dynamically
on 10/04/2008 Andy Fleming wrote:
> TBIPA needs to be set to a value (on connected MDIO buses) that doesn't
> conflict with PHYs on the bus. By hardcoding it to 0x1f, we were preventing
> boards with PHYs at 0x1f from working properly. Instead, scan the bus when
> it comes up, and find an address that doesn't have a PHY on it. The TBI PHY
> configuration code then trusts that the value in TBIPA is either safe, or
> doesn't matter (ie - it's not an active bus with other PHYs).
>
> Signed-off-by: Andy Fleming <afleming@freescale.com>
> ---
>
> I think this should go in, but I'd like to see some testing first. I don't
> have hardware which is affected by this. I've only confirmed that it doesn't
> break current hardware.
I've tested on a board with the primary PHY at 0x1f, and it seems OK.
I'f I'm understanding this correctly, you are explicitly setting TBIPA
to zero, doing a bus walk but excluding zero, and then assigning the
found free address, which re-opens zero to be used by a real PHY.
I've made some changes to what you'd sent out, those being:
-changed the "if (i < 0) return -EBUSY to "i == 0"
-remove the now unused TBIPA_VALUE define
-remove the prototypes from gianfar.c now that you've
added them into gianfar.h
-factor out the code to read the PHY ID so we don't have
it duplicated in two places.
Thanks,
Paul.
------
>From 51389f8ca0ed0f45dcb1038069d07bdd32a55c14 Mon Sep 17 00:00:00 2001
From: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Fri, 11 Apr 2008 11:21:32 -0400
Subject: [PATCH] phylib: factor out get_phy_id from within get_phy_device
We were already doing what amounts to a get_phy_id from within
get_phy_device, and rather than duplicate this for the TBIPA
probing, we might as well just factor it out and make it available
instead.
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
drivers/net/phy/phy_device.c | 38 +++++++++++++++++++++++++++++---------
include/linux/phy.h | 1 +
2 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index f4c4fd8..8b1121b 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -86,35 +86,55 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
EXPORT_SYMBOL(phy_device_create);
/**
- * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * get_phy_id - reads the specified addr for its ID.
* @bus: the target MII bus
* @addr: PHY address on the MII bus
+ * @phy_id: where to store the ID retrieved.
*
* Description: Reads the ID registers of the PHY at @addr on the
- * @bus, then allocates and returns the phy_device to represent it.
+ * @bus, stores it in @phy_id and returns zero on success.
*/
-struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
+int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
{
int phy_reg;
- u32 phy_id;
- struct phy_device *dev = NULL;
/* Grab the bits from PHYIR1, and put them
* in the upper half */
phy_reg = bus->read(bus, addr, MII_PHYSID1);
if (phy_reg < 0)
- return ERR_PTR(phy_reg);
+ return -EIO;
- phy_id = (phy_reg & 0xffff) << 16;
+ *phy_id = (phy_reg & 0xffff) << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
phy_reg = bus->read(bus, addr, MII_PHYSID2);
if (phy_reg < 0)
- return ERR_PTR(phy_reg);
+ return -EIO;
+
+ *phy_id |= (phy_reg & 0xffff);
+
+ return 0;
+}
+
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ * @bus, then allocates and returns the phy_device to represent it.
+ */
+struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
+{
+ struct phy_device *dev = NULL;
+ u32 phy_id;
+ int r;
- phy_id |= (phy_reg & 0xffff);
+ r = get_phy_id(bus, addr, &phy_id);
+ if (r)
+ return ERR_PTR(r);
/* If the phy_id is all Fs, there is no device there */
if (0xffffffff == phy_id)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 5e43ae7..e794c4d 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -361,6 +361,7 @@ struct phy_driver {
int phy_read(struct phy_device *phydev, u16 regnum);
int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
+int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
int phy_clear_interrupt(struct phy_device *phydev);
int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
--
1.5.4.3
>From 87b3a8137049e23b75454a6bf2b37d24622afdfa Mon Sep 17 00:00:00 2001
From: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Fri, 11 Apr 2008 11:35:37 -0400
Subject: [PATCH] gianfar: Determine TBIPA value dynamically
TBIPA needs to be set to a value (on connected MDIO buses) that doesn't
conflict with PHYs on the bus. By hardcoding it to 0x1f, we were preventing
boards with PHYs at 0x1f from working properly. Instead, scan the bus when
it comes up, and find an address that doesn't have a PHY on it. The TBI PHY
configuration code then trusts that the value in TBIPA is either safe, or
doesn't matter (ie - it's not an active bus with other PHYs).
Signed-off-by: Andy Fleming <afleming@freescale.com>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
drivers/net/gianfar.c | 27 ++++++++++++++-------------
drivers/net/gianfar.h | 1 -
drivers/net/gianfar_mii.c | 38 +++++++++++++++++++++++++++++++++-----
drivers/net/gianfar_mii.h | 3 +++
4 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 718cf77..b30809b 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -130,8 +130,6 @@ static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
static void gfar_configure_serdes(struct net_device *dev);
-extern int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, int regnum, u16 value);
-extern int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
#ifdef CONFIG_GFAR_NAPI
static int gfar_poll(struct napi_struct *napi, int budget);
#endif
@@ -476,24 +474,30 @@ static int init_phy(struct net_device *dev)
return 0;
}
+/*
+ * Initialize TBI PHY interface for communicating with the
+ * SERDES lynx PHY on the chip. We communicate with this PHY
+ * through the MDIO bus on each controller, treating it as a
+ * "normal" PHY at the address found in the TBIPA register. We assume
+ * that the TBIPA register is valid. Either the MDIO bus code will set
+ * it to a value that doesn't conflict with other PHYs on the bus, or the
+ * value doesn't matter, as there are no other PHYs on the bus.
+ */
static void gfar_configure_serdes(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar_mii __iomem *regs =
(void __iomem *)&priv->regs->gfar_mii_regs;
+ int tbipa = gfar_read(&priv->regs->tbipa);
- /* Initialise TBI i/f to communicate with serdes (lynx phy) */
+ /* Single clk mode, mii mode off(for serdes communication) */
+ gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT);
- /* Single clk mode, mii mode off(for aerdes communication) */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT);
-
- /* Supported pause and full-duplex, no half-duplex */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE,
+ gfar_local_mdio_write(regs, tbipa, MII_ADVERTISE,
ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
ADVERTISE_1000XPSE_ASYM);
- /* ANEG enable, restart ANEG, full duplex mode, speed[1] set */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE |
+ gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE |
BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
}
@@ -540,9 +544,6 @@ static void init_registers(struct net_device *dev)
/* Initialize the Minimum Frame Length Register */
gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS);
-
- /* Assign the TBI an address which won't conflict with the PHYs */
- gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 46cd773..771aa5e 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -130,7 +130,6 @@ extern const char gfar_driver_version[];
#define DEFAULT_RXCOUNT 16
#define DEFAULT_RXTIME 4
-#define TBIPA_VALUE 0x1f
#define MIIMCFG_INIT_VALUE 0x00000007
#define MIIMCFG_RESET 0x80000000
#define MIIMIND_BUSY 0x00000001
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index 2432762..4f23e60 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -78,7 +78,6 @@ int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
* same as system mdio bus, used for controlling the external PHYs, for eg.
*/
int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum)
-
{
u16 value;
@@ -122,7 +121,7 @@ int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
}
/* Reset the MIIM registers, and wait for the bus to free */
-int gfar_mdio_reset(struct mii_bus *bus)
+static int gfar_mdio_reset(struct mii_bus *bus)
{
struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
unsigned int timeout = PHY_INIT_TIMEOUT;
@@ -152,14 +151,15 @@ int gfar_mdio_reset(struct mii_bus *bus)
}
-int gfar_mdio_probe(struct device *dev)
+static int gfar_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gianfar_mdio_data *pdata;
struct gfar_mii __iomem *regs;
+ struct gfar __iomem *enet_regs;
struct mii_bus *new_bus;
struct resource *r;
- int err = 0;
+ int i, err = 0;
if (NULL == dev)
return -EINVAL;
@@ -199,6 +199,34 @@ int gfar_mdio_probe(struct device *dev)
new_bus->dev = dev;
dev_set_drvdata(dev, new_bus);
+ /*
+ * This is mildly evil, but so is our hardware for doing this.
+ * Also, we have to cast back to struct gfar_mii because of
+ * definition weirdness done in gianfar.h.
+ */
+ enet_regs = (struct gfar __iomem *)
+ ((char *)regs - offsetof(struct gfar, gfar_mii_regs));
+
+ /* Scan the bus, looking for an empty spot for TBIPA */
+ gfar_write(&enet_regs->tbipa, 0);
+ for (i = PHY_MAX_ADDR; i > 0; i--) {
+ u32 phy_id;
+ int r;
+
+ r = get_phy_id(new_bus, i, &phy_id);
+ if (r)
+ return r;
+
+ if (phy_id == 0xffffffff)
+ break;
+ }
+
+ /* The bus is full. We don't support using 31 PHYs, sorry */
+ if (i == 0)
+ return -EBUSY;
+
+ gfar_write(&enet_regs->tbipa, i);
+
err = mdiobus_register(new_bus);
if (0 != err) {
@@ -218,7 +246,7 @@ reg_map_fail:
}
-int gfar_mdio_remove(struct device *dev)
+static int gfar_mdio_remove(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index b373091..2af28b1 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -41,6 +41,9 @@ struct gfar_mii {
int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
+ int regnum, u16 value);
+int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
int __init gfar_mdio_init(void);
void gfar_mdio_exit(void);
#endif /* GIANFAR_PHY_H */
--
1.5.4.3
^ permalink raw reply related
* Re: zImage.embedded
From: Guillaume Dargaud @ 2008-04-11 15:51 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <fa686aa40804110655x48120e84tde01a52d8bb39a3@mail.gmail.com>
>> is the file zImage.elf my proper network image ?
>
> What bootloader is on your board? zImage.elf *might* be the proper
> image. If you're using u-boot, then you want to build a uImage
> instead.
I... ahem... what would you recommand for a ML405 ?
Builroot gives to options of U-Boot or Yaboot. Haven't tried either yet.
Will do on tuesday.
I don't know if Xilinx has another solution (I remember seeing some boot
function in the API, usable from a standalone elf file).
--
Guillaume Dargaud
http://www.gdargaud.net/
^ permalink raw reply
* Re: [PATCH] CPM: Always use new binding.
From: Kumar Gala @ 2008-04-11 15:58 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <20080411144620.GA2534@loki.buserror.net>
On Apr 11, 2008, at 9:46 AM, Scott Wood wrote:
> On Thu, Apr 10, 2008 at 06:44:24PM -0500, Kumar Gala wrote:
>>
>> On Apr 10, 2008, at 3:45 PM, Scott Wood wrote:
>>> The kconfig entry can go away once arch/ppc and references to the
>>> config in
>>> drivers are removed.
>>
>> just to be clear. arch/powerpc will always just use the new
>> binding and
>> arch/ppc uses the old (or has the option)?
>
> Yes, CONFIG_PPC_NEW_BINDING is effectively an alias for
> CONFIG_PPC_MERGE
> after this patch (but I figure there's no point changing the drivers
> to use
> the latter, just to make another change in a couple months when arch/
> ppc
> dies).
Ok (just wanted to make sure I was clear) and agreed on not wanting to
change the drivers.
- k
^ permalink raw reply
* Re: zImage.embedded
From: Grant Likely @ 2008-04-11 16:04 UTC (permalink / raw)
To: Guillaume Dargaud; +Cc: linuxppc-dev
In-Reply-To: <016801c89beb$fbff6de0$ad289e86@LPSC0173W>
On Fri, Apr 11, 2008 at 9:51 AM, Guillaume Dargaud
<dargaud@lpsc.in2p3.fr> wrote:
>
> >
> > > is the file zImage.elf my proper network image ?
> > >
> >
> > What bootloader is on your board? zImage.elf *might* be the proper
> > image. If you're using u-boot, then you want to build a uImage
> > instead.
> >
>
> I... ahem... what would you recommand for a ML405 ?
> Builroot gives to options of U-Boot or Yaboot. Haven't tried either yet.
> Will do on tuesday.
>
> I don't know if Xilinx has another solution (I remember seeing some boot
> function in the API, usable from a standalone elf file).
zImage.elf is what you want. If you *do* get u-boot building on your
board, then you'll want a uImage; but zImage.elf will work for you
now.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 2/2] [POWERPC] UCC nodes cleanup
From: Anton Vorontsov @ 2008-04-11 16:06 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, Jeff Garzik, linux-serial, netdev
In-Reply-To: <82E8E38A-C159-4C23-BDE8-086D4429F366@kernel.crashing.org>
On Fri, Apr 11, 2008 at 09:13:36AM -0500, Kumar Gala wrote:
>
> On Mar 11, 2008, at 12:10 PM, Anton Vorontsov wrote:
>> - get rid of `model = "UCC"' in the ucc nodes
>> It isn't used anywhere, so remove it. If we'll ever need something
>> like this, we'll use compatible property instead.
>> - replace cell-index and device-id properties by fsl,ucc.
>>
>> Drivers are modified for backward compatibility's sake.
>
> I'd prefer we use cell-index and not introduce "fsl,ucc". I'm ok with
> dropping device-id and model (its implied in the compatiable).
Ok. Here it is. netdev and linux-serial Cc'ed.
- - - -
From: Anton Vorontsov <avorontsov@ru.mvista.com>
Subject: [POWERPC] UCC nodes cleanup
- get rid of `model = "UCC"' in the ucc nodes
It isn't used anywhere, so remove it. If we'll ever need something
like this, we'll use compatible property instead.
- replace last occurrences of device-id with cell-index.
Drivers are modified for backward compatibility's sake.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
Documentation/powerpc/booting-without-of.txt | 6 ++----
arch/powerpc/boot/dts/mpc832x_mds.dts | 7 +------
arch/powerpc/boot/dts/mpc832x_rdb.dts | 4 ----
arch/powerpc/boot/dts/mpc836x_mds.dts | 4 ----
arch/powerpc/boot/dts/mpc8568mds.dts | 4 ----
drivers/net/ucc_geth.c | 8 +++++++-
drivers/net/ucc_geth_mii.c | 11 ++++++++---
drivers/serial/ucc_uart.c | 16 ++++++++++++----
8 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index be41a5c..f0a99aa 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1619,8 +1619,7 @@ platforms are moved over to use the flattened-device-tree model.
- device_type : should be "network", "hldc", "uart", "transparent"
"bisync", "atm", or "serial".
- compatible : could be "ucc_geth" or "fsl_atm" and so on.
- - model : should be "UCC".
- - device-id : the ucc number(1-8), corresponding to UCCx in UM.
+ - cell-index : the ucc number(1-8), corresponding to UCCx in UM.
- reg : Offset and length of the register set for the device
- interrupts : <a b> where a is the interrupt number and b is a
field that represents an encoding of the sense and level
@@ -1677,8 +1676,7 @@ platforms are moved over to use the flattened-device-tree model.
ucc@2000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
- device-id = <1>;
+ cell-index = <1>;
reg = <2000 200>;
interrupts = <a0 0>;
interrupt-parent = <700>;
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index 9bb4083..539e02f 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -255,9 +255,7 @@
enet0: ucc@2200 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <3>;
- device-id = <3>;
reg = <0x2200 0x200>;
interrupts = <34>;
interrupt-parent = <&qeic>;
@@ -271,9 +269,7 @@
enet1: ucc@3200 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <4>;
- device-id = <4>;
reg = <0x3200 0x200>;
interrupts = <35>;
interrupt-parent = <&qeic>;
@@ -287,8 +283,7 @@
ucc@2400 {
device_type = "serial";
compatible = "ucc_uart";
- model = "UCC";
- device-id = <5>; /* The UCC number, 1-7*/
+ cell-index = <5>; /* The UCC number, 1-7*/
port-number = <0>; /* Which ttyQEx device */
soft-uart; /* We need Soft-UART */
reg = <0x2400 0x200>;
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
index 94f93d2..179c81c 100644
--- a/arch/powerpc/boot/dts/mpc832x_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -208,9 +208,7 @@
enet0: ucc@3000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <2>;
- device-id = <2>;
reg = <0x3000 0x200>;
interrupts = <33>;
interrupt-parent = <&qeic>;
@@ -224,9 +222,7 @@
enet1: ucc@2200 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <3>;
- device-id = <3>;
reg = <0x2200 0x200>;
interrupts = <34>;
interrupt-parent = <&qeic>;
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index 55f03e8..8160ff2 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -257,9 +257,7 @@
enet0: ucc@2000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <1>;
- device-id = <1>;
reg = <0x2000 0x200>;
interrupts = <32>;
interrupt-parent = <&qeic>;
@@ -274,9 +272,7 @@
enet1: ucc@3000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <2>;
- device-id = <2>;
reg = <0x3000 0x200>;
interrupts = <33>;
interrupt-parent = <&qeic>;
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index 97bc048..df4b5e8 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -324,9 +324,7 @@
enet2: ucc@2000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <1>;
- device-id = <1>;
reg = <2000 200>;
interrupts = <20>;
interrupt-parent = <&qeic>;
@@ -341,9 +339,7 @@
enet3: ucc@3000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <2>;
- device-id = <2>;
reg = <3000 200>;
interrupts = <21>;
interrupt-parent = <&qeic>;
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index fba0811..3a68b94 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3852,7 +3852,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ugeth_vdbg("%s: IN", __FUNCTION__);
- prop = of_get_property(np, "device-id", NULL);
+ prop = of_get_property(np, "cell-index", NULL);
+ if (!prop) {
+ prop = of_get_property(np, "device-id", NULL);
+ if (!prop)
+ return -ENODEV;
+ }
+
ucc_num = *prop - 1;
if ((ucc_num < 0) || (ucc_num > 7))
return -ENODEV;
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
index c69e654..8a48ddb 100644
--- a/drivers/net/ucc_geth_mii.c
+++ b/drivers/net/ucc_geth_mii.c
@@ -203,9 +203,14 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma
if ((res.start >= tempres.start) &&
(res.end <= tempres.end)) {
/* set this UCC to be the MII master */
- const u32 *id = of_get_property(tempnp, "device-id", NULL);
- if (id == NULL)
- goto bus_register_fail;
+ const u32 *id;
+
+ id = of_get_property(tempnp, "cell-index", NULL);
+ if (!id) {
+ id = of_get_property(tempnp, "device-id", NULL);
+ if (!id)
+ goto bus_register_fail;
+ }
ucc_set_qe_mux_mii_mng(*id - 1);
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index e0994f0..5e4310c 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -1270,10 +1270,18 @@ static int ucc_uart_probe(struct of_device *ofdev,
/* Get the UCC number (device ID) */
/* UCCs are numbered 1-7 */
- iprop = of_get_property(np, "device-id", NULL);
- if (!iprop || (*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
- dev_err(&ofdev->dev,
- "missing or invalid UCC specified in device tree\n");
+ iprop = of_get_property(np, "cell-index", NULL);
+ if (!iprop) {
+ iprop = of_get_property(np, "device-id", NULL);
+ if (!iprop) {
+ dev_err(&ofdev->dev, "UCC is unspecified in "
+ "device tree\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
+ dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop);
kfree(qe_port);
return -ENODEV;
}
--
1.5.4.5
^ permalink raw reply related
* Re: [PATCH 2/8] [POWERPC] fsl_lbc: implement few routines to manage FSL UPMs
From: Anton Vorontsov @ 2008-04-11 16:13 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <EE642BFC-4262-44E8-BD48-E76E5418C276@kernel.crashing.org>
On Fri, Apr 11, 2008 at 09:09:57AM -0500, Kumar Gala wrote:
>
> On Mar 11, 2008, at 12:24 PM, Anton Vorontsov wrote:
>> These will be used by the FSL UPM NAND driver.
>
> can this be a bit more descriptive. What exactly are these functions
> trying to accomplish.
Yeah, sorry about that. Here is updated patch, with a bit more descriptive
comment, and highly kernel-doc'ed functions.
>> +int fsl_upm_find(u32 base, struct fsl_upm *upm)
>
> what is base?
Address base, as in LBC Base address register. Fixed down below.
Thanks for looking into this.
- - - -
From: Anton Vorontsov <avorontsov@ru.mvista.com>
Subject: [POWERPC] fsl_lbc: implement few UPM routines
Freescale UPM can be used to adjust localbus timings or to generate
orbitrary, pre-programmed "patterns" on the external Localbus signals.
This patch implements few routines so drivers could work with UPMs in
safe and generic manner.
So far there is just one user of these routines: Freescale UPM NAND
driver.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
arch/powerpc/Kconfig | 5 ++
arch/powerpc/sysdev/Makefile | 1 +
arch/powerpc/sysdev/fsl_lbc.c | 111 +++++++++++++++++++++++++++++++++++++++++
include/asm-powerpc/fsl_lbc.h | 87 ++++++++++++++++++++++++++++++++
4 files changed, 204 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/sysdev/fsl_lbc.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index ef12db0..9c68592 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -491,6 +491,11 @@ config FSL_PCI
bool
select PPC_INDIRECT_PCI
+config FSL_LBC
+ bool
+ help
+ Freescale Localbus support
+
# Yes MCA RS/6000s exist but Linux-PPC does not currently support any
config MCA
bool
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 15f3e85..62b6ef0 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_U3_DART) += dart_iommu.o
obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o
+obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
obj-$(CONFIG_RAPIDIO) += fsl_rio.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
new file mode 100644
index 0000000..147e4e0
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -0,0 +1,111 @@
+/*
+ * Freescale LBC and UPM routines.
+ *
+ * Copyright (c) 2007-2008 MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <asm/fsl_lbc.h>
+
+spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
+
+struct fsl_lbc_regs __iomem *fsl_lbc_regs;
+EXPORT_SYMBOL(fsl_lbc_regs);
+
+static char __initdata *compat_lbc[] = {
+ "fsl,pq2-localbus",
+ "fsl,pq2pro-localbus",
+ "fsl,pq3-localbus",
+ "fsl,elbc",
+};
+
+static int __init fsl_lbc_init(void)
+{
+ struct device_node *lbus;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
+ lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
+ if (lbus)
+ goto found;
+ }
+ return -ENODEV;
+
+found:
+ fsl_lbc_regs = of_iomap(lbus, 0);
+ of_node_put(lbus);
+ if (!fsl_lbc_regs)
+ return -ENOMEM;
+ return 0;
+}
+arch_initcall(fsl_lbc_init);
+
+/**
+ * fsl_upm_find - find pre-programmed UPM via base address
+ * @addr_base: base address of the memory bank controlled by the UPM
+ * @upm: pointer to the allocated fsl_upm structure
+ *
+ * This function walks UPMs comparing "Base address" field of the BR registers
+ * with the supplied addr_base argument. When bases are match, this function
+ * fills fsl_upm structure so you can use it with the rest of UPM API. On
+ * success this function returns 0, otherwise it returns appropriate errno
+ * value.
+ */
+int fsl_upm_find(u32 addr_base, struct fsl_upm *upm)
+{
+ int i;
+ __be32 br;
+ __be32 or;
+
+ if (!fsl_lbc_regs)
+ return -ENODEV;
+
+ for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
+ br = in_be32(&fsl_lbc_regs->bank[i].br);
+ or = in_be32(&fsl_lbc_regs->bank[i].or);
+
+ if (br & BR_V && (br & or & BR_BA) == addr_base)
+ goto found;
+ }
+
+ return -ENOENT;
+found:
+ switch (br & BR_MSEL) {
+ case BR_MS_UPMA:
+ upm->mxmr = &fsl_lbc_regs->mamr;
+ break;
+ case BR_MS_UPMB:
+ upm->mxmr = &fsl_lbc_regs->mbmr;
+ break;
+ case BR_MS_UPMC:
+ upm->mxmr = &fsl_lbc_regs->mcmr;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (br & BR_PS) {
+ case BR_PS_8:
+ upm->width = 8;
+ break;
+ case BR_PS_16:
+ upm->width = 16;
+ break;
+ case BR_PS_32:
+ upm->width = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(fsl_upm_find);
diff --git a/include/asm-powerpc/fsl_lbc.h b/include/asm-powerpc/fsl_lbc.h
index 13a3c28..960f781 100644
--- a/include/asm-powerpc/fsl_lbc.h
+++ b/include/asm-powerpc/fsl_lbc.h
@@ -24,6 +24,8 @@
#define __ASM_FSL_LBC_H
#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
struct fsl_lbc_bank {
__be32 br; /**< Base Register */
@@ -98,6 +100,11 @@ struct fsl_lbc_regs {
__be32 mar; /**< UPM Address Register */
u8 res1[0x4];
__be32 mamr; /**< UPMA Mode Register */
+#define MxMR_OP_NO (0 << 28) /**< normal operation */
+#define MxMR_OP_WA (1 << 28) /**< write array */
+#define MxMR_OP_RA (2 << 28) /**< read array */
+#define MxMR_OP_RP (3 << 28) /**< run pattern */
+#define MxMR_MAD 0x3f /**< machine address */
__be32 mbmr; /**< UPMB Mode Register */
__be32 mcmr; /**< UPMC Mode Register */
u8 res2[0x8];
@@ -220,4 +227,84 @@ struct fsl_lbc_regs {
u8 res8[0xF00];
};
+extern struct fsl_lbc_regs __iomem *fsl_lbc_regs;
+extern spinlock_t fsl_lbc_lock;
+
+/*
+ * FSL UPM routines
+ */
+struct fsl_upm {
+ __be32 __iomem *mxmr;
+ int width;
+};
+
+extern int fsl_upm_find(u32 addr_base, struct fsl_upm *upm);
+
+/**
+ * fsl_upm_start_pattern - start UPM patterns execution
+ * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find
+ * @pat_offset: UPM pattern offset for the command to be executed
+ *
+ * This routine programmes UPM so the next memory access that hits an UPM
+ * will trigger pattern execution, starting at pat_offset.
+ */
+static inline void fsl_upm_start_pattern(struct fsl_upm *upm, u8 pat_offset)
+{
+ clrsetbits_be32(upm->mxmr, MxMR_MAD, MxMR_OP_RP | pat_offset);
+}
+
+/**
+ * fsl_upm_end_pattern - end UPM patterns execution
+ * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find
+ *
+ * This routine reverts UPM to normal operation mode.
+ */
+static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
+{
+ clrbits32(upm->mxmr, MxMR_OP_RP);
+
+ while (in_be32(upm->mxmr) & MxMR_OP_RP)
+ cpu_relax();
+}
+
+/**
+ * fsl_upm_run_pattern - actually run an UPM pattern
+ * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find
+ * @io_base: remapped pointer to where memory access should happen
+ * @mar: MAR register content during pattern execution
+ *
+ * This function triggers dummy write to the memory specified by the io_base,
+ * thus UPM pattern actually executed. Note that mar usage depends on the
+ * pre-programmed AMX bits in the UPM RAM.
+ */
+static inline int fsl_upm_run_pattern(struct fsl_upm *upm,
+ void __iomem *io_base, u32 mar)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fsl_lbc_lock, flags);
+
+ out_be32(&fsl_lbc_regs->mar, mar << (32 - upm->width));
+
+ switch (upm->width) {
+ case 8:
+ out_8(io_base, 0x0);
+ break;
+ case 16:
+ out_be16(io_base, 0x0);
+ break;
+ case 32:
+ out_be32(io_base, 0x0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ spin_unlock_irqrestore(&fsl_lbc_lock, flags);
+
+ return ret;
+}
+
#endif /* __ASM_FSL_LBC_H */
--
1.5.4.5
^ permalink raw reply related
* Re: [PATCH 2/8] [POWERPC] fsl_lbc: implement few routines to manage FSL UPMs
From: Scott Wood @ 2008-04-11 16:18 UTC (permalink / raw)
To: avorontsov; +Cc: linuxppc-dev
In-Reply-To: <20080411161311.GA28067@polina.dev.rtsoft.ru>
Anton Vorontsov wrote:
> On Fri, Apr 11, 2008 at 09:09:57AM -0500, Kumar Gala wrote:
>> On Mar 11, 2008, at 12:24 PM, Anton Vorontsov wrote:
>>> These will be used by the FSL UPM NAND driver.
>> can this be a bit more descriptive. What exactly are these functions
>> trying to accomplish.
>
> Yeah, sorry about that. Here is updated patch, with a bit more descriptive
> comment, and highly kernel-doc'ed functions.
>
>>> +int fsl_upm_find(u32 base, struct fsl_upm *upm)
>> what is base?
>
> Address base, as in LBC Base address register. Fixed down below.
Should it be phys_addr_t?
> +/**
> + * fsl_upm_find - find pre-programmed UPM via base address
> + * @addr_base: base address of the memory bank controlled by the UPM
> + * @upm: pointer to the allocated fsl_upm structure
> + *
> + * This function walks UPMs comparing "Base address" field of the BR registers
> + * with the supplied addr_base argument. When bases are match, this function
> + * fills fsl_upm structure so you can use it with the rest of UPM API. On
> + * success this function returns 0, otherwise it returns appropriate errno
> + * value.
> + */
The FCM driver does something very similar; could we name this something
more generic such as fsl_lbc_find?
-Scott
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox