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, ®, 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, ®, 1); if (rc < 0) { pr_err("PM8058 write failed\n"); return rc; } return rc; }
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, ®, 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; }
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; }
int pm8058_rtc0_alarm_irq_disable(void) { int rc; uint8_t reg; rc = pm8058_read(PM8058_RTC_CTRL, ®, 1); if (rc) { return rc; } reg = (reg & ~PM8058_RTC_ALARM_ENABLE); rc = pm8058_write(PM8058_RTC_CTRL, ®, 1); if (rc) { return rc; } return rc; }
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); } }
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, ®, 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, ®, 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, ®, 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, ®, 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 , ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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 , ®, 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, ®, 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; }
/* * 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; }