示例#1
0
static int palmas_extreg_init(struct palmas *palmas, int id,
		struct palmas_reg_init *reg_init)
{
	unsigned int addr;
	int ret;
	unsigned int val = 0;
	struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata;
	struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];

	addr = rinfo->ctrl_addr;

	if (reg_init->mode_sleep)
		val = PALMAS_REGEN1_CTRL_MODE_SLEEP;

	ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
			addr, PALMAS_REGEN1_CTRL_MODE_SLEEP, val);
	if (ret < 0) {
		dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n",
			addr, ret);
		return ret;
	}

	if (reg_init->roof_floor) {
		/* Enable externally controlled regulator */
		ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
				addr, PALMAS_REGEN1_CTRL_MODE_ACTIVE,
				PALMAS_REGEN1_CTRL_MODE_ACTIVE);
		if (ret < 0) {
			dev_err(palmas->dev,
				"Resource Register 0x%02x update failed %d\n",
				addr, ret);
			return ret;
		}
		return palmas_regulator_config_external(palmas, id, reg_init);
	}
	return 0;
}
示例#2
0
static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
{
	struct palmas_gpio *pg = gpiochip_get_data(gc);
	struct palmas *palmas = pg->palmas;
	int ret;
	unsigned int reg;
	int gpio16 = (offset/8);

	offset %= 8;
	reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;

	ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0);
	if (ret < 0)
		dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,
			ret);
	return ret;
}
示例#3
0
static int palmas_ldo_init(struct palmas *palmas, int id,
		struct palmas_reg_init *reg_init)
{
	unsigned int reg;
	unsigned int addr;
	int ret;
	struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata;
	struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];

	addr = rinfo->ctrl_addr;

	ret = palmas_ldo_read(palmas, addr, &reg);
	if (ret)
		return ret;

	if (reg_init->warm_reset)
		reg |= PALMAS_LDO1_CTRL_WR_S;
	else
		reg &= ~PALMAS_LDO1_CTRL_WR_S;

	if (reg_init->mode_sleep)
		reg |= PALMAS_LDO1_CTRL_MODE_SLEEP;
	else
		reg &= ~PALMAS_LDO1_CTRL_MODE_SLEEP;

	ret = palmas_ldo_write(palmas, addr, reg);
	if (ret)
		return ret;

	if (reg_init->roof_floor) {
		/* Enable externally controlled regulator */
		ret = palmas_update_bits(palmas, PALMAS_LDO_BASE,
				addr, PALMAS_LDO1_CTRL_MODE_ACTIVE,
				PALMAS_LDO1_CTRL_MODE_ACTIVE);
		if (ret < 0) {
			dev_err(palmas->dev,
				"LDO Register 0x%02x update failed %d\n",
				addr, ret);
			return ret;
		}
		return palmas_regulator_config_external(palmas, id, reg_init);
	}
	return 0;
}
示例#4
0
文件: palmas.c 项目: ChrisOHu/linux
static int palmas_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
	struct palmas *palmas;
	struct palmas_platform_data *pdata;
	struct device_node *node = i2c->dev.of_node;
	int ret = 0, i;
	unsigned int reg, addr, *features;
	int slave;
	const struct of_device_id *match;

	pdata = dev_get_platdata(&i2c->dev);

	if (node && !pdata) {
		pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);

		if (!pdata)
			return -ENOMEM;

		palmas_dt_to_pdata(i2c, pdata);
	}

	if (!pdata)
		return -EINVAL;

	palmas = devm_kzalloc(&i2c->dev, sizeof(struct palmas), GFP_KERNEL);
	if (palmas == NULL)
		return -ENOMEM;

	i2c_set_clientdata(i2c, palmas);
	palmas->dev = &i2c->dev;
	palmas->irq = i2c->irq;

	match = of_match_device(of_match_ptr(of_palmas_match_tbl), &i2c->dev);

	if (!match)
		return -ENODATA;

	features = (unsigned int *)match->data;
	palmas->features = *features;

	for (i = 0; i < PALMAS_NUM_CLIENTS; i++) {
		if (i == 0)
			palmas->i2c_clients[i] = i2c;
		else {
			palmas->i2c_clients[i] =
					i2c_new_dummy(i2c->adapter,
							i2c->addr + i);
			if (!palmas->i2c_clients[i]) {
				dev_err(palmas->dev,
					"can't attach client %d\n", i);
				ret = -ENOMEM;
				goto err;
			}
			palmas->i2c_clients[i]->dev.of_node = of_node_get(node);
		}
		palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i],
				&palmas_regmap_config[i]);
		if (IS_ERR(palmas->regmap[i])) {
			ret = PTR_ERR(palmas->regmap[i]);
			dev_err(palmas->dev,
				"Failed to allocate regmap %d, err: %d\n",
				i, ret);
			goto err;
		}
	}

	if (!palmas->irq) {
		dev_warn(palmas->dev, "IRQ missing: skipping irq request\n");
		goto no_irq;
	}

	/* Change interrupt line output polarity */
	if (pdata->irq_flags & IRQ_TYPE_LEVEL_HIGH)
		reg = PALMAS_POLARITY_CTRL_INT_POLARITY;
	else
		reg = 0;
	ret = palmas_update_bits(palmas, PALMAS_PU_PD_OD_BASE,
			PALMAS_POLARITY_CTRL, PALMAS_POLARITY_CTRL_INT_POLARITY,
			reg);
	if (ret < 0) {
		dev_err(palmas->dev, "POLARITY_CTRL updat failed: %d\n", ret);
		goto err;
	}

	/* Change IRQ into clear on read mode for efficiency */
	slave = PALMAS_BASE_TO_SLAVE(PALMAS_INTERRUPT_BASE);
	addr = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, PALMAS_INT_CTRL);
	reg = PALMAS_INT_CTRL_INT_CLEAR;

	regmap_write(palmas->regmap[slave], addr, reg);

	ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq,
			IRQF_ONESHOT | pdata->irq_flags, 0, &palmas_irq_chip,
			&palmas->irq_data);
	if (ret < 0)
		goto err;

