Commit f00d738f authored by Wolfgang Grandegger's avatar Wolfgang Grandegger Committed by Ben Dooks

i2c-mpc: add support for the MPC512x processors from Freescale

As I2C interrupts must  be enabled for the MPC512x by the setup function
as well, "fsl,preserve-clocking" is handled in a slighly different way.
Also, the old settings are now reported calling dev_dbg(). For the
MPC512x the clock setup function of the MPC52xx can be re-used.
Furthermore, the Kconfig help has been updated and corrected.
Signed-off-by: default avatarWolfgang Grandegger <wg@denx.de>
Reviewed-by: default avatarWolfram Sang <w.sang@pengutronix.de>
Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
parent a9352211
...@@ -419,13 +419,12 @@ config I2C_IXP2000 ...@@ -419,13 +419,12 @@ config I2C_IXP2000
instead. instead.
config I2C_MPC config I2C_MPC
tristate "MPC107/824x/85xx/52xx/86xx" tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
depends on PPC32 depends on PPC32
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and built-in I2C interface on the MPC107, Tsi107, MPC512x, MPC52xx,
MPC85xx/MPC8641 family processors. The driver may also work on 52xx MPC8240, MPC8245, MPC83xx, MPC85xx and MPC8641 family processors.
family processors, though interrupts are known not to work.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-mpc. will be called i2c-mpc.
......
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
#define DRV_NAME "mpc-i2c" #define DRV_NAME "mpc-i2c"
#define MPC_I2C_CLOCK_LEGACY 0
#define MPC_I2C_CLOCK_PRESERVE (~0U)
#define MPC_I2C_FDR 0x04 #define MPC_I2C_FDR 0x04
#define MPC_I2C_CR 0x08 #define MPC_I2C_CR 0x08
#define MPC_I2C_SR 0x0c #define MPC_I2C_SR 0x0c
...@@ -163,7 +166,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) ...@@ -163,7 +166,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
return 0; return 0;
} }
#ifdef CONFIG_PPC_MPC52xx #if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x)
static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = { static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = {
{20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23}, {20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
{28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02}, {28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02},
...@@ -193,7 +196,7 @@ static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, ...@@ -193,7 +196,7 @@ static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
u32 divider; u32 divider;
int i; int i;
if (!clock) if (clock == MPC_I2C_CLOCK_LEGACY)
return -EINVAL; return -EINVAL;
/* Determine divider value */ /* Determine divider value */
...@@ -221,6 +224,12 @@ static void __devinit mpc_i2c_setup_52xx(struct device_node *node, ...@@ -221,6 +224,12 @@ static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
{ {
int ret, fdr; int ret, fdr;
if (clock == MPC_I2C_CLOCK_PRESERVE) {
dev_dbg(i2c->dev, "using fdr %d\n",
readb(i2c->base + MPC_I2C_FDR));
return;
}
ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler); ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler);
fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */ fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
...@@ -229,13 +238,49 @@ static void __devinit mpc_i2c_setup_52xx(struct device_node *node, ...@@ -229,13 +238,49 @@ static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
if (ret >= 0) if (ret >= 0)
dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr); dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr);
} }
#else /* !CONFIG_PPC_MPC52xx */ #else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
static void __devinit mpc_i2c_setup_52xx(struct device_node *node, static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
struct mpc_i2c *i2c, struct mpc_i2c *i2c,
u32 clock, u32 prescaler) u32 clock, u32 prescaler)
{ {
} }
#endif /* CONFIG_PPC_MPC52xx*/ #endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
#ifdef CONFIG_PPC_MPC512x
static void __devinit mpc_i2c_setup_512x(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler)
{
struct device_node *node_ctrl;
void __iomem *ctrl;
const u32 *pval;
u32 idx;
/* Enable I2C interrupts for mpc5121 */
node_ctrl = of_find_compatible_node(NULL, NULL,
"fsl,mpc5121-i2c-ctrl");
if (node_ctrl) {
ctrl = of_iomap(node_ctrl, 0);
if (ctrl) {
/* Interrupt enable bits for i2c-0/1/2: bit 24/26/28 */
pval = of_get_property(node, "reg", NULL);
idx = (*pval & 0xff) / 0x20;
setbits32(ctrl, 1 << (24 + idx * 2));
iounmap(ctrl);
}
of_node_put(node_ctrl);
}
/* The clock setup for the 52xx works also fine for the 512x */
mpc_i2c_setup_52xx(node, i2c, clock, prescaler);
}
#else /* CONFIG_PPC_MPC512x */
static void __devinit mpc_i2c_setup_512x(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler)
{
}
#endif /* CONFIG_PPC_MPC512x */
#ifdef CONFIG_FSL_SOC #ifdef CONFIG_FSL_SOC
static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] __devinitconst = { static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] __devinitconst = {
...@@ -294,7 +339,7 @@ static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, ...@@ -294,7 +339,7 @@ static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
u32 divider; u32 divider;
int i; int i;
if (!clock) if (clock == MPC_I2C_CLOCK_LEGACY)
return -EINVAL; return -EINVAL;
/* Determine proper divider value */ /* Determine proper divider value */
...@@ -327,6 +372,13 @@ static void __devinit mpc_i2c_setup_8xxx(struct device_node *node, ...@@ -327,6 +372,13 @@ static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
{ {
int ret, fdr; int ret, fdr;
if (clock == MPC_I2C_CLOCK_PRESERVE) {
dev_dbg(i2c->dev, "using dfsrr %d, fdr %d\n",
readb(i2c->base + MPC_I2C_DFSRR),
readb(i2c->base + MPC_I2C_FDR));
return;
}
ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler); ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler);
fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */ fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
...@@ -495,7 +547,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op, ...@@ -495,7 +547,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
{ {
struct mpc_i2c *i2c; struct mpc_i2c *i2c;
const u32 *prop; const u32 *prop;
u32 clock = 0; u32 clock = MPC_I2C_CLOCK_LEGACY;
int result = 0; int result = 0;
int plen; int plen;
...@@ -524,20 +576,21 @@ static int __devinit fsl_i2c_probe(struct of_device *op, ...@@ -524,20 +576,21 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
} }
} }
if (!of_get_property(op->node, "fsl,preserve-clocking", NULL)) { if (of_get_property(op->node, "fsl,preserve-clocking", NULL)) {
clock = MPC_I2C_CLOCK_PRESERVE;
} else {
prop = of_get_property(op->node, "clock-frequency", &plen); prop = of_get_property(op->node, "clock-frequency", &plen);
if (prop && plen == sizeof(u32)) if (prop && plen == sizeof(u32))
clock = *prop; clock = *prop;
}
if (match->data) { if (match->data) {
struct mpc_i2c_data *data = struct mpc_i2c_data *data = match->data;
(struct mpc_i2c_data *)match->data; data->setup(op->node, i2c, clock, data->prescaler);
data->setup(op->node, i2c, clock, data->prescaler); } else {
} else { /* Backwards compatibility */
/* Backwards compatibility */ if (of_get_property(op->node, "dfsrr", NULL))
if (of_get_property(op->node, "dfsrr", NULL)) mpc_i2c_setup_8xxx(op->node, i2c, clock, 0);
mpc_i2c_setup_8xxx(op->node, i2c, clock, 0);
}
} }
dev_set_drvdata(&op->dev, i2c); dev_set_drvdata(&op->dev, i2c);
...@@ -582,6 +635,10 @@ static int __devexit fsl_i2c_remove(struct of_device *op) ...@@ -582,6 +635,10 @@ static int __devexit fsl_i2c_remove(struct of_device *op)
return 0; return 0;
}; };
static struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
.setup = mpc_i2c_setup_512x,
};
static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = { static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
.setup = mpc_i2c_setup_52xx, .setup = mpc_i2c_setup_52xx,
}; };
...@@ -604,6 +661,7 @@ static const struct of_device_id mpc_i2c_of_match[] = { ...@@ -604,6 +661,7 @@ static const struct of_device_id mpc_i2c_of_match[] = {
{.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, }, {.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
{.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, }, {.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, },
{.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, }, {.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
{.compatible = "fsl,mpc5121-i2c", .data = &mpc_i2c_data_512x, },
{.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, }, {.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, },
{.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, }, {.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, },
{.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, }, {.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, },
...@@ -613,7 +671,6 @@ static const struct of_device_id mpc_i2c_of_match[] = { ...@@ -613,7 +671,6 @@ static const struct of_device_id mpc_i2c_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, mpc_i2c_of_match); MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
/* Structure for a device driver */ /* Structure for a device driver */
static struct of_platform_driver mpc_i2c_driver = { static struct of_platform_driver mpc_i2c_driver = {
.match_table = mpc_i2c_of_match, .match_table = mpc_i2c_of_match,
...@@ -646,5 +703,5 @@ module_exit(fsl_i2c_exit); ...@@ -646,5 +703,5 @@ module_exit(fsl_i2c_exit);
MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>"); MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and " MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
"MPC824x/85xx/52xx processors"); "MPC824x/83xx/85xx/86xx/512x/52xx processors");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment