예제 #1
0
파일: pm8xxx-irq.c 프로젝트: 03199618/linux
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
{
	int	rc;

	spin_lock(&chip->pm_irq_lock);
	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
	if (rc) {
		pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
		goto bail;
	}

	rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
	if (rc)
		pr_err("Failed Reading Status rc=%d\n", rc);
bail:
	spin_unlock(&chip->pm_irq_lock);
	return rc;
}
예제 #2
0
static void led_lc_set(struct pm8xxx_led_data *led, enum led_brightness value)
{
	int rc, offset;
	u8 level;
	level = (value << PM8XXX_DRV_LED_CTRL_SHIFT) &
				PM8XXX_DRV_LED_CTRL_MASK;

	offset = PM8XXX_LED_OFFSET(led->id);

	led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
	led->reg |= level;

	rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset),
								led->reg);
	if (rc)
		dev_err(led->cdev.dev, "can't set (%d) led value rc=%d\n",
				led->id, rc);
}
예제 #3
0
static int pm8xxx_debug_data_set(void *data, u64 val)
{
	struct pm8xxx_debug_device *debugdev = data;
	u8 reg = val;
	int rc;

	mutex_lock(&debugdev->debug_mutex);

	if (pm8xxx_debug_addr_is_valid(debugdev->addr)) {
		rc = pm8xxx_writeb(debugdev->parent, debugdev->addr, reg);

		if (rc)
			pr_err("pm8xxx_writeb(0x%03X)=0x%02X failed: rc=%d\n",
				debugdev->addr, reg, rc);
	}

	mutex_unlock(&debugdev->debug_mutex);
	return 0;
}
예제 #4
0
static int pm8xxx_misc_masked_write(struct pm8xxx_misc_chip *chip, u16 addr,
				    u8 mask, u8 val)
{
	int rc;
	u8 reg;

	rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
	if (rc) {
		pr_err("pm8xxx_readb(0x%03X) failed, rc=%d\n", addr, rc);
		return rc;
	}
	reg &= ~mask;
	reg |= val & mask;
	rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
	if (rc)
		pr_err("pm8xxx_writeb(0x%03X)=0x%02X failed, rc=%d\n", addr,
			reg, rc);
	return rc;
}
예제 #5
0
static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
							u8 mask, u8 val)
{
	int rc;
	u8 reg;

	rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
	if (rc) {
		pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
		return rc;
	}
	reg &= ~mask;
	reg |= val & mask;
	rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
	if (rc) {
		pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
		return rc;
	}
	return 0;
}
예제 #6
0
int pm8xxx_vibrator_config(struct pm8xxx_vib_config *vib_config)
{
    u8 reg = 0;
    int rc;

    mutex_lock(&vib_dev->vib_mutex);
    VIB_DEBUG_LOG(KERN_INFO, "called.drive_mV=%d,active_low=%d,enable_mode=%d\n"
        ,vib_config->drive_mV, vib_config->active_low, vib_config->enable_mode);

    if (vib_dev == NULL) {
        VIB_LOG(KERN_ERR, "vib_dev is NULL\n");
        mutex_unlock(&vib_dev->vib_mutex);
        return -EINVAL;
    }

    if (vib_config->drive_mV) {
        if ((vib_config->drive_mV < VIB_MIN_LEVEL_mV) ||
            (vib_config->drive_mV > VIB_MAX_LEVEL_mV)) {
            VIB_LOG(KERN_ERR, "Invalid vibrator drive strength\n");
            mutex_unlock(&vib_dev->vib_mutex);
            return -EINVAL;
        }
    }

    reg = (vib_config->drive_mV / 100) << VIB_DRV_SEL_SHIFT;

    reg |= (!!vib_config->active_low) << VIB_DRV_LOGIC_SHIFT;

    reg |= vib_config->enable_mode;

    rc = pm8xxx_writeb(vib_dev->dev->parent, VIB_DRV, reg);
    VIB_DEBUG_LOG(KERN_INFO, 
    "pm8xxx_writeb() called. rc=%d,reg=0x%02X,data=0x%02X\n", rc, VIB_DRV, reg);
    if (rc)
        VIB_LOG(KERN_ERR, "pm8xxx write failed: rc=%d\n",rc);

    mutex_unlock(&vib_dev->vib_mutex);
    VIB_DEBUG_LOG(KERN_INFO, "end.rc=%d\n", rc);
    return rc;
}
예제 #7
0
/**
 * pm8xxx_get_irq_stat - get the status of the irq line
 * @chip: pointer to identify a pmic irq controller
 * @irq: the irq number
 *
 * The pm8xxx gpio and mpp rely on the interrupt block to read
 * the values on their pins. This function is to facilitate reading
 * the status of a gpio or an mpp line. The caller has to convert the
 * gpio number to irq number.
 *
 * RETURNS:
 * an int indicating the value read on that line
 */
int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
{
	int pmirq, rc;
	u8  block, bits, bit;
	unsigned long flags;

	if (chip == NULL || irq < chip->irq_base ||
			irq >= chip->irq_base + chip->num_irqs)
		return -EINVAL;

	pmirq = irq - chip->irq_base;

	block = pmirq / 8;
	bit = pmirq % 8;

	spin_lock_irqsave(&chip->pm_irq_lock, flags);

	rc = pm8xxx_writeb(chip->dev,
			SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), block);
	if (rc) {
		pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
			irq, pmirq, block, rc);
		goto bail_out;
	}

	rc = pm8xxx_readb(chip->dev,
			SSBI_REG_ADDR_IRQ_RT_STATUS(chip->base_addr), &bits);
	if (rc) {
		pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
			irq, pmirq, block, rc);
		goto bail_out;
	}

	rc = (bits & (1 << bit)) ? 1 : 0;