no_irq:
	slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
	addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
			PALMAS_PRIMARY_SECONDARY_PAD1);

	if (pdata->mux_from_pdata) {
		reg = pdata->pad1;
		ret = regmap_write(palmas->regmap[slave], addr, reg);
		if (ret)
			goto err_irq;
	} else {
		ret = regmap_read(palmas->regmap[slave], addr, &reg);
		if (ret)
			goto err_irq;
	}

	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0))
		palmas->gpio_muxed |= PALMAS_GPIO_0_MUXED;
	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK))
		palmas->gpio_muxed |= PALMAS_GPIO_1_MUXED;
	else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
			(2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
		palmas->led_muxed |= PALMAS_LED1_MUXED;
	else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
			(3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
		palmas->pwm_muxed |= PALMAS_PWM1_MUXED;
	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK))
		palmas->gpio_muxed |= PALMAS_GPIO_2_MUXED;
	else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
			(2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
		palmas->led_muxed |= PALMAS_LED2_MUXED;
	else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
			(3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
		palmas->pwm_muxed |= PALMAS_PWM2_MUXED;
	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3))
		palmas->gpio_muxed |= PALMAS_GPIO_3_MUXED;

	addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
			PALMAS_PRIMARY_SECONDARY_PAD2);

	if (pdata->mux_from_pdata) {
		reg = pdata->pad2;
		ret = regmap_write(palmas->regmap[slave], addr, reg);
		if (ret)
			goto err_irq;
	} else {
		ret = regmap_read(palmas->regmap[slave], addr, &reg);
		if (ret)
			goto err_irq;
	}

	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4))
		palmas->gpio_muxed |= PALMAS_GPIO_4_MUXED;
	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK))
		palmas->gpio_muxed |= PALMAS_GPIO_5_MUXED;
	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6))
		palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED;
	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK))
		palmas->gpio_muxed |= PALMAS_GPIO_7_MUXED;

	dev_info(palmas->dev, "Muxing GPIO %x, PWM %x, LED %x\n",
			palmas->gpio_muxed, palmas->pwm_muxed,
			palmas->led_muxed);

	reg = pdata->power_ctrl;

	slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
	addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_POWER_CTRL);

	ret = regmap_write(palmas->regmap[slave], addr, reg);
	if (ret)
		goto err_irq;

	/*
	 * If we are probing with DT do this the DT way and return here
	 * otherwise continue and add devices using mfd helpers.
	 */
	if (node) {
		ret = of_platform_populate(node, NULL, NULL, &i2c->dev);
		if (ret < 0)
			goto err_irq;
		else
			return ret;
	}

	return ret;

