r4064 - branches/src/target/kernel/2.6.24.x/patches

werner at sita.openmoko.org werner at sita.openmoko.org
Fri Feb 15 04:28:28 CET 2008


Author: werner
Date: 2008-02-15 04:28:23 +0100 (Fri, 15 Feb 2008)
New Revision: 4064

Modified:
   branches/src/target/kernel/2.6.24.x/patches/pcf50633.patch
Log:
fix-pcf50633-use-second-as-initial-kick.patch

    From: Andy Green <andy at openmoko.com>

    Enable the SECOND 1Hz interrupt at probetime so the work function
    gets an initial kick and deals with coldplug.
     
    Move coldplug to work function.

fix-pcf50633-charger-type-detect.patch

    From: Andy Green <andy at openmoko.com>

    In this code there are three kinds of charger understood:

     - no charger -- nothing active is in the USB socket... no charging
     - Host / 500mA charger -- we are plugged into a host OR a dumb wall
       adapter, charge at <=500mA
       NOTE: the pcf50633 maintains total max draw at 500mA in this case,
       making sure that the device gets the current it needs to operate and
       any left over goes to the battery
     - 1A charger -- if it sees the magic ID resistor in the 1A charger, it
       allows to charge to 1A

    Fix the ADC code so that ACCSW is enabled, otherwise we will just
    see 0V everywhere.

    Turn the ADC code around so it is serviced by the workqueue handler only.
    Deal with different mux requests by creating a FIFO to queue them.
    Change battvolt to use the FIFO method with sleeping spinning.

    Add /sys nodes

    cat /sys/devices/platform/s3c2440-i2c/i2c-adapter/i2c-0/0-0073/charger_adc
    43

    gets you the raw ADC reading of the charger type resistor

    cat /sys/devices/platform/s3c2440-i2c/i2c-adapter/i2c-0/0-0073/charger_type
    charger 1A mode 1A

    get you the device's understanding of what is plugged into it.  The mode
    part is the current limit setting for charging on the PMU itself.

    Also remove some inline attributes.

    Delete temp stuff that isn't used on GTA02 (we have temp from battery
    itself)

    Adjust sysfs table so it doesn't have literal length and add warnings
    that it is modified at runtime 

Signed-off-by: Andy Green <andy at openmoko.com>

---

 drivers/i2c/chips/pcf50633.c |   44 +++++++++++++++++++++++++++++++-----------
 1 files changed, 32 insertions(+), 12 deletions(-)
 drivers/i2c/chips/pcf50633.c |  341 ++++++++++++++++++++++++++++++------------
 1 files changed, 242 insertions(+), 99 deletions(-)



Modified: branches/src/target/kernel/2.6.24.x/patches/pcf50633.patch
===================================================================
--- branches/src/target/kernel/2.6.24.x/patches/pcf50633.patch	2008-02-15 01:32:23 UTC (rev 4063)
+++ branches/src/target/kernel/2.6.24.x/patches/pcf50633.patch	2008-02-15 03:28:23 UTC (rev 4064)
@@ -34,7 +34,7 @@
 ===================================================================
 --- /dev/null
 +++ linux-2.6.24/drivers/i2c/chips/pcf50633.c