bail_out:
	spin_unlock_irqrestore(&chip->pm_irq_lock, flags);

	return rc;
}
static int pm8xxx_pwm_bank_enable(struct pwm_device *pwm, int enable)
{
	int	rc;
	u8	reg;
	struct pm8xxx_pwm_chip	*chip;

	chip = pwm->chip;

	if (enable)
		reg = chip->bank_mask | (1 << pwm->pwm_id);
	else
		reg = chip->bank_mask & ~(1 << pwm->pwm_id);

	rc = pm8xxx_writeb(chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_EN, reg);
	if (rc) {
		pr_err("pm8xxx_writeb(): rc=%d (Enable LPG Bank)\n", rc);
		return rc;
	}
	chip->bank_mask = reg;

	return 0;
}
static int pmic8xxx_set_pon1(struct device *dev, u32 debounce_us, bool pull_up)
{
	int err;
	u32 delay;
	u8 pon_cntl;

	
	if (debounce_us > USEC_PER_SEC * 2 ||
		debounce_us < USEC_PER_SEC / 64) {
		dev_err(dev, "invalid power key trigger delay\n");
		return -EINVAL;
	}

	delay = (debounce_us << 6) / USEC_PER_SEC;
	delay = ilog2(delay);

	err = pm8xxx_readb(dev->parent, PON_CNTL_1, &pon_cntl);
	if (err < 0) {
		dev_err(dev, "failed reading PON_CNTL_1 err=%d\n", err);
		return err;
	}

	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);

	if (pull_up)
		pon_cntl |= PON_CNTL_PULL_UP;
	else
		pon_cntl &= ~PON_CNTL_PULL_UP;

	err = pm8xxx_writeb(dev->parent, PON_CNTL_1, pon_cntl);
	if (err < 0) {
		dev_err(dev, "failed writing PON_CNTL_1 err=%d\n", err);
		return err;
	}

	return 0;
}
예제 #10
0
static void
led_flash_set(struct pm8xxx_led_data *led, enum led_brightness value)
{
	int rc;
	u8 level;
	u16 reg_addr;

	level = (value << PM8XXX_DRV_FLASH_SHIFT) &
				 PM8XXX_DRV_FLASH_MASK;

	led->reg &= ~PM8XXX_DRV_FLASH_MASK;
	led->reg |= level;

	if (led->id == PM8XXX_ID_FLASH_LED_0)
		reg_addr = SSBI_REG_ADDR_FLASH_DRV0;
	else
		reg_addr = SSBI_REG_ADDR_FLASH_DRV1;

	rc = pm8xxx_writeb(led->dev->parent, reg_addr, led->reg);
	if (rc < 0)
		dev_err(led->cdev.dev, "can't set flash led%d level rc=%d\n",
			 led->id, rc);
}
예제 #11
0
static int pm8821_irq_masked_write(struct pm_irq_chip *chip, u16 addr,
							u8 mask, u8 val)
{
	int rc;
	u8 reg;

	rc = pm8xxx_readb(chip->dev, addr, &reg);
	if (rc) {
		pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
		return rc;
	}

	reg &= ~mask;
	reg |= val & mask;

	rc = pm8xxx_writeb(chip->dev, addr, reg);
	if (rc) {
		pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
		return rc;
	}

	return 0;
}
static int pm8xxx_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
{
	int	rc;
	u8	reg;

	if (start) {
		reg = pwm->pwm_lpg_ctl[0] | PM8XXX_PWM_PWM_START;
		if (ramp_start)
			reg |= PM8XXX_PWM_RAMP_GEN_START;
		else
			reg &= ~PM8XXX_PWM_RAMP_GEN_START;
	} else {
		reg = pwm->pwm_lpg_ctl[0] & ~PM8XXX_PWM_PWM_START;
		reg &= ~PM8XXX_PWM_RAMP_GEN_START;
	}

	rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
			   reg);
	if (rc)
		pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl 0)\n", rc);
	else
		pwm->pwm_lpg_ctl[0] = reg;
	return rc;
}
int pm8058_mic_bias_enable(bool enable)
{
	int rc = 0;
	u8 reg;
	u16 mic_bias_addr = loc_dat->mic_bias_pf->mic_bias_addr;

	dev_dbg(loc_dat->dev, "%s - %s MIC Bias\n", __func__,
			enable ? "Enabling" : "Disabling");

	LOCK(&loc_dat->lock);

	if (enable) {
		if (!loc_dat->mic_bias_enable_counter) {
			rc = pm8xxx_readb(loc_dat->dev->parent,
					mic_bias_addr, &reg);
			if (rc < 0) {
				dev_err(loc_dat->dev, "pm8058 read failed\n");
				goto error;
			}

			reg &= PM8058_OTHC_EN_SIG_MASK;
			reg |= (OTHC_SIGNAL_ALWAYS_ON <<
					PM8058_OTHC_EN_SIG_SHIFT);

			rc = pm8xxx_writeb(loc_dat->dev->parent,
					mic_bias_addr, reg);
			if (rc < 0) {
				dev_err(loc_dat->dev, "pm8058 write failed\n");
				goto error;
			}

			/*Wait a bit to get basicly stable ADC value*/
			msleep(WAIT_MIC_BIAS_VOLTAGE_STABLE_DELAY);
		}
		loc_dat->mic_bias_enable_counter++;
		dev_vdbg(loc_dat->dev,
				"%s - Increasing MIC_BIAS_COUNTER %u\n",
				__func__,
				loc_dat->mic_bias_enable_counter);
	} else {
		if (1 <= loc_dat->mic_bias_enable_counter) {
			if (1 == loc_dat->mic_bias_enable_counter) {
				rc = pm8xxx_readb(loc_dat->dev->parent,
						mic_bias_addr, &reg);
				if (rc < 0) {
					dev_err(loc_dat->dev, "pm8058 read failed\n");
					goto error;
				}

				reg &= PM8058_OTHC_EN_SIG_MASK;
				reg |= (OTHC_SIGNAL_OFF <<
						PM8058_OTHC_EN_SIG_SHIFT);

				rc = pm8xxx_writeb(loc_dat->dev->parent,
						mic_bias_addr, reg);
				if (rc < 0) {
					dev_err(loc_dat->dev, "pm8058 write failed\n");
					goto error;
				}

				if (!rc)
					dev_dbg(loc_dat->dev,
							"%s - MIC Bias disabled\n",
							__func__);
			}
			loc_dat->mic_bias_enable_counter--;
			dev_vdbg(loc_dat->dev,
					"%s - Decreasing MIC_BIAS_COUNTER %u\n",
					__func__,
					loc_dat->mic_bias_enable_counter);
		} else {
			dev_vdbg(loc_dat->dev, "%s - No need to decrease "
					"MIC_BIAS_COUNTER\n", __func__);
		}
	}

error:
	UNLOCK(&loc_dat->lock);

	if (rc)
		dev_err(loc_dat->dev, "Unable to toggle MIC Bias\n");

	return rc;
}
예제 #14
0
/*
 * Set an SMPS regulator to be disabled in its CTRL register, but enabled
 * in the master enable register.  Also set it's pull down enable bit.
 * Take care to make sure that the output voltage doesn't change if switching
 * from advanced mode to legacy mode.
 */
