コード例 #1
0
static int adc_result(struct pcf50633 *pcf)
{
	u8 adcs1, adcs3;
	u16 result;

	adcs1 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS1);
	adcs3 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS3);
	result = (adcs1 << 2) | (adcs3 & PCF50633_ADCS3_ADCDAT1L_MASK);

	dev_dbg(pcf->dev, "adc result = %d\n", result);

	return result;
}
コード例 #2
0
ファイル: mach-gta02.c プロジェクト: mirko/openwrt-x-burst
static void gta02_bl_set_intensity(int intensity)
{
	struct pcf50633 *pcf = gta02_pcf;
	int old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
	int ret;

	intensity >>= 2;

	/*
	 * One code path that leads here is from a kernel panic. Trying to turn
	 * the backlight on just gives us a nearly endless stream of complaints
	 * and accomplishes nothing. We can't win. Just give up.
	 *
	 * In the unlikely event that there's another path leading here while
	 * we're atomic, we print at least a warning.
	 */
	if (in_atomic()) {
		printk(KERN_ERR
		    "gta02_bl_set_intensity called while atomic\n");
		return;
	}

	if (!(pcf50633_reg_read(pcf, PCF50633_REG_LEDENA) & 3))
		old_intensity = 0;
	else
		old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);

	if (intensity == old_intensity)
		return;

	/* We can't do this anywhere else */
	pcf50633_reg_write(pcf, PCF50633_REG_LEDDIM, 5);

	/*
	 * The PCF50633 cannot handle LEDOUT = 0 (datasheet p60)
	 * if seen, you have to re-enable the LED unit
	 */
	if (!intensity || !old_intensity)
		pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0);

	if (!intensity) /* illegal to set LEDOUT to 0 */
		ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f,
									     2);
	else
		ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f,
			       intensity);

	if (intensity)
		pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 2);

}
コード例 #3
0
ファイル: pcf50633-charger.c プロジェクト: Lyude/linux
static int pcf50633_mbc_probe(struct platform_device *pdev)
{
	struct power_supply_config psy_cfg = {};
	struct pcf50633_mbc *mbc;
	int i;
	u8 mbcs1;

	mbc = devm_kzalloc(&pdev->dev, sizeof(*mbc), GFP_KERNEL);
	if (!mbc)
		return -ENOMEM;

	platform_set_drvdata(pdev, mbc);
	mbc->pcf = dev_to_pcf50633(pdev->dev.parent);

	/* Set up IRQ handlers */
	for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
		pcf50633_register_irq(mbc->pcf, mbc_irq_handlers[i],
					pcf50633_mbc_irq_handler, mbc);

	psy_cfg.supplied_to		= mbc->pcf->pdata->batteries;
	psy_cfg.num_supplicants		= mbc->pcf->pdata->num_batteries;
	psy_cfg.drv_data		= mbc;

	/* Create power supplies */
	mbc->adapter = power_supply_register(&pdev->dev,
					     &pcf50633_mbc_adapter_desc,
					     &psy_cfg);
	if (IS_ERR(mbc->adapter)) {
		dev_err(mbc->pcf->dev, "failed to register adapter\n");
		return PTR_ERR(mbc->adapter);
	}

	mbc->usb = power_supply_register(&pdev->dev, &pcf50633_mbc_usb_desc,
					 &psy_cfg);
	if (IS_ERR(mbc->usb)) {
		dev_err(mbc->pcf->dev, "failed to register usb\n");
		power_supply_unregister(mbc->adapter);
		return PTR_ERR(mbc->usb);
	}

	mbc->ac = power_supply_register(&pdev->dev, &pcf50633_mbc_ac_desc,
					&psy_cfg);
	if (IS_ERR(mbc->ac)) {
		dev_err(mbc->pcf->dev, "failed to register ac\n");
		power_supply_unregister(mbc->adapter);
		power_supply_unregister(mbc->usb);
		return PTR_ERR(mbc->ac);
	}

	if (sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group))
		dev_err(mbc->pcf->dev, "failed to create sysfs entries\n");

	mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1);
	if (mbcs1 & PCF50633_MBCS1_USBPRES)
		pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc);
	if (mbcs1 & PCF50633_MBCS1_ADAPTPRES)
		pcf50633_mbc_irq_handler(PCF50633_IRQ_ADPINS, mbc);

	return 0;
}
コード例 #4
0
ファイル: pcf50633-charger.c プロジェクト: Lyude/linux
int pcf50633_mbc_get_status(struct pcf50633 *pcf)
{
	struct pcf50633_mbc *mbc  = platform_get_drvdata(pcf->mbc_pdev);
	int status = 0;
	u8 chgmod;

	if (!mbc)
		return 0;

	chgmod = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2)
		& PCF50633_MBCS2_MBC_MASK;

	if (mbc->usb_online)
		status |= PCF50633_MBC_USB_ONLINE;
	if (chgmod == PCF50633_MBCS2_MBC_USB_PRE ||
	    chgmod == PCF50633_MBCS2_MBC_USB_PRE_WAIT ||
	    chgmod == PCF50633_MBCS2_MBC_USB_FAST ||
	    chgmod == PCF50633_MBCS2_MBC_USB_FAST_WAIT)
		status |= PCF50633_MBC_USB_ACTIVE;
	if (mbc->adapter_online)
		status |= PCF50633_MBC_ADAPTER_ONLINE;
	if (chgmod == PCF50633_MBCS2_MBC_ADP_PRE ||
	    chgmod == PCF50633_MBCS2_MBC_ADP_PRE_WAIT ||
	    chgmod == PCF50633_MBCS2_MBC_ADP_FAST ||
	    chgmod == PCF50633_MBCS2_MBC_ADP_FAST_WAIT)
		status |= PCF50633_MBC_ADAPTER_ACTIVE;

	return status;
}
コード例 #5
0
static ssize_t show_dump_regs(struct device *dev, struct device_attribute *attr,
                              char *buf)
{
    struct pcf50633 *pcf = dev_get_drvdata(dev);
    u8 dump[16];
    int n, n1, idx = 0;
    char *buf1 = buf;
    static u8 address_no_read[] = {
        PCF50633_REG_INT1,
        PCF50633_REG_INT2,
        PCF50633_REG_INT3,
        PCF50633_REG_INT4,
        PCF50633_REG_INT5,
        0
    };

    for (n = 0; n < 256; n += sizeof(dump)) {
        for (n1 = 0; n1 < sizeof(dump); n1++)
            if (n == address_no_read[idx]) {
                idx++;
                dump[n1] = 0x00;
            } else
                dump[n1] = pcf50633_reg_read(pcf, n + n1);

        hex_dump_to_buffer(dump, sizeof(dump), 16, 1, buf1, 128, 0);
        buf1 += strlen(buf1);
        *buf1++ = '\n';
        *buf1 = '\0';
    }

    return buf1 - buf;
}
コード例 #6
0
ファイル: mach-gta02.c プロジェクト: 0x0f/adam-kernel
static void gta02_bl_set_intensity(int intensity)
{
	struct pcf50633 *pcf = gta02_pcf;
	int old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);

	/* We map 8-bit intensity to 6-bit intensity in hardware. */
	intensity >>= 2;

	/*
	 * This can happen during, eg, print of panic on blanked console,
	 * but we can't service i2c without interrupts active, so abort.
	 */
	if (in_atomic()) {
		printk(KERN_ERR "gta02_bl_set_intensity called while atomic\n");
		return;
	}

	old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
	if (intensity == old_intensity)
		return;

	/* We can't do this anywhere else. */
	pcf50633_reg_write(pcf, PCF50633_REG_LEDDIM, 5);

	if (!(pcf50633_reg_read(pcf, PCF50633_REG_LEDENA) & 3))
		old_intensity = 0;

	/*
	 * The PCF50633 cannot handle LEDOUT = 0 (datasheet p60)
	 * if seen, you have to re-enable the LED unit.
	 */
	if (!intensity || !old_intensity)
		pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0);

	/* Illegal to set LEDOUT to 0. */
	if (!intensity)
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f, 2);
	else
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f,
					  intensity);

	if (intensity)
		pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 2);

}
コード例 #7
0
u8 pcf50633_gpio_get(struct pcf50633 *pcf, int gpio)
{
	u8 reg, val;

	reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
	val = pcf50633_reg_read(pcf, reg) & 0x07;

	return val;
}
コード例 #8
0
int pcf50633_gpio_invert_get(struct pcf50633 *pcf, int gpio)
{
	u8 reg, val;

	reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
	val = pcf50633_reg_read(pcf, reg);

	return val & (1 << 3);
}
コード例 #9
0
static ssize_t
show_chgmode(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct pcf50633_mbc *mbc = dev_get_drvdata(dev);

	u8 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
	u8 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);

	return sprintf(buf, "%d\n", chgmod);
}
コード例 #10
0
ファイル: pcf50633-charger.c プロジェクト: Lyude/linux
static ssize_t
show_chglim(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
	u8 mbcc5 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC5);
	unsigned int ma;

	if (!mbc->pcf->pdata->charger_reference_current_ma)
		return -ENODEV;

	ma = (mbc->pcf->pdata->charger_reference_current_ma *  mbcc5) >> 8;

	return sprintf(buf, "%u\n", ma);
}
コード例 #11
0
static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
{
	struct pcf50633 *pcf = rdev_get_drvdata(rdev);
	int regulator_id = rdev_get_id(rdev);
	u8 regnr;

	regulator_id = rdev_get_id(rdev);
	if (regulator_id >= PCF50633_NUM_REGULATORS)
		return -EINVAL;

	/* the *ENA register is always one after the *OUT register */
	regnr = pcf50633_regulator_registers[regulator_id] + 1;

	return pcf50633_reg_read(pcf, regnr) & PCF50633_REGULATOR_ON;
}
コード例 #12
0
static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
{
	struct pcf50633 *pcf;
	int regulator_id;
	u8 volt_bits, regnr;

	pcf = rdev_get_drvdata(rdev);

	regulator_id = rdev_get_id(rdev);
	if (regulator_id >= PCF50633_NUM_REGULATORS)
		return -EINVAL;

	regnr = pcf50633_regulator_registers[regulator_id];

	volt_bits = pcf50633_reg_read(pcf, regnr);

	return pcf50633_regulator_voltage_value(regulator_id, volt_bits);
}
コード例 #13
0
int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
{
	struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
	int ret = 0;
	u8 bits;
	int charging_start = 1;
	u8 mbcs2, chgmod;

	if (ma >= 1000)
		bits = PCF50633_MBCC7_USB_1000mA;
	else if (ma >= 500)
		bits = PCF50633_MBCC7_USB_500mA;
	else if (ma >= 100)
		bits = PCF50633_MBCC7_USB_100mA;
	else {
		bits = PCF50633_MBCC7_USB_SUSPEND;
		charging_start = 0;
	}

	ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
					PCF50633_MBCC7_USB_MASK, bits);
	if (ret)
		dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma);
	else
		dev_info(pcf->dev, "usb curlim to %d mA\n", ma);

	
	mbcs2 = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
	chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);

	
	if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
	else
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME);

	mbc->usb_active = charging_start;

	power_supply_changed(&mbc->usb);

	return ret;
}
コード例 #14
0
static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
{
	struct pcf50633 *pcf;
	int regulator_id, millivolts, volt_bits;
	u8 regnr;

	pcf = rdev_get_drvdata(rdev);;

	regulator_id = rdev_get_id(rdev);
	if (regulator_id >= PCF50633_NUM_REGULATORS)
		return -EINVAL;

	regnr = pcf50633_regulator_registers[regulator_id];

	volt_bits = pcf50633_reg_read(pcf, regnr);
	if (volt_bits < 0)
		return -1;

	switch (regulator_id) {
	case PCF50633_REGULATOR_AUTO:
		millivolts = auto_voltage_value(volt_bits);
		break;
	case PCF50633_REGULATOR_DOWN1:
		millivolts = down_voltage_value(volt_bits);
		break;
	case PCF50633_REGULATOR_DOWN2:
		millivolts = down_voltage_value(volt_bits);
		break;
	case PCF50633_REGULATOR_LDO1:
	case PCF50633_REGULATOR_LDO2:
	case PCF50633_REGULATOR_LDO3:
	case PCF50633_REGULATOR_LDO4:
	case PCF50633_REGULATOR_LDO5:
	case PCF50633_REGULATOR_LDO6:
	case PCF50633_REGULATOR_HCLDO:
		millivolts = ldo_voltage_value(volt_bits);
		break;
	default:
		return -EINVAL;
	}

	return millivolts * 1000;
}
コード例 #15
0
static void
pcf50633_input_irq(int irq, void *data)
{
	struct pcf50633_input *input;
	int onkey_released;

	input = data;

	/*                                                            */
	onkey_released = pcf50633_reg_read(input->pcf, PCF50633_REG_OOCSTAT)
						& PCF50633_OOCSTAT_ONKEY;

	if (irq == PCF50633_IRQ_ONKEYF && !onkey_released)
		input_report_key(input->input_dev, KEY_POWER, 1);
	else if (irq == PCF50633_IRQ_ONKEYR && onkey_released)
		input_report_key(input->input_dev, KEY_POWER, 0);

	input_sync(input->input_dev);
}
コード例 #16
0
static ssize_t
show_usblim(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
	u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
						PCF50633_MBCC7_USB_MASK;
	unsigned int ma;

	if (usblim == PCF50633_MBCC7_USB_1000mA)
		ma = 1000;
	else if (usblim == PCF50633_MBCC7_USB_500mA)
		ma = 500;
	else if (usblim == PCF50633_MBCC7_USB_100mA)
		ma = 100;
	else
		ma = 0;

	return sprintf(buf, "%u\n", ma);
}
コード例 #17
0
ファイル: pcf50633-charger.c プロジェクト: Lyude/linux
static int ac_get_property(struct power_supply *psy,
			enum power_supply_property psp,
			union power_supply_propval *val)
{
	struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
	int ret = 0;
	u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
						PCF50633_MBCC7_USB_MASK;

