static int palmas_gpadc_calibrate(struct palmas_gpadc *adc, int adc_chan)
{
	s64 k;
	int d1;
	int d2;
	int ret;
	int x1 =  adc->adc_info[adc_chan].x1;
	int x2 =  adc->adc_info[adc_chan].x2;

	ret = palmas_read(adc->palmas, PALMAS_TRIM_GPADC_BASE,
				adc->adc_info[adc_chan].trim1_reg, &d1);
	if (ret < 0) {
		dev_err(adc->dev, "TRIM read failed: %d\n", ret);
		goto scrub;
	}

	ret = palmas_read(adc->palmas, PALMAS_TRIM_GPADC_BASE,
				adc->adc_info[adc_chan].trim2_reg, &d2);
	if (ret < 0) {
		dev_err(adc->dev, "TRIM read failed: %d\n", ret);
		goto scrub;
	}

	/* Gain Calculation */
	k = PRECISION_MULTIPLIER;
	k += div64_s64(PRECISION_MULTIPLIER * (d2 - d1), x2 - x1);
	adc->adc_info[adc_chan].gain = k;

	/* Offset Calculation */
	adc->adc_info[adc_chan].offset = (d1 * PRECISION_MULTIPLIER);
	adc->adc_info[adc_chan].offset -= ((k - PRECISION_MULTIPLIER) * x1);

scrub:
	return ret;
}
Exemple #2
0
static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
{
	struct palmas_gpio *pg = gpiochip_get_data(gc);
	struct palmas *palmas = pg->palmas;
	unsigned int val;
	int ret;
	unsigned int reg;
	int gpio16 = (offset/8);

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

	ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
	if (ret < 0) {
		dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
		return ret;
	}

	if (val & BIT(offset))
		reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT;
	else
		reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN;

	ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
	if (ret < 0) {
		dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
		return ret;
	}
	return !!(val & BIT(offset));
}
Exemple #3
0
static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
{
	struct palmas_usb *palmas_usb = _palmas_usb;
	unsigned int vbus_line_state;

	palmas_read(palmas_usb->palmas, PALMAS_INTERRUPT_BASE,
		PALMAS_INT3_LINE_STATE, &vbus_line_state);

	dev_info(palmas_usb->dev, "vbus-irq() INT3_LINE_STATE 0x%02x\n",
			vbus_line_state);
	if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) {
		if (palmas_usb->vbus_linkstat != PALMAS_USB_STATE_VBUS) {
			palmas_usb->vbus_linkstat = PALMAS_USB_STATE_VBUS;
			extcon_set_cable_state(&palmas_usb->edev, "USB", true);
			dev_info(palmas_usb->dev, "USB cable is attached\n");
		} else {
			dev_info(palmas_usb->dev,
				"Spurious connect event detected\n");
		}
	} else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) {
		if (palmas_usb->vbus_linkstat == PALMAS_USB_STATE_VBUS) {
			palmas_usb->vbus_linkstat = PALMAS_USB_STATE_DISCONNECT;
			extcon_set_cable_state(&palmas_usb->edev, "USB", false);
			dev_info(palmas_usb->dev, "USB cable is detached\n");
		} else {
			dev_info(palmas_usb->dev,
				"Spurious disconnect event detected\n");
		}
	}

	return IRQ_HANDLED;
}
Exemple #4
0
static int palmas_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
    unsigned char alarm_data[PALMAS_NUM_TIME_REGS];
    u32 int_val;
    struct palmas *palmas = dev_get_drvdata(dev->parent);
    int ret;

    ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE,
                           PALMAS_ALARM_SECONDS_REG,
                           alarm_data, PALMAS_NUM_TIME_REGS);
    if (ret < 0) {
        dev_err(dev, "RTC_ALARM_SECONDS read failed, err = %d\n", ret);
        return ret;
    }

    alm->time.tm_sec = bcd2bin(alarm_data[0]);
    alm->time.tm_min = bcd2bin(alarm_data[1]);
    alm->time.tm_hour = bcd2bin(alarm_data[2]);
    alm->time.tm_mday = bcd2bin(alarm_data[3]);
    alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
    alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;

    ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_INTERRUPTS_REG,
                      &int_val);
    if (ret < 0) {
        dev_err(dev, "RTC_INTERRUPTS reg read failed, err = %d\n", ret);
        return ret;
    }

    if (int_val & PALMAS_RTC_INTERRUPTS_REG_IT_ALARM)
        alm->enabled = 1;
    return ret;
}
Exemple #5
0
static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
{
	unsigned int set, id_src;
	struct palmas_usb *palmas_usb = _palmas_usb;
	struct extcon_dev *edev = palmas_usb->edev;

	palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
		PALMAS_USB_ID_INT_LATCH_SET, &set);
	palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
		PALMAS_USB_ID_INT_SRC, &id_src);

	if ((set & PALMAS_USB_ID_INT_SRC_ID_GND) &&
				(id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
		palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
			PALMAS_USB_ID_INT_LATCH_CLR,
			PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
		palmas_usb->linkstat = PALMAS_USB_STATE_ID;
		extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
		dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
	} else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) &&
				(id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) {
		palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
			PALMAS_USB_ID_INT_LATCH_CLR,
			PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
		palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
		extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
		dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
	} else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
				(!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
		palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
		extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
		dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
	} else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) &&
				(id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
		palmas_usb->linkstat = PALMAS_USB_STATE_ID;
		extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
		dev_info(palmas_usb->dev, " USB-HOST cable is attached\n");
	}

	return IRQ_HANDLED;
}
Exemple #6
0
static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
{
	unsigned int set;
	struct palmas_usb *palmas_usb = _palmas_usb;

	palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
		PALMAS_USB_ID_INT_LATCH_SET, &set);

	palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
		PALMAS_USB_ID_INT_LATCH_CLR, set);

	schedule_delayed_work(&palmas_usb->cable_update_wq,
			msecs_to_jiffies(palmas_usb->cable_debounce_time));
	return IRQ_HANDLED;
}
Exemple #7
0
static irqreturn_t palmas_gpadc_irq_auto(int irq, void *data)
{
	struct palmas_gpadc *adc = data;
	unsigned int val = 0;
	int ret;

	ret = palmas_read(adc->palmas, PALMAS_INTERRUPT_BASE,
			PALMAS_INT3_LINE_STATE, &val);
	if (ret < 0)
		dev_err(adc->dev, "%s: Failed to read INT3_LINE_STATE, %d\n",
			__func__, ret);

	if (val & PALMAS_INT3_LINE_STATE_GPADC_AUTO_0)
		dev_info(adc->dev, "Auto0 threshold interrupt occurred\n");
	if (val & PALMAS_INT3_LINE_STATE_GPADC_AUTO_1)
		dev_info(adc->dev, "Auto1 threshold interrupt occurred\n");

	return IRQ_HANDLED;
}
Exemple #8
0
static int palmas_clear_interrupts(struct device *dev)
{
    struct palmas *palmas = dev_get_drvdata(dev->parent);
    unsigned int rtc_reg;
    int ret;

    ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,
                      &rtc_reg);
    if (ret < 0) {
        dev_err(dev, "RTC_STATUS read failed, err = %d\n", ret);
        return ret;
    }

    ret = palmas_write(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,
                       rtc_reg);
    if (ret < 0) {
        dev_err(dev, "RTC_STATUS write failed, err = %d\n", ret);
        return ret;
    }
    return 0;
}
Exemple #9
0
static int palmas_usb_id_state_update(struct palmas_usb *palmas_usb)
{
	unsigned int id_src;
	int ret;
	int new_state;
	int new_cable_index;
	int retry = 5;

src_again:
	ret = palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
		PALMAS_USB_ID_INT_SRC, &id_src);
	if (ret < 0) {
		dev_err(palmas_usb->dev, "ID_INT_SRC read failed: %d\n", ret);
		return ret;
	}

	dev_info(palmas_usb->dev, "id-state: 0x%02x\n", id_src);
	if (!id_src) {
		dev_err(palmas_usb->dev, "Improper ID state found\n");
		if (retry--) {
			msleep(200);
			goto src_again;
		}
		return -EAGAIN;
	}

	/* If two ID states show sign then allow debouncing to settle */
	if (id_src & (id_src - 1)) {
		dev_info(palmas_usb->dev,
			"ID states are not settled, try later\n");
		return -EAGAIN;
	}

	if (id_src & PALMAS_USB_ID_INT_SRC_ID_GND) {
		new_state = PALMAS_USB_STATE_ID_GND;
		new_cable_index = 1;
	} else if (id_src & PALMAS_USB_ID_INT_SRC_ID_A) {
		new_state = PALMAS_USB_STATE_ID_A;
		new_cable_index = 2;
	} else if (id_src & PALMAS_USB_ID_INT_SRC_ID_B) {
		new_state = PALMAS_USB_STATE_ID_B;
		new_cable_index = 3;
	} else if (id_src & PALMAS_USB_ID_INT_SRC_ID_C) {
		new_state = PALMAS_USB_STATE_ID_C;
		new_cable_index = 4;
	} else if (id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT) {
		new_state = PALMAS_USB_STATE_ID_FLOAT;
		new_cable_index = -1;
	} else {
		dev_info(palmas_usb->dev, "ID_SRC is not valid\n");
		new_state = PALMAS_USB_STATE_ID_FLOAT;
		new_cable_index = 0;
	}

	if (palmas_usb->id_linkstat == new_state) {
		dev_info(palmas_usb->dev,
			"No change in ID state: Old %d and New %d\n",
			palmas_usb->id_linkstat, new_state);
		palmas_usb_id_int_set(palmas_usb);
		return 0;
	}

	if (palmas_usb->cur_cable_index > 0) {
		dev_info(palmas_usb->dev, "Cable %s detached\n",
			palmas_extcon_cable[palmas_usb->cur_cable_index]);
		extcon_set_cable_state(&palmas_usb->edev,
			palmas_extcon_cable[palmas_usb->cur_cable_index],
			false);
	}

	if ((new_cable_index < 0) && (!palmas_usb->cur_cable_index)) {
		dev_info(palmas_usb->dev, "All cable detached\n");
		extcon_set_cable_state(&palmas_usb->edev,
					palmas_extcon_cable[1], false);
		extcon_set_cable_state(&palmas_usb->edev,
					palmas_extcon_cable[2], false);
		extcon_set_cable_state(&palmas_usb->edev,
					palmas_extcon_cable[3], false);
		extcon_set_cable_state(&palmas_usb->edev,
					palmas_extcon_cable[4], false);
	}

	palmas_usb->cur_cable_index = new_cable_index;
	palmas_usb->id_linkstat = new_state;
	if (palmas_usb->cur_cable_index <= 0)
		goto end;

	dev_info(palmas_usb->dev, "Cable %s attached\n",
		palmas_extcon_cable[palmas_usb->cur_cable_index]);
	extcon_set_cable_state(&palmas_usb->edev,
			palmas_extcon_cable[palmas_usb->cur_cable_index], true);

end:
	palmas_usb_id_int_set(palmas_usb);
	return 0;
}
Exemple #10
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);
}
Exemple #11
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);
}