Esempio n. 1
0
int pm8058_reset_pwr_off(int reset)
{
	int rc;
	uint8_t pon, ctrl, smpl;

	/* Set regulator L22 to 1.225V in high power mode. */
	rc = pm8058_read(SSBI_REG_ADDR_L22_CTRL, &ctrl, 1);
	if (rc) {
		goto get_out3;
	}
	/* Leave pull-down state intact. */
	ctrl &= 0x40;
	ctrl |= 0x93;

	rc = pm8058_write(SSBI_REG_ADDR_L22_CTRL, &ctrl, 1);
	if (rc) {
	}

get_out3:
	if (!reset) {
		/* Only modify the SLEEP_CNTL reg if shutdown is desired. */
		rc = pm8058_read(SSBI_REG_ADDR_SLEEP_CNTL, &smpl, 1);
		if (rc) {
			goto get_out2;
		}

		smpl &= ~PM8058_SLEEP_SMPL_EN_MASK;
		smpl |= PM8058_SLEEP_SMPL_EN_PWR_OFF;

		rc = pm8058_write(SSBI_REG_ADDR_SLEEP_CNTL, &smpl, 1);
		if (rc)
		{
		}
	}

get_out2:
	rc = pm8058_read(SSBI_REG_ADDR_PON_CNTL_1, &pon, 1);
	if (rc) {
		goto get_out;
	}

	pon &= ~PM8058_PON_WD_EN_MASK;
	pon |= reset ? PM8058_PON_WD_EN_RESET : PM8058_PON_WD_EN_PWR_OFF;

	/* Enable all pullups */
	pon |= PM8058_PON_PUP_MASK;

	rc = pm8058_write(SSBI_REG_ADDR_PON_CNTL_1, &pon, 1);
	if (rc) {
		goto get_out;
	}

get_out:
	return rc;
}
static int pm8058_init_regulator(struct pm8058_chip *chip,
		struct pm8058_vreg *vreg)
{
	int rc = 0, i;
	u8 bank;

	/* save the current control register state */
	rc = pm8058_read(chip, vreg->ctrl_addr, &vreg->ctrl_reg, 1);
	if (rc)
		return rc;

	/* save the current test/test2 register state */
	if (vreg->type == REGULATOR_TYPE_LDO) {
		for (i = 0; i < LDO_TEST_BANKS; i++) {
			bank = REGULATOR_BANK_SEL(i);
			rc = pm8058_write(chip, vreg->test_addr,
					&bank, 1);
			if (rc)
				goto bail;

			rc = pm8058_read(chip, vreg->test_addr,
					&vreg->test_reg[i], 1);
			if (rc)
				goto bail;
		}
	} else if (vreg->type == REGULATOR_TYPE_SMPS) {
		for (i = 0; i < SMPS_TEST_BANKS; i++) {
			bank = REGULATOR_BANK_SEL(i);
			rc = pm8058_write(chip, vreg->test2_addr,
					&bank, 1);
			if (rc)
				goto bail;

			rc = pm8058_read(chip, vreg->test2_addr,
					&vreg->test2_reg[i], 1);
			if (rc)
				goto bail;
		}

		rc = pm8058_read(chip, vreg->clk_ctrl_addr,
				&vreg->clk_ctrl_reg, 1);
		if (rc)
			goto bail;
	}

bail:
	if (rc)
		pr_err("%s: pm8058_read/write failed\n", __func__);

	return rc;
}
static irqreturn_t pm8058_chg_chgval_handler(int irq, void *dev_id)
{
    u8 old, temp;
    int ret;

    if (!is_chg_plugged_in()) {	/*this debounces it */
        ret = pm8058_read(pm8058_chg.pm_chip, PM8058_OVP_TEST_REG,
                          &old, 1);
        temp = old | BIT(FORCE_OVP_OFF);
        ret = pm8058_write(pm8058_chg.pm_chip, PM8058_OVP_TEST_REG,
                           &temp, 1);
        temp = 0xFC;
        ret = pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST,
                           &temp, 1);
        pr_debug("%s forced wrote 0xFC to test ret=%d\n",
                 __func__, ret);
        /* 20 ms sleep is for the VCHG to discharge */
        msleep(20);
        temp = 0xF0;
        ret = pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST,
                           &temp, 1);
        ret = pm8058_write(pm8058_chg.pm_chip, PM8058_OVP_TEST_REG,
                           &old, 1);
    }

    return IRQ_HANDLED;
}
/*
 * The API pm8058_micbias_enable() allows to configure
 * the MIC_BIAS. Only the lines which are not used for
 * headset detection can be configured using this API.
 * The API returns an error code if it fails to configure
 * the specified MIC_BIAS line, else it returns 0.
 */
int pm8058_micbias_enable(enum othc_micbias micbias,
		enum othc_micbias_enable enable)
{
	int rc;
	u8 reg;
	struct pm8058_othc *dd = config[micbias];

	if (dd == NULL) {
		pr_err("MIC_BIAS not registered, cannot enable\n");
		return -ENODEV;
	}