err_irq:
	regmap_del_irq_chip(palmas->irq, palmas->irq_data);
err:
	return ret;
}
示例#5
0
static int palmas_gpadc_auto_conv_configure(struct palmas_gpadc *adc)
{
	int adc_period, conv;
	int i;
	int ch0 = 0, ch1 = 0;
	int thres;
	int ret;

	if (!adc->auto_conv0_enable && !adc->auto_conv1_enable)
		return 0;

	adc_period = adc->auto_conversion_period;
	for (i = 0; i < 16; ++i) {
		if (((1000 * (1 << i))/32) > adc_period)
			break;
	}
	if (i > 0)
		i--;
	adc_period = i;
	ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
			PALMAS_GPADC_AUTO_CTRL,
			PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK,
			adc_period);
	if (ret < 0) {
		dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret);
		return ret;
	}

	conv = 0;
	if (adc->auto_conv0_enable) {
		int is_high;

		ch0 = adc->auto_conv0_data.adc_channel_number;
		conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN;
		conv |= (adc->auto_conv0_data.adc_shutdown ?
			PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0 : 0);
		if (adc->auto_conv0_data.adc_high_threshold > 0) {
			thres = adc->auto_conv0_data.adc_high_threshold;
			is_high = 0;
		} else {
			thres = adc->auto_conv0_data.adc_low_threshold;
			is_high = BIT(7);
		}

		ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
				PALMAS_GPADC_THRES_CONV0_LSB, thres & 0xFF);
		if (ret < 0) {
			dev_err(adc->dev,
				"THRES_CONV0_LSB write failed: %d\n", ret);
			return ret;
		}

		ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
				PALMAS_GPADC_THRES_CONV0_MSB,
				((thres >> 8) & 0xF) | is_high);
		if (ret < 0) {
			dev_err(adc->dev,
				"THRES_CONV0_MSB write failed: %d\n", ret);
			return ret;
		}
	}
示例#6
0
static int palmas_gpadc_read_raw(struct iio_dev *indio_dev,
	struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
	struct  palmas_gpadc *adc = iio_priv(indio_dev);
	int adc_chan = chan->channel;
	int ret = 0;

	if (adc_chan > PALMAS_ADC_CH_MAX)
		return -EINVAL;

	mutex_lock(&indio_dev->mlock);

	switch (mask) {
	case IIO_CHAN_INFO_RAW:
	case IIO_CHAN_INFO_PROCESSED:
		ret = palmas_gpadc_read_prepare(adc, adc_chan);
		if (ret < 0)
			goto out;

		ret = palmas_gpadc_start_convertion(adc, adc_chan);
		if (ret < 0) {
			dev_err(adc->dev,
			"ADC start coversion failed\n");
			goto out;
		}

		if (mask == IIO_CHAN_INFO_PROCESSED)
			ret = palmas_gpadc_get_calibrated_code(
							adc, adc_chan, ret);

		*val = ret;

		ret = IIO_VAL_INT;
		goto out;

	case IIO_CHAN_INFO_RAW_DUAL:
	case IIO_CHAN_INFO_PROCESSED_DUAL:
		ret = palmas_gpadc_read_prepare(adc, adc_chan);
		if (ret < 0)
			goto out;

		ret = palmas_gpadc_start_convertion(adc, adc_chan);
		if (ret < 0) {
			dev_err(adc->dev,
				"ADC start coversion failed\n");
			goto out;
		}

		if (mask == IIO_CHAN_INFO_PROCESSED_DUAL)
			ret = palmas_gpadc_get_calibrated_code(
							adc, adc_chan, ret);

		*val = ret;

		if ((adc_chan == PALMAS_ADC_CH_IN3)
				&& adc->ch3_dual_current && val2) {
			unsigned int reg_mask, reg_val;

			reg_mask = PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_MASK;
			reg_val = ((adc->ch3_current + 1)
				<< PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT);
			ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
						PALMAS_GPADC_CTRL1,
						reg_mask, reg_val);
			if (ret < 0) {
				dev_err(adc->dev, "CTRL1 update failed\n");
				goto out;
			}

			ret = palmas_gpadc_start_convertion(adc, adc_chan);
			if (ret < 0) {
				dev_err(adc->dev,
					"ADC start coversion failed\n");
				goto out;
			}

			if (mask == IIO_CHAN_INFO_PROCESSED_DUAL)
				ret = palmas_gpadc_get_calibrated_code(
							adc, adc_chan, ret);

			*val2 = ret;
		}

		ret = IIO_VAL_INT;
		goto out;
	}

	mutex_unlock(&indio_dev->mlock);
	return ret;