	switch (psp) {
	case POWER_SUPPLY_PROP_ONLINE:
		val->intval = mbc->usb_online &&
				(usblim == PCF50633_MBCC7_USB_1000mA);
		break;
	default:
		ret = -EINVAL;
		break;
	}
	return ret;
}
コード例 #18
0
static void pcf50633_mbc_charging_restart(struct work_struct *work)
{
	struct pcf50633_mbc *mbc;
	u8 mbcs2, chgmod;

	mbc = container_of(work, struct pcf50633_mbc,
				charging_restart_work.work);

	mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
	chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);

	if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
		return;

	
	pcf50633_reg_set_bit_mask(mbc->pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME);
	mbc->usb_active = 1;
	power_supply_changed(&mbc->usb);

	dev_info(mbc->pcf->dev, "Charging restarted\n");
}
コード例 #19
0
ファイル: pcf50633-charger.c プロジェクト: Lyude/linux
int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
{
	struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
	int ret = 0;
	u8 bits;
	u8 mbcs2, chgmod;
	unsigned int mbcc5;

	if (ma >= 1000) {
		bits = PCF50633_MBCC7_USB_1000mA;
		ma = 1000;
	} else if (ma >= 500) {
		bits = PCF50633_MBCC7_USB_500mA;
		ma = 500;
	} else if (ma >= 100) {
		bits = PCF50633_MBCC7_USB_100mA;
		ma = 100;
	} else {
		bits = PCF50633_MBCC7_USB_SUSPEND;
		ma = 0;
	}

	ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
					PCF50633_MBCC7_USB_MASK, bits);
	if (ret)
		dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma);
	else
		dev_info(pcf->dev, "usb curlim to %d mA\n", ma);

	/*
	 * We limit the charging current to be the USB current limit.
	 * The reason is that on pcf50633, when it enters PMU Standby mode,
	 * which it does when the device goes "off", the USB current limit
	 * reverts to the variant default.  In at least one common case, that
	 * default is 500mA.  By setting the charging current to be the same
	 * as the USB limit we set here before PMU standby, we enforce it only
	 * using the correct amount of current even when the USB current limit
	 * gets reset to the wrong thing
	 */

	if (mbc->pcf->pdata->charger_reference_current_ma) {
		mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
		if (mbcc5 > 255)
			mbcc5 = 255;
		pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
	}

	mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
	chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);

	/* If chgmod == BATFULL, setting chgena has no effect.
	 * Datasheet says we need to set resume instead but when autoresume is
	 * used resume doesn't work. Clear and set chgena instead.
	 */
	if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
	else {
		pcf50633_reg_clear_bits(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA);
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
	}

	power_supply_changed(mbc->usb);

	return ret;
}
コード例 #20
0
static int __devinit pcf50633_probe(struct i2c_client *client,
                                    const struct i2c_device_id *ids)
{
    struct pcf50633 *pcf;
    struct pcf50633_platform_data *pdata = client->dev.platform_data;
    int i, ret;
    int version, variant;

    if (!client->irq) {
        dev_err(&client->dev, "Missing IRQ\n");
        return -ENOENT;
    }

    pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
    if (!pcf)
        return -ENOMEM;

    pcf->pdata = pdata;

    mutex_init(&pcf->lock);

    pcf->regmap = regmap_init_i2c(client, &pcf50633_regmap_config);
    if (IS_ERR(pcf->regmap)) {
        ret = PTR_ERR(pcf->regmap);
        dev_err(pcf->dev, "Failed to allocate register map: %d\n",
                ret);
        goto err_free;
    }

    i2c_set_clientdata(client, pcf);
    pcf->dev = &client->dev;

    version = pcf50633_reg_read(pcf, 0);
    variant = pcf50633_reg_read(pcf, 1);
    if (version < 0 || variant < 0) {
        dev_err(pcf->dev, "Unable to probe pcf50633\n");
        ret = -ENODEV;
        goto err_regmap;
    }

    dev_info(pcf->dev, "Probed device version %d variant %d\n",
             version, variant);

    pcf50633_irq_init(pcf, client->irq);


    pcf50633_client_dev_register(pcf, "pcf50633-input",
                                 &pcf->input_pdev);
    pcf50633_client_dev_register(pcf, "pcf50633-rtc",
                                 &pcf->rtc_pdev);
    pcf50633_client_dev_register(pcf, "pcf50633-mbc",
                                 &pcf->mbc_pdev);
    pcf50633_client_dev_register(pcf, "pcf50633-adc",
                                 &pcf->adc_pdev);
    pcf50633_client_dev_register(pcf, "pcf50633-backlight",
                                 &pcf->bl_pdev);


    for (i = 0; i < PCF50633_NUM_REGULATORS; i++) {
        struct platform_device *pdev;

        pdev = platform_device_alloc("pcf50633-regltr", i);
        if (!pdev) {
            dev_err(pcf->dev, "Cannot create regulator %d\n", i);
            continue;
        }

        pdev->dev.parent = pcf->dev;
        platform_device_add_data(pdev, &pdata->reg_init_data[i],
                                 sizeof(pdata->reg_init_data[i]));
        pcf->regulator_pdev[i] = pdev;

        platform_device_add(pdev);
    }

    ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group);
    if (ret)
        dev_err(pcf->dev, "error creating sysfs entries\n");

    if (pdata->probe_done)
        pdata->probe_done(pcf);

    return 0;