	if (dd->othc_pdata->micbias_capability != OTHC_MICBIAS) {
		pr_err("MIC_BIAS enable capability not supported\n");
		return -EINVAL;
	}

	rc = pm8058_read(dd->pm_chip, dd->othc_base + 1, &reg, 1);
	if (rc < 0) {
		pr_err("PM8058 read failed\n");
		return rc;
	}

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

	rc = pm8058_write(dd->pm_chip, dd->othc_base + 1, &reg, 1);
	if (rc < 0) {
		pr_err("PM8058 write failed\n");
		return rc;
	}

	return rc;
}
Esempio n. 5
0
static int data_get(void *data, u64 *val)
{
	struct pm8058_dbg_device *dbgdev = data;
	int rc;
	u8 reg;

	mutex_lock(&dbgdev->dbg_mutex);

	rc = check_addr(dbgdev->addr, __func__);
	if (rc)
		goto done;

	rc = pm8058_read(dbgdev->pm_chip, dbgdev->addr, &reg, 1);

	if (rc) {
		pr_err("%s: FAIL pm8058_read(0x%03X)=0x%02X: rc=%d\n",
			__func__, dbgdev->addr, reg, rc);
		goto done;
	}

	*val = reg;
done:
	mutex_unlock(&dbgdev->dbg_mutex);
	return rc;
}
static int kp_get_state(struct pm8058_chip *pm_chip, struct kp_key *key)
{
	u8 data;
	if (pm8058_read(pm_chip, SSBI_REG_ADDR_IRQ_RT_STATUS, &data, 1))
		return 0;

	return !(data & (1 << key->id));
}
/* REVISIT: just for debugging, will be removed in final working version */
static void __dump_vib_regs(struct pmic8058_vib *vib, char *msg)
{
	u8 temp;

	dev_dbg(vib->dev, "%s\n", msg);

	pm8058_read(vib->pm_chip, VIB_DRV, &temp, 1);
	dev_dbg(vib->dev, "VIB_DRV - %X\n", temp);
}
static inline int pm8058_tm_read_ctrl(struct pm8058_chip *chip, u8 *reg)
{
	int rc;

	rc = pm8058_read(chip, SSBI_REG_TEMP_ALRM_CTRL, reg, 1);
	if (rc)
		pr_err("%s: pm8058_read FAIL: rc=%d\n", __func__, rc);

	return rc;
}
Esempio n. 9
0
static int pmic8058_kp_read(struct pmic8058_kp *kp,
				 u8 *data, u16 reg, unsigned num_bytes)
{
	int rc;

	rc = pm8058_read(kp->pm_chip, reg, data, num_bytes);
	if (rc < 0)
		dev_warn(kp->dev, "Error reading pmic8058: %X - ret %X\n",
				reg, rc);

	return rc;
}
static int pmic8058_vib_read_u8(struct pmic8058_vib *vib,
				 u8 *data, u16 reg)
{
	int rc;

	rc = pm8058_read(vib->pm_chip, reg, data, 1);
	if (rc < 0)
		dev_warn(vib->dev, "Error reading pmic8058: %X - ret %X\n",
				reg, rc);

	return rc;
}
int pm8058_dump_mpp(struct seq_file *m, int curr_len, char *gpio_buffer)
{
	static const char *ctype[] = { "d_in", "d_out", "bi_dir", "a_in",
		"a_out", "sink", "dtest_sink", "dtest_out" };
	struct pm8058_chip *pm_chip;
	u8 type, state, ctrl;
	const char *label;
	int i, len;
	char gpio_buf[128];
	char *title_msg = "---------- PMIC 8058 MPP ----------";

	if (m) {
		seq_printf(m, "%s\n", title_msg);
	} else {
		pr_info("%s\n", title_msg);
		curr_len += sprintf(gpio_buffer + curr_len,
		"%s\n", title_msg);
	}

	pm_chip = dev_get_drvdata(pm8058_mpp_chip.dev);

	for (i = 0; i < PM8058_MPPS; i++) {

		memset(gpio_buf, 0, sizeof(gpio_buf));
		len = 0;

		pm8058_read(pm_chip, SSBI_MPP_CNTRL(i), &ctrl, 1);
		label = gpiochip_is_requested(&pm8058_mpp_chip, i);
		type = (ctrl & PM8058_MPP_TYPE_MASK) >>
			PM8058_MPP_TYPE_SHIFT;
		state = pm8058_mpp_get(&pm8058_mpp_chip, i);

		len += sprintf(gpio_buf + len, "GPIO[%2d]: ", i);
		len += sprintf(gpio_buf + len, "[TYPE]%10s, ", ctype[type]);
		len += sprintf(gpio_buf + len, "[VAL]%s, ", state? "HIGH" : " LOW");
		len += sprintf(gpio_buf + len, "[CTRL][0x%02x]", ctrl);

		gpio_buf[127] = '\0';
		pr_info("%s\n", gpio_buf);
		if (m) {
			seq_printf(m, "%s\n", gpio_buf);
		} else {
			pr_info("%s\n", gpio_buf);
			curr_len += sprintf(gpio_buffer +
			curr_len, "%s\n", gpio_buf);
		}

	}

	return curr_len;
}
static int pm8058_usb_voltage_lower_limit(void)
{
    u8 temp, old;
    int ret = 0;

    temp = 0x10;
    ret |= pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST, &temp, 1);
    ret |= pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TEST, &old, 1);
    old = old & ~BIT(IGNORE_LL);
    temp = 0x90  | (0xF & old);
    pr_debug("%s writing 0x%x to test\n", __func__, temp);
    ret |= pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST, &temp, 1);

    return ret;
}
Esempio n. 13
0
int pm8058_rtc0_alarm_irq_disable(void)
{
	int rc;
	uint8_t reg;

	rc = pm8058_read(PM8058_RTC_CTRL, &reg, 1);
	if (rc)
	{
		return rc;
	}
	reg = (reg & ~PM8058_RTC_ALARM_ENABLE);

	rc = pm8058_write(PM8058_RTC_CTRL, &reg, 1);
	if (rc) {
		return rc;
	}

	return rc;
}
Esempio n. 14
0
static void pm8058_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
	static const char *ctype[] = { "d_in", "d_out", "bi_dir", "a_in",
		"a_out", "sink", "dtest_sink", "dtest_out" };
	struct pm8058_chip *pm_chip = dev_get_drvdata(chip->dev);
	u8 type, state, ctrl;
	const char *label;
	int i;

	for (i = 0; i < PM8058_MPPS; i++) {
		pm8058_read(pm_chip, SSBI_MPP_CNTRL(i), &ctrl, 1);
		label = gpiochip_is_requested(chip, i);
		type = (ctrl & PM8058_MPP_TYPE_MASK) >>
			PM8058_MPP_TYPE_SHIFT;
		state = pm8058_mpp_get(chip, i);
		seq_printf(s, "gpio-%-3d (%-12.12s) %-10.10s"
				" %s 0x%02x\n",
				chip->base + i,
				label ? label : "--",
				ctype[type],
				state ? "hi" : "lo",
				ctrl);
	}
}
Esempio n. 15
0
static int pm8058_configure_othc(struct pm8058_othc *dd)
{
	int rc;
	u8 reg, value;
	u32 value1;
	u16 base_addr = dd->othc_base;
	struct othc_hsed_config *hsed_config = dd->othc_pdata->hsed_config;

	/* Intialize the OTHC module */
	/* Control Register 1*/
	rc = pm8058_read(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* set iDAC high current threshold */
	value = (hsed_config->othc_highcurr_thresh_uA / 100) - 2;
	reg =  (reg & PM8058_OTHC_HIGH_CURR_MASK) | value;

	rc = pm8058_write(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 2*/
	rc = pm8058_read(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = dd->othc_pdata->micbias_enable;
	reg &= PM8058_OTHC_EN_SIG_MASK;
	reg |= (value << PM8058_OTHC_EN_SIG_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_hyst_prediv_us << 10) / USEC_PER_SEC;
	while (value1 != 0) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 7) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_PREDIV_MASK;
	reg |= (value << PM8058_OTHC_HYST_PREDIV_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_period_clkdiv_us << 10) / USEC_PER_SEC;
	while (value1 != 1) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 8) {
		pr_err("%s: Invalid input argument - othc_period_clkdiv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg &  PM8058_OTHC_CLK_PREDIV_MASK) | (value - 1);

	rc = pm8058_write(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 3 */
	rc = pm8058_read(dd->pm_chip, base_addr + 2 , &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = hsed_config->othc_hyst_clk_us /
					hsed_config->othc_hyst_prediv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_CLK_MASK;
	reg |= value << PM8058_OTHC_HYST_CLK_SHIFT;

	value = hsed_config->othc_period_clk_us /
					hsed_config->othc_period_clkdiv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg & PM8058_OTHC_PERIOD_CLK_MASK) | value;

	rc = pm8058_write(dd->pm_chip, base_addr + 2, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Configure the ADC if n_switch_headset is supported */
	if (dd->othc_support_n_switch == true) {
		rc = adc_channel_open(dd->switch_config->adc_channel,
							&dd->adc_handle);
		if (rc) {
			pr_err("%s: Unable to open ADC channel\n", __func__);
			return -ENODEV;
		}
		pr_debug("%s: ADC channel open SUCCESS\n", __func__);
	}

	return 0;
}
static int pm8058_configure_othc(struct pm8058_othc *dd)
{
	int rc;
	u8 reg, value;
	u32 value1;
	u16 base_addr = dd->othc_base;
	struct othc_hsed_config *hsed_config = dd->othc_pdata->hsed_config;

	/* Intialize the OTHC module */
	/* Control Register 1*/
	rc = pm8058_read(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	if (hsed_config->othc_headset == OTHC_HEADSET_NO) {
		/* set iDAC high current threshold */
		value = (hsed_config->othc_highcurr_thresh_uA / 100) - 2;
		reg =  (reg & PM8058_OTHC_HIGH_CURR_MASK) | value;
	} else {
		/* set iDAC low current threshold */
		value = (hsed_config->othc_lowcurr_thresh_uA / 10) - 1;
		reg &= PM8058_OTHC_LOW_CURR_MASK;
		reg |= (value << PM8058_OTHC_LOW_CURR_SHIFT);
	}

	rc = pm8058_write(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 2*/
	rc = pm8058_read(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = dd->othc_pdata->micbias_enable;
	reg &= PM8058_OTHC_EN_SIG_MASK;
	reg |= (value << PM8058_OTHC_EN_SIG_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_hyst_prediv_us << 10) / USEC_PER_SEC;
	while (value1 != 0) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 7) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_PREDIV_MASK;
	reg |= (value << PM8058_OTHC_HYST_PREDIV_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_period_clkdiv_us << 10) / USEC_PER_SEC;
	while (value1 != 1) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 8) {
		pr_err("%s: Invalid input argument - othc_period_clkdiv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg &  PM8058_OTHC_CLK_PREDIV_MASK) | (value - 1);

	rc = pm8058_write(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 3 */
	rc = pm8058_read(dd->pm_chip, base_addr + 2 , &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = hsed_config->othc_hyst_clk_us /
					hsed_config->othc_hyst_prediv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_CLK_MASK;
	reg |= value << PM8058_OTHC_HYST_CLK_SHIFT;

	value = hsed_config->othc_period_clk_us /
					hsed_config->othc_period_clkdiv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg & PM8058_OTHC_PERIOD_CLK_MASK) | value;

	rc = pm8058_write(dd->pm_chip, base_addr + 2, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	return 0;
}
static int irda_uart_release(struct inode *inode, struct file *file)
{
	down(&irc->sem);
	printk(KERN_INFO DRV_NAME ": %s\n", __func__);

	/* Decrement refcount */
	irc->refcount--;

	/* Check refcount */
	if (irc->refcount == 0) {
		/* do discard flush */
		if (irc->rx_state == IRDA_RX_START) {
			irc->rx_state = IRDA_RX_IDLE;
			msm_dmov_stop_cmd(irc->pfdata->chan_uartdm_rx,
						&irc->rxdmov_cmd, 0);
		}

		/* Deactivate RXLEV IRQ */
		irc->imr_reg &= ~BIT_RXLEV;
		msm_uartdm_write(UARTDM_IMR, irc->imr_reg);
		/* (state change)--> IRDA_UART_OPEN */
		irc->state = IRDA_UART_CLOSE;
		/* Disable the IRDA transceiver */
		msm_uartdm_write(UARTDM_IRDA, IRUART_IRDA_DISABLE);
		/* Disable Transmitter and Receiver */
		msm_uartdm_write(UARTDM_CR, BIT_UART_TX_DISABLE);
		msm_uartdm_write(UARTDM_CR, BIT_UART_RX_DISABLE);

		/* Desable TXDM and RXDM mode */
		msm_uartdm_write(UARTDM_DMEN, IRUART_IRDA_DISABLE);

		/* Wait 1usec */
		udelay(1);
		/* Setting PM power off (Hig) */
		pm8058_gpio_config(irc->pfdata->gpio_pow,
				   irc->pfdata->gpio_pwcfg_hig);

		/* Clear UART SW buffer */
		irda_txbuf_clear(&irc->txbuf);
		irda_rxbuf_clear(&irc->rxbuf);
		/* Reset TX and RX*/
		msm_uartdm_write(UARTDM_CR, CCMD_RESET_RECEIVER);
		msm_uartdm_write(UARTDM_CR, CCMD_RESET_TRANSMITTER);
		msm_uartdm_write(UARTDM_CR, CCMD_RESET_ERROR_STATUS);
		msm_uartdm_write(UARTDM_CR, CCMD_RESET_STALE_INTERRUPT);
		/* Release DMOV data */
		dma_free_coherent(NULL, sizeof(dmov_box),
					irc->txbox, irc->mapped_txbox);
		dma_free_coherent(NULL, sizeof(dmov_box),
					irc->rxbox, irc->mapped_rxbox);
		dma_free_coherent(NULL, sizeof(u32 *),
					irc->txbox_ptr, irc->mapped_txbox_ptr);
		dma_free_coherent(NULL, sizeof(u32 *),
					irc->rxbox_ptr, irc->mapped_rxbox_ptr);
		/* UARTDM clock stop */
		clk_disable(irc->clk_uartdm);
		/* UARTDM iounmap */
		if (irc->iores_uartdm)
			release_mem_region((u32) irc->pfdata->paddr_uartdm,
						UARTDM_SIZE);
		iounmap(irc->vaddr_uartdm);
		/* Remove IRQ for UARTDM */
		free_irq(irc->pfdata->irq_uartdm, irc);
		/* Remove tasklets for UARTDM */
		tasklet_kill(&irc->tasklet_rxfer_s);
		tasklet_kill(&irc->tasklet_rxfer_e);
		tasklet_kill(&irc->tasklet_txfer);
		/* PM8058 UART MUX reset */
		pm8058_misc_control(irc->nfcdev->pm_chip,
				PM8058_UART_MUX_MASK, PM8058_UART_MUX_NO);
		{
			u8 misc = 0x0;
			int ret = pm8058_read(irc->nfcdev->pm_chip,
						SSBI_REG_ADDR_MISC, &misc, 1);
			if (ret)
				printk(KERN_ERR DRV_NAME
					": cannot read pm8058 UART MUX reg.\n");
			else
				printk(KERN_INFO DRV_NAME
					": misc register = %x\n", misc);
		}
	}
	printk(KERN_INFO DRV_NAME ": Closed. Refcount = %d\n", irc->refcount);
	up(&irc->sem);

	return 0;
}
static int irda_uart_open(struct inode *inode, struct file *file)
{
	int ret;
	u8 misc = 0x0;

	down(&irc->sem);
	printk(KERN_INFO DRV_NAME ": %s\n", __func__);

	/* Check refcount */
	if (irc->refcount > 0) {
		irc->refcount++;
		printk(KERN_INFO DRV_NAME
			": refirence counter count up(%d).\n", irc->refcount);
		up(&irc->sem);
		return 0;
	}
	/* PM8058-NFC Request */
	irc->nfcdev = pm8058_nfc_request();
	if (irc->nfcdev == NULL) {
		printk(KERN_ERR DRV_NAME ": pm8058 nfc not found.\n");
		ret = -ENODEV;
		goto error_pm_nfc_request;
	}

	/* PM8058 UART MUX setting */
	ret = pm8058_read(irc->nfcdev->pm_chip, SSBI_REG_ADDR_MISC, &misc, 1);
	if (ret)
		printk(KERN_ERR DRV_NAME
			": cannot read pm8058 UART MUX reg.\n");
	else
		printk(KERN_INFO DRV_NAME ": misc register = %x\n", misc);
	misc &= PM8058_UART_MUX_MASK;
	switch (misc) {
	case PM8058_UART_MUX_NO:
		pm8058_misc_control(irc->nfcdev->pm_chip,
				PM8058_UART_MUX_MASK, PM8058_UART_MUX_3);
		printk(KERN_INFO DRV_NAME
			": OK. UART MUX = neutral --> IrDA.\n");
		break;
	case PM8058_UART_MUX_1:
		printk(KERN_ERR DRV_NAME ": Now, uart_mux = 1 (FeliCa)\n");
		ret = -EBUSY;
		goto err_set_uart_mux;
	case PM8058_UART_MUX_2:
		printk(KERN_ERR DRV_NAME ": Now, uart_mux = 2 (unknown)\n");
		ret = -EBUSY;
		goto err_set_uart_mux;
	default:
		printk(KERN_ERR DRV_NAME ": UART MUX unavaible.\n");
		ret = -EIO;
		goto err_set_uart_mux;
	}

	/* init IMR value */
	irc->imr_reg = 0x0;

	/* init wait queue */
	init_waitqueue_head(&irc->wait_tx);
	init_waitqueue_head(&irc->wait_rx);

	/* init tasklet */
	tasklet_init(&irc->tasklet_rxfer_s, irda_uart_rxfer_start, 0);
	tasklet_init(&irc->tasklet_rxfer_e, irda_uart_rxfer_end,   0);
	tasklet_init(&irc->tasklet_txfer,   irda_uart_txfer_exec,  0);

	/* Register UARTDM IRQ */
	ret = request_irq(irc->pfdata->irq_uartdm, irda_uart_irq_handler,
				IRQF_TRIGGER_HIGH,  "irda_uart", irc);
	if (ret) {
		printk(KERN_ERR DRV_NAME ": request IRQ failed. (UARTDM)\n");
		goto err_request_irq_uart;
	}

	/* UARTDM ioremap */
	/* memory protection */
	irc->iores_uartdm = request_mem_region((u32) irc->pfdata->paddr_uartdm,
						UARTDM_SIZE, "irda_uart");
	if (!irc->iores_uartdm) {
		printk(KERN_ERR DRV_NAME
			": UARTDM request_mem_region failed.\n");
		ret = -EBUSY;
		goto err_request_mem_region;
	}
	irc->vaddr_uartdm = ioremap_nocache((u32) irc->pfdata->paddr_uartdm,
						UARTDM_SIZE);
	if (!irc->vaddr_uartdm) {
		printk(KERN_ERR DRV_NAME ": UARTDM ioremap failed.\n");
		ret = -ENOMEM;
		goto err_ioremap_uartdm;
	}

	/* UARTDM clock set and start */
	/* default 9600 bps */
	irc->bps = 9600;
	clk_set_rate(irc->clk_uartdm, IRUART_UARTDM_CLK(9600));
	clk_enable(irc->clk_uartdm);
	msm_uartdm_write(UARTDM_CSR, IRUART_DEF_BAUDRATE_CSR);

	/* UARTDM register setting */
	/* Data-stop-parity setting (MR2) */
	msm_uartdm_write(UARTDM_MR2, IRUART_DATA_STOP_PARITY);

	/* RX&TX wartermark setting */
	msm_uartdm_write(UARTDM_TFWR, 0x0);
	msm_uartdm_write(UARTDM_RFWR, 0x0);

	/* Stale time-out setting */
	msm_uartdm_write(UARTDM_IPR,
			(IRUART_DEF_RXSTALE & BIT_STALE_TIMEOUT_LSB)
			| ((IRUART_DEF_RXSTALE << 2) & BIT_STALE_TIMEOUT_MSB));

	/* Enable TXDM and RXDM mode */
	msm_uartdm_write(UARTDM_DMEN, BIT_RX_DM_EN|BIT_TX_DM_EN);

	/* Enable the IRDA transceiver */
	msm_uartdm_write(UARTDM_IRDA, IRUART_IRDA_EN);

	/* TX DMOV mapping */
	irc->txbox = dma_alloc_coherent(NULL, sizeof(dmov_box),
					&irc->mapped_txbox, GFP_KERNEL);
	if (!irc->txbox) {
		printk(KERN_ERR DRV_NAME ": no enough mem for TX DMOV(1).\n");
		ret = -ENOMEM;
		goto err_alloc_txbox;
	}
	irc->txbox_ptr = dma_alloc_coherent(NULL, sizeof(u32 *),
					&irc->mapped_txbox_ptr, GFP_KERNEL);
	if (!irc->txbox_ptr) {
		printk(KERN_ERR DRV_NAME ": no enough mem for TX DMOV(2).\n");
		ret = -ENOMEM;
		goto err_alloc_txbox_ptr;
	}
	*irc->txbox_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(irc->mapped_txbox);
	irc->txdmov_cmd.cmdptr = DMOV_CMD_ADDR(irc->mapped_txbox_ptr);
	irc->txdmov_cmd.complete_func = irda_txdmov_callback;
	irc->txdmov_cmd.cmdptr = DMOV_CMD_ADDR(irc->mapped_txbox_ptr);
	irc->txbox->cmd =
		CMD_LC
		| CMD_DST_CRCI(irc->pfdata->crci_uartdm_tx) | CMD_MODE_BOX;
	/* TX DMOV BOX command */
	irc->txbox->src_row_addr = 0x0;
	irc->txbox->dst_row_addr = (u32)irc->pfdata->paddr_uartdm + UARTDM_TF;
	irc->txbox->src_dst_len = (UARTDM_BURST_SIZE<<16)|UARTDM_BURST_SIZE;
	irc->txbox->num_rows = 0x0;
	irc->txbox->row_offset = (UARTDM_BURST_SIZE<<16);

	/* RX DMOV mapping */
	irc->rxbox = dma_alloc_coherent(NULL, sizeof(dmov_box),
					&irc->mapped_rxbox, GFP_KERNEL);
	if (!irc->rxbox) {
		printk(KERN_ERR DRV_NAME ": no enough mem for RX DMOV(1).\n");
		ret = -ENOMEM;
		goto err_alloc_rxbox;
	}
	irc->rxbox_ptr = dma_alloc_coherent(NULL, sizeof(u32 *),
					&irc->mapped_rxbox_ptr, GFP_KERNEL);
	if (!irc->rxbox_ptr) {
		printk(KERN_ERR DRV_NAME ": no enough mem for RX DMOV(2).\n");
		ret = -ENOMEM;
		goto err_alloc_rxbox_ptr;
	}
	*irc->rxbox_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(irc->mapped_rxbox);
	irc->rxdmov_cmd.cmdptr = DMOV_CMD_ADDR(irc->mapped_rxbox_ptr);
	irc->rxdmov_cmd.complete_func = irda_rxdmov_callback;
	irc->rxdmov_cmd.cmdptr = DMOV_CMD_ADDR(irc->mapped_rxbox_ptr);
	irc->rxbox->cmd =
		CMD_LC
		| CMD_SRC_CRCI(irc->pfdata->crci_uartdm_rx)
		| CMD_MODE_BOX;
	/* RX DMOV BOX command */
	irc->rxbox->src_row_addr =
		(u32)irc->pfdata->paddr_uartdm + UARTDM_RF;
	irc->rxbox->dst_row_addr = 0x0;
	irc->rxbox->src_dst_len = (UARTDM_BURST_SIZE<<16)|UARTDM_BURST_SIZE;
	irc->rxbox->num_rows =
		(IRUART_SW_RXBUF_SIZE >> 4 << 16) | IRUART_SW_RXBUF_SIZE >> 4;
	irc->rxbox->row_offset = UARTDM_BURST_SIZE;

	/* Enable Command Register Protection */
	msm_uartdm_write(UARTDM_CR, GCMD_CR_PROTECTION_ENABLE);

	/* Reset TX and RX */
	msm_uartdm_write(UARTDM_CR, CCMD_RESET_RECEIVER);
	msm_uartdm_write(UARTDM_CR, CCMD_RESET_TRANSMITTER);
	msm_uartdm_write(UARTDM_CR, CCMD_RESET_ERROR_STATUS);
	msm_uartdm_write(UARTDM_CR, CCMD_RESET_STALE_INTERRUPT);

	/* Setting PM power on (Low) */
	ret = pm8058_gpio_config(irc->pfdata->gpio_pow,
				 irc->pfdata->gpio_pwcfg_low);
	if (ret) {
		printk(KERN_ERR DRV_NAME ": pmic gpio write failed\n");
		goto err_gpio_config;
	}
	/* Wait 200usec */
	udelay(200);

	/* Enable Transmitter and Receiver */
	msm_uartdm_write(UARTDM_CR, BIT_UART_TX_EN);
	msm_uartdm_write(UARTDM_CR, BIT_UART_RX_EN);

	/* Clear UART SW buffer */
	irda_txbuf_clear(&irc->txbuf);
	irda_rxbuf_clear(&irc->rxbuf);

	/* init Overflow flag */
	irc->rx_overflow = IRDA_NORMAL;

	/* Increment refcount */
	irc->refcount++;

	/* (state change)--> IRDA_UART_OPEN */
	irc->state = IRDA_UART_OPEN;
	irc->rx_state = IRDA_RX_IDLE;

	printk(KERN_INFO DRV_NAME
		": succecssfly opened, refcount = %d\n", irc->refcount);

	/* Activate RXLEV IRQ */
	irc->imr_reg |= BIT_RXLEV;
	msm_uartdm_write(UARTDM_IMR, irc->imr_reg);

	up(&irc->sem);
	return 0;

/* Error handling */
err_gpio_config:
	dma_free_coherent(NULL,
			sizeof(u32 *), irc->rxbox_ptr, irc->mapped_txbox_ptr);
err_alloc_rxbox_ptr:
	dma_free_coherent(NULL,
			sizeof(dmov_box), irc->rxbox, irc->mapped_rxbox);
err_alloc_rxbox:
	dma_free_coherent(NULL,
			sizeof(u32 *), irc->txbox_ptr, irc->mapped_txbox_ptr);
err_alloc_txbox_ptr:
	dma_free_coherent(NULL,
			sizeof(dmov_box), irc->txbox, irc->mapped_txbox);
err_alloc_txbox:
	msm_uartdm_write(UARTDM_IRDA, IRUART_IRDA_DISABLE);
	clk_disable(irc->clk_uartdm);
	iounmap(irc->vaddr_uartdm);
err_ioremap_uartdm:
	release_mem_region((u32) irc->pfdata->paddr_uartdm, UARTDM_SIZE);
err_request_mem_region:
	free_irq(irc->pfdata->irq_uartdm, irc);
err_request_irq_uart:
	tasklet_kill(&irc->tasklet_rxfer_s);
	tasklet_kill(&irc->tasklet_rxfer_e);
	tasklet_kill(&irc->tasklet_txfer);
	pm8058_misc_control(irc->nfcdev->pm_chip,
				PM8058_UART_MUX_MASK, PM8058_UART_MUX_NO);
err_set_uart_mux:
error_pm_nfc_request:
	up(&irc->sem);
	return ret;
}
Esempio n. 19
0
/*
 * keypad controller should be initialized in the following sequence
 * only, otherwise it might get into FSM stuck state.
 *
 * - Initialize keypad control parameters, like no. of rows, columns,
 *   timing values etc.,
 * - configure rows and column gpios pull up/down.
 * - set irq edge type.
 * - enable the keypad controller.
 */
static int __devinit pmic8058_kp_probe(struct platform_device *pdev)
{
	struct pmic8058_keypad_data *pdata = pdev->dev.platform_data;
	struct pmic8058_kp *kp;
	int rc, i;
	unsigned short *keycodes;
	u8 ctrl_val;

	if (!pdata || !pdata->num_cols || !pdata->num_rows ||
		pdata->num_cols > MATRIX_MAX_COLS ||
		pdata->num_rows > MATRIX_MAX_ROWS ||
		!pdata->keymap) {
		dev_err(&pdev->dev, "invalid platform data\n");
		return -EINVAL;
	}

	if (pdata->rows_gpio_start < 0 || pdata->cols_gpio_start < 0) {
		dev_err(&pdev->dev, "invalid gpio_start platform data\n");
		return -EINVAL;
	}

	if (!pdata->scan_delay_ms || pdata->scan_delay_ms > MAX_SCAN_DELAY
		|| pdata->scan_delay_ms < MIN_SCAN_DELAY ||
		!is_power_of_2(pdata->scan_delay_ms)) {
		dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
		return -EINVAL;
	}

	rc = pm8058_read(PM8058_REV, &rev, 1);
	pr_info("PMIC4 is at %X revision\n", rev);

	if (rev == PMIC8058_REV_A0) {
		if (!pdata->debounce_ms || !is_power_of_2(pdata->debounce_ms)
				|| pdata->debounce_ms > MAX_DEBOUNCE_A0_TIME
				|| pdata->debounce_ms < MIN_DEBOUNCE_A0_TIME) {
			dev_err(&pdev->dev, "invalid debounce time supplied\n");
			return -EINVAL;
		}
	} else {
		if (!pdata->debounce_ms || ((pdata->debounce_ms % 5) != 0)
				|| pdata->debounce_ms > MAX_DEBOUNCE_B0_TIME
				|| pdata->debounce_ms < MIN_DEBOUNCE_B0_TIME) {
			dev_err(&pdev->dev, "invalid debounce time supplied\n");
			return -EINVAL;
		}
	}

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

	keycodes = kzalloc(MATRIX_MAX_SIZE * sizeof(keycodes), GFP_KERNEL);
	if (!keycodes) {
		rc = -ENOMEM;
		goto err_alloc_mem;
	}

	platform_set_drvdata(pdev, kp);

	kp->pdata	= pdata;
	kp->dev		= &pdev->dev;
	kp->keycodes	= keycodes;

	/* REVISIT: actual revision with the fix */
	if (rev <= PMIC8058_REV_B0)
		kp->flags |= KEYF_FIX_LAST_ROW;

	kp->input = input_allocate_device();
	if (!kp->input) {
		dev_err(&pdev->dev, "unable to allocate input device\n");
		rc = -ENOMEM;
		goto err_alloc_device;
	}

	kp->key_sense_irq = platform_get_irq(pdev, 0);
	if (kp->key_sense_irq < 0) {
		dev_err(&pdev->dev, "unable to get keypad sense irq\n");
		rc = -ENXIO;
		goto err_get_irq;
	}

	kp->key_stuck_irq = platform_get_irq(pdev, 1);
	if (kp->key_stuck_irq < 0) {
		dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
		rc = -ENXIO;
		goto err_get_irq;
	}

	if (pdata->input_name)
		kp->input->name = pdata->input_name;
	else
		kp->input->name = "PMIC8058 keypad";

	if (pdata->input_phys_device)
		kp->input->phys = pdata->input_phys_device;
	else
		kp->input->phys = "pmic8058_keypad/input0";

	kp->input->dev.parent	= &pdev->dev;

	kp->input->id.bustype	= BUS_HOST;
	kp->input->id.version	= 0x0001;
	kp->input->id.product	= 0x0001;
	kp->input->id.vendor	= 0x0001;

	kp->input->evbit[0]	= BIT_MASK(EV_KEY);

	if (pdata->rep)
		__set_bit(EV_REP, kp->input->evbit);

	kp->input->keycode	= keycodes;
	kp->input->keycodemax	= MATRIX_MAX_SIZE;
	kp->input->keycodesize	= sizeof(*keycodes);

	/* build keycodes for faster scanning */
	for (i = 0; i < pdata->keymap_size; i++) {
		unsigned int row = KEY_ROW(pdata->keymap[i]);
		unsigned int col = KEY_COL(pdata->keymap[i]);
		unsigned short keycode = KEY_VAL(pdata->keymap[i]);

		keycodes[(row << 3) + col] = keycode;
		__set_bit(keycode, kp->input->keybit);
	}
	__clear_bit(KEY_RESERVED, kp->input->keybit);

	input_set_capability(kp->input, EV_MSC, MSC_SCAN);
	input_set_drvdata(kp->input, kp);

	rc = input_register_device(kp->input);
	if (rc < 0) {
		dev_err(&pdev->dev, "unable to register keypad input device\n");
		goto err_get_irq;
	}

	/* initialize keypad state */
	memset(kp->keystate, 0xff, sizeof(kp->keystate));

	rc = pmic8058_kpd_init(kp);
	if (rc < 0) {
		dev_err(&pdev->dev, "unable to initialize keypad controller\n");
		goto err_kpd_init;
	}

	rc = pm8058_gpio_config_kypd_sns(pdata->cols_gpio_start,
						 pdata->num_cols);
	if (rc < 0) {
		dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
		goto err_gpio_config;
	}

	rc = pm8058_gpio_config_kypd_drv(pdata->rows_gpio_start,
						 pdata->num_rows);
	if (rc < 0) {
		dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
		goto err_gpio_config;
	}

	rc = request_irq(kp->key_sense_irq, pmic8058_kp_irq,
				 IRQF_TRIGGER_RISING, "pmic-keypad", kp);
	if (rc < 0) {
		dev_err(&pdev->dev, "failed to request keypad sense irq\n");
		goto err_req_sense_irq;
	}

	rc = request_irq(kp->key_stuck_irq, pmic8058_kp_stuck_irq,
				 IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp);
	if (rc < 0) {
		dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
		goto err_req_stuck_irq;
	}

	rc = pmic8058_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
	ctrl_val |= KEYP_CTRL_KEYP_EN;
	rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL);

	__dump_kp_regs(kp, "probe");

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

	return 0;

err_req_stuck_irq:
	free_irq(kp->key_sense_irq, NULL);
err_req_sense_irq:
err_gpio_config:
err_kpd_init:
	input_unregister_device(kp->input);
	kp->input = NULL;
err_get_irq:
	input_free_device(kp->input);
err_alloc_device:
	kfree(keycodes);
err_alloc_mem:
	kfree(kp);
	return rc;
}