Commit 730745a5 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[PATCH] 1/5 powerpc: Rework PowerMac i2c part 1

This is the first part of a rework of the PowerMac i2c code. It
completely reworks the "low_i2c" layer. It is now more flexible,
supports KeyWest, SMU and PMU i2c busses, and provides functions to
match device nodes to i2c busses and adapters.

This patch also extends & fix some bugs in the SMU driver related to i2c
support and removes the clock spreading hacks from the pmac feature code
rather than adapting them to the new API since they'll be replaced by
the platform function code completely in patch 3/5
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 002ec58e
......@@ -1677,124 +1677,6 @@ intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
}
void pmac_tweak_clock_spreading(int enable)
{
struct macio_chip *macio = &macio_chips[0];
/* Hack for doing clock spreading on some machines PowerBooks and
* iBooks. This implements the "platform-do-clockspreading" OF
* property as decoded manually on various models. For safety, we also
* check the product ID in the device-tree in cases we'll whack the i2c
* chip to make reasonably sure we won't set wrong values in there
*
* Of course, ultimately, we have to implement a real parser for
* the platform-do-* stuff...
*/
if (macio->type == macio_intrepid) {
struct device_node *clock =
of_find_node_by_path("/uni-n@f8000000/hw-clock");
if (clock && get_property(clock, "platform-do-clockspreading",
NULL)) {
printk(KERN_INFO "%sabling clock spreading on Intrepid"
" ASIC\n", enable ? "En" : "Dis");
if (enable)
UN_OUT(UNI_N_CLOCK_SPREADING, 2);
else
UN_OUT(UNI_N_CLOCK_SPREADING, 0);
mdelay(40);
}
of_node_put(clock);
}
while (machine_is_compatible("PowerBook5,2") ||
machine_is_compatible("PowerBook5,3") ||
machine_is_compatible("PowerBook6,2") ||
machine_is_compatible("PowerBook6,3")) {
struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
u8 buffer[9];
u32 *productID;
int i, rc, changed = 0;
if (dt == NULL)
break;
productID = (u32 *)get_property(dt, "pid#", NULL);
if (productID == NULL)
break;
while(ui2c) {
struct device_node *p = of_get_parent(ui2c);
if (p && !strcmp(p->name, "uni-n"))
break;
ui2c = of_find_node_by_type(ui2c, "i2c");
}
if (ui2c == NULL)
break;
DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
rc = pmac_low_i2c_open(ui2c, 1);
if (rc != 0)
break;
pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
DBG("read result: %d,", rc);
if (rc != 0) {
pmac_low_i2c_close(ui2c);
break;
}
for (i=0; i<9; i++)
DBG(" %02x", buffer[i]);
DBG("\n");
switch(*productID) {
case 0x1182: /* AlBook 12" rev 2 */
case 0x1183: /* iBook G4 12" */
buffer[0] = (buffer[0] & 0x8f) | 0x70;
buffer[2] = (buffer[2] & 0x7f) | 0x00;
buffer[5] = (buffer[5] & 0x80) | 0x31;
buffer[6] = (buffer[6] & 0x40) | 0xb0;
buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
buffer[8] = (buffer[8] & 0x00) | 0x30;
changed = 1;
break;
case 0x3142: /* AlBook 15" (ATI M10) */
case 0x3143: /* AlBook 17" (ATI M10) */
buffer[0] = (buffer[0] & 0xaf) | 0x50;
buffer[2] = (buffer[2] & 0x7f) | 0x00;
buffer[5] = (buffer[5] & 0x80) | 0x31;
buffer[6] = (buffer[6] & 0x40) | 0xb0;
buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
buffer[8] = (buffer[8] & 0x00) | 0x30;
changed = 1;
break;
default:
DBG("i2c-hwclock: Machine model not handled\n");
break;
}
if (!changed) {
pmac_low_i2c_close(ui2c);
break;
}
printk(KERN_INFO "%sabling clock spreading on i2c clock chip\n",
enable ? "En" : "Dis");
pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
DBG("write result: %d,", rc);
pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
DBG("read result: %d,", rc);
if (rc != 0) {
pmac_low_i2c_close(ui2c);
break;
}
for (i=0; i<9; i++)
DBG(" %02x", buffer[i]);
pmac_low_i2c_close(ui2c);
break;
}
}
static int
core99_sleep(void)
{
......@@ -2980,12 +2862,6 @@ set_initial_features(void)
MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
}
/* Some machine models need the clock chip to be properly setup for
* clock spreading now. This should be a platform function but we
* don't do these at the moment
*/
pmac_tweak_clock_spreading(1);
#endif /* CONFIG_POWER4 */
/* On all machines, switch modem & serial ports off */
......@@ -3013,9 +2889,6 @@ pmac_feature_init(void)
return;
}
/* Setup low-level i2c stuffs */
pmac_init_low_i2c();
/* Probe machine type */
if (probe_motherboard())
printk(KERN_WARNING "Unknown PowerMac !\n");
......
This diff is collapsed.
......@@ -652,27 +652,22 @@ static int __init pmac_declare_of_platform_devices(void)
{
struct device_node *np, *npp;
np = find_devices("uni-n");
if (np) {
for (np = np->child; np != NULL; np = np->sibling)
if (strncmp(np->name, "i2c", 3) == 0) {
of_platform_device_create(np, "uni-n-i2c",
NULL);
break;
}
}
np = find_devices("valkyrie");
np = of_find_node_by_name(NULL, "valkyrie");
if (np)
of_platform_device_create(np, "valkyrie", NULL);
np = find_devices("platinum");
np = of_find_node_by_name(NULL, "platinum");
if (np)
of_platform_device_create(np, "platinum", NULL);
npp = of_find_node_by_name(NULL, "uni-n");
if (npp == NULL)
npp = of_find_node_by_name(NULL, "u3");
if (npp == NULL)
npp = of_find_node_by_name(NULL, "u4");
if (npp) {
for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) {
if (strncmp(np->name, "i2c", 3) == 0) {
of_platform_device_create(np, "u3-i2c", NULL);
of_platform_device_create(np, "uni-n-i2c",
NULL);
of_node_put(np);
break;
}
......
......@@ -482,7 +482,7 @@ static void __devinit smp_core99_take_timebase(void)
/*
* G5s enable/disable the timebase via an i2c-connected clock chip.
*/
static struct device_node *pmac_tb_clock_chip_host;
static struct pmac_i2c_bus *pmac_tb_clock_chip_host;
static u8 pmac_tb_pulsar_addr;
static void smp_core99_cypress_tb_freeze(int freeze)
......@@ -493,20 +493,20 @@ static void smp_core99_cypress_tb_freeze(int freeze)
/* Strangely, the device-tree says address is 0xd2, but darwin
* accesses 0xd0 ...
*/
pmac_low_i2c_setmode(pmac_tb_clock_chip_host,
pmac_low_i2c_mode_combined);
rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
0xd0 | pmac_low_i2c_read,
0x81, &data, 1);
pmac_i2c_setmode(pmac_tb_clock_chip_host,
pmac_i2c_mode_combined);
rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
0xd0 | pmac_i2c_read,
1, 0x81, &data, 1);
if (rc != 0)
goto bail;
data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);
pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
0xd0 | pmac_low_i2c_write,
0x81, &data, 1);
pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
0xd0 | pmac_i2c_write,
1, 0x81, &data, 1);
bail:
if (rc != 0) {
......@@ -522,20 +522,20 @@ static void smp_core99_pulsar_tb_freeze(int freeze)
u8 data;
int rc;
pmac_low_i2c_setmode(pmac_tb_clock_chip_host,
pmac_low_i2c_mode_combined);
rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
pmac_tb_pulsar_addr | pmac_low_i2c_read,
0x2e, &data, 1);
pmac_i2c_setmode(pmac_tb_clock_chip_host,
pmac_i2c_mode_combined);
rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
pmac_tb_pulsar_addr | pmac_i2c_read,
1, 0x2e, &data, 1);
if (rc != 0)
goto bail;
data = (data & 0x88) | (freeze ? 0x11 : 0x22);
pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
pmac_tb_pulsar_addr | pmac_low_i2c_write,
0x2e, &data, 1);
pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
pmac_tb_pulsar_addr | pmac_i2c_write,
1, 0x2e, &data, 1);
bail:
if (rc != 0) {
printk(KERN_ERR "Pulsar Timebase %s rc: %d\n",
......@@ -560,13 +560,15 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
if (!ok)
continue;
pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);
if (pmac_tb_clock_chip_host == NULL)
continue;
reg = (u32 *)get_property(cc, "reg", NULL);
if (reg == NULL)
continue;
switch (*reg) {
case 0xd2:
if (device_is_compatible(cc, "pulsar-legacy-slewing")) {
if (device_is_compatible(cc,"pulsar-legacy-slewing")) {
pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
pmac_tb_pulsar_addr = 0xd2;
name = "Pulsar";
......@@ -585,30 +587,19 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
break;
}
if (pmac_tb_freeze != NULL) {
struct device_node *p = of_get_parent(cc);
of_node_put(cc);
while(p && strcmp(p->type, "i2c")) {
cc = of_get_parent(p);
of_node_put(p);
p = cc;
}
if (p == NULL)
goto no_i2c_sync;
/* Open i2c bus for synchronous access */
if (pmac_low_i2c_open(p, 0)) {
printk(KERN_ERR "Failed top open i2c bus %s for clock"
" sync, fallback to software sync !\n",
p->full_name);
of_node_put(p);
if (pmac_i2c_open(pmac_tb_clock_chip_host, 1)) {
printk(KERN_ERR "Failed top open i2c bus for clock"
" sync, fallback to software sync !\n");
goto no_i2c_sync;
}
pmac_tb_clock_chip_host = p;
printk(KERN_INFO "Processor timebase sync using %s i2c clock\n",
name);
return;
}
no_i2c_sync:
pmac_tb_freeze = NULL;
pmac_tb_clock_chip_host = NULL;
}
#endif /* CONFIG_PPC64 */
......@@ -752,8 +743,18 @@ static int __init smp_core99_probe(void)
if (ncpus <= 1)
return 1;
/* We need to perform some early initialisations before we can start
* setting up SMP as we are running before initcalls
*/
pmac_i2c_init();
/* Setup various bits like timebase sync method, ability to nap, ... */
smp_core99_setup(ncpus);
/* Install IPIs */
mpic_request_ipis();
/* Collect l2cr and l3cr values from CPU 0 */
core99_init_caches(0);
return ncpus;
......@@ -817,7 +818,7 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)
/* Close i2c bus if it was used for tb sync */
if (pmac_tb_clock_chip_host) {
pmac_low_i2c_close(pmac_tb_clock_chip_host);
pmac_i2c_close(pmac_tb_clock_chip_host);
pmac_tb_clock_chip_host = NULL;
}
......
......@@ -103,8 +103,8 @@ static s32 smu_smbus_xfer( struct i2c_adapter* adap,
cmd.info.subaddr[1] = 0;
cmd.info.subaddr[2] = 0;
if (!read) {
cmd.info.data[0] = data->byte & 0xff;
cmd.info.data[1] = (data->byte >> 8) & 0xff;
cmd.info.data[0] = data->word & 0xff;
cmd.info.data[1] = (data->word >> 8) & 0xff;
}
break;
/* Note that these are broken vs. the expected smbus API where
......@@ -116,7 +116,7 @@ static s32 smu_smbus_xfer( struct i2c_adapter* adap,
case I2C_SMBUS_BLOCK_DATA:
cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
cmd.info.datalen = data->block[0] + 1;
if (cmd.info.datalen > 6)
if (cmd.info.datalen > (SMU_I2C_WRITE_MAX + 1))
return -EINVAL;
if (!read)
memcpy(cmd.info.data, data->block, cmd.info.datalen);
......@@ -273,7 +273,13 @@ static int dispose_iface(struct device *dev)
static int create_iface_of_platform(struct of_device* dev,
const struct of_device_id *match)
{
return create_iface(dev->node, &dev->dev);
struct device_node *node = dev->node;
if (device_is_compatible(node, "smu-i2c") ||
(node->parent != NULL &&
device_is_compatible(node->parent, "smu-i2c-control")))
return create_iface(node, &dev->dev);
return -ENODEV;
}
......@@ -288,6 +294,9 @@ static struct of_device_id i2c_smu_match[] =
{
.compatible = "smu-i2c",
},
{
.compatible = "i2c-bus",
},
{},
};
static struct of_platform_driver i2c_smu_of_platform_driver =
......
......@@ -94,6 +94,8 @@ struct smu_device {
static struct smu_device *smu;
static DECLARE_MUTEX(smu_part_access);
static void smu_i2c_retry(unsigned long data);
/*
* SMU driver low level stuff
*/
......@@ -469,7 +471,6 @@ int __init smu_init (void)
smu->of_node = np;
smu->db_irq = NO_IRQ;
smu->msg_irq = NO_IRQ;
init_timer(&smu->i2c_timer);
/* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a
* 32 bits value safely
......@@ -544,6 +545,10 @@ static int smu_late_init(void)
if (!smu)
return 0;
init_timer(&smu->i2c_timer);
smu->i2c_timer.function = smu_i2c_retry;
smu->i2c_timer.data = (unsigned long)smu;
/*
* Try to request the interrupts
*/
......@@ -570,28 +575,41 @@ static int smu_late_init(void)
return 0;
}
arch_initcall(smu_late_init);
/* This has to be before arch_initcall as the low i2c stuff relies on the
* above having been done before we reach arch_initcalls
*/
core_initcall(smu_late_init);
/*
* sysfs visibility
*/
static void smu_expose_childs(void *unused)
static void smu_create_i2c(struct device_node *np)
{
struct device_node *np;
for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) {
if (device_is_compatible(np, "smu-i2c")) {
char name[32];
u32 *reg = (u32 *)get_property(np, "reg", NULL);
if (reg == NULL)
continue;
if (reg != NULL) {
sprintf(name, "smu-i2c-%02x", *reg);
of_platform_device_create(np, name, &smu->of_dev->dev);
}
}
static void smu_expose_childs(void *unused)
{
struct device_node *np, *gp;
for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) {
if (device_is_compatible(np, "smu-i2c-control")) {
gp = NULL;
while ((gp = of_get_next_child(np, gp)) != NULL)
if (device_is_compatible(gp, "i2c-bus"))
smu_create_i2c(gp);
} else if (device_is_compatible(np, "smu-i2c"))
smu_create_i2c(np);
if (device_is_compatible(np, "smu-sensors"))
of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev);
of_platform_device_create(np, "smu-sensors",
&smu->of_dev->dev);
}
}
......@@ -712,13 +730,13 @@ static void smu_i2c_complete_command(struct smu_i2c_cmd *cmd, int fail)
static void smu_i2c_retry(unsigned long data)
{
struct smu_i2c_cmd *cmd = (struct smu_i2c_cmd *)data;
struct smu_i2c_cmd *cmd = smu->cmd_i2c_cur;
DPRINTK("SMU: i2c failure, requeuing...\n");
/* requeue command simply by resetting reply_len */
cmd->pdata[0] = 0xff;
cmd->scmd.reply_len = 0x10;
cmd->scmd.reply_len = sizeof(cmd->pdata);
smu_queue_cmd(&cmd->scmd);
}
......@@ -747,10 +765,8 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
*/
if (fail && --cmd->retries > 0) {
DPRINTK("SMU: i2c failure, starting timer...\n");
smu->i2c_timer.function = smu_i2c_retry;
smu->i2c_timer.data = (unsigned long)cmd;
smu->i2c_timer.expires = jiffies + msecs_to_jiffies(5);
add_timer(&smu->i2c_timer);
BUG_ON(cmd != smu->cmd_i2c_cur);
mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5));
return;
}
......@@ -764,7 +780,7 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
/* Ok, initial command complete, now poll status */
scmd->reply_buf = cmd->pdata;
scmd->reply_len = 0x10;
scmd->reply_len = sizeof(cmd->pdata);
scmd->data_buf = cmd->pdata;
scmd->data_len = 1;
cmd->pdata[0] = 0;
......@@ -786,7 +802,7 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
cmd->scmd.done = smu_i2c_low_completion;
cmd->scmd.misc = cmd;
cmd->scmd.reply_buf = cmd->pdata;
cmd->scmd.reply_len = 0x10;
cmd->scmd.reply_len = sizeof(cmd->pdata);
cmd->scmd.data_buf = (u8 *)(char *)&cmd->info;
cmd->scmd.status = 1;
cmd->stage = 0;
......
......@@ -197,7 +197,6 @@ static int pmu_adb_reset_bus(void);
#endif /* CONFIG_ADB */
static int init_pmu(void);
static int pmu_queue_request(struct adb_request *req);
static void pmu_start(void);
static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
......@@ -1802,258 +1801,6 @@ pmu_present(void)
return via != 0;
}
struct pmu_i2c_hdr {
u8 bus;
u8 mode;
u8 bus2;
u8 address;
u8 sub_addr;
u8 comb_addr;
u8 count;
};
int
pmu_i2c_combined_read(int bus, int addr, int subaddr, u8* data, int len)
{
struct adb_request req;
struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1];
int retry;
int rc;
for (retry=0; retry<16; retry++) {
memset(&req, 0, sizeof(req));
hdr->bus = bus;
hdr->address = addr & 0xfe;
hdr->mode = PMU_I2C_MODE_COMBINED;
hdr->bus2 = 0;
hdr->sub_addr = subaddr;
hdr->comb_addr = addr | 1;
hdr->count = len;
req.nbytes = sizeof(struct pmu_i2c_hdr) + 1;
req.reply_expected = 0;
req.reply_len = 0;
req.data[0] = PMU_I2C_CMD;
req.reply[0] = 0xff;
rc = pmu_queue_request(&req);
if (rc)
return rc;
while(!req.complete)
pmu_poll();
if (req.reply[0] == PMU_I2C_STATUS_OK)
break;
mdelay(15);
}
if (req.reply[0] != PMU_I2C_STATUS_OK)
return -1;
for (retry=0; retry<16; retry++) {
memset(&req, 0, sizeof(req));
mdelay(15);
hdr->bus = PMU_I2C_BUS_STATUS;
req.reply[0] = 0xff;
req.nbytes = 2;
req.reply_expected = 0;
req.reply_len = 0;
req.data[0] = PMU_I2C_CMD;
rc = pmu_queue_request(&req);
if (rc)
return rc;
while(!req.complete)
pmu_poll();
if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) {
memcpy(data, &req.reply[1], req.reply_len - 1);
return req.reply_len - 1;
}
}
return -1;
}
int
pmu_i2c_stdsub_write(int bus, int addr, int subaddr, u8* data, int len)
{
struct adb_request req;
struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1];
int retry;
int rc;
for (retry=0; retry<16; retry++) {
memset(&req, 0, sizeof(req));
hdr->bus = bus;
hdr->address = addr & 0xfe;
hdr->mode = PMU_I2C_MODE_STDSUB;
hdr->bus2 = 0;
hdr->sub_addr = subaddr;
hdr->comb_addr = addr & 0xfe;
hdr->count = len;
req.data[0] = PMU_I2C_CMD;
memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len);
req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1;
req.reply_expected = 0;
req.reply_len = 0;
req.reply[0] = 0xff;
rc = pmu_queue_request(&req);
if (rc)
return rc;
while(!req.complete)
pmu_poll();
if (req.reply[0] == PMU_I2C_STATUS_OK)
break;
mdelay(15);
}
if (req.reply[0] != PMU_I2C_STATUS_OK)
return -1;
for (retry=0; retry<16; retry++) {
memset(&req, 0, sizeof(req));
mdelay(15);
hdr->bus = PMU_I2C_BUS_STATUS;
req.reply[0] = 0xff;
req.nbytes = 2;
req.reply_expected = 0;
req.reply_len = 0;
req.data[0] = PMU_I2C_CMD;
rc = pmu_queue_request(&req);
if (rc)
return rc;
while(!req.complete)
pmu_poll();
if (req.reply[0] == PMU_I2C_STATUS_OK)
return len;
}
return -1;
}
int
pmu_i2c_simple_read(int bus, int addr, u8* data, int len)
{
struct adb_request req;
struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1];
int retry;
int rc;
for (retry=0; retry<16; retry++) {
memset(&req, 0, sizeof(req));
hdr->bus = bus;
hdr->address = addr | 1;
hdr->mode = PMU_I2C_MODE_SIMPLE;
hdr->bus2 = 0;
hdr->sub_addr = 0;
hdr->comb_addr = 0;
hdr->count = len;
req.data[0] = PMU_I2C_CMD;
req.nbytes = sizeof(struct pmu_i2c_hdr) + 1;
req.reply_expected = 0;
req.reply_len = 0;
req.reply[0] = 0xff;
rc = pmu_queue_request(&req);
if (rc)
return rc;
while(!req.complete)
pmu_poll();
if (req.reply[0] == PMU_I2C_STATUS_OK)
break;
mdelay(15);
}
if (req.reply[0] != PMU_I2C_STATUS_OK)
return -1;
for (retry=0; retry<16; retry++) {
memset(&req, 0, sizeof(req));
mdelay(15);
hdr->bus = PMU_I2C_BUS_STATUS;
req.reply[0] = 0xff;
req.nbytes = 2;
req.reply_expected = 0;
req.reply_len = 0;
req.data[0] = PMU_I2C_CMD;
rc = pmu_queue_request(&req);
if (rc)
return rc;
while(!req.complete)
pmu_poll();
if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) {
memcpy(data, &req.reply[1], req.reply_len - 1);
return req.reply_len - 1;
}
}
return -1;
}
int
pmu_i2c_simple_write(int bus, int addr, u8* data, int len)
{
struct adb_request req;
struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1];
int retry;
int rc;
for (retry=0; retry<16; retry++) {
memset(&req, 0, sizeof(req));
hdr->bus = bus;
hdr->address = addr & 0xfe;
hdr->mode = PMU_I2C_MODE_SIMPLE;
hdr->bus2 = 0;
hdr->sub_addr = 0;
hdr->comb_addr = 0;
hdr->count = len;
req.data[0] = PMU_I2C_CMD;
memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len);
req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1;
req.reply_expected = 0;
req.reply_len = 0;
req.reply[0] = 0xff;
rc = pmu_queue_request(&req);
if (rc)
return rc;
while(!req.complete)
pmu_poll();
if (req.reply[0] == PMU_I2C_STATUS_OK)
break;
mdelay(15);
}
if (req.reply[0] != PMU_I2C_STATUS_OK)
return -1;
for (retry=0; retry<16; retry++) {
memset(&req, 0, sizeof(req));
mdelay(15);
hdr->bus = PMU_I2C_BUS_STATUS;
req.reply[0] = 0xff;
req.nbytes = 2;
req.reply_expected = 0;
req.reply_len = 0;
req.data[0] = PMU_I2C_CMD;
rc = pmu_queue_request(&req);
if (rc)
return rc;
while(!req.complete)
pmu_poll();
if (req.reply[0] == PMU_I2C_STATUS_OK)
return len;
}
return -1;
}
#ifdef CONFIG_PM
static LIST_HEAD(sleep_notifiers);
......@@ -2358,9 +2105,6 @@ pmac_suspend_devices(void)
return -EBUSY;
}
/* Disable clock spreading on some machines */
pmac_tweak_clock_spreading(0);
/* Stop preemption */
preempt_disable();
......@@ -2431,9 +2175,6 @@ pmac_wakeup_devices(void)
mdelay(10);
preempt_enable();
/* Re-enable clock spreading on some machines */
pmac_tweak_clock_spreading(1);
/* Resume devices */
device_resume();
......@@ -3150,16 +2891,13 @@ static int __init init_pmu_sysfs(void)
subsys_initcall(init_pmu_sysfs);
EXPORT_SYMBOL(pmu_request);
EXPORT_SYMBOL(pmu_queue_request);
EXPORT_SYMBOL(pmu_poll);
EXPORT_SYMBOL(pmu_poll_adb);
EXPORT_SYMBOL(pmu_wait_complete);
EXPORT_SYMBOL(pmu_suspend);
EXPORT_SYMBOL(pmu_resume);
EXPORT_SYMBOL(pmu_unlock);
EXPORT_SYMBOL(pmu_i2c_combined_read);
EXPORT_SYMBOL(pmu_i2c_stdsub_write);
EXPORT_SYMBOL(pmu_i2c_simple_read);
EXPORT_SYMBOL(pmu_i2c_simple_write);
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
EXPORT_SYMBOL(pmu_enable_irled);
EXPORT_SYMBOL(pmu_battery_count);
......
......@@ -318,10 +318,6 @@ extern void pmac_register_agp_pm(struct pci_dev *bridge,
extern void pmac_suspend_agp_for_card(struct pci_dev *dev);
extern void pmac_resume_agp_for_card(struct pci_dev *dev);
/* Used by the via-pmu driver for suspend/resume
*/
extern void pmac_tweak_clock_spreading(int enable);
/*
* The part below is for use by macio_asic.c only, do not rely
* on the data structures or constants below in a normal driver
......
......@@ -15,30 +15,87 @@
/* i2c mode (based on the platform functions format) */
enum {
pmac_low_i2c_mode_dumb = 1,
pmac_low_i2c_mode_std = 2,
pmac_low_i2c_mode_stdsub = 3,
pmac_low_i2c_mode_combined = 4,
pmac_i2c_mode_dumb = 1,
pmac_i2c_mode_std = 2,
pmac_i2c_mode_stdsub = 3,
pmac_i2c_mode_combined = 4,
};
/* RW bit in address */
enum {
pmac_low_i2c_read = 0x01,
pmac_low_i2c_write = 0x00
pmac_i2c_read = 0x01,
pmac_i2c_write = 0x00
};
/* i2c bus type */
enum {
pmac_i2c_bus_keywest = 0,
pmac_i2c_bus_pmu = 1,
pmac_i2c_bus_smu = 2,
};
/* i2c bus features */
enum {
/* can_largesub : supports >1 byte subaddresses (SMU only) */
pmac_i2c_can_largesub = 0x00000001u,
/* multibus : device node holds multiple busses, bus number is
* encoded in bits 0xff00 of "reg" of a given device
*/
pmac_i2c_multibus = 0x00000002u,
};
/* i2c busses in the system */
struct pmac_i2c_bus;
struct i2c_adapter;
/* Init, called early during boot */
extern void pmac_init_low_i2c(void);
extern int pmac_i2c_init(void);
/* Lookup an i2c bus for a device-node. The node can be either the bus
* node itself or a device below it. In the case of a multibus, the bus
* node itself is the controller node, else, it's a child of the controller
* node
*/
extern struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node);
/* Get the address for an i2c device. This strips the bus number if
* necessary. The 7 bits address is returned 1 bit right shifted so that the
* direction can be directly ored in
*/
extern u8 pmac_i2c_get_dev_addr(struct device_node *device);
/* Get infos about a bus */
extern struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus);
extern struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus);
extern int pmac_i2c_get_type(struct pmac_i2c_bus *bus);
extern int pmac_i2c_get_flags(struct pmac_i2c_bus *bus);
/* i2c layer adapter attach/detach */
extern void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
struct i2c_adapter *adapter);
extern void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
struct i2c_adapter *adapter);
extern struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus);
/* March a device or bus with an i2c adapter structure, to be used by drivers
* to match device-tree nodes with i2c adapters during adapter discovery
* callbacks
*/
extern int pmac_i2c_match_adapter(struct device_node *dev,
struct i2c_adapter *adapter);
/* Locking functions exposed to i2c-keywest */
int pmac_low_i2c_lock(struct device_node *np);
int pmac_low_i2c_unlock(struct device_node *np);
/* (legacy) Locking functions exposed to i2c-keywest */
extern int pmac_low_i2c_lock(struct device_node *np);
extern int pmac_low_i2c_unlock(struct device_node *np);
/* Access functions for platform code */
int pmac_low_i2c_open(struct device_node *np, int channel);
int pmac_low_i2c_close(struct device_node *np);
int pmac_low_i2c_setmode(struct device_node *np, int mode);
int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len);
extern int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled);
extern void pmac_i2c_close(struct pmac_i2c_bus *bus);
extern int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode);
extern int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
u32 subaddr, u8 *data, int len);
#endif /* __KERNEL__ */
......
......@@ -358,6 +358,9 @@ extern unsigned long smu_cmdbuf_abs;
* Kenrel asynchronous i2c interface
*/
#define SMU_I2C_READ_MAX 0x1d
#define SMU_I2C_WRITE_MAX 0x15
/* SMU i2c header, exactly matches i2c header on wire */
struct smu_i2c_param
{
......@@ -368,12 +371,9 @@ struct smu_i2c_param
u8 subaddr[3]; /* subaddress */
u8 caddr; /* combined address, filled by SMU driver */
u8 datalen; /* length of transfer */
u8 data[7]; /* data */
u8 data[SMU_I2C_READ_MAX]; /* data */
};
#define SMU_I2C_READ_MAX 0x0d
#define SMU_I2C_WRITE_MAX 0x05
struct smu_i2c_cmd
{
/* public */
......@@ -387,7 +387,7 @@ struct smu_i2c_cmd
int read;
int stage;
int retries;
u8 pdata[0x10];
u8 pdata[32];
struct list_head link;
};
......
......@@ -140,7 +140,7 @@ extern int find_via_pmu(void);
extern int pmu_request(struct adb_request *req,
void (*done)(struct adb_request *), int nbytes, ...);
extern int pmu_queue_request(struct adb_request *req);
extern void pmu_poll(void);
extern void pmu_poll_adb(void); /* For use by xmon */
extern void pmu_wait_complete(struct adb_request *req);
......@@ -160,12 +160,6 @@ extern void pmu_unlock(void);
extern int pmu_present(void);
extern int pmu_get_model(void);
extern int pmu_i2c_combined_read(int bus, int addr, int subaddr, u8* data, int len);
extern int pmu_i2c_stdsub_write(int bus, int addr, int subaddr, u8* data, int len);
extern int pmu_i2c_simple_read(int bus, int addr, u8* data, int len);
extern int pmu_i2c_simple_write(int bus, int addr, u8* data, int len);
#ifdef CONFIG_PM
/*
* Stuff for putting the powerbook to sleep and waking it again.
......
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