err_regmap:
    regmap_exit(pcf->regmap);
err_free:
    kfree(pcf);

    return ret;
}
コード例 #21
0
static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
{
	struct pcf50633_mbc *mbc;
	struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
	int ret;
	int i;
	u8 mbcs1;

	mbc = kzalloc(sizeof(*mbc), GFP_KERNEL);
	if (!mbc)
		return -ENOMEM;

	platform_set_drvdata(pdev, mbc);
	mbc->pcf = pdata->pcf;

	
	for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
		pcf50633_register_irq(mbc->pcf, mbc_irq_handlers[i],
					pcf50633_mbc_irq_handler, mbc);

	
	mbc->adapter.name		= "adapter";
	mbc->adapter.type		= POWER_SUPPLY_TYPE_MAINS;
	mbc->adapter.properties		= power_props;
	mbc->adapter.num_properties	= ARRAY_SIZE(power_props);
	mbc->adapter.get_property	= &adapter_get_property;
	mbc->adapter.supplied_to	= mbc->pcf->pdata->batteries;
	mbc->adapter.num_supplicants	= mbc->pcf->pdata->num_batteries;

	mbc->usb.name			= "usb";
	mbc->usb.type			= POWER_SUPPLY_TYPE_USB;
	mbc->usb.properties		= power_props;
	mbc->usb.num_properties		= ARRAY_SIZE(power_props);
	mbc->usb.get_property		= usb_get_property;
	mbc->usb.supplied_to		= mbc->pcf->pdata->batteries;
	mbc->usb.num_supplicants	= mbc->pcf->pdata->num_batteries;

	ret = power_supply_register(&pdev->dev, &mbc->adapter);
	if (ret) {
		dev_err(mbc->pcf->dev, "failed to register adapter\n");
		kfree(mbc);
		return ret;
	}

	ret = power_supply_register(&pdev->dev, &mbc->usb);
	if (ret) {
		dev_err(mbc->pcf->dev, "failed to register usb\n");
		power_supply_unregister(&mbc->adapter);
		kfree(mbc);
		return ret;
	}

	INIT_DELAYED_WORK(&mbc->charging_restart_work,
				pcf50633_mbc_charging_restart);

	ret = sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group);
	if (ret)
		dev_err(mbc->pcf->dev, "failed to create sysfs entries\n");

	mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1);
	if (mbcs1 & PCF50633_MBCS1_USBPRES)
		pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc);
	if (mbcs1 & PCF50633_MBCS1_ADAPTPRES)
		pcf50633_mbc_irq_handler(PCF50633_IRQ_ADPINS, mbc);

	return 0;
}
コード例 #22
0
static irqreturn_t pcf50633_irq(int irq, void *data)
{
    struct pcf50633 *pcf = data;
    int ret, i, j;
    u8 pcf_int[5], chgstat;

    /* Read the 5 INT regs in one transaction */
    ret = pcf50633_read_block(pcf, PCF50633_REG_INT1,
                              ARRAY_SIZE(pcf_int), pcf_int);
    if (ret != ARRAY_SIZE(pcf_int)) {
        dev_err(pcf->dev, "Error reading INT registers\n");

        /*
         * If this doesn't ACK the interrupt to the chip, we'll be
         * called once again as we're level triggered.
         */
        goto out;
    }

    /* defeat 8s death from lowsys on A5 */
    pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN,  0x04);

    /* We immediately read the usb and adapter status. We thus make sure
     * only of USBINS/USBREM IRQ handlers are called */
    if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
        chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
        if (chgstat & (0x3 << 4))
            pcf_int[0] &= ~PCF50633_INT1_USBREM;
        else
            pcf_int[0] &= ~PCF50633_INT1_USBINS;
    }

    /* Make sure only one of ADPINS or ADPREM is set */
    if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) {
        chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
        if (chgstat & (0x3 << 4))
            pcf_int[0] &= ~PCF50633_INT1_ADPREM;
        else
            pcf_int[0] &= ~PCF50633_INT1_ADPINS;
    }

    dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x "
            "INT4=0x%02x INT5=0x%02x\n", pcf_int[0],
            pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]);

    /* Some revisions of the chip don't have a 8s standby mode on
     * ONKEY1S press. We try to manually do it in such cases. */
    if ((pcf_int[0] & PCF50633_INT1_SECOND) && pcf->onkey1s_held) {
        dev_info(pcf->dev, "ONKEY1S held for %d secs\n",
                 pcf->onkey1s_held);
        if (pcf->onkey1s_held++ == PCF50633_ONKEY1S_TIMEOUT)
            if (pcf->pdata->force_shutdown)
                pcf->pdata->force_shutdown(pcf);
    }

    if (pcf_int[2] & PCF50633_INT3_ONKEY1S) {
        dev_info(pcf->dev, "ONKEY1S held\n");
        pcf->onkey1s_held = 1 ;

        /* Unmask IRQ_SECOND */
        pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT1M,
                                PCF50633_INT1_SECOND);

        /* Unmask IRQ_ONKEYR */
        pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT2M,
                                PCF50633_INT2_ONKEYR);
    }

    if ((pcf_int[1] & PCF50633_INT2_ONKEYR) && pcf->onkey1s_held) {
        pcf->onkey1s_held = 0;

        /* Mask SECOND and ONKEYR interrupts */
        if (pcf->mask_regs[0] & PCF50633_INT1_SECOND)
            pcf50633_reg_set_bit_mask(pcf,
                                      PCF50633_REG_INT1M,
                                      PCF50633_INT1_SECOND,
                                      PCF50633_INT1_SECOND);

        if (pcf->mask_regs[1] & PCF50633_INT2_ONKEYR)
            pcf50633_reg_set_bit_mask(pcf,
                                      PCF50633_REG_INT2M,
                                      PCF50633_INT2_ONKEYR,
                                      PCF50633_INT2_ONKEYR);
    }

    /* Have we just resumed ? */
    if (pcf->is_suspended) {
        pcf->is_suspended = 0;

        /* Set the resume reason filtering out non resumers */
        for (i = 0; i < ARRAY_SIZE(pcf_int); i++)
            pcf->resume_reason[i] = pcf_int[i] &
                                    pcf->pdata->resumers[i];

        /* Make sure we don't pass on any ONKEY events to
         * userspace now */
        pcf_int[1] &= ~(PCF50633_INT2_ONKEYR | PCF50633_INT2_ONKEYF);
    }

    for (i = 0; i < ARRAY_SIZE(pcf_int); i++) {
        /* Unset masked interrupts */
        pcf_int[i] &= ~pcf->mask_regs[i];

        for (j = 0; j < 8 ; j++)
            if (pcf_int[i] & (1 << j))
                pcf50633_irq_call_handler(pcf, (i * 8) + j);
    }

