PatchSet 158 Date: 2003/12/20 22:23:53 Log: Make I2C speed on MPC5200 configurable by module parameter Index: arch/ppc/kernel/ppc_ksyms.c =================================================================== RCS file: /cvsroot/linuxppc_2_4_devel/arch/ppc/kernel/ppc_ksyms.c,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- arch/ppc/kernel/ppc_ksyms.c 15 Nov 2003 01:11:32 -0000 1.9 +++ arch/ppc/kernel/ppc_ksyms.c 20 Dec 2003 22:23:53 -0000 1.10 @@ -355,7 +355,7 @@ EXPORT_SYMBOL(debugger_fault_handler); #endif -#if defined(CONFIG_8xx) || defined(CONFIG_4xx) +#if defined(CONFIG_8xx) || defined(CONFIG_4xx) || defined(CONFIG_6xx) EXPORT_SYMBOL(__res); #endif #ifdef CONFIG_8xx Index: drivers/i2c/i2c-algo-mpc5xxx.c =================================================================== RCS file: /cvsroot/linuxppc_2_4_devel/drivers/i2c/i2c-algo-mpc5xxx.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- drivers/i2c/i2c-algo-mpc5xxx.c 5 Dec 2003 11:59:56 -0000 1.2 +++ drivers/i2c/i2c-algo-mpc5xxx.c 20 Dec 2003 22:23:53 -0000 1.3 @@ -16,6 +16,9 @@ #include #include #include +#ifdef CONFIG_UBOOT +#include +#endif #include #include @@ -24,6 +27,11 @@ #define MPC5xxx_TIMEOUT 100 #define MPC5xxx_RETRIES 3 +static int speed = 100; + +MODULE_PARM(speed, "i"); + + static int mpc5xxx_in(volatile u32 *reg) { return in_be32(reg) >> 24; @@ -108,6 +116,53 @@ return 0; } +static int mpc5xxx_get_fdr(void) +{ + int i2c_speed = speed * 1000; + ulong best_speed = 0; + ulong divider; + ulong scl; +#ifdef CONFIG_UBOOT + extern unsigned char __res[]; + bd_t *bd = (bd_t *)__res; + ulong ipb = bd->bi_ipbfreq; +#else + ulong ipb = CONFIG_PPC_5xxx_IPBFREQ +#endif + ulong bestmatch = 0xffffffffUL; + int best_i = 0, best_j = 0, i, j; + int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8}; + struct {int scl2tap, tap2tap; } scltap[] = { + {4, 1}, + {4, 2}, + {6, 4}, + {6, 8}, + {14, 16}, + {30, 32}, + {62, 64}, + {126, 128} + }; + + for (i = 7; i >= 0; i--) { + for (j = 7; j >= 0; j--) { + scl = 2 * (scltap[j].scl2tap + + (SCL_Tap[i] - 1) * scltap[j].tap2tap + 2); + if (ipb <= i2c_speed*scl) { + if ((i2c_speed*scl - ipb) < bestmatch) { + bestmatch = i2c_speed*scl - ipb; + best_i = i; + best_j = j; + best_speed = ipb/scl; + } + } + } + } + + divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2); + + return divider; +} + static void mpc5xxx_init(struct i2c_algo_mpc5xxx_data *algo_data) { struct mpc5xxx_i2c *regs = algo_data->regs; @@ -121,9 +176,7 @@ */ mpc5xxx_out(®s->madr, algo_data->addr, 0); - /* Make clock run maximum slow. - */ - mpc5xxx_out(®s->mfdr, MPC5xxx_I2C_100HZ, 0); + mpc5xxx_out(®s->mfdr, mpc5xxx_get_fdr(), 0); /* Enable module and disable interrupts. */ @@ -377,5 +430,5 @@ EXPORT_SYMBOL(i2c_mpc5xxx_add_bus); EXPORT_SYMBOL(i2c_mpc5xxx_del_bus); -MODULE_LICENSE("GPL") +MODULE_LICENSE("GPL");