-@@ -0,0 +1,1791 @@
+@@ -0,0 +1,1954 @@
 +/* Philips PCF50633 Power Management Unit (PMU) driver
 + *
 + * (C) 2006-2007 by OpenMoko, Inc.
@@ -72,6 +72,7 @@
 +#include <linux/interrupt.h>
 +#include <linux/irq.h>
 +#include <linux/workqueue.h>
++#include <linux/delay.h>
 +#include <linux/rtc.h>
 +#include <linux/bcd.h>
 +#include <linux/watchdog.h>
@@ -131,6 +132,17 @@
 +	CLOSE_STATE_ALLOW = 0x2342,
 +};
 +
++enum charger_type {
++	CHARGER_TYPE_NONE = 0,
++	CHARGER_TYPE_HOSTUSB,
++	CHARGER_TYPE_1A
++};
++
++#define ADC_NOM_CHG_DETECT_1A 6
++#define ADC_NOM_CHG_DETECT_NONE 43
++
++#define MAX_ADC_FIFO_DEPTH 8
++
 +struct pcf50633_data {
 +	struct i2c_client client;
 +	struct pcf50633_platform_data *pdata;
@@ -145,6 +157,21 @@
 +	int allow_close;
 +	int onkey_seconds;
 +	int irq;
++
++	int coldplug_done; /* cleared by probe, set by first work service */
++	int flag_bat_voltage_read; /* ipc to /sys batt voltage read func */
++
++	int charger_adc_result_raw;
++	enum charger_type charger_type;
++
++	/* we have a FIFO of ADC measurement requests that are used only by
++	 * the workqueue service code after the ADC completion interrupt
++	 */
++	int adc_queue_mux[MAX_ADC_FIFO_DEPTH]; /* which ADC input to use */
++	int adc_queue_avg[MAX_ADC_FIFO_DEPTH]; /* amount of averaging */
++	int adc_queue_head; /* head owned by foreground code */
++	int adc_queue_tail; /* tail owned by service code */
++
 +#ifdef CONFIG_PM
 +	struct {
 +		u_int8_t int1m, int2m, int3m, int4m, int5m;
@@ -169,26 +196,11 @@
 +
 +static struct platform_device *pcf50633_pdev;
 +
-+/* This is a mitsubishi TN11-3H103J T,B NTC Thermistor -10..79 centigrade */
-+static const u_int16_t ntc_table_tn11_3h103j[] = {
-+	/* -10 */
-+	40260, 38560, 36950, 35410, 33950, 32550, 31220, 29960, 28750, 27590,
-+	26490, 25440, 24440, 23480, 22560, 21680, 20830, 20020, 19240, 18500,
-+	17780, 17710, 16440, 15810, 15210, 14630, 14070, 13540, 13030, 12540,
-+	12070, 11620, 11190, 10780, 10380, 10000, 9635, 9286, 8950, 8629,
-+	8320, 8024, 7740, 7467, 7205, 6954, 6713, 6481, 6258, 6044,
-+	5839, 5641, 5451, 5269, 5093, 4924, 4762, 4605, 4455, 4310,
-+	4171, 4037, 3908, 3784, 3664, 3549, 3438, 3313, 3227, 3128,
-+	3032, 2939, 2850, 2763, 2680, 2600, 2522, 2448, 2375, 2306,
-+	2239, 2174, 2111, 2050, 1922, 1935, 1881, 1828, 1776, 1727,
-+};
-+
-+
 +/***********************************************************************
 + * Low-Level routines
 + ***********************************************************************/
 +
-+static inline int __reg_write(struct pcf50633_data *pcf, u_int8_t reg, u_int8_t val)
++static int __reg_write(struct pcf50633_data *pcf, u_int8_t reg, u_int8_t val)
 +{
 +	return i2c_smbus_write_byte_data(&pcf->client, reg, val);
 +}
@@ -204,7 +216,7 @@
 +	return ret;
 +}
 +
-+static inline int32_t __reg_read(struct pcf50633_data *pcf, u_int8_t reg)
++static int32_t __reg_read(struct pcf50633_data *pcf, u_int8_t reg)
 +{
 +	int32_t ret;
 +
@@ -260,43 +272,33 @@
 +	return ret;
 +}
 +
-+/* synchronously read one ADC channel (busy-wait for result to be complete) */
-+static u_int16_t adc_read(struct pcf50633_data *pcf,  int channel, int avg,
-+			  u_int16_t *data2)
++/* asynchronously setup reading one ADC channel */
++static void async_adc_read_setup(struct pcf50633_data *pcf,
++				 int channel, int avg)
 +{
-+	u_int8_t adcs3, adcs2, adcs1;
-+	u_int16_t ret;
-+
-+	DEBUGP("entering (pcf=%p, channel=%u, data2=%p)\n",
-+		pcf, channel, data2);
-+
 +	channel &= PCF50633_ADCC1_ADCMUX_MASK;
 +
-+	mutex_lock(&pcf->lock);
++	/* kill ratiometric, but enable ACCSW biasing */
++	__reg_write(pcf, PCF50633_REG_ADCC2, 0x00);
++	__reg_write(pcf, PCF50633_REG_ADCC3, 0x01);
 +
 +	/* start ADC conversion of selected channel */
 +	__reg_write(pcf, PCF50633_REG_ADCC1, channel | avg |
 +		    PCF50633_ADCC1_ADCSTART | PCF50633_ADCC1_RES_10BIT);
 +
-+	do {
-+		adcs3 = __reg_read(pcf, PCF50633_REG_ADCS3);
-+	} while (!(adcs3 & PCF50633_ADCS3_ADCRDY));
++}
 +
-+	adcs1 = __reg_read(pcf, PCF50633_REG_ADCS1);
-+	ret = (adcs1 << 2) | (adcs3 & PCF50633_ADCS3_ADCDAT1L_MASK);
++static u_int16_t async_adc_complete(struct pcf50633_data *pcf)
++{
++	u_int16_t ret = (__reg_read(pcf, PCF50633_REG_ADCS1) << 2) |
++			(__reg_read(pcf, PCF50633_REG_ADCS3) &
++						  PCF50633_ADCS3_ADCDAT1L_MASK);
 +
-+	if (data2) {
-+		adcs2 = __reg_read(pcf, PCF50633_REG_ADCS2);
-+		*data2 = (adcs2 << 2) | (adcs3 & PCF50633_ADCS3_ADCDAT2L_MASK)
-+					>> PCF50633_ADCS3_ADCDAT2L_SHIFT;
-+	}
++	return ret;
++}
 +
-+	mutex_unlock(&pcf->lock);
 +
-+	DEBUGP("returning %u %u\n", ret, data2 ? *data2 : 0);
 +
-+	return ret;
-+}
 +
 +/***********************************************************************
 + * Voltage / ADC
@@ -522,12 +524,77 @@
 +}
 +EXPORT_SYMBOL_GPL(pcf50633_gpio_get);
 +
++static int interpret_charger_type_from_adc(struct pcf50633_data *pcf,
++					   int sample)
++{
++	/* 1A capable charger? */
++
++	if (sample < ((ADC_NOM_CHG_DETECT_NONE + ADC_NOM_CHG_DETECT_1A) / 2))
++		return CHARGER_TYPE_1A;
++
++	/* well then, nothing in the USB hole, or USB host / unk adapter */
++
++	if (pcf->flags & PCF50633_F_USB_PRESENT) /* ooh power is in there */
++		return CHARGER_TYPE_HOSTUSB; /* HOSTUSB is the catchall */
++
++	return CHARGER_TYPE_NONE; /* no really -- nothing in there */
++}
++
++
++
++static void configure_pmu_for_charger(struct pcf50633_data *pcf,
++				      enum charger_type type)
++{
++	switch (type) {
++	case CHARGER_TYPE_NONE:
++		__reg_write(pcf, PCF50633_REG_MBCC7,
++						    PCF50633_MBCC7_USB_SUSPEND);
++		break;
++	/*
++	 * the PCF50633 has a feature that it will supply only excess current
++	 * from the charger that is not used to power the device.  So this
++	 * 500mA setting is "up to 500mA" according to that.
++	 */
++	case CHARGER_TYPE_HOSTUSB:
++		__reg_write(pcf, PCF50633_REG_MBCC7, PCF50633_MBCC7_USB_500mA);
++		break;
++	case CHARGER_TYPE_1A:
++		__reg_write(pcf, PCF50633_REG_MBCC7, PCF50633_MBCC7_USB_1000mA);
++		break;
++	}
++}
++
++static void trigger_next_adc_job_if_any(struct pcf50633_data *pcf)
++{
++	if (pcf->adc_queue_head == pcf->adc_queue_tail)
++		return;
++	async_adc_read_setup(pcf,
++			     pcf->adc_queue_mux[pcf->adc_queue_tail],
++			     pcf->adc_queue_avg[pcf->adc_queue_tail]);
++}
++
++static void add_request_to_adc_queue(struct pcf50633_data *pcf,
++				     int mux, int avg)
++{
++	int old_head = pcf->adc_queue_head;
++	pcf->adc_queue_mux[pcf->adc_queue_head] = mux;
++	pcf->adc_queue_avg[pcf->adc_queue_head] = avg;
++
++	pcf->adc_queue_head = (pcf->adc_queue_head + 1) &
++			      (MAX_ADC_FIFO_DEPTH - 1);
++
++	/* it was idle before we just added this?  we need to kick it then */
++	if (old_head == pcf->adc_queue_tail)
++		trigger_next_adc_job_if_any(pcf);
++}
++
 +static void pcf50633_work(struct work_struct *work)
 +{
 +	struct pcf50633_data *pcf =
 +			container_of(work, struct pcf50633_data, work);
 +	u_int8_t pcfirq[5];
 +	int ret;
++	int tail;
 +
 +	mutex_lock(&pcf->working_lock);
 +	pcf->working = 1;
@@ -540,6 +607,35 @@
 +	if (ret != 5)
 +		DEBUGP("Oh crap PMU IRQ register read failed %d\n", ret);
 +
++	if (!pcf->coldplug_done) {
++		DEBUGP("PMU Coldplug init\n");
++
++		/* we used SECOND to kick ourselves started -- turn it off */
++		pcfirq[0] &= ~PCF50633_INT1_SECOND;
++		reg_set_bit_mask(pcf, PCF50633_REG_INT1M,
++					PCF50633_INT1_SECOND,
++					PCF50633_INT1_SECOND);
++
++		/* coldplug the USB if present */
++		if ((__reg_read(pcf, PCF50633_REG_MBCS1) &
++		    (PCF50633_MBCS1_USBPRES | PCF50633_MBCS1_USBOK)) ==
++		    (PCF50633_MBCS1_USBPRES | PCF50633_MBCS1_USBOK)) {
++			DEBUGPC("COLD USBINS\n");
++			input_report_key(pcf->input_dev, KEY_POWER2, 1);
++			apm_queue_event(APM_POWER_STATUS_CHANGE);
++			pcf->flags |= PCF50633_F_USB_PRESENT;
++			if (pcf->pdata->cb)
++				pcf->pdata->cb(&pcf->client.dev,
++					PCF50633_FEAT_MBC, PMU_EVT_USB_INSERT);
++		}
++
++		/* figure out our initial charging stance */
++		add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
++					      PCF50633_ADCC1_AVERAGE_16);
++
++		pcf->coldplug_done = 1;
++	}
++
 +	DEBUGP("INT1=0x%02x INT2=0x%02x INT3=0x%02x INT4=0x%02x INT5=0x%02x\n",
 +		pcfirq[0], pcfirq[1], pcfirq[2], pcfirq[3], pcfirq[4]);
 +