out:
    return IRQ_HANDLED;
}
コード例 #23
0
static int __devinit pcf50633_probe(struct i2c_client *client,
				const struct i2c_device_id *ids)
{
	struct pcf50633 *pcf;
	struct pcf50633_platform_data *pdata = client->dev.platform_data;
	int i, ret = 0;
	int version, variant;

	pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
	if (!pcf)
		return -ENOMEM;

	pcf->pdata = pdata;

	mutex_init(&pcf->lock);

	i2c_set_clientdata(client, pcf);
	pcf->dev = &client->dev;
	pcf->i2c_client = client;
	pcf->irq = client->irq;
	pcf->work_queue = create_singlethread_workqueue("pcf50633");

	INIT_WORK(&pcf->irq_work, pcf50633_irq_worker);

	version = pcf50633_reg_read(pcf, 0);
	variant = pcf50633_reg_read(pcf, 1);
	if (version < 0 || variant < 0) {
		dev_err(pcf->dev, "Unable to probe pcf50633\n");
		ret = -ENODEV;
		goto err;
	}

	dev_info(pcf->dev, "Probed device version %d variant %d\n",
							version, variant);

	/* Enable all interrupts except RTC SECOND */
	pcf->mask_regs[0] = 0x80;
	pcf50633_reg_write(pcf, PCF50633_REG_INT1M, pcf->mask_regs[0]);
	pcf50633_reg_write(pcf, PCF50633_REG_INT2M, 0x00);
	pcf50633_reg_write(pcf, PCF50633_REG_INT3M, 0x00);
	pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00);
	pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00);

	/* Create sub devices */
	pcf50633_client_dev_register(pcf, "pcf50633-input",
						&pcf->input_pdev);
	pcf50633_client_dev_register(pcf, "pcf50633-rtc",
						&pcf->rtc_pdev);
	pcf50633_client_dev_register(pcf, "pcf50633-mbc",
						&pcf->mbc_pdev);
	pcf50633_client_dev_register(pcf, "pcf50633-adc",
						&pcf->adc_pdev);

	for (i = 0; i < PCF50633_NUM_REGULATORS; i++) {
		struct platform_device *pdev;

		pdev = platform_device_alloc("pcf50633-regltr", i);
		if (!pdev) {
			dev_err(pcf->dev, "Cannot create regulator\n");
			continue;
		}

		pdev->dev.parent = pcf->dev;
		pdev->dev.platform_data = &pdata->reg_init_data[i];
		dev_set_drvdata(&pdev->dev, pcf);
		pcf->regulator_pdev[i] = pdev;

		platform_device_add(pdev);
	}

	if (client->irq) {
		ret = request_irq(client->irq, pcf50633_irq,
				IRQF_TRIGGER_LOW, "pcf50633", pcf);

		if (ret) {
			dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
			goto err;
		}
	} else {
		dev_err(pcf->dev, "No IRQ configured\n");
		goto err;
	}

	if (enable_irq_wake(client->irq) < 0)
		dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source"
			"in this hardware revision", client->irq);

	ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group);
	if (ret)
		dev_err(pcf->dev, "error creating sysfs entries\n");

	if (pdata->probe_done)
		pdata->probe_done(pcf);

	return 0;

err:
	destroy_workqueue(pcf->work_queue);
	kfree(pcf);
	return ret;
}