out:
	palmas_gpadc_read_done(adc, adc_chan);
	mutex_unlock(&indio_dev->mlock);
	return ret;
}
示例#7
0
文件: rtc-palmas.c 项目: mhei/linux
static int palmas_rtc_probe(struct platform_device *pdev)
{
    struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
    struct palmas_rtc *palmas_rtc = NULL;
    int ret;
    bool enable_bb_charging = false;
    bool high_bb_charging = false;

    if (pdev->dev.of_node) {
        enable_bb_charging = of_property_read_bool(pdev->dev.of_node,
                             "ti,backup-battery-chargeable");
        high_bb_charging = of_property_read_bool(pdev->dev.of_node,
                           "ti,backup-battery-charge-high-current");
    }

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

    /* Clear pending interrupts */
    ret = palmas_clear_interrupts(&pdev->dev);
    if (ret < 0) {
        dev_err(&pdev->dev, "clear RTC int failed, err = %d\n", ret);
        return ret;
    }

    palmas_rtc->dev = &pdev->dev;
    platform_set_drvdata(pdev, palmas_rtc);

    if (enable_bb_charging) {
        unsigned reg = PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG;

        if (high_bb_charging)
            reg = 0;

        ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
                                 PALMAS_BACKUP_BATTERY_CTRL,
                                 PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG, reg);
        if (ret < 0) {
            dev_err(&pdev->dev,
                    "BACKUP_BATTERY_CTRL update failed, %d\n", ret);
            return ret;
        }

        ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
                                 PALMAS_BACKUP_BATTERY_CTRL,
                                 PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN,
                                 PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN);
        if (ret < 0) {
            dev_err(&pdev->dev,
                    "BACKUP_BATTERY_CTRL update failed, %d\n", ret);
            return ret;
        }
    }

    /* Start RTC */
    ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
                             PALMAS_RTC_CTRL_REG_STOP_RTC,
                             PALMAS_RTC_CTRL_REG_STOP_RTC);
    if (ret < 0) {
        dev_err(&pdev->dev, "RTC_CTRL write failed, err = %d\n", ret);
        return ret;
    }

    palmas_rtc->irq = platform_get_irq(pdev, 0);

    device_init_wakeup(&pdev->dev, 1);
    palmas_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                      &palmas_rtc_ops, THIS_MODULE);
    if (IS_ERR(palmas_rtc->rtc)) {
        ret = PTR_ERR(palmas_rtc->rtc);
        dev_err(&pdev->dev, "RTC register failed, err = %d\n", ret);
        return ret;
    }

    ret = devm_request_threaded_irq(&pdev->dev, palmas_rtc->irq, NULL,
                                    palmas_rtc_interrupt,
                                    IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                                    dev_name(&pdev->dev), palmas_rtc);
    if (ret < 0) {
        dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret);
        return ret;
    }

    return 0;
}
示例#8
0
static void palmas_power_off(void *drv_data)
{
	struct palmas_pm *palmas_pm = drv_data;
	struct palmas *palmas = palmas_pm->palmas;
	unsigned int val;
	int i;
	int ret;
	unsigned int vbus_line_state, ldo_short_status2;

	palmas_allow_atomic_xfer(palmas);

	if (palmas_pm->need_rtc_power_on)
		palmas_auto_power_on(palmas_pm);

	for (i = 0; i < palmas_pm->num_int_mask_regs; ++i) {
		ret = palmas_write(palmas, PALMAS_INTERRUPT_BASE,
				palmas_pm->int_mask_reg_add[i],
				palmas_pm->int_mask_val[i]);
		if (ret < 0)
			dev_err(palmas_pm->dev,
				"register 0x%02x write failed: %d\n",
				palmas_pm->int_mask_reg_add[i], ret);

		ret = palmas_read(palmas, PALMAS_INTERRUPT_BASE,
					palmas_pm->int_status_reg_add[i], &val);
		if (ret < 0)
			dev_err(palmas_pm->dev,
				"register 0x%02x read failed: %d\n",
				palmas_pm->int_status_reg_add[i], ret);
	}

	if (palmas_pm->enable_boot_up_at_vbus ||
		palmas_pm->need_usb_event_power_on) {
		ret = palmas_update_bits(palmas, PALMAS_INTERRUPT_BASE,
			PALMAS_INT3_MASK,
			PALMAS_INT3_MASK_VBUS | PALMAS_INT3_MASK_VBUS_OTG, 0);
		if (ret < 0)
			dev_err(palmas_pm->dev,
				"INT3_MASK update failed: %d\n", ret);
	}

	/* Mask all COLD RST condition */
	palmas_write(palmas, PALMAS_PMU_CONTROL_BASE,
				PALMAS_SWOFF_COLDRST, 0x0);

	dev_info(palmas_pm->dev, "Powering off the device\n");

	palmas_read(palmas, PALMAS_INTERRUPT_BASE,
		PALMAS_INT3_LINE_STATE, &vbus_line_state);

	if (palmas_pm->enable_boot_up_at_vbus &&
		(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) {
		dev_info(palmas_pm->dev, "VBUS found, boot on system by timer interrupt\n");
		ret = palmas_update_bits(palmas, PALMAS_RTC_BASE,
			PALMAS_RTC_INTERRUPTS_REG,
			PALMAS_RTC_INTERRUPTS_REG_IT_TIMER,
			PALMAS_RTC_INTERRUPTS_REG_IT_TIMER);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"RTC_INTERRUPTS update failed: %d\n", ret);
			goto poweroff_direct;
		}

		ret = palmas_update_bits(palmas, PALMAS_RTC_BASE,
			PALMAS_RTC_INTERRUPTS_REG,
			PALMAS_RTC_INTERRUPTS_REG_EVERY_MASK, 0);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"RTC_INTERRUPTS update failed: %d\n", ret);
			goto poweroff_direct;
		}

		ret = palmas_update_bits(palmas, PALMAS_RTC_BASE,
			PALMAS_RTC_CTRL_REG, PALMAS_RTC_CTRL_REG_STOP_RTC,
			PALMAS_RTC_CTRL_REG_STOP_RTC);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"RTC_CTRL_REG update failed: %d\n", ret);
			goto poweroff_direct;
		}

		ret = palmas_update_bits(palmas, PALMAS_INTERRUPT_BASE,
			PALMAS_INT2_MASK,
			PALMAS_INT2_MASK_RTC_TIMER, 0);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"INT2_MASK update failed: %d\n", ret);
			goto poweroff_direct;
		}
	}