@@ -575,28 +671,34 @@
 +		if (pcf->pdata->cb)
 +			pcf->pdata->cb(&pcf->client.dev,
 +				       PCF50633_FEAT_MBC, PMU_EVT_USB_INSERT);
-+
++		/* completion irq will figure out our charging stance */
++		add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
++				     PCF50633_ADCC1_AVERAGE_16);
 +	}
 +	if (pcfirq[0] & PCF50633_INT1_USBREM) {
 +		DEBUGPC("USBREM ");
-+		input_report_key(pcf->input_dev, KEY_POWER2, 0);
-+		apm_queue_event(APM_POWER_STATUS_CHANGE);
-+		pcf->flags &= ~PCF50633_F_USB_PRESENT;
-+		if (pcf->pdata->cb)
-+			pcf->pdata->cb(&pcf->client.dev,
-+				       PCF50633_FEAT_MBC, PMU_EVT_USB_REMOVE);
++		/* only deal if we had understood it was in */
++		if (pcf->flags & PCF50633_F_USB_PRESENT) {
++			input_report_key(pcf->input_dev, KEY_POWER2, 0);
++			apm_queue_event(APM_POWER_STATUS_CHANGE);
++			pcf->flags &= ~PCF50633_F_USB_PRESENT;
++			if (pcf->pdata->cb)
++				pcf->pdata->cb(&pcf->client.dev,
++					PCF50633_FEAT_MBC, PMU_EVT_USB_REMOVE);
++			/* completion irq will figure out our charging stance */
++			add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
++					PCF50633_ADCC1_AVERAGE_16);
++		}
 +	}
 +	if (pcfirq[0] & PCF50633_INT1_ALARM) {
 +		DEBUGPC("ALARM ");
 +		if (pcf->pdata->used_features & PCF50633_FEAT_RTC)
-+			rtc_update_irq(pcf->rtc, 1,
-+				       RTC_AF | RTC_IRQF);
++			rtc_update_irq(pcf->rtc, 1, RTC_AF | RTC_IRQF);
 +	}
 +	if (pcfirq[0] & PCF50633_INT1_SECOND) {
 +		DEBUGPC("SECOND ");
 +		if (pcf->flags & PCF50633_F_RTC_SECOND)
-+			rtc_update_irq(pcf->rtc, 1,
-+				       RTC_PF | RTC_IRQF);
++			rtc_update_irq(pcf->rtc, 1, RTC_PF | RTC_IRQF);
 +
 +		if (pcf->onkey_seconds >= 0 &&
 +		    pcf->flags & PCF50633_F_PWR_PRESSED) {
@@ -641,6 +743,10 @@
 +	}
 +	if (pcfirq[2] & PCF50633_INT3_CHGHALT) {
 +		DEBUGPC("CHGHALT ");
++		/*
++		 * this is really "battery not pulling current" -- it can
++		 * appear with no battery attached
++		 */
 +		/* FIXME: signal this to userspace */
 +	}
 +	if (pcfirq[2] & PCF50633_INT3_THLIMON) {
@@ -664,6 +770,26 @@
 +	if (pcfirq[2] & PCF50633_INT3_ADCRDY) {
 +		/* ADC result ready */
 +		DEBUGPC("ADCRDY ");
++		tail = pcf->adc_queue_tail;
++		pcf->adc_queue_tail = (pcf->adc_queue_tail + 1) &
++				      (MAX_ADC_FIFO_DEPTH - 1);
++
++		switch (pcf->adc_queue_mux[tail]) {
++		case PCF50633_ADCC1_MUX_BATSNS_RES: /* battery voltage */
++			pcf->flag_bat_voltage_read =
++						  async_adc_complete(pcf);
++			break;
++		case PCF50633_ADCC1_MUX_ADCIN1: /* charger type */
++			pcf->charger_adc_result_raw = async_adc_complete(pcf);
++			pcf->charger_type = interpret_charger_type_from_adc(
++					     pcf, pcf->charger_adc_result_raw);
++			configure_pmu_for_charger(pcf, pcf->charger_type);
++			break;
++		default:
++			async_adc_complete(pcf);
++			break;
++		}
++		trigger_next_adc_job_if_any(pcf);
 +	}
 +	if (pcfirq[2] & PCF50633_INT3_ONKEY1S) {
 +		/* ONKEY pressed for more than 1 second */
@@ -693,13 +819,26 @@
 +		DEBUGPC("HIGHTMP ");
 +		apm_queue_event(APM_CRITICAL_SUSPEND);
 +	}
-+	if (pcfirq[3] & (PCF50633_INT4_AUTOPWRFAIL|PCF50633_INT4_DWN1PWRFAIL|
-+		   PCF50633_INT4_DWN2PWRFAIL|PCF50633_INT4_LEDPWRFAIL|
-+		   PCF50633_INT4_LEDOVP)) {
-+		/* Some regulator failed */
-+		DEBUGPC("REGULATOR_FAIL ");
++	if (pcfirq[3] & PCF50633_INT4_AUTOPWRFAIL) {
++		DEBUGPC("PCF50633_INT4_AUTOPWRFAIL ");
 +		/* FIXME: deal with this */
 +	}
++	if (pcfirq[3] & PCF50633_INT4_DWN1PWRFAIL) {
++		DEBUGPC("PCF50633_INT4_DWN1PWRFAIL ");
++		/* FIXME: deal with this */
++	}
++	if (pcfirq[3] & PCF50633_INT4_DWN2PWRFAIL) {
++		DEBUGPC("PCF50633_INT4_DWN2PWRFAIL ");
++		/* FIXME: deal with this */
++	}
++	if (pcfirq[3] & PCF50633_INT4_LEDPWRFAIL) {
++		DEBUGPC("PCF50633_INT4_LEDPWRFAIL ");
++		/* FIXME: deal with this */
++	}
++	if (pcfirq[3] & PCF50633_INT4_LEDOVP) {
++		DEBUGPC("PCF50633_INT4_LEDOVP ");
++		/* FIXME: deal with this */
++	}
 +
 +	DEBUGPC("\n");
 +
@@ -746,10 +885,21 @@
 +
 +u_int16_t pcf50633_battvolt(struct pcf50633_data *pcf)
 +{
-+	u_int16_t adc;
-+	adc = adc_read(pcf, PCF50633_ADCC1_MUX_BATSNS_RES, 0, NULL);
++	int count = 10;
 +
-+	return adc_to_batt_millivolts(adc);
++	pcf->flag_bat_voltage_read = -1;
++	add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_BATSNS_RES,
++				      PCF50633_ADCC1_AVERAGE_16);
++
++	while ((count--) && (pcf->flag_bat_voltage_read < 0))
++		msleep(1);
++
++	if (count < 0) { /* timeout somehow */
++		DEBUGPC("pcf50633_battvolt timeout :-(\n");
++		return -1;
++	}
++
++	return adc_to_batt_millivolts(pcf->flag_bat_voltage_read);
 +}
 +EXPORT_SYMBOL_GPL(pcf50633_battvolt);
 +
@@ -921,8 +1071,9 @@
 +}
 +EXPORT_SYMBOL_GPL(pcf50633_charge_enable);
 +
++#if 0
 +#define ONE			1000000
-+static inline u_int16_t adc_to_rntc(struct pcf50633_data *pcf, u_int16_t adc)
++static u_int16_t adc_to_rntc(struct pcf50633_data *pcf, u_int16_t adc)
 +{
 +	u_int32_t r_batt = (adc * pcf->pdata->r_fix_batt) / (1023 - adc);
 +	u_int16_t r_ntc;
@@ -932,57 +1083,25 @@
 +
 +	return r_ntc;
 +}
-+
-+static inline int16_t rntc_to_temp(u_int16_t rntc)
-+{
-+	int i;
-+
-+	for (i = 0; i < ARRAY_SIZE(ntc_table_tn11_3h103j); i++) {
-+		if (rntc > ntc_table_tn11_3h103j[i])
-+			return i - 10;
-+	}
-+	return 2342;
-+}
-+
++#endif
 +static ssize_t show_battemp(struct device *dev, struct device_attribute *attr,
 +			    char *buf)
 +{
-+#if 0
-+	struct i2c_client *client = to_i2c_client(dev);
-+	struct pcf50633_data *pcf = i2c_get_clientdata(client);
-+	u_int16_t adc;
-+
-+	adc = adc_read(pcf, PCF50633_ADCC1_MUX_BATTEMP, 0, NULL);
-+
-+	return sprintf(buf, "%d\n", rntc_to_temp(adc_to_rntc(pcf, adc)));
-+#endif
 +	return sprintf(buf, "\n");
 +}
 +static DEVICE_ATTR(battemp, S_IRUGO | S_IWUSR, show_battemp, NULL);
-+
-+static inline u_int16_t adc_to_chg_milliamps(struct pcf50633_data *pcf,
++#if 0
++static u_int16_t adc_to_chg_milliamps(struct pcf50633_data *pcf,
 +					     u_int16_t adc_adcin1,
 +					     u_int16_t adc_batvolt)
 +{
 +	u_int32_t res = ((adc_adcin1 - adc_batvolt) * 6000);
 +	return res / (pcf->pdata->r_sense_milli * 1024 / 1000);
 +}
-+
++#endif
 +static ssize_t show_chgcur(struct device *dev, struct device_attribute *attr,
 +			   char *buf)
 +{
-+#if 0
-+	struct i2c_client *client = to_i2c_client(dev);
-+	struct pcf50633_data *pcf = i2c_get_clientdata(client);
-+	u_int16_t adc_batvolt, adc_adcin1;
-+	u_int16_t ma;
-+
-+	adc_batvolt = adc_read(pcf, PCF50606_ADCMUX_BATVOLT_ADCIN1,
-+			       &adc_adcin1);
-+	ma = adc_to_chg_milliamps(pcf, adc_adcin1, adc_batvolt);
-+
-+	return sprintf(buf, "%u\n", ma);
-+#endif
 +	return sprintf(buf, "\n");
 +}
 +static DEVICE_ATTR(chgcur, S_IRUGO | S_IWUSR, show_chgcur, NULL);
@@ -1329,6 +1448,50 @@
 +};
 +
 +/*
++ * Charger type
++ */
++
++static ssize_t show_charger_type(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	struct pcf50633_data *pcf = i2c_get_clientdata(client);
++	static const char *names_charger_type[] = {
++		[CHARGER_TYPE_NONE] 	= "none",
++		[CHARGER_TYPE_HOSTUSB] 	= "host/500mA usb",
++		[CHARGER_TYPE_1A] 	= "charger 1A",
++	};
++	static const char *names_charger_modes[] = {
++		[PCF50633_MBCC7_USB_1000mA] 	= "1A",
++		[PCF50633_MBCC7_USB_500mA] 	= "500mA",
++		[PCF50633_MBCC7_USB_100mA] 	= "100mA",
++		[PCF50633_MBCC7_USB_SUSPEND] 	= "suspend",
++	};
++	int mode = reg_read(pcf, PCF50633_REG_MBCC7) & PCF56033_MBCC7_USB_MASK;
++
++	return sprintf(buf, "%s mode %s\n",
++			    names_charger_type[pcf->charger_type],
++			    names_charger_modes[mode]);
++}
++
++static DEVICE_ATTR(charger_type, 0444, show_charger_type, NULL);
++
++/*
++ * Charger adc
++ */
++
++static ssize_t show_charger_adc(struct device *dev,
++				struct device_attribute *attr, char *buf)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	struct pcf50633_data *pcf = i2c_get_clientdata(client);
++
++	return sprintf(buf, "%d\n", pcf->charger_adc_result_raw);
++}
++
++static DEVICE_ATTR(charger_adc, 0444, show_charger_adc, NULL);
++
++/*
 + * Dump regs
 + */
 +