static int
__pm8058_disable_smps_locally_set_pull_down(struct pm8xxx_misc_chip *chip,
	u16 ctrl_addr, u16 test2_addr, u16 master_enable_addr,
	u8 master_enable_bit)
{
	int rc = 0;
	u8 vref_sel, vlow_sel, band, vprog, bank, reg;

	bank = PM8058_REGULATOR_BANK_SEL(7);
	rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
	if (rc) {
		pr_err("%s: pm8xxx_writeb(0x%03X) failed: rc=%d\n", __func__,
			test2_addr, rc);
		goto done;
	}

	rc = pm8xxx_readb(chip->dev->parent, test2_addr, &reg);
	if (rc) {
		pr_err("%s: FAIL pm8xxx_readb(0x%03X): rc=%d\n",
		       __func__, test2_addr, rc);
		goto done;
	}

	/* Check if in advanced mode. */
	if ((reg & PM8058_SMPS_ADVANCED_MODE_MASK) ==
					PM8058_SMPS_ADVANCED_MODE) {
		/* Determine current output voltage. */
		rc = pm8xxx_readb(chip->dev->parent, ctrl_addr, &reg);
		if (rc) {
			pr_err("%s: FAIL pm8xxx_readb(0x%03X): rc=%d\n",
			       __func__, ctrl_addr, rc);
			goto done;
		}

		band = (reg & PM8058_SMPS_ADVANCED_BAND_MASK)
			>> PM8058_SMPS_ADVANCED_BAND_SHIFT;
		switch (band) {
		case 3:
			vref_sel = 0;
			vlow_sel = 0;
			break;
		case 2:
			vref_sel = PM8058_SMPS_LEGACY_VREF_SEL;
			vlow_sel = 0;
			break;
		case 1:
			vref_sel = PM8058_SMPS_LEGACY_VREF_SEL;
			vlow_sel = PM8058_SMPS_LEGACY_VLOW_SEL;
			break;
		default:
			pr_err("%s: regulator already disabled\n", __func__);
			return -EPERM;
		}
		vprog = (reg & PM8058_SMPS_ADVANCED_VPROG_MASK);
		/* Round up if fine step is in use. */
		vprog = (vprog + 1) >> 1;
		if (vprog > PM8058_SMPS_LEGACY_VPROG_MASK)
			vprog = PM8058_SMPS_LEGACY_VPROG_MASK;

		/* Set VLOW_SEL bit. */
		bank = PM8058_REGULATOR_BANK_SEL(1);
		rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
		if (rc) {
			pr_err("%s: FAIL pm8xxx_writeb(0x%03X): rc=%d\n",
			       __func__, test2_addr, rc);
			goto done;
		}

		rc = pm8xxx_misc_masked_write(chip, test2_addr,
			PM8058_REGULATOR_BANK_WRITE | PM8058_REGULATOR_BANK_MASK
				| PM8058_SMPS_LEGACY_VLOW_SEL,
			PM8058_REGULATOR_BANK_WRITE |
			PM8058_REGULATOR_BANK_SEL(1) | vlow_sel);
		if (rc)
			goto done;

		/* Switch to legacy mode */
		bank = PM8058_REGULATOR_BANK_SEL(7);
		rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
		if (rc) {
			pr_err("%s: FAIL pm8xxx_writeb(0x%03X): rc=%d\n",
					__func__, test2_addr, rc);
			goto done;
		}
		rc = pm8xxx_misc_masked_write(chip, test2_addr,
				PM8058_REGULATOR_BANK_WRITE |
				PM8058_REGULATOR_BANK_MASK |
				PM8058_SMPS_ADVANCED_MODE_MASK,
				PM8058_REGULATOR_BANK_WRITE |
				PM8058_REGULATOR_BANK_SEL(7) |
				PM8058_SMPS_LEGACY_MODE);
		if (rc)
			goto done;

		/* Enable locally, enable pull down, keep voltage the same. */
		rc = pm8xxx_misc_masked_write(chip, ctrl_addr,
			PM8058_REGULATOR_ENABLE_MASK |
			PM8058_REGULATOR_PULL_DOWN_MASK |
			PM8058_SMPS_LEGACY_VREF_SEL |
			PM8058_SMPS_LEGACY_VPROG_MASK,
			PM8058_REGULATOR_ENABLE | PM8058_REGULATOR_PULL_DOWN_EN
				| vref_sel | vprog);
		if (rc)
			goto done;
	}
예제 #15
0
static void pm8xxx_led_current_set(struct led_classdev *led_cdev, enum led_brightness brightness)
{
	struct pm8xxx_led_data *led = container_of(led_cdev,  struct pm8xxx_led_data, cdev);
	int rc, offset;
	u8 level;

	int *pduties;

	LED_INFO("%s, bank:%d, brightness:%d\n", __func__, led->bank, brightness);
	cancel_delayed_work_sync(&led->fade_delayed_work);
	virtual_key_state = brightness;
	if (flag_hold_virtual_key == 1) {
		LED_INFO("%s, key control \n", __func__);
		return;
	}

	if(brightness) {
		level = (led->out_current << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;

		offset = PM8XXX_LED_OFFSET(led->id);
		led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
		led->reg |= level;
		rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), led->reg);
		if (rc)
			LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, led->id, rc);

		if (led->function_flags & LED_BRETH_FUNCTION) {
			pduties = led->duties;
			pm8xxx_pwm_lut_config(led->pwm_led,
						led->period_us,
						pduties,
						led->duty_time_ms,
						led->start_index,
						led->duites_size,
						0, 0,
						led->lut_flag);
			pm8xxx_pwm_lut_enable(led->pwm_led, 0);
			pm8xxx_pwm_lut_enable(led->pwm_led, 1);
		} else {
			pwm_config(led->pwm_led, 64000, 64000);
			pwm_enable(led->pwm_led);
		}
	} else {
		if (led->function_flags & LED_BRETH_FUNCTION) {
			pduties = led->duties + led->duites_size;
			pm8xxx_pwm_lut_config(led->pwm_led,
						led->period_us,
						pduties,
						led->duty_time_ms,
						led->start_index,
						led->duites_size,
						0, 0,
						led->lut_flag);
			pm8xxx_pwm_lut_enable(led->pwm_led, 0);
			pm8xxx_pwm_lut_enable(led->pwm_led, 1);
			queue_delayed_work(g_led_work_queue,
						&led->fade_delayed_work,
						msecs_to_jiffies(led->duty_time_ms*led->duites_size));
		} else {
			pwm_disable(led->pwm_led);
			level = (0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
			offset = PM8XXX_LED_OFFSET(led->id);
			led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
			led->reg |= level;
			rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), led->reg);
			if (rc)
				LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, led->id, rc);
		}
	}
}
예제 #16
0
static ssize_t pm8xxx_led_blink_store(struct device *dev,
				       struct device_attribute *attr,
				       const char *buf, size_t count)
{
	struct led_classdev *led_cdev;
	struct pm8xxx_led_data *ldata;
	int val;
	int level, offset;
	int led_is_green;

	val = -1;
	sscanf(buf, "%u", &val);
	if (val < 0 || val > 255)
		return -EINVAL;
	current_blink= val;
	led_cdev = (struct led_classdev *) dev_get_drvdata(dev);
	ldata = container_of(led_cdev, struct pm8xxx_led_data, cdev);

	LED_INFO("%s: bank %d blink %d sync %d\n", __func__, ldata->bank, val, ldata->led_sync);
	printk("%s: [BB] bank %d blink %d sync %d\n", __func__, ldata->bank, val, ldata->led_sync);
	if (!strcmp(ldata->cdev.name, "green")) {
		led_is_green = 1;
	}
	if (!strcmp(ldata->cdev.name, "amber")) {
		led_is_green = 0;
	}

	switch (val) {
	case BLINK_STOP:
		if (ldata->gpio_status_switch != NULL)
			ldata->gpio_status_switch(0);
		pwm_disable(ldata->pwm_led);

		if(ldata->led_sync) {
			if 	(!strcmp(ldata->cdev.name, "green")) {
				if (green_back_led_data->gpio_status_switch != NULL)
					green_back_led_data->gpio_status_switch(0);
				pwm_disable(green_back_led_data->pwm_led);
			}
			if 	(!strcmp(ldata->cdev.name, "amber")) {
				if (amber_back_led_data->gpio_status_switch != NULL)
					amber_back_led_data->gpio_status_switch(0);
				pwm_disable(amber_back_led_data->pwm_led);
			}
		}
		if (blink_buttons > 0) {
			if (led_is_green == 1) {
				green_blink_value = 0;
			} else {
				amber_blink_value = 0;
			}
			pm8xxx_buttons_blink(0);
		}
		break;
	case BLINK_UNCHANGE:
		pwm_disable(ldata->pwm_led);
		if (led_cdev->brightness) {
			if (ldata->gpio_status_switch != NULL)
				ldata->gpio_status_switch(1);
			pwm_config(ldata->pwm_led, 6400 * ldata->pwm_coefficient / 100, 6400);
			pwm_enable(ldata->pwm_led);

			if(ldata->led_sync) {
				if	(!strcmp(ldata->cdev.name, "green")) {
					if (green_back_led_data->gpio_status_switch != NULL)
						green_back_led_data->gpio_status_switch(1);
					pwm_config(green_back_led_data->pwm_led, 64000, 64000);
					pwm_enable(green_back_led_data->pwm_led);
				}
				if	(!strcmp(ldata->cdev.name, "amber")) {
					if (amber_back_led_data->gpio_status_switch != NULL)
						amber_back_led_data->gpio_status_switch(1);
					pwm_config(amber_back_led_data->pwm_led, 64000, 64000);
					pwm_enable(amber_back_led_data->pwm_led);
				}
			}
			if (blink_buttons > 0 && val > 0) {
				if (led_is_green == 1) {
					green_blink_value = 1;
				} else {
					amber_blink_value = 1;
				}
				pm8xxx_buttons_blink(1);
			}
		} else {
			pwm_disable(ldata->pwm_led);
			if (ldata->gpio_status_switch != NULL)
				ldata->gpio_status_switch(0);

			if(ldata->led_sync) {
				if (!strcmp(ldata->cdev.name, "green")){
					if (green_back_led_data->gpio_status_switch != NULL)
						green_back_led_data->gpio_status_switch(0);
					pwm_disable(green_back_led_data->pwm_led);
					level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
					offset = PM8XXX_LED_OFFSET(green_back_led_data->id);
					green_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
					green_back_led_data->reg |= level;
					pm8xxx_writeb(green_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), green_back_led_data->reg);
				}
				if (!strcmp(ldata->cdev.name, "amber")){
					if (amber_back_led_data->gpio_status_switch != NULL)
						amber_back_led_data->gpio_status_switch(0);
					pwm_disable(amber_back_led_data->pwm_led);
					level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
					offset = PM8XXX_LED_OFFSET(amber_back_led_data->id);
					amber_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
					amber_back_led_data->reg |= level;
					pm8xxx_writeb(amber_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), amber_back_led_data->reg);
				}
			}
			if (blink_buttons > 0) {
				if (led_is_green == 1) {
					green_blink_value = 0;
				} else {
					amber_blink_value = 0;
				}
				pm8xxx_buttons_blink(0);
			}
		}
		break;
	case BLINK_64MS_PER_2SEC:
		if (ldata->gpio_status_switch != NULL)
			ldata->gpio_status_switch(1);
		pwm_disable(ldata->pwm_led);
		pwm_config(ldata->pwm_led, ldata->blink_duty_per_2sec, 2000000);
		pwm_enable(ldata->pwm_led);

		if(ldata->led_sync) {
			if	(!strcmp(ldata->cdev.name, "green")) {
				if (green_back_led_data->gpio_status_switch != NULL)
					green_back_led_data->gpio_status_switch(1);
				pwm_disable(green_back_led_data->pwm_led);
				pwm_config(green_back_led_data->pwm_led, ldata->blink_duty_per_2sec, 2000000);
				pwm_enable(green_back_led_data->pwm_led);
			}
			if	(!strcmp(ldata->cdev.name, "amber")) {
				if (amber_back_led_data->gpio_status_switch != NULL)
					amber_back_led_data->gpio_status_switch(1);
				pwm_disable(amber_back_led_data->pwm_led);
				pwm_config(amber_back_led_data->pwm_led, ldata->blink_duty_per_2sec, 2000000);
				pwm_enable(amber_back_led_data->pwm_led);
			}
		}
		if (blink_buttons > 0 && val > 0) {
			if (led_is_green == 1) {
				green_blink_value = 1;
			} else {
				amber_blink_value = 1;
			}
			pm8xxx_buttons_blink(1);
		}
		break;
	case BLINK_64MS_ON_310MS_PER_2SEC:
		cancel_delayed_work_sync(&ldata->blink_delayed_work);
		pwm_disable(ldata->pwm_led);
		ldata->duty_time_ms = 64;
		ldata->period_us = 2000000;

		if(ldata->led_sync) {
			if	(!strcmp(ldata->cdev.name, "green")) {
				pwm_disable(green_back_led_data->pwm_led);
				green_back_led_data->duty_time_ms = 64;
				green_back_led_data->period_us = 2000000;
			}
			if	(!strcmp(ldata->cdev.name, "amber")) {
				pwm_disable(amber_back_led_data->pwm_led);
				amber_back_led_data->duty_time_ms = 64;
				amber_back_led_data->period_us = 2000000;
			}
		}
		queue_delayed_work(g_led_work_queue, &ldata->blink_delayed_work,
				   msecs_to_jiffies(310));
		break;
	case BLINK_64MS_ON_2SEC_PER_2SEC:
		cancel_delayed_work_sync(&ldata->blink_delayed_work);
		pwm_disable(ldata->pwm_led);
		ldata->duty_time_ms = 64;
		ldata->period_us = 2000000;

		if(ldata->led_sync) {
			if	(!strcmp(ldata->cdev.name, "green")) {
				pwm_disable(green_back_led_data->pwm_led);
				green_back_led_data->duty_time_ms = 64;
				green_back_led_data->period_us = 2000000;
			}
			if	(!strcmp(ldata->cdev.name, "amber")) {
				pwm_disable(amber_back_led_data->pwm_led);
				amber_back_led_data->duty_time_ms = 64;
				amber_back_led_data->period_us = 2000000;
			}
		}
		queue_delayed_work(g_led_work_queue, &ldata->blink_delayed_work,
				   msecs_to_jiffies(1000));
		break;
	case BLINK_1SEC_PER_2SEC:
		pwm_disable(ldata->pwm_led);
		pwm_config(ldata->pwm_led, 1000000, 2000000);
		pwm_enable(ldata->pwm_led);

		if(ldata->led_sync) {
			if	(!strcmp(ldata->cdev.name, "green")) {
				pwm_disable(green_back_led_data->pwm_led);
				pwm_config(green_back_led_data->pwm_led, 1000000, 2000000);
				pwm_enable(green_back_led_data->pwm_led);
			}
			if	(!strcmp(ldata->cdev.name, "amber")) {
				pwm_disable(amber_back_led_data->pwm_led);
				pwm_config(amber_back_led_data->pwm_led, 1000000, 2000000);
				pwm_enable(amber_back_led_data->pwm_led);
			}
		}
		break;
	default:
		LED_ERR("%s: bank %d did not support blink type %d\n", __func__, ldata->bank, val);
		return -EINVAL;
	}

	return count;
}
예제 #17
0
static void pm8xxx_led_gpio_set(struct led_classdev *led_cdev, enum led_brightness brightness)
{
	int rc, offset;
	u8 level;

	struct pm8xxx_led_data *led = container_of(led_cdev,  struct pm8xxx_led_data, cdev);
	LED_INFO("%s, bank:%d, brightness:%d sync: %d\n", __func__, led->bank, brightness, led->led_sync);
	if (led->gpio_status_switch != NULL)
		led->gpio_status_switch(0);
	pwm_disable(led->pwm_led);
	if(led->led_sync) {
		if (!strcmp(led->cdev.name, "green")){
			if (green_back_led_data->gpio_status_switch != NULL)
				green_back_led_data->gpio_status_switch(0);
			pwm_disable(green_back_led_data->pwm_led);
			level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
			offset = PM8XXX_LED_OFFSET(green_back_led_data->id);
			green_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
			green_back_led_data->reg |= level;
			rc = pm8xxx_writeb(green_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), green_back_led_data->reg);
		}
		if (!strcmp(led->cdev.name, "amber")){
			if (amber_back_led_data->gpio_status_switch != NULL)
				amber_back_led_data->gpio_status_switch(0);
			pwm_disable(amber_back_led_data->pwm_led);
			level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
			offset = PM8XXX_LED_OFFSET(amber_back_led_data->id);
			amber_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
			amber_back_led_data->reg |= level;
			rc = pm8xxx_writeb(amber_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), amber_back_led_data->reg);
		}
	}
	if (brightness) {
		if (led->gpio_status_switch != NULL)
			led->gpio_status_switch(1);
		pwm_config(led->pwm_led, 6400 * led->pwm_coefficient / 100, 6400);
		pwm_enable(led->pwm_led);
		if(led->led_sync) {
			if 	(!strcmp(led->cdev.name, "green")) {
				if (green_back_led_data->gpio_status_switch != NULL)
					green_back_led_data->gpio_status_switch(1);
				level = (green_back_led_data->out_current << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
				offset = PM8XXX_LED_OFFSET(green_back_led_data->id);
				green_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
				green_back_led_data->reg |= level;
				rc = pm8xxx_writeb(green_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), green_back_led_data->reg);
				pwm_config(green_back_led_data->pwm_led, 64000, 64000);
				pwm_enable(green_back_led_data->pwm_led);
			}
			if 	(!strcmp(led->cdev.name, "amber")) {
				if (amber_back_led_data->gpio_status_switch != NULL)
					amber_back_led_data->gpio_status_switch(1);
				level = (amber_back_led_data->out_current << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
				offset = PM8XXX_LED_OFFSET(amber_back_led_data->id);
				amber_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
				amber_back_led_data->reg |= level;
				rc = pm8xxx_writeb(amber_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), amber_back_led_data->reg);
				pwm_config(amber_back_led_data->pwm_led, 64000, 64000);
				pwm_enable(amber_back_led_data->pwm_led);
			}
		}
	}
}
예제 #18
0
static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
{
	struct input_dev *pwr;
	int key_release_irq = platform_get_irq(pdev, 0);
	int key_press_irq = platform_get_irq(pdev, 1);
	int err;
	unsigned int delay;
	u8 pon_cntl;
	struct pmic8xxx_pwrkey *pwrkey;
	const struct pm8xxx_pwrkey_platform_data *pdata =
					dev_get_platdata(&pdev->dev);

	if (!pdata) {
		dev_err(&pdev->dev, "power key platform data not supplied\n");
		return -EINVAL;
	}

	if (pdata->kpd_trigger_delay_us > 62500) {
		dev_err(&pdev->dev, "invalid power key trigger delay\n");
		return -EINVAL;
	}

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

	pwr = input_allocate_device();
	if (!pwr) {
		dev_dbg(&pdev->dev, "Can't allocate power button\n");
		err = -ENOMEM;
		goto free_pwrkey;
	}

	input_set_capability(pwr, EV_KEY, KEY_POWER);

	pwr->name = "pmic8xxx_pwrkey";
	pwr->phys = "pmic8xxx_pwrkey/input0";
	pwr->dev.parent = &pdev->dev;

	delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
	delay = 1 + ilog2(delay);

	err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
	if (err < 0) {
		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
		goto free_input_dev;
	}

	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
	if (pdata->pull_up)
		pon_cntl |= PON_CNTL_PULL_UP;
	else
		pon_cntl &= ~PON_CNTL_PULL_UP;

	err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
	if (err < 0) {
		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
		goto free_input_dev;
	}

	err = input_register_device(pwr);
	if (err) {
		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
		goto free_input_dev;
	}

	pwrkey->key_press_irq = key_press_irq;
	pwrkey->pwr = pwr;
#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_SWEEP2WAKE
	sweep2wake_setdev(pwr);
#endif
	platform_set_drvdata(pdev, pwrkey);

	platform_set_drvdata(pdev, pwrkey);

	err = request_irq(key_press_irq, pwrkey_press_irq,
		IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
	if (err < 0) {
		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
				 key_press_irq, err);
		goto unreg_input_dev;
	}

	err = request_irq(key_release_irq, pwrkey_release_irq,
		 IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
	if (err < 0) {
		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
				 key_release_irq, err);

		goto free_press_irq;
	}

	device_init_wakeup(&pdev->dev, pdata->wakeup);

	return 0;

free_press_irq:
	free_irq(key_press_irq, NULL);
unreg_input_dev:
	platform_set_drvdata(pdev, NULL);
	input_unregister_device(pwr);
	pwr = NULL;
free_input_dev:
	input_free_device(pwr);
free_pwrkey:
	kfree(pwrkey);
	return err;
}
예제 #19
0
static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
{
	struct input_dev *pwr;
	int key_release_irq = platform_get_irq(pdev, 0);
	int key_press_irq = platform_get_irq(pdev, 1);
	int err;
	unsigned int delay;
	u8 pon_cntl;
	struct pmic8xxx_pwrkey *pwrkey;
	const struct pm8xxx_pwrkey_platform_data *pdata =
					dev_get_platdata(&pdev->dev);

	if (!pdata) {
		dev_err(&pdev->dev, "power key platform data not supplied\n");
		return -EINVAL;
	}

	/* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
	if (pdata->kpd_trigger_delay_us > USEC_PER_SEC * 2 ||
		pdata->kpd_trigger_delay_us < USEC_PER_SEC / 64) {
		dev_err(&pdev->dev, "invalid power key trigger delay\n");
		return -EINVAL;
	}

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

	pwrkey->pdata = pdata;

	pwr = input_allocate_device();
	if (!pwr) {
		dev_dbg(&pdev->dev, "Can't allocate power button\n");
		err = -ENOMEM;
		goto free_pwrkey;
	}

	input_set_capability(pwr, EV_KEY, KEY_POWER);

	pwr->name = "pmic8xxx_pwrkey";
	pwr->phys = "pmic8xxx_pwrkey/input0";
	pwr->dev.parent = &pdev->dev;

	delay = (pdata->kpd_trigger_delay_us << 6) / USEC_PER_SEC;
	delay = ilog2(delay);

	err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
	if (err < 0) {
		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
		goto free_input_dev;
	}

	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
	if (pdata->pull_up)
		pon_cntl |= PON_CNTL_PULL_UP;
	else
		pon_cntl &= ~PON_CNTL_PULL_UP;

	err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
	if (err < 0) {
		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
		goto free_input_dev;
	}

	err = input_register_device(pwr);
	if (err) {
		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
		goto free_input_dev;
	}

	pwrkey->key_press_irq = key_press_irq;
	pwrkey->key_release_irq = key_release_irq;
	pwrkey->pwr = pwr;

	platform_set_drvdata(pdev, pwrkey);

	/* check power key status during boot */
	err = pm8xxx_read_irq_stat(pdev->dev.parent, key_press_irq);
	if (err < 0) {
		dev_err(&pdev->dev, "reading irq status failed\n");
		goto unreg_input_dev;
	}
	pwrkey->press = !!err;

	if (pwrkey->press) {
		input_report_key(pwrkey->pwr, KEY_POWER, 1);
		input_sync(pwrkey->pwr);
	}
#ifdef CONFIG_TOUCHSCREEN_PREVENT_SLEEP
#ifdef CONFIG_TOUCHSCREEN_SWEEP2WAKE
	pr_info("[wake_up_display]: set device %s\n", pwr->name);
#else
        power_on_display_dt2w(pwr);
	pr_info("[wake_up_display]: set device %s\n", pwr->name);
#endif
#endif
	err = request_any_context_irq(key_press_irq, pwrkey_press_irq,
		IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
	if (err < 0) {
		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
				 key_press_irq, err);
		goto unreg_input_dev;
	}

	err = request_any_context_irq(key_release_irq, pwrkey_release_irq,
		 IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
	if (err < 0) {
		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
				 key_release_irq, err);

		goto free_press_irq;
	}

	device_init_wakeup(&pdev->dev, pdata->wakeup);

	return 0;

free_press_irq:
	free_irq(key_press_irq, NULL);
unreg_input_dev:
	platform_set_drvdata(pdev, NULL);
	input_unregister_device(pwr);
	pwr = NULL;
free_input_dev:
	input_free_device(pwr);
free_pwrkey:
	kfree(pwrkey);
	return err;
}
예제 #20
0
extern void pm8xxx_led_current_set(struct led_classdev *led_cdev, enum led_brightness brightness)
{
    struct pm8xxx_led_data *led = container_of(led_cdev,  struct pm8xxx_led_data, cdev);
	int rc, offset;
	u8 level;

	int *pduties;

	LED_INFO("%s, bank:%d, brightness:%d\n", __func__, led->bank, brightness);
	cancel_delayed_work_sync(&led->fade_delayed_work);
	virtual_key_state = brightness;
	if (flag_hold_virtual_key == 1) {
		LED_INFO("%s, key control \n", __func__);
		return;
	}

	if(brightness) {
		level = (led->out_current << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
		offset = PM8XXX_LED_OFFSET(led->id);
		led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
		led->reg |= level;
		rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), led->reg);
		if (rc)
			LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, led->id, rc);

		if (led->function_flags & LED_BRETH_FUNCTION) {
			pduties = led->duties;
			pm8xxx_pwm_lut_config(led->pwm_led,
						led->period_us,
						pduties,
						led->duty_time_ms,
						led->start_index,
						led->duites_size,
						0, 0,
						led->lut_flag);
			pm8xxx_pwm_lut_enable(led->pwm_led, 0);
			pm8xxx_pwm_lut_enable(led->pwm_led, 1);
		} else {
			pwm_config(led->pwm_led, 64000, 64000);
			pwm_enable(led->pwm_led);
		}
	} else {
		if (led->function_flags & LED_BRETH_FUNCTION) {
			wake_lock_timeout(&pmic_led_wake_lock, HZ*2);
			pduties = led->duties + led->duites_size;
			pm8xxx_pwm_lut_config(led->pwm_led,
						led->period_us,
						pduties,
						led->duty_time_ms,
						led->start_index,
						led->duites_size,
						0, 0,
						led->lut_flag);
			pm8xxx_pwm_lut_enable(led->pwm_led, 0);
			pm8xxx_pwm_lut_enable(led->pwm_led, 1);
			queue_delayed_work(g_led_work_queue,
						&led->fade_delayed_work,
						msecs_to_jiffies(led->duty_time_ms*led->duites_size));
		} else {
			pwm_disable(led->pwm_led);
			level = (0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
			offset = PM8XXX_LED_OFFSET(led->id);
			led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
			led->reg |= level;
			rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), led->reg);
			if (rc)
				LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, led->id, rc);
		}
	}
	// checking for buttons device
	if (led_cdev_buttons == led_cdev)
	{
		printk("[BB] led_current_set %d \n", brightness);
		if (brightness>0)
		{
			// screen turning off together with buttons led
			buttons_turning_on_with_screen_on = 1;
		} else
		{
			// screen turning off together without buttons led
			buttons_turning_on_with_screen_on = 0;
		}
	}
	// no blink needed
	pm8xxx_led_current_set_flagged( led_cdev, brightness, 0);
}
static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
{
	struct input_dev *pwr;
	int key_release_irq = platform_get_irq(pdev, 0);
	int key_press_irq = platform_get_irq(pdev, 1);
	int err;
	unsigned int delay;
	u8 pon_cntl;
	struct pmic8xxx_pwrkey *pwrkey;
	const struct pm8xxx_pwrkey_platform_data *pdata =
					dev_get_platdata(&pdev->dev);

	if (!pdata) {
		dev_err(&pdev->dev, "power key platform data not supplied\n");
		return -EINVAL;
	}

	/* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
	if (pdata->kpd_trigger_delay_us > USEC_PER_SEC * 2 ||
		pdata->kpd_trigger_delay_us < USEC_PER_SEC / 64) {
		dev_err(&pdev->dev, "invalid power key trigger delay\n");
		return -EINVAL;
	}

	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
	if (!pwrkey)
		return -ENOMEM;
	init_timer(&pwrkey->hibernate_timer);
	pwrkey->hibernate_timer.data = (unsigned long)pwrkey;
	pwrkey->hibernate_timer.function = hibernate_timer_handle;
	
	pwrkey->pdata = pdata;

	pwr = input_allocate_device();
	if (!pwr) {
		dev_dbg(&pdev->dev, "Can't allocate power button\n");
		err = -ENOMEM;
		goto free_pwrkey;
	}

	input_set_capability(pwr, EV_KEY, KEY_POWER);

	pwr->name = "pmic8xxx_pwrkey";
	pwr->phys = "pmic8xxx_pwrkey/input0";
	pwr->dev.parent = &pdev->dev;

	delay = (pdata->kpd_trigger_delay_us << 6) / USEC_PER_SEC;
	delay = ilog2(delay);

	err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
	if (err < 0) {
		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
		goto free_input_dev;
	}

	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
	if (pdata->pull_up)
		pon_cntl |= PON_CNTL_PULL_UP;
	else
		pon_cntl &= ~PON_CNTL_PULL_UP;

	err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
	if (err < 0) {
		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
		goto free_input_dev;
	}

	err = input_register_device(pwr);
	if (err) {
		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
		goto free_input_dev;
	}

	pwrkey->key_press_irq = key_press_irq;
	pwrkey->pwr = pwr;

	platform_set_drvdata(pdev, pwrkey);
	the_pwrkey = pwrkey;

	err = request_any_context_irq(key_press_irq, pwrkey_press_irq,
		IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
	if (err < 0) {
		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
				 key_press_irq, err);
		goto unreg_input_dev;
	}

	err = request_any_context_irq(key_release_irq, pwrkey_release_irq,
		 IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
	if (err < 0) {
		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
				 key_release_irq, err);

		goto free_press_irq;
	}

	device_init_wakeup(&pdev->dev, pdata->wakeup);

	return 0;

free_press_irq:
	free_irq(key_press_irq, NULL);
unreg_input_dev:
	platform_set_drvdata(pdev, NULL);
	input_unregister_device(pwr);
	pwr = NULL;
free_input_dev:
	input_free_device(pwr);
free_pwrkey:
	kfree(pwrkey);
	return err;
}
예제 #22
0
static void pm8xxx_led_current_set_flagged(struct led_classdev *led_cdev, enum led_brightness brightness, int blink)
{
	struct pm8xxx_led_data *led = container_of(led_cdev,  struct pm8xxx_led_data, cdev);
	int rc, offset;
	u8 level;

	int *pduties;

	LED_INFO("%s, bank:%d, brightness:%d\n", __func__, led->bank, brightness);
	cancel_delayed_work_sync(&led->fade_delayed_work);
	virtual_key_state = brightness;
	if (flag_hold_virtual_key == 1) {
		LED_INFO("%s, key control \n", __func__);
		return;
	}

	if(brightness) {
		level = (led->out_current << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
		offset = PM8XXX_LED_OFFSET(led->id);
		led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
		led->reg |= level;
		rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), led->reg);
		if (rc)
			LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, led->id, rc);

		if (led->function_flags & LED_BRETH_FUNCTION) {
			if (blink == 0) {
				buttons_led_is_on = 1;
				// no blink needed
				pduties = &dutys_array[0];
				pm8xxx_pwm_lut_config(led->pwm_led,
							led->period_us,
							pduties,
							led->duty_time_ms,
							led->start_index,
							led->duites_size,
							0, 0,
							led->lut_flag);
			} else {
				pduties = &dutys_array[0];
				// LUT_LOOP for blinking
				pm8xxx_pwm_lut_config(led->pwm_led,
							led->period_us,
							pduties,
							led->duty_time_ms, // slower, 2x
							led->start_index,
							led->duites_size * 8, // 16 duty entries -> original size * 2, + 6 * 8 zeroes for pause
							0, 0,
							PM_PWM_LUT_LOOP | PM_PWM_LUT_PAUSE_HI_EN);
			}
			pm8xxx_pwm_lut_enable(led->pwm_led, 0);
			pm8xxx_pwm_lut_enable(led->pwm_led, 1);
		} else {
			pwm_config(led->pwm_led, 6400 * led->pwm_coefficient / 100, 6400);
			pwm_enable(led->pwm_led);
		}
	} else {
		if (led->function_flags & LED_BRETH_FUNCTION) {
			buttons_led_is_on = 0;
			wake_lock_timeout(&pmic_led_wake_lock, HZ*2);
			pduties = &dutys_array[8];
			pm8xxx_pwm_lut_config(led->pwm_led,
						led->period_us,
						pduties,
						led->duty_time_ms,
						led->start_index,
						led->duites_size,
						0, 0,
						led->lut_flag);
			pm8xxx_pwm_lut_enable(led->pwm_led, 0);
			pm8xxx_pwm_lut_enable(led->pwm_led, 1);
			queue_delayed_work(g_led_work_queue,
						&led->fade_delayed_work,
						msecs_to_jiffies(led->duty_time_ms*led->duites_size));
		} else {
			pwm_disable(led->pwm_led);
			level = (0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
			offset = PM8XXX_LED_OFFSET(led->id);
			led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
			led->reg |= level;
			rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), led->reg);
			if (rc)
				LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, led->id, rc);
		}
	}
}
예제 #23
0
static int
__pm8058_disable_smps_locally_set_pull_down(struct pm8xxx_misc_chip *chip,
	u16 ctrl_addr, u16 test2_addr, u16 master_enable_addr,
	u8 master_enable_bit)
{
	int rc = 0;
	u8 vref_sel, vlow_sel, band, vprog, bank, reg;

	bank = PM8058_REGULATOR_BANK_SEL(7);
	rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
	if (rc) {
		pr_err("%s: pm8xxx_writeb(0x%03X) failed: rc=%d\n", __func__,
			test2_addr, rc);
		goto done;
	}

	rc = pm8xxx_readb(chip->dev->parent, test2_addr, &reg);
	if (rc) {
		pr_err("%s: FAIL pm8xxx_readb(0x%03X): rc=%d\n",
		       __func__, test2_addr, rc);
		goto done;
	}

	
	if ((reg & PM8058_SMPS_ADVANCED_MODE_MASK) ==
					PM8058_SMPS_ADVANCED_MODE) {
		
		rc = pm8xxx_readb(chip->dev->parent, ctrl_addr, &reg);
		if (rc) {
			pr_err("%s: FAIL pm8xxx_readb(0x%03X): rc=%d\n",
			       __func__, ctrl_addr, rc);
			goto done;
		}

		band = (reg & PM8058_SMPS_ADVANCED_BAND_MASK)
			>> PM8058_SMPS_ADVANCED_BAND_SHIFT;
		switch (band) {
		case 3:
			vref_sel = 0;
			vlow_sel = 0;
			break;
		case 2:
			vref_sel = PM8058_SMPS_LEGACY_VREF_SEL;
			vlow_sel = 0;
			break;
		case 1:
			vref_sel = PM8058_SMPS_LEGACY_VREF_SEL;
			vlow_sel = PM8058_SMPS_LEGACY_VLOW_SEL;
			break;
		default:
			pr_err("%s: regulator already disabled\n", __func__);
			return -EPERM;
		}
		vprog = (reg & PM8058_SMPS_ADVANCED_VPROG_MASK);
		
		vprog = (vprog + 1) >> 1;
		if (vprog > PM8058_SMPS_LEGACY_VPROG_MASK)
			vprog = PM8058_SMPS_LEGACY_VPROG_MASK;

		
		bank = PM8058_REGULATOR_BANK_SEL(1);
		rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
		if (rc) {
			pr_err("%s: FAIL pm8xxx_writeb(0x%03X): rc=%d\n",
			       __func__, test2_addr, rc);
			goto done;
		}

		rc = pm8xxx_misc_masked_write(chip, test2_addr,
			PM8058_REGULATOR_BANK_WRITE | PM8058_REGULATOR_BANK_MASK
				| PM8058_SMPS_LEGACY_VLOW_SEL,
			PM8058_REGULATOR_BANK_WRITE |
			PM8058_REGULATOR_BANK_SEL(1) | vlow_sel);
		if (rc)
			goto done;

		
		bank = PM8058_REGULATOR_BANK_SEL(7);
		rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
		if (rc) {
			pr_err("%s: FAIL pm8xxx_writeb(0x%03X): rc=%d\n",
					__func__, test2_addr, rc);
			goto done;
		}
		rc = pm8xxx_misc_masked_write(chip, test2_addr,
				PM8058_REGULATOR_BANK_WRITE |
				PM8058_REGULATOR_BANK_MASK |
				PM8058_SMPS_ADVANCED_MODE_MASK,
				PM8058_REGULATOR_BANK_WRITE |
				PM8058_REGULATOR_BANK_SEL(7) |
				PM8058_SMPS_LEGACY_MODE);
		if (rc)
			goto done;

		
		rc = pm8xxx_misc_masked_write(chip, ctrl_addr,
			PM8058_REGULATOR_ENABLE_MASK |
			PM8058_REGULATOR_PULL_DOWN_MASK |
			PM8058_SMPS_LEGACY_VREF_SEL |
			PM8058_SMPS_LEGACY_VPROG_MASK,
			PM8058_REGULATOR_ENABLE | PM8058_REGULATOR_PULL_DOWN_EN
				| vref_sel | vprog);
		if (rc)
			goto done;
	}
static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
{
	struct input_dev *pwr;
	int key_release_irq = platform_get_irq(pdev, 0);
	int key_press_irq = platform_get_irq(pdev, 1);
	int err;
	unsigned int delay;
	u8 pon_cntl;
	int ret;
	struct pmic8xxx_pwrkey *pwrkey;
	struct device *sec_powerkey;
	const struct pm8xxx_pwrkey_platform_data *pdata =
					dev_get_platdata(&pdev->dev);

	if (!pdata) {
		dev_err(&pdev->dev, "power key platform data not supplied\n");
		return -EINVAL;
	}

	/* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
	if (pdata->kpd_trigger_delay_us > USEC_PER_SEC * 2 ||
		pdata->kpd_trigger_delay_us < USEC_PER_SEC / 64) {
		dev_err(&pdev->dev, "invalid power key trigger delay\n");
		return -EINVAL;
	}

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

	pwrkey->pdata = pdata;

	pwr = input_allocate_device();
	if (!pwr) {
		dev_dbg(&pdev->dev, "Can't allocate power button\n");
		err = -ENOMEM;
		goto free_pwrkey;
	}

	input_set_capability(pwr, EV_KEY, KEY_POWER);

	pwr->name = "pmic8xxx_pwrkey";
	pwr->phys = "pmic8xxx_pwrkey/input0";
	pwr->dev.parent = &pdev->dev;

	delay = (pdata->kpd_trigger_delay_us << 6) / USEC_PER_SEC;
	delay = ilog2(delay);

	err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
	if (err < 0) {
		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
		goto free_input_dev;
	}

	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
	if (pdata->pull_up)
		pon_cntl |= PON_CNTL_PULL_UP;
	else
		pon_cntl &= ~PON_CNTL_PULL_UP;

	err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
	if (err < 0) {
		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
		goto free_input_dev;
	}

	err = input_register_device(pwr);
	if (err) {
		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
		goto free_input_dev;
	}

	pwrkey->key_press_irq = key_press_irq;
	pwrkey->key_release_irq = key_release_irq;
	pwrkey->pwr = pwr;

	platform_set_drvdata(pdev, pwrkey);

	if (poweroff_charging)
		wake_lock_init(&pwrkey->wake_lock, WAKE_LOCK_SUSPEND, "pmic_pwrkey");

	/* check power key status during boot */
	err = pm8xxx_read_irq_stat(pdev->dev.parent, key_press_irq);
	if (err < 0) {
		dev_err(&pdev->dev, "reading irq status failed\n");
		goto unreg_input_dev;
	}
	pwrkey->press = !!err;

	if (pwrkey->press) {
		input_report_key(pwrkey->pwr, KEY_POWER, 1);
		input_sync(pwrkey->pwr);
	}

	err = request_any_context_irq(key_press_irq, pwrkey_press_irq,
		IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
	if (err < 0) {
		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
				 key_press_irq, err);
		goto unreg_input_dev;
	}

	err = request_any_context_irq(key_release_irq, pwrkey_release_irq,
		 IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
	if (err < 0) {
		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
				 key_release_irq, err);

		goto free_press_irq;
	}

	sec_powerkey = device_create(sec_class, NULL, 0, NULL, "sec_powerkey");
	if (IS_ERR(sec_powerkey))
		pr_err("Failed to create device(sec_powerkey)!\n");
	ret = device_create_file(sec_powerkey, &dev_attr_sec_powerkey_pressed);
	if (ret) {
		pr_err("Failed to create device file in sysfs entries(%s)!\n",
			dev_attr_sec_powerkey_pressed.attr.name);
	}
	dev_set_drvdata(sec_powerkey, pwrkey);
	device_init_wakeup(&pdev->dev, pdata->wakeup);

	return 0;

free_press_irq:
	free_irq(key_press_irq, NULL);
unreg_input_dev:
	platform_set_drvdata(pdev, NULL);
	input_unregister_device(pwr);
	pwr = NULL;
free_input_dev:
	input_free_device(pwr);
free_pwrkey:
	kfree(pwrkey);
	return err;
}