poweroff_direct:
	/* Errata
	 * clear VANA short status before switch-off
	 */
	palmas_read(palmas, PALMAS_LDO_BASE, PALMAS_LDO_SHORT_STATUS2,
				&ldo_short_status2);

	/* Power off the device */
	palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
				PALMAS_DEV_CTRL, 1, 0);
}
示例#9
0
static void palmas_power_reset(void *drv_data)
{
	struct palmas_pm *palmas_pm = drv_data;
	struct palmas *palmas = palmas_pm->palmas;
	unsigned int val;
	int i;
	int ret;

	palmas_allow_atomic_xfer(palmas);

	for (i = 0; i < palmas_pm->num_int_mask_regs; ++i) {
		ret = palmas_write(palmas, PALMAS_INTERRUPT_BASE,
				palmas_pm->int_mask_reg_add[i],
				palmas_pm->int_mask_val[i]);
		if (ret < 0)
			dev_err(palmas_pm->dev,
				"register 0x%02x write failed: %d\n",
				palmas_pm->int_mask_reg_add[i], ret);

		ret = palmas_read(palmas, PALMAS_INTERRUPT_BASE,
					palmas_pm->int_status_reg_add[i], &val);
		if (ret < 0)
			dev_err(palmas_pm->dev,
				"register 0x%02x read failed: %d\n",
				palmas_pm->int_status_reg_add[i], ret);
	}

	/* SW-WAR for ES Version 2.1, 2.0 and 1.0 */
	if (palmas_is_es_version_or_less(palmas, 2, 1)) {
		dev_info(palmas_pm->dev, "Resetting Palmas through RTC\n");
		ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
				PALMAS_DEV_CTRL, PALMAS_DEV_CTRL_SW_RST, 0);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"DEV_CTRL update failed: %d\n", ret);
			goto reset_direct;
		}

		ret = palmas_update_bits(palmas, PALMAS_RTC_BASE,
				PALMAS_RTC_INTERRUPTS_REG,
				PALMAS_RTC_INTERRUPTS_REG_IT_TIMER,
				PALMAS_RTC_INTERRUPTS_REG_IT_TIMER);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"RTC_INTERRUPTS update failed: %d\n", ret);
			goto reset_direct;
		}

		ret = palmas_update_bits(palmas, PALMAS_RTC_BASE,
			PALMAS_RTC_CTRL_REG, PALMAS_RTC_CTRL_REG_STOP_RTC,
			PALMAS_RTC_CTRL_REG_STOP_RTC);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"RTC_CTRL_REG update failed: %d\n", ret);
			goto reset_direct;
		}

		ret = palmas_update_bits(palmas, PALMAS_INTERRUPT_BASE,
			PALMAS_INT2_MASK, PALMAS_INT2_MASK_RTC_TIMER, 0);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"INT2_MASK update failed: %d\n", ret);
			goto reset_direct;
		}

		ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
				PALMAS_SWOFF_COLDRST, PALMAS_SWOFF_COLDRST_SW_RST,
					PALMAS_SWOFF_COLDRST_SW_RST);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"SWOFF_COLDRST update failed: %d\n", ret);
			goto reset_direct;
		}

		ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
				PALMAS_DEV_CTRL, PALMAS_DEV_CTRL_SW_RST,
				PALMAS_DEV_CTRL_SW_RST);
		if (ret < 0) {
			dev_err(palmas_pm->dev,
				"DEV_CTRL update failed: %d\n", ret);
			goto reset_direct;
		}
		return;
	}

