patch-2.4.22 linux-2.4.22/drivers/macintosh/via-pmu.c
Next file: linux-2.4.22/drivers/md/md.c
Previous file: linux-2.4.22/drivers/macintosh/via-cuda.c
Back to the patch index
Back to the overall index
- Lines: 638
- Date:
2003-08-25 04:44:42.000000000 -0700
- Orig file:
linux-2.4.21/drivers/macintosh/via-pmu.c
- Orig date:
2002-11-28 15:53:13.000000000 -0800
diff -urN linux-2.4.21/drivers/macintosh/via-pmu.c linux-2.4.22/drivers/macintosh/via-pmu.c
@@ -345,11 +345,6 @@
} else
pmu_kind = PMU_UNKNOWN;
-#ifdef CONFIG_PMAC_PBOOK
- if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
- can_sleep = 1;
-#endif /* CONFIG_PMAC_PBOOK */
-
via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
@@ -410,6 +405,8 @@
bright_req_3.complete = 1;
#ifdef CONFIG_PMAC_PBOOK
batt_req.complete = 1;
+ if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
+ can_sleep = 1;
#endif
if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
@@ -436,12 +433,20 @@
#ifdef CONFIG_PMAC_PBOOK
if (machine_is_compatible("AAPL,3400/2400") ||
- machine_is_compatible("AAPL,3500"))
+ machine_is_compatible("AAPL,3500")) {
+ int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+ NULL, PMAC_MB_INFO_MODEL, 0);
pmu_battery_count = 1;
- else if (machine_is_compatible("AAPL,PowerBook1998") ||
- machine_is_compatible("PowerBook1,1"))
+ if (mb == PMAC_TYPE_COMET)
+ pmu_batteries[0].flags |= PMU_BATT_TYPE_COMET;
+ else
+ pmu_batteries[0].flags |= PMU_BATT_TYPE_HOOPER;
+ } else if (machine_is_compatible("AAPL,PowerBook1998") ||
+ machine_is_compatible("PowerBook1,1")) {
pmu_battery_count = 2;
- else {
+ pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
+ pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
+ } else {
struct device_node* prim = find_devices("power-mgt");
u32 *prim_info = NULL;
if (prim)
@@ -449,6 +454,9 @@
if (prim_info) {
/* Other stuffs here yet unknown */
pmu_battery_count = (prim_info[6] >> 16) & 0xff;
+ pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
+ if (pmu_battery_count > 1)
+ pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
}
}
#endif /* CONFIG_PMAC_PBOOK */
@@ -558,148 +566,12 @@
#ifdef CONFIG_PMAC_PBOOK
-/*
- * WARNING ! This code probably needs some debugging... -- BenH.
+/* This new version of the code for 2400/3400/3500 powerbooks
+ * is inspired from the implementation in gkrellm-pmu
*/
-#ifdef NEW_OHARE_CODE
-static void __pmac
-done_battery_state_ohare(struct adb_request* req)
-{
- unsigned int bat_flags = 0;
- int current = 0;
- unsigned int capa, max, voltage, time;
- int lrange[] = { 0, 275, 850, 1680, 2325,
- 2765, 3160, 3500, 3830, 4115,
- 4360, 4585, 4795, 4990, 5170,
- 5340, 5510, 5710, 5930, 6150,
- 6370, 6500
- };
-
- if (req->reply[0] & 0x01)
- pmu_power_flags |= PMU_PWR_AC_PRESENT;
- else
- pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
-
- if (req->reply[0] & 0x04) {
- int vb, i, j, k, charge, pcharge;
- bat_flags |= PMU_BATT_PRESENT;
- vb = (req->reply[1] << 8) | req->reply[2];
- voltage = ((vb * 2650) + 726650)/100;
- vb *= 100;
- current = req->reply[5];
- if ((req->reply[0] & 0x01) == 0 && (current > 200))
- vb += (current - 200) * 15;
- else if (req->reply[0] & 0x02)
- vb = (vb - 2000);
- i = (33000 - vb) / 10;
- j = i - (i % 100);
- k = j/100;
- if (k <= 0)
- charge = 0;
- else if (k >= 21)
- charge = 650000;
- else
- charge = (lrange[k + 1] - lrange[k]) * (i - j) + (lrange[k] * 100);
- charge = (1000 - charge / 650) / 10;
- if (req->reply[0] & 0x40) {
- pcharge = (req->reply[6] << 8) + req->reply[7];
- if (pcharge > 6500)
- pcharge = 6500;
- pcharge *= 100;
- pcharge = (1000 - pcharge / 650) / 10;
- if (pcharge < charge)
- charge = pcharge;
- }
- capa = charge;
- max = 100;
- time = (charge * 16440) / current;
- current = -current;
-
- } else
- capa = max = current = voltage = time = 0;
-
- if (req->reply[0] & 0x02)
- bat_flags |= PMU_BATT_CHARGING;
-
- pmu_batteries[pmu_cur_battery].flags = bat_flags;
- pmu_batteries[pmu_cur_battery].charge = capa;
- pmu_batteries[pmu_cur_battery].max_charge = max;
- pmu_batteries[pmu_cur_battery].current = current;
- pmu_batteries[pmu_cur_battery].voltage = voltage;
- pmu_batteries[pmu_cur_battery].time_remaining = time;
-}
-#else /* NEW_OHARE_CODE */
static void __pmac
done_battery_state_ohare(struct adb_request* req)
{
- unsigned int bat_flags = 0;
- int current = 0;
- unsigned int capa, max, voltage, time;
- int lrange[] = { 0, 275, 850, 1680, 2325,
- 2765, 3160, 3500, 3830, 4115,
- 4360, 4585, 4795, 4990, 5170,
- 5340, 5510, 5710, 5930, 6150,
- 6370, 6500
- };
-
- if (req->reply[0] & 0x01)
- pmu_power_flags |= PMU_PWR_AC_PRESENT;
- else
- pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
-
- if (req->reply[0] & 0x04) {
- int vb, i, j, charge, pcharge;
- bat_flags |= PMU_BATT_PRESENT;
- vb = (req->reply[1] << 8) | req->reply[2];
- voltage = ((vb * 2650) + 726650)/100;
- current = *((signed char *)&req->reply[5]);
- if ((req->reply[0] & 0x01) == 0 && (current > 200))
- vb += (current - 200) * 15;
- else if (req->reply[0] & 0x02)
- vb = (vb - 10) * 100;
- i = (33000 - vb) / 10;
- j = i - (i % 100);
- if (j <= 0)
- charge = 0;
- else if (j >= 21)
- charge = 650000;
- else
- charge = (lrange[j + 1] - lrange[j]) * (i - j) + (lrange[j] * 100);
- charge = (1000 - charge / 650) / 10;
- if (req->reply[0] & 0x40) {
- pcharge = (req->reply[6] << 8) + req->reply[7];
- if (pcharge > 6500)
- pcharge = 6500;
- pcharge *= 100;
- pcharge = (1000 - pcharge / 650) / 10;
- if (pcharge < charge)
- charge = pcharge;
- }
- capa = charge;
- max = 100;
- time = (charge * 274) / current;
- current = -current;
-
- } else
- capa = max = current = voltage = time = 0;
-
- if ((req->reply[0] & 0x02) && (current > 0))
- bat_flags |= PMU_BATT_CHARGING;
- if (req->reply[0] & 0x04) /* CHECK THIS ONE */
- bat_flags |= PMU_BATT_PRESENT;
-
- pmu_batteries[pmu_cur_battery].flags = bat_flags;
- pmu_batteries[pmu_cur_battery].charge = capa;
- pmu_batteries[pmu_cur_battery].max_charge = max;
- pmu_batteries[pmu_cur_battery].current = current;
- pmu_batteries[pmu_cur_battery].voltage = voltage;
- pmu_batteries[pmu_cur_battery].time_remaining = time;
-}
-#endif /* NEW_OHARE_CODE */
-
- static void __pmac
-done_battery_state_comet(struct adb_request* req)
-{
/* format:
* [0] : flags
* 0x01 : AC indicator
@@ -718,57 +590,62 @@
* [6][7] : pcharge
* --tkoba
*/
+ unsigned int bat_flags = PMU_BATT_TYPE_HOOPER;
+ long pcharge, charge, vb, vmax, lmax;
+ long vmax_charging, vmax_charged;
+ long current, voltage, time, max;
+ int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+ NULL, PMAC_MB_INFO_MODEL, 0);
- unsigned int bat_flags = 0;
- int current = 0;
- unsigned int max = 100;
- unsigned int charge, voltage, time;
- int lrange[] = { 0, 600, 750, 900, 1000, 1080,
- 1180, 1250, 1300, 1340, 1360,
- 1390, 1420, 1440, 1470, 1490,
- 1520, 1550, 1580, 1610, 1650,
- 1700
- };
-
if (req->reply[0] & 0x01)
pmu_power_flags |= PMU_PWR_AC_PRESENT;
else
pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
+
+ if (mb == PMAC_TYPE_COMET) {
+ vmax_charged = 189;
+ vmax_charging = 213;
+ lmax = 6500;
+ } else {
+ vmax_charged = 330;
+ vmax_charging = 330;
+ lmax = 6500;
+ }
+ vmax = vmax_charged;
- if (req->reply[0] & 0x04) { /* battery exist */
- int vb, i;
+ /* If battery installed */
+ if (req->reply[0] & 0x04) {
bat_flags |= PMU_BATT_PRESENT;
+ if (req->reply[0] & 0x02)
+ bat_flags |= PMU_BATT_CHARGING;
vb = (req->reply[1] << 8) | req->reply[2];
- voltage = ((vb * 2650) + 726650)/100;
- vb *= 10;
+ voltage = (vb * 265 + 72665) / 10;
current = req->reply[5];
- if ((req->reply[0] & 0x01) == 0 && (current > 200))
- vb += ((current - 200) * 3); /* vb = 500<->1800 */
- else if (req->reply[0] & 0x02)
- vb = ((vb - 800) * 1700/13)/100; /* in charging vb = 1300<->2130 */
-
- if (req->reply[0] & 0x20) { /* full charged */
- charge = max;
- } else {
- if (lrange[21] < vb)
- charge = max;
- else {
- if (vb < lrange[1])
- charge = 0;
- else {
- for (i=21; vb < lrange[i]; --i);
- charge = (i * 100)/21;
- }
- }
- if (charge > max) charge = max;
+ if ((req->reply[0] & 0x01) == 0) {
+ if (current > 200)
+ vb += ((current - 200) * 15)/100;
+ } else if (req->reply[0] & 0x02) {
+ vb = (vb * 97) / 100;
+ vmax = vmax_charging;
}
- time = (charge * 72);
+ charge = (100 * vb) / vmax;
+ if (req->reply[0] & 0x40) {
+ pcharge = (req->reply[6] << 8) + req->reply[7];
+ if (pcharge > lmax)
+ pcharge = lmax;
+ pcharge *= 100;
+ pcharge = 100 - pcharge / lmax;
+ if (pcharge < charge)
+ charge = pcharge;
+ }
+ if (current > 0)
+ time = (charge * 16440) / current;
+ else
+ time = 0;
+ max = 100;
current = -current;
} else
- max = current = voltage = time = 0;
-
- if (req->reply[0] & 0x02)
- bat_flags |= PMU_BATT_CHARGING;
+ charge = max = current = voltage = time = 0;
pmu_batteries[pmu_cur_battery].flags = bat_flags;
pmu_batteries[pmu_cur_battery].charge = charge;
@@ -800,7 +677,7 @@
* [8][9] : voltage
*/
- unsigned int bat_flags = 0;
+ unsigned int bat_flags = PMU_BATT_TYPE_SMART;
int current;
unsigned int capa, max, voltage;
@@ -858,17 +735,10 @@
{
if (!batt_req.complete)
return;
- if (pmu_kind == PMU_OHARE_BASED) {
- int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
- NULL, PMAC_MB_INFO_MODEL, 0);
-
- if (mb == PMAC_TYPE_COMET)
- pmu_request(&batt_req, done_battery_state_comet,
- 1, PMU_BATTERY_STATE);
- else
- pmu_request(&batt_req, done_battery_state_ohare,
- 1, PMU_BATTERY_STATE);
- } else
+ if (pmu_kind == PMU_OHARE_BASED)
+ pmu_request(&batt_req, done_battery_state_ohare,
+ 1, PMU_BATTERY_STATE);
+ else
pmu_request(&batt_req, done_battery_state_smart,
2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
}
@@ -1220,9 +1090,14 @@
static inline void
pmu_done(struct adb_request *req)
{
+ void (*done)(struct adb_request *) = req->done;
+ mb();
req->complete = 1;
- if (req->done)
- (*req->done)(req);
+ /* Here, we assume that if the request has a done member, the
+ * struct request will survive to setting req->complete to 1
+ */
+ if (done)
+ (*done)(req);
}
static void __openfirmware
@@ -1557,7 +1432,8 @@
wait_for_ack();
send_byte(PMU_INT_ACK);
adb_int_pending = 0;
-no_free_slot:
+no_free_slot:
+ ;
} else if (current_req)
pmu_start();
}
@@ -1714,6 +1590,259 @@
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;
+}
+
+
#if defined(DEBUG_SLEEP) || defined(DEBUG_FREQ)
/* N.B. This doesn't work on the 3400 */
void
@@ -2794,6 +2923,10 @@
EXPORT_SYMBOL(pmu_poll);
EXPORT_SYMBOL(pmu_suspend);
EXPORT_SYMBOL(pmu_resume);
+EXPORT_SYMBOL(pmu_i2c_combined_read);
+EXPORT_SYMBOL(pmu_i2c_stdsub_write);
+EXPORT_SYMBOL(pmu_i2c_simple_read);
+EXPORT_SYMBOL(pmu_i2c_simple_write);
#ifdef CONFIG_PMAC_PBOOK
EXPORT_SYMBOL(pmu_register_sleep_notifier);
EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)