@@ -1386,6 +1549,9 @@
 +};
 +#endif
 +
++/*
++ * CARE!  This table is modified at runtime!
++ */
 +static struct attribute *pcf_sysfs_entries[] = {
 +	&dev_attr_voltage_auto.attr,
 +	&dev_attr_voltage_down1.attr,
@@ -1398,8 +1564,16 @@
 +	&dev_attr_voltage_ldo5.attr,
 +	&dev_attr_voltage_ldo6.attr,
 +	&dev_attr_voltage_hcldo.attr,
++	&dev_attr_charger_type.attr,
++	&dev_attr_charger_adc.attr,
 +	&dev_attr_dump_regs.attr,
-+	NULL
++	NULL, /* going to add things at this point! */
++	NULL,
++	NULL,
++	NULL,
++	NULL,
++	NULL,
++	NULL,
 +};
 +
 +static struct attribute_group pcf_attr_group = {
@@ -1520,7 +1694,7 @@
 +		goto exit_sysfs;
 +
 +	/* configure interrupt mask */
-+	reg_write(data, PCF50633_REG_INT1M, PCF50633_INT1_SECOND);
++	reg_write(data, PCF50633_REG_INT1M, 0x00); /* we want SECOND to kick */
 +	reg_write(data, PCF50633_REG_INT2M, 0x00);
 +	reg_write(data, PCF50633_REG_INT3M, 0x00);
 +	reg_write(data, PCF50633_REG_INT4M, 0x00);
@@ -1571,17 +1745,6 @@
 +	}
 +#endif
 +
-+	/* coldplug the USB if present */
-+	if (reg_read(data, PCF50633_REG_MBCS1) & 3) { /* usb present, power ok */
-+		DEBUGPC("USBINS ");
-+		input_report_key(data->input_dev, KEY_POWER2, 1);
-+		apm_queue_event(APM_POWER_STATUS_CHANGE);
-+		data->flags |= PCF50633_F_USB_PRESENT;
-+		if (data->pdata->cb)
-+			data->pdata->cb(&data->client.dev,
-+				       PCF50633_FEAT_MBC, PMU_EVT_USB_INSERT);
-+	}
-+
 +	return 0;
 +exit_rtc:
 +	if (data->pdata->used_features & PCF50633_FEAT_RTC)





More information about the commitlog mailing list