reset_direct:
	dev_info(palmas_pm->dev, "Power reset the device\n");
	palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
			PALMAS_SWOFF_COLDRST, PALMAS_SWOFF_COLDRST_SW_RST,
			PALMAS_SWOFF_COLDRST_SW_RST);
	palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
				PALMAS_DEV_CTRL, 0x2, 0x2);
}
示例#10
0
static int palmas_usb_probe(struct platform_device *pdev)
{
	struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
	struct palmas_usb_platform_data	*pdata = dev_get_platdata(&pdev->dev);
	struct device_node *node = pdev->dev.of_node;
	struct palmas_usb *palmas_usb;
	int status;

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

	if (node && !pdata) {
		palmas_usb->wakeup = of_property_read_bool(node, "ti,wakeup");
		palmas_usb->enable_id_detection = of_property_read_bool(node,
						"ti,enable-id-detection");
		palmas_usb->enable_vbus_detection = of_property_read_bool(node,
						"ti,enable-vbus-detection");
	} else {
		palmas_usb->wakeup = true;
		palmas_usb->enable_id_detection = true;
		palmas_usb->enable_vbus_detection = true;

		if (pdata)
			palmas_usb->wakeup = pdata->wakeup;
	}

	palmas_usb->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id",
							GPIOD_IN);
	if (IS_ERR(palmas_usb->id_gpiod)) {
		dev_err(&pdev->dev, "failed to get id gpio\n");
		return PTR_ERR(palmas_usb->id_gpiod);
	}

	palmas_usb->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus",
							GPIOD_IN);
	if (IS_ERR(palmas_usb->vbus_gpiod)) {
		dev_err(&pdev->dev, "failed to get vbus gpio\n");
		return PTR_ERR(palmas_usb->vbus_gpiod);
	}

	if (palmas_usb->enable_id_detection && palmas_usb->id_gpiod) {
		palmas_usb->enable_id_detection = false;
		palmas_usb->enable_gpio_id_detection = true;
	}

	if (palmas_usb->enable_vbus_detection && palmas_usb->vbus_gpiod) {
		palmas_usb->enable_vbus_detection = false;
		palmas_usb->enable_gpio_vbus_detection = true;
	}

	if (palmas_usb->enable_gpio_id_detection) {
		u32 debounce;

		if (of_property_read_u32(node, "debounce-delay-ms", &debounce))
			debounce = USB_GPIO_DEBOUNCE_MS;

		status = gpiod_set_debounce(palmas_usb->id_gpiod,
					    debounce * 1000);
		if (status < 0)
			palmas_usb->sw_debounce_jiffies = msecs_to_jiffies(debounce);
	}

	INIT_DELAYED_WORK(&palmas_usb->wq_detectid, palmas_gpio_id_detect);

	palmas->usb = palmas_usb;
	palmas_usb->palmas = palmas;

	palmas_usb->dev	 = &pdev->dev;

	palmas_usb_wakeup(palmas, palmas_usb->wakeup);

	platform_set_drvdata(pdev, palmas_usb);

	palmas_usb->edev = devm_extcon_dev_allocate(&pdev->dev,
						    palmas_extcon_cable);
	if (IS_ERR(palmas_usb->edev)) {
		dev_err(&pdev->dev, "failed to allocate extcon device\n");
		return -ENOMEM;
	}

	status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev);
	if (status) {
		dev_err(&pdev->dev, "failed to register extcon device\n");
		return status;
	}

	if (palmas_usb->enable_id_detection) {
		palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data,
							     PALMAS_ID_OTG_IRQ);
		palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data,
							 PALMAS_ID_IRQ);
		status = devm_request_threaded_irq(palmas_usb->dev,
				palmas_usb->id_irq,
				NULL, palmas_id_irq_handler,
				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
				IRQF_ONESHOT,
				"palmas_usb_id", palmas_usb);
		if (status < 0) {
			dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
					palmas_usb->id_irq, status);
			return status;
		}
	} else if (palmas_usb->enable_gpio_id_detection) {
		palmas_usb->gpio_id_irq = gpiod_to_irq(palmas_usb->id_gpiod);
		if (palmas_usb->gpio_id_irq < 0) {
			dev_err(&pdev->dev, "failed to get id irq\n");
			return palmas_usb->gpio_id_irq;
		}
		status = devm_request_threaded_irq(&pdev->dev,
						   palmas_usb->gpio_id_irq,
						   NULL,
						   palmas_gpio_id_irq_handler,
						   IRQF_TRIGGER_RISING |
						   IRQF_TRIGGER_FALLING |
						   IRQF_ONESHOT,
						   "palmas_usb_id",
						   palmas_usb);
		if (status < 0) {
			dev_err(&pdev->dev,
				"failed to request handler for id irq\n");
			return status;
		}
	}

	if (palmas_usb->enable_vbus_detection) {
		palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data,
						       PALMAS_VBUS_OTG_IRQ);
		palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
							   PALMAS_VBUS_IRQ);
		status = devm_request_threaded_irq(palmas_usb->dev,
				palmas_usb->vbus_irq, NULL,
				palmas_vbus_irq_handler,
				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
				IRQF_ONESHOT,
				"palmas_usb_vbus", palmas_usb);
		if (status < 0) {
			dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
					palmas_usb->vbus_irq, status);
			return status;
		}
	} else if (palmas_usb->enable_gpio_vbus_detection) {
		/* remux GPIO_1 as VBUSDET */
		status = palmas_update_bits(palmas,
			PALMAS_PU_PD_OD_BASE,
			PALMAS_PRIMARY_SECONDARY_PAD1,
			PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK,
			(1 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT));
		if (status < 0) {
			dev_err(&pdev->dev, "can't remux GPIO1\n");
			return status;
		}

		palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data,
						       PALMAS_VBUS_OTG_IRQ);
		palmas_usb->gpio_vbus_irq = gpiod_to_irq(palmas_usb->vbus_gpiod);
		if (palmas_usb->gpio_vbus_irq < 0) {
			dev_err(&pdev->dev, "failed to get vbus irq\n");
			return palmas_usb->gpio_vbus_irq;
		}
		status = devm_request_threaded_irq(&pdev->dev,
						palmas_usb->gpio_vbus_irq,
						NULL,
						palmas_vbus_irq_handler,
						IRQF_TRIGGER_FALLING |
						IRQF_TRIGGER_RISING |
						IRQF_ONESHOT,
						"palmas_usb_vbus",
						palmas_usb);
		if (status < 0) {
			dev_err(&pdev->dev,
				"failed to request handler for vbus irq\n");
			return status;
		}
	}

	palmas_enable_irq(palmas_usb);
	/* perform initial detection */
	if (palmas_usb->enable_gpio_vbus_detection)
		palmas_vbus_irq_handler(palmas_usb->gpio_vbus_irq, palmas_usb);
	palmas_gpio_id_detect(&palmas_usb->wq_detectid.work);
	device_set_wakeup_capable(&pdev->dev, true);
	return 0;
}