exynos5: Re-factor I2C code

This re-factors the Exynos5 I2C code to be simpler and use the
new API, and updates users accordingly.

- i2c_read() and i2c_write() functions updated to take bus number
  as an argument.

- Get rid of the EEPROM_ADDR_OVERFLOW stuff in i2c_read() and
  i2c_write(). If a chip needs special handling we should take care
  of it elsewhere, not in every low-level i2c driver.

- All the confusing bus config functions eliminated. No more
  i2c_set_early_config() or i2c_set_bus() or i2c_get_bus(). All this
  is handled automatically when the caller does a transaction and
  specifies the desired bus number.

- i2c_probe() eliminated. We're not a command-line utility.

- Let the compiler place static variables automatically. We don't need
  any of this fancy manual data placement.

- Remove dead code while we're at it. This stuff was ported early on
  and much of it was left commented out in case we needed it. Some
  also includes nested macros which caused gcc to complain.

- Clean up #includes (no more common.h, woohoo!), replace debug() with
  printk().

Change-Id: I8e1f974ea4c6c7db9f33b77bbc4fb16008ed0d2a
Signed-off-by: David Hendricks <dhendrix@chromium.org>
Reviewed-on: http://review.coreboot.org/3044
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
David Hendricks 2013-04-05 16:11:12 -07:00 committed by Ronald G. Minnich
parent cfb73607be
commit b959fbb87a
8 changed files with 126 additions and 613 deletions

View File

@ -33,7 +33,7 @@
#include <cpu/samsung/exynos5250/sysreg.h> #include <cpu/samsung/exynos5250/sysreg.h>
#include <drivers/maxim/max77686/max77686.h> #include <drivers/maxim/max77686/max77686.h>
#include "device/i2c-old.h" #include "device/i2c.h"
#include "cpu/samsung/exynos5-common/i2c.h" #include "cpu/samsung/exynos5-common/i2c.h"
#include "cpu/samsung/exynos5250/dsim.h" #include "cpu/samsung/exynos5250/dsim.h"
#include "cpu/samsung/exynos5250/fimd.h" #include "cpu/samsung/exynos5250/fimd.h"

View File

@ -26,19 +26,14 @@
* The different address mapping is handled by the s3c24xx.h files below. * The different address mapping is handled by the s3c24xx.h files below.
*/ */
#include <common.h> #include <delay.h>
#include <arch/io.h> #include <arch/io.h>
#include "clk.h" #include <console/console.h>
#include <device/i2c.h>
#include "cpu/samsung/exynos5-common/clk.h" #include "cpu/samsung/exynos5-common/clk.h"
#include "cpu/samsung/exynos5250/cpu.h" #include "cpu/samsung/exynos5-common/i2c.h"
#include "gpio.h"
#include "cpu/samsung/exynos5250/gpio.h"
#include "cpu/samsung/exynos5250/pinmux.h" #include "cpu/samsung/exynos5250/pinmux.h"
//#include <fdtdec.h>
#include "device/i2c-old.h"
#include "i2c.h"
#define I2C_WRITE 0 #define I2C_WRITE 0
#define I2C_READ 1 #define I2C_READ 1
@ -65,54 +60,49 @@ enum {
I2C_STOP_TIMEOUT_US = 200, /* waiting for stop events */ I2C_STOP_TIMEOUT_US = 200, /* waiting for stop events */
}; };
/* We should not rely on any particular ordering of these IDs */ static struct s3c24x0_i2c_bus i2c_buses[] = {
#if 0 /* FIXME: exynos5250-specific? */
#ifndef CONFIG_OF_CONTROL {
static enum periph_id periph_for_dev[EXYNOS_I2C_MAX_CONTROLLERS] = { .bus_num = 0,
PERIPH_ID_I2C0, .regs = (struct s3c24x0_i2c *)0x12c60000,
PERIPH_ID_I2C1, .periph_id = PERIPH_ID_I2C0,
PERIPH_ID_I2C2, },
PERIPH_ID_I2C3, {
PERIPH_ID_I2C4, .bus_num = 1,
PERIPH_ID_I2C5, .regs = (struct s3c24x0_i2c *)0x12c70000,
PERIPH_ID_I2C6, .periph_id = PERIPH_ID_I2C1,
PERIPH_ID_I2C7, },
{
.bus_num = 2,
.regs = (struct s3c24x0_i2c *)0x12c80000,
.periph_id = PERIPH_ID_I2C2,
},
{
.bus_num = 3,
.regs = (struct s3c24x0_i2c *)0x12c90000,
.periph_id = PERIPH_ID_I2C3,
},
{
.bus_num = 4,
.regs = (struct s3c24x0_i2c *)0x12ca0000,
.periph_id = PERIPH_ID_I2C4,
},
{
.bus_num = 5,
.regs = (struct s3c24x0_i2c *)0x12cb0000,
.periph_id = PERIPH_ID_I2C5,
},
{
.bus_num = 6,
.regs = (struct s3c24x0_i2c *)0x12cc0000,
.periph_id = PERIPH_ID_I2C6,
},
{
.bus_num = 7,
.regs = (struct s3c24x0_i2c *)0x12cd0000,
.periph_id = PERIPH_ID_I2C7,
},
}; };
#endif
#endif
static unsigned int g_current_bus __attribute__((section(".data")));
static struct s3c24x0_i2c *g_early_i2c_config __attribute__((section(".data")));
static struct s3c24x0_i2c_bus i2c_bus[EXYNOS_I2C_MAX_CONTROLLERS]
__attribute__((section(".data")));
static int i2c_busses __attribute__((section(".data")));
void i2c_set_early_reg(unsigned int base)
{
g_early_i2c_config = (struct s3c24x0_i2c *)base;
}
static struct s3c24x0_i2c_bus *get_bus(int bus_idx)
{
/* If an early i2c config exists we just use that */
if (g_early_i2c_config) {
/* FIXME: value not retained from i2c_set_early_reg()? (but then, how
* did if (!i2c) check pass earlier on? Corrupt value? */
i2c_bus[0].regs = g_early_i2c_config;
return &i2c_bus[0];
}
if (bus_idx < i2c_busses)
return &i2c_bus[bus_idx];
debug("Undefined bus: %d\n", bus_idx);
return NULL;
}
static inline struct exynos5_gpio_part1 *exynos_get_base_gpio1(void)
{
return (struct exynos5_gpio_part1 *)(EXYNOS5_GPIO_PART1_BASE);
}
static int WaitForXfer(struct s3c24x0_i2c *i2c) static int WaitForXfer(struct s3c24x0_i2c *i2c)
{ {
@ -121,7 +111,7 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c)
i = I2C_XFER_TIMEOUT_MS * 20; i = I2C_XFER_TIMEOUT_MS * 20;
while (!(readl(&i2c->iiccon) & I2CCON_IRPND)) { while (!(readl(&i2c->iiccon) & I2CCON_IRPND)) {
if (i == 0) { if (i == 0) {
debug("%s: i2c xfer timeout\n", __func__); printk(BIOS_ERR, "%s: i2c xfer timeout\n", __func__);
return I2C_NOK_TOUT; return I2C_NOK_TOUT;
} }
udelay(50); udelay(50);
@ -142,15 +132,14 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c)
x = readl(&i2c->iiccon); x = readl(&i2c->iiccon);
writel(x & ~I2CCON_IRPND, &i2c->iiccon); writel(x & ~I2CCON_IRPND, &i2c->iiccon);
/* FIXME(dhendrix): cannot use nested macro (compilation failure) */
// writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
} }
static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) static void i2c_ch_init(struct s3c24x0_i2c_bus *bus, int speed, int slaveadd)
{ {
unsigned long freq, pres = 16, div; unsigned long freq, pres = 16, div;
unsigned long val;
freq = clock_get_periph_rate(PERIPH_ID_I2C0); freq = clock_get_periph_rate(bus->periph_id);
/* calculate prescaler and divisor values */ /* calculate prescaler and divisor values */
if ((freq / pres / (16 + 1)) > speed) if ((freq / pres / (16 + 1)) > speed)
/* set prescaler to 512 */ /* set prescaler to 512 */
@ -162,136 +151,25 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
div++; div++;
/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */ /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon); val = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0);
writel(val, &bus->regs->iiccon);
/* init to SLAVE REVEIVE and set slaveaddr */ /* init to SLAVE RECEIVE mode and clear I2CADDn */
writel(0, &i2c->iicstat); writel(0, &bus->regs->iicstat);
writel(slaveadd, &i2c->iicadd); writel(slaveadd, &bus->regs->iicadd);
/* program Master Transmit (and implicit STOP) */ /* program Master Transmit (and implicit STOP) */
writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); writel(I2C_MODE_MT | I2C_TXRX_ENA, &bus->regs->iicstat);
} }
/* TODO: determine if this is necessary to init board using FDT-provided info */
#if 0
void board_i2c_init(const void *blob)
{
/*
* Turn off the early i2c configuration and init the i2c properly,
* this is done here to enable the use of i2c configs from FDT.
*/
i2c_set_early_reg(0);
#ifdef CONFIG_OF_CONTROL
int node_list[EXYNOS_I2C_MAX_CONTROLLERS];
int i, count;
count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_SAMSUNG_S3C2440_I2C, node_list,
EXYNOS_I2C_MAX_CONTROLLERS);
for (i = 0; i < count; i++) {
struct s3c24x0_i2c_bus *bus;
int node = node_list[i];
if (node < 0)
continue;
bus = &i2c_bus[i2c_busses];
bus->regs = (struct s3c24x0_i2c *)
fdtdec_get_addr(blob, node, "reg");
bus->id = (enum periph_id)
fdtdec_get_int(blob, node, "samsung,periph-id", -1);
bus->node = node;
bus->bus_num = i2c_busses++;
}
#else
int i;
for (i = 0; i < EXYNOS_I2C_MAX_CONTROLLERS; i++) {
unsigned intptr_t reg_addr = samsung_get_base_i2c() +
EXYNOS_I2C_SPACING * i;
i2c_bus[i].regs = (struct s3c24x0_i2c_bus *)reg_addr;
i2c_bus[i].id = periph_for_dev[i];
}
i2c_busses = EXYNOS_I2C_MAX_CONTROLLERS;
#endif
}
#endif
/* /*
* MULTI BUS I2C support * MULTI BUS I2C support
*/ */
static void i2c_bus_init(struct s3c24x0_i2c_bus *i2c, unsigned int bus) static void i2c_bus_init(struct s3c24x0_i2c_bus *bus, int speed, int slaveadd)
{ {
exynos_pinmux_config(i2c->id, 0); exynos_pinmux_config(bus->periph_id, 0);
i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); i2c_ch_init(bus, speed, slaveadd);
} }
#ifdef CONFIG_I2C_MULTI_BUS
int i2c_set_bus_num(unsigned int bus)
{
struct s3c24x0_i2c_bus *i2c;
i2c = get_bus(bus);
if (!i2c)
return -1;
g_current_bus = bus;
i2c_bus_init(i2c, g_current_bus);
return 0;
}
unsigned int i2c_get_bus_num(void)
{
return g_current_bus;
}
#endif
#ifdef CONFIG_OF_CONTROL
int i2c_get_bus_num_fdt(const void *blob, int node)
{
enum fdt_compat_id compat;
fdt_addr_t reg;
int i;
compat = fdtdec_lookup(blob, node);
if (compat != COMPAT_SAMSUNG_S3C2440_I2C) {
debug("%s: Not a supported I2C node\n", __func__);
return -1;
}
reg = fdtdec_get_addr(blob, node, "reg");
for (i = 0; i < i2c_busses; i++)
if (reg == (fdt_addr_t)(unsigned intptr_t)i2c_bus[i].regs)
return i;
debug("%s: Can't find any matched I2C bus\n", __func__);
return -1;
}
int i2c_reset_port_fdt(const void *blob, int node)
{
struct s3c24x0_i2c_bus *i2c;
int bus;
bus = i2c_get_bus_num_fdt(blob, node);
if (bus < 0) {
printf("could not get bus for node %d\n", node);
return -1;
}
i2c = get_bus(bus);
if (!i2c) {
printf("get_bus() failed for node node %d\n", node);
return -1;
}
i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 0;
}
#endif
/* /*
* Verify the whether I2C ACK was received or not * Verify the whether I2C ACK was received or not
* *
@ -321,21 +199,13 @@ static int i2c_send_verify(struct s3c24x0_i2c *i2c, unsigned char buf[],
return result; return result;
} }
void i2c_init(int speed, int slaveadd) void i2c_init(unsigned bus_num, int speed, int slaveadd)
{ {
struct s3c24x0_i2c_bus *i2c; struct s3c24x0_i2c_bus *i2c;
struct exynos5_gpio_part1 *gpio;
int i; int i;
uint32_t x;
/* By default i2c channel 0 is the current bus */ i2c = &i2c_buses[bus_num];
g_current_bus = 0; i2c_bus_init(i2c, speed, slaveadd);
i2c = get_bus(g_current_bus);
if (!i2c)
return;
i2c_bus_init(i2c, g_current_bus);
/* wait for some time to give previous transfer a chance to finish */ /* wait for some time to give previous transfer a chance to finish */
i = I2C_INIT_TIMEOUT_MS * 20; i = I2C_INIT_TIMEOUT_MS * 20;
@ -344,13 +214,7 @@ void i2c_init(int speed, int slaveadd)
i--; i--;
} }
gpio = exynos_get_base_gpio1(); i2c_ch_init(i2c, speed, slaveadd);
/* FIXME(dhendrix): cannot use nested macro (compilation failure) */
// writel((readl(&gpio->b3.con) & ~0x00FF) | 0x0022, &gpio->b3.con);
x = readl(&gpio->b3.con);
writel((x & ~0x00FF) | 0x0022, &gpio->b3.con);
i2c_ch_init(i2c->regs, speed, slaveadd);
} }
/* /*
@ -397,7 +261,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
if (data == 0 || data_len == 0) { if (data == 0 || data_len == 0) {
/* Don't support data transfer of no length or to address 0 */ /* Don't support data transfer of no length or to address 0 */
debug("i2c_transfer: bad call\n"); printk(BIOS_ERR, "i2c_transfer: bad call\n");
return I2C_NOK; return I2C_NOK;
} }
@ -409,12 +273,10 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
} }
if (readl(&i2c->iicstat) & I2CSTAT_BSY) { if (readl(&i2c->iicstat) & I2CSTAT_BSY) {
debug("%s: bus busy\n", __func__); printk(BIOS_ERR, "%s: bus busy\n", __func__);
return I2C_NOK_TOUT; return I2C_NOK_TOUT;
} }
/* FIXME(dhendrix): cannot use nested macro (compilation failure) */
//writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
x = readl(&i2c->iiccon); x = readl(&i2c->iiccon);
writel(x | I2CCON_ACKGEN, &i2c->iiccon); writel(x | I2CCON_ACKGEN, &i2c->iiccon);
@ -465,12 +327,6 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
while ((i < data_len) && (result == I2C_OK)) { while ((i < data_len) && (result == I2C_OK)) {
/* disable ACK for final READ */ /* disable ACK for final READ */
if (i == data_len - 1) { if (i == data_len - 1) {
/* FIXME(dhendrix): nested macro */
#if 0
writel(readl(&i2c->iiccon) &
~I2CCON_ACKGEN,
&i2c->iiccon);
#endif
x = readl(&i2c->iiccon) & ~I2CCON_ACKGEN; x = readl(&i2c->iiccon) & ~I2CCON_ACKGEN;
writel(x, &i2c->iiccon); writel(x, &i2c->iiccon);
} }
@ -488,7 +344,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
} }
default: default:
debug("i2c_transfer: bad call\n"); printk(BIOS_ERR, "i2c_transfer: bad call\n");
result = stop_bit_result = I2C_NOK; result = stop_bit_result = I2C_NOK;
break; break;
} }
@ -501,35 +357,15 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
return (result == I2C_OK) ? stop_bit_result : result; return (result == I2C_OK) ? stop_bit_result : result;
} }
int i2c_probe(unsigned char chip) int i2c_read(unsigned bus, unsigned chip, unsigned addr,
{ unsigned alen, unsigned char *buf, unsigned len)
struct s3c24x0_i2c_bus *i2c;
unsigned char buf[1];
int ret;
i2c = get_bus(g_current_bus);
if (!i2c)
return -1;
buf[0] = 0;
/*
* What is needed is to send the chip address and verify that the
* address was <ACK>ed (i.e. there was a chip at that address which
* drove the data line low).
*/
ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1, 0, 0, buf, 1);
return ret != I2C_OK;
}
int i2c_read(unsigned char chip, unsigned int addr, int alen, unsigned char *buffer, int len)
{ {
struct s3c24x0_i2c_bus *i2c; struct s3c24x0_i2c_bus *i2c;
unsigned char xaddr[4]; unsigned char xaddr[4];
int ret; int ret;
if (alen > 4) { if (alen > 4) {
debug("I2C read: addr len %d not supported\n", alen); printk(BIOS_ERR, "I2C read: addr len %d not supported\n", alen);
return 1; return 1;
} }
@ -540,42 +376,26 @@ int i2c_read(unsigned char chip, unsigned int addr, int alen, unsigned char *buf
xaddr[3] = addr & 0xFF; xaddr[3] = addr & 0xFF;
} }
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW i2c = &i2c_buses[bus];
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
if (alen > 0)
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
i2c = get_bus(g_current_bus);
if (!i2c)
return -1;
ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1, &xaddr[4 - alen], ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1, &xaddr[4 - alen],
alen, buffer, len); alen, buf, len);
if (ret) { if (ret) {
debug("I2c read: failed %d\n", ret); printk(BIOS_ERR, "I2c read: failed %d\n", ret);
return 1; return 1;
} }
return 0; return 0;
} }
int i2c_write(unsigned char chip, unsigned int addr, int alen, unsigned char *buffer, int len) int i2c_write(unsigned bus, unsigned chip, unsigned addr,
unsigned alen, unsigned char *buf, unsigned len)
{ {
struct s3c24x0_i2c_bus *i2c; struct s3c24x0_i2c_bus *i2c;
unsigned char xaddr[4]; unsigned char xaddr[4];
int ret; int ret;
if (alen > 4) { if (alen > 4) {
debug("I2C write: addr len %d not supported\n", alen); printk(BIOS_ERR, "I2C write: addr len %d not supported\n",
alen);
return 1; return 1;
} }
@ -585,28 +405,10 @@ int i2c_write(unsigned char chip, unsigned int addr, int alen, unsigned char *bu
xaddr[2] = (addr >> 8) & 0xFF; xaddr[2] = (addr >> 8) & 0xFF;
xaddr[3] = addr & 0xFF; xaddr[3] = addr & 0xFF;
} }
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
if (alen > 0)
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
i2c = get_bus(g_current_bus);
if (!i2c)
return -1;
i2c = &i2c_buses[bus];
ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1, &xaddr[4 - alen], ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1, &xaddr[4 - alen],
alen, buffer, len); alen, buf, len);
return ret != 0; return ret != 0;
} }

View File

@ -35,9 +35,11 @@ struct s3c24x0_i2c {
}; };
struct s3c24x0_i2c_bus { struct s3c24x0_i2c_bus {
int node; /* device tree node */ int bus_num;
int bus_num; /* i2c bus number */
struct s3c24x0_i2c *regs; struct s3c24x0_i2c *regs;
enum periph_id id; enum periph_id periph_id;
}; };
void i2c_init(unsigned bus, int speed, int slaveadd);
#endif /* _S3C24X0_I2C_H */ #endif /* _S3C24X0_I2C_H */

View File

@ -23,8 +23,7 @@
#include <arch/io.h> #include <arch/io.h>
#include <common.h> #include <common.h>
//#include <smbus.h> #include <device/i2c.h>
#include <device/i2c-old.h>
#include "max77686.h" #include "max77686.h"
@ -91,10 +90,10 @@ struct max77686_para max77686_param[] = {/*{vol_addr, vol_bitpos,
* @param val value to be written * @param val value to be written
* *
*/ */
static inline int max77686_i2c_write(unsigned char chip_addr, static inline int max77686_i2c_write(unsigned int bus, unsigned char chip_addr,
unsigned int reg, unsigned char val) unsigned int reg, unsigned char val)
{ {
return i2c_write(chip_addr, reg, 1, &val, 1); return i2c_write(bus, chip_addr, reg, 1, &val, 1);
} }
/* /*
@ -105,10 +104,10 @@ static inline int max77686_i2c_write(unsigned char chip_addr,
* @param val value to be written * @param val value to be written
* *
*/ */
static inline int max77686_i2c_read(unsigned char chip_addr, static inline int max77686_i2c_read(unsigned int bus, unsigned char chip_addr,
unsigned int reg, unsigned char *val) unsigned int reg, unsigned char *val)
{ {
return i2c_read(chip_addr, reg, 1, val, 1); return i2c_read(bus, chip_addr, reg, 1, val, 1);
} }
/* /*
@ -121,7 +120,7 @@ static inline int max77686_i2c_read(unsigned char chip_addr,
needed to set the buck/ldo enable bit OFF needed to set the buck/ldo enable bit OFF
* @return Return 0 if ok, else -1 * @return Return 0 if ok, else -1
*/ */
static int max77686_enablereg(enum max77686_regnum reg, int enable) static int max77686_enablereg(unsigned int bus, enum max77686_regnum reg, int enable)
{ {
struct max77686_para *pmic; struct max77686_para *pmic;
unsigned char read_data; unsigned char read_data;
@ -129,7 +128,7 @@ static int max77686_enablereg(enum max77686_regnum reg, int enable)
pmic = &max77686_param[reg]; pmic = &max77686_param[reg];
ret = max77686_i2c_read(MAX77686_I2C_ADDR, pmic->reg_enaddr, ret = max77686_i2c_read(bus, MAX77686_I2C_ADDR, pmic->reg_enaddr,
&read_data); &read_data);
if (ret != 0) { if (ret != 0) {
debug("max77686 i2c read failed.\n"); debug("max77686 i2c read failed.\n");
@ -145,7 +144,7 @@ static int max77686_enablereg(enum max77686_regnum reg, int enable)
pmic->reg_enbiton << pmic->reg_enbitpos); pmic->reg_enbiton << pmic->reg_enbitpos);
} }
ret = max77686_i2c_write(MAX77686_I2C_ADDR, ret = max77686_i2c_write(bus, MAX77686_I2C_ADDR,
pmic->reg_enaddr, read_data); pmic->reg_enaddr, read_data);
if (ret != 0) { if (ret != 0) {
debug("max77686 i2c write failed.\n"); debug("max77686 i2c write failed.\n");
@ -155,8 +154,8 @@ static int max77686_enablereg(enum max77686_regnum reg, int enable)
return 0; return 0;
} }
static int max77686_do_volsetting(enum max77686_regnum reg, unsigned int volt, int max77686_volsetting(unsigned int bus, enum max77686_regnum reg,
int enable, int volt_units) unsigned int volt, int enable, int volt_units)
{ {
struct max77686_para *pmic; struct max77686_para *pmic;
unsigned char read_data; unsigned char read_data;
@ -170,7 +169,7 @@ static int max77686_do_volsetting(enum max77686_regnum reg, unsigned int volt,
return -1; return -1;
} }
ret = max77686_i2c_read(MAX77686_I2C_ADDR, pmic->vol_addr, &read_data); ret = max77686_i2c_read(bus, MAX77686_I2C_ADDR, pmic->vol_addr, &read_data);
if (ret != 0) { if (ret != 0) {
debug("max77686 i2c read failed.\n"); debug("max77686 i2c read failed.\n");
return -1; return -1;
@ -190,13 +189,13 @@ static int max77686_do_volsetting(enum max77686_regnum reg, unsigned int volt,
clrsetbits_8(&read_data, pmic->vol_bitmask << pmic->vol_bitpos, clrsetbits_8(&read_data, pmic->vol_bitmask << pmic->vol_bitpos,
vol_level << pmic->vol_bitpos); vol_level << pmic->vol_bitpos);
ret = max77686_i2c_write(MAX77686_I2C_ADDR, pmic->vol_addr, read_data); ret = max77686_i2c_write(bus, MAX77686_I2C_ADDR, pmic->vol_addr, read_data);
if (ret != 0) { if (ret != 0) {
debug("max77686 i2c write failed.\n"); debug("max77686 i2c write failed.\n");
return -1; return -1;
} }
ret = max77686_enablereg(reg, enable); ret = max77686_enablereg(bus, reg, enable);
if (ret != 0) { if (ret != 0) {
debug("Failed to enable buck/ldo.\n"); debug("Failed to enable buck/ldo.\n");
return -1; return -1;
@ -204,31 +203,17 @@ static int max77686_do_volsetting(enum max77686_regnum reg, unsigned int volt,
return 0; return 0;
} }
int max77686_volsetting(enum max77686_regnum reg, unsigned int volt, int max77686_enable_32khz_cp(unsigned int bus)
int enable, int volt_units)
{ {
int old_bus = i2c_get_bus_num(); return max77686_enablereg(bus, PMIC_EN32KHZ_CP, REG_ENABLE);
int ret;
i2c_set_bus_num(0);
ret = max77686_do_volsetting(reg, volt, enable, volt_units);
i2c_set_bus_num(old_bus);
return ret;
} }
int max77686_enable_32khz_cp(void) int max77686_disable_backup_batt(unsigned int bus)
{
i2c_set_bus_num(0);
return max77686_enablereg(PMIC_EN32KHZ_CP, REG_ENABLE);
}
int max77686_disable_backup_batt(void)
{ {
unsigned char val; unsigned char val;
int ret; int ret;
i2c_set_bus_num(0); ret = max77686_i2c_read(bus, MAX77686_I2C_ADDR, REG_BBAT, &val);
ret = max77686_i2c_read(MAX77686_I2C_ADDR, REG_BBAT, &val);
if (ret) { if (ret) {
debug("max77686 i2c read failed\n"); debug("max77686 i2c read failed\n");
return ret; return ret;
@ -241,7 +226,7 @@ int max77686_disable_backup_batt(void)
/* First disable charging */ /* First disable charging */
val &= ~BBAT_BBCHOSTEN_MASK; val &= ~BBAT_BBCHOSTEN_MASK;
ret = max77686_i2c_write(MAX77686_I2C_ADDR, REG_BBAT, val); ret = max77686_i2c_write(bus, MAX77686_I2C_ADDR, REG_BBAT, val);
if (ret) { if (ret) {
debug("max77686 i2c write failed\n"); debug("max77686 i2c write failed\n");
return -1; return -1;
@ -249,7 +234,7 @@ int max77686_disable_backup_batt(void)
/* Finally select 3.5V to minimize power consumption */ /* Finally select 3.5V to minimize power consumption */
val |= BBAT_BBCVS_MASK; val |= BBAT_BBCVS_MASK;
ret = max77686_i2c_write(MAX77686_I2C_ADDR, REG_BBAT, val); ret = max77686_i2c_write(bus, MAX77686_I2C_ADDR, REG_BBAT, val);
if (ret) { if (ret) {
debug("max77686 i2c write failed\n"); debug("max77686 i2c write failed\n");
return -1; return -1;

View File

@ -105,13 +105,16 @@ enum {
/** /**
* This function enables the 32KHz coprocessor clock. * This function enables the 32KHz coprocessor clock.
* *
* @param bus i2c bus
*
* Return 0 if ok, else -1 * Return 0 if ok, else -1
*/ */
int max77686_enable_32khz_cp(void); int max77686_enable_32khz_cp(unsigned int bus);
/** /**
* Set the required voltage level of pmic * Set the required voltage level of pmic
* *
* @param bus i2c bus
* @param reg register number of buck/ldo to be set * @param reg register number of buck/ldo to be set
* @param volt voltage level to be set * @param volt voltage level to be set
* @param enable enable or disable bit * @param enable enable or disable bit
@ -120,14 +123,16 @@ int max77686_enable_32khz_cp(void);
* *
* @return Return 0 if ok, else -1 * @return Return 0 if ok, else -1
*/ */
int max77686_volsetting(enum max77686_regnum reg, unsigned int volt, int max77686_volsetting(unsigned int bus, enum max77686_regnum reg,
int enable, int volt_units); unsigned int volt, int enable, int volt_units);
/** /**
* Disable charging of the RTC backup battery * Disable charging of the RTC backup battery
* *
* @param bus i2c bus
*
* @return Return 0 if ok, else -1 * @return Return 0 if ok, else -1
*/ */
int max77686_disable_backup_batt(void); int max77686_disable_backup_batt(unsigned int bus);
#endif /* __MAX77686_PMIC_H_ */ #endif /* __MAX77686_PMIC_H_ */

View File

@ -1,281 +0,0 @@
/*
* (C) Copyright 2001
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* The original I2C interface was
* (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
* AIRVENT SAM s.p.a - RIMINI(ITALY)
* but has been changed substantially.
*/
#ifndef _I2C_H_
#define _I2C_H_
/*
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*
* The implementation MUST NOT use static or global variables if the
* I2C routines are used to read SDRAM configuration information
* because this is done before the memories are initialized. Limited
* use of stack-based variables are OK (the initial stack size is
* limited).
*
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*/
/*
* Configuration items.
*/
#define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */
#ifdef CONFIG_I2C_MULTI_BUS
#define MAX_I2C_BUS 2
#define I2C_MULTI_BUS 1
#else
#define MAX_I2C_BUS 1
#define I2C_MULTI_BUS 0
#endif
#if !defined(CONFIG_SYS_MAX_I2C_BUS)
#define CONFIG_SYS_MAX_I2C_BUS MAX_I2C_BUS
#endif
/* define the I2C bus number for RTC and DTT if not already done */
#if !defined(CONFIG_SYS_RTC_BUS_NUM)
#define CONFIG_SYS_RTC_BUS_NUM 0
#endif
#if !defined(CONFIG_SYS_DTT_BUS_NUM)
#define CONFIG_SYS_DTT_BUS_NUM 0
#endif
#if !defined(CONFIG_SYS_SPD_BUS_NUM)
#define CONFIG_SYS_SPD_BUS_NUM 0
#endif
#ifndef I2C_SOFT_DECLARATIONS
# if defined(CONFIG_MPC8260)
# define I2C_SOFT_DECLARATIONS volatile ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, I2C_PORT);
# elif defined(CONFIG_8xx)
# define I2C_SOFT_DECLARATIONS volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
# elif (defined(CONFIG_AT91RM9200) || \
defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9261) || \
defined(CONFIG_AT91SAM9263)) && !defined(CONFIG_AT91_LEGACY)
# define I2C_SOFT_DECLARATIONS at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA;
# else
# define I2C_SOFT_DECLARATIONS
# endif
#endif
#ifdef CONFIG_8xx
/* Set default value for the I2C bus speed on 8xx. In the
* future, we'll define these in all 8xx board config files.
*/
#ifndef CONFIG_SYS_I2C_SPEED
#define CONFIG_SYS_I2C_SPEED 50000
#endif
#endif
/*
* Many boards/controllers/drivers don't support an I2C slave interface so
* provide a default slave address for them for use in common code. A real
* value for CONFIG_SYS_I2C_SLAVE should be defined for any board which does
* support a slave interface.
*/
#ifndef CONFIG_SYS_I2C_SLAVE
#define CONFIG_SYS_I2C_SLAVE 0xfe
#endif
/*
* Initialization, must be called once on start up, may be called
* repeatedly to change the speed and slave addresses.
*/
void i2c_init(int speed, int slaveaddr);
void i2c_init_board(void);
#ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT
void i2c_board_late_init(void);
#endif
#if defined(CONFIG_I2C_MUX)
typedef struct _mux {
unsigned char chip;
unsigned char channel;
char *name;
struct _mux *next;
} I2C_MUX;
typedef struct _mux_device {
int busid;
I2C_MUX *mux; /* List of muxes, to reach the device */
struct _mux_device *next;
} I2C_MUX_DEVICE;
I2C_MUX_DEVICE *i2c_mux_search_device(int id);
I2C_MUX_DEVICE *i2c_mux_ident_muxstring (unsigned char *buf);
int i2x_mux_select_mux(int bus);
int i2c_mux_ident_muxstring_f (unsigned char *buf);
#endif
/*
* Probe the given I2C chip address. Returns 0 if a chip responded,
* not 0 on failure.
*/
int i2c_probe(unsigned char chip);
/*
* Read/Write interface:
* chip: I2C chip address, range 0..127
* addr: Memory (register) address within the chip
* alen: Number of bytes to use for addr (typically 1, 2 for larger
* memories, 0 for register type devices with only one
* register)
* buffer: Where to read/write the data
* len: How many bytes to read/write
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_read(unsigned char chip, unsigned int addr, int alen,
unsigned char *buffer, int len);
int i2c_write(unsigned char chip, unsigned int addr, int alen,
unsigned char *buffer, int len);
/*
* Utility routines to read/write registers.
*/
static inline u8 i2c_reg_read(u8 addr, u8 reg)
{
u8 buf;
#ifdef CONFIG_8xx
/* MPC8xx needs this. Maybe one day we can get rid of it. */
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
#ifdef DEBUG
printf("%s: addr=0x%02x, reg=0x%02x\n", __func__, addr, reg);
#endif
i2c_read(addr, reg, 1, &buf, 1);
return buf;
}
static inline void i2c_reg_write(u8 addr, u8 reg, u8 val)
{
#ifdef CONFIG_8xx
/* MPC8xx needs this. Maybe one day we can get rid of it. */
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
#ifdef DEBUG
printf("%s: addr=0x%02x, reg=0x%02x, val=0x%02x\n",
__func__, addr, reg, val);
#endif
i2c_write(addr, reg, 1, &val, 1);
}
/*
* Functions for setting the current I2C bus and its speed
*/
/*
* i2c_set_bus_num:
*
* Change the active I2C bus. Subsequent read/write calls will
* go to this one.
*
* bus - bus index, zero based
*
* Returns: 0 on success, not 0 on failure
*
*/
int i2c_set_bus_num(unsigned int bus);
/*
* i2c_get_bus_num:
*
* Returns index of currently active I2C bus. Zero-based.
*/
unsigned int i2c_get_bus_num(void);
/*
* i2c_set_bus_speed:
*
* Change the speed of the active I2C bus
*
* speed - bus speed in Hz
*
* Returns: 0 on success, not 0 on failure
*
*/
int i2c_set_bus_speed(unsigned int);
/*
* i2c_get_bus_speed:
*
* Returns speed of currently active I2C bus in Hz
*/
unsigned int i2c_get_bus_speed(void);
/* NOTE: These two functions MUST be always_inline to avoid code growth! */
static inline unsigned int I2C_GET_BUS(void) __attribute__((always_inline));
static inline unsigned int I2C_GET_BUS(void)
{
return I2C_MULTI_BUS ? i2c_get_bus_num() : 0;
}
static inline void I2C_SET_BUS(unsigned int bus) __attribute__((always_inline));
static inline void I2C_SET_BUS(unsigned int bus)
{
if (I2C_MULTI_BUS)
i2c_set_bus_num(bus);
}
/*
* Set an early register base for a given i2c peripheral.
* This is used to access a single i2c bus early on in the boot sequence.
*
* @param base: The base address of the i2c peripheral's register map
*/
void i2c_set_early_reg(unsigned int base);
/**
* Find the I2C bus number by given a FDT I2C node.
*
* @param blob Device tree blbo
* @param node FDT I2C node to find
* @return the number of I2C bus (zero based), or -1 on error
*/
int i2c_get_bus_num_fdt(const void *blob, int node);
/**
* Reset the I2C bus represented by the given a FDT I2C node.
*
* @param blob Device tree blbo
* @param node FDT I2C node to find
* @return 0 if port was reset, -1 if not found
*/
int i2c_reset_port_fdt(const void *blob, int node);
#endif /* _I2C_H_ */

View File

@ -25,8 +25,6 @@
#include <cpu/samsung/exynos5250/periph.h> #include <cpu/samsung/exynos5250/periph.h>
#include <cpu/samsung/exynos5250/pinmux.h> #include <cpu/samsung/exynos5250/pinmux.h>
#define I2C0_BASE 0x12c60000
void bootblock_mainboard_init(void); void bootblock_mainboard_init(void);
void bootblock_mainboard_init(void) void bootblock_mainboard_init(void)
{ {

View File

@ -25,6 +25,7 @@
#include <arch/cache.h> #include <arch/cache.h>
#include <arch/gpio.h> #include <arch/gpio.h>
#include <cpu/samsung/exynos5-common/i2c.h>
#include <cpu/samsung/exynos5250/clk.h> #include <cpu/samsung/exynos5250/clk.h>
#include <cpu/samsung/exynos5250/dmc.h> #include <cpu/samsung/exynos5250/dmc.h>
#include <cpu/samsung/exynos5250/gpio.h> #include <cpu/samsung/exynos5250/gpio.h>
@ -36,10 +37,11 @@
#include <arch/stages.h> #include <arch/stages.h>
#include <drivers/maxim/max77686/max77686.h> #include <drivers/maxim/max77686/max77686.h>
#include <device/i2c-old.h> #include <device/i2c.h>
#include "mainboard.h" #include "mainboard.h"
#define PMIC_BUS 0
#define MMC0_GPIO_PIN (58) #define MMC0_GPIO_PIN (58)
#if 0 #if 0
@ -69,23 +71,23 @@ static int setup_pmic(void)
* *
* Disable Coin BATT Charging * Disable Coin BATT Charging
*/ */
error = max77686_disable_backup_batt(); error = max77686_disable_backup_batt(PMIC_BUS);
error |= max77686_volsetting(PMIC_BUCK2, CONFIG_VDD_ARM_MV, error |= max77686_volsetting(PMIC_BUS, PMIC_BUCK2, CONFIG_VDD_ARM_MV,
REG_ENABLE, MAX77686_MV); REG_ENABLE, MAX77686_MV);
error |= max77686_volsetting(PMIC_BUCK3, CONFIG_VDD_INT_UV, error |= max77686_volsetting(PMIC_BUS, PMIC_BUCK3, CONFIG_VDD_INT_UV,
REG_ENABLE, MAX77686_UV); REG_ENABLE, MAX77686_UV);
error |= max77686_volsetting(PMIC_BUCK1, CONFIG_VDD_MIF_MV, error |= max77686_volsetting(PMIC_BUS, PMIC_BUCK1, CONFIG_VDD_MIF_MV,
REG_ENABLE, MAX77686_MV); REG_ENABLE, MAX77686_MV);
error |= max77686_volsetting(PMIC_BUCK4, CONFIG_VDD_G3D_MV, error |= max77686_volsetting(PMIC_BUS, PMIC_BUCK4, CONFIG_VDD_G3D_MV,
REG_ENABLE, MAX77686_MV); REG_ENABLE, MAX77686_MV);
error |= max77686_volsetting(PMIC_LDO2, CONFIG_VDD_LDO2_MV, error |= max77686_volsetting(PMIC_BUS, PMIC_LDO2, CONFIG_VDD_LDO2_MV,
REG_ENABLE, MAX77686_MV); REG_ENABLE, MAX77686_MV);
error |= max77686_volsetting(PMIC_LDO3, CONFIG_VDD_LDO3_MV, error |= max77686_volsetting(PMIC_BUS, PMIC_LDO3, CONFIG_VDD_LDO3_MV,
REG_ENABLE, MAX77686_MV); REG_ENABLE, MAX77686_MV);
error |= max77686_volsetting(PMIC_LDO5, CONFIG_VDD_LDO5_MV, error |= max77686_volsetting(PMIC_BUS, PMIC_LDO5, CONFIG_VDD_LDO5_MV,
REG_ENABLE, MAX77686_MV); REG_ENABLE, MAX77686_MV);
error |= max77686_volsetting(PMIC_LDO10, CONFIG_VDD_LDO10_MV, error |= max77686_volsetting(PMIC_BUS, PMIC_LDO10, CONFIG_VDD_LDO10_MV,
REG_ENABLE, MAX77686_MV); REG_ENABLE, MAX77686_MV);
if (error) if (error)
@ -133,10 +135,10 @@ void main(void)
console_init(); console_init();
i2c_set_early_reg(0x12c60000); i2c_init(0, CONFIG_SYS_I2C_SPEED, 0x00);
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
if (power_init()) if (power_init())
power_shutdown(); power_shutdown();
printk(BIOS_DEBUG, "%s: setting up pmic...\n", __func__);
if (setup_pmic()) if (setup_pmic())
power_shutdown(); power_shutdown();