static int palmas_extreg_init(struct palmas *palmas, int id, struct palmas_reg_init *reg_init) { unsigned int addr; int ret; unsigned int val = 0; struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata; struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; addr = rinfo->ctrl_addr; if (reg_init->mode_sleep) val = PALMAS_REGEN1_CTRL_MODE_SLEEP; ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, addr, PALMAS_REGEN1_CTRL_MODE_SLEEP, val); if (ret < 0) { dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n", addr, ret); return ret; } if (reg_init->roof_floor) { /* Enable externally controlled regulator */ ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, addr, PALMAS_REGEN1_CTRL_MODE_ACTIVE, PALMAS_REGEN1_CTRL_MODE_ACTIVE); if (ret < 0) { dev_err(palmas->dev, "Resource Register 0x%02x update failed %d\n", addr, ret); return ret; } return palmas_regulator_config_external(palmas, id, reg_init); } return 0; }
static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset) { struct palmas_gpio *pg = gpiochip_get_data(gc); struct palmas *palmas = pg->palmas; int ret; unsigned int reg; int gpio16 = (offset/8); offset %= 8; reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0); if (ret < 0) dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg, ret); return ret; }
static int palmas_ldo_init(struct palmas *palmas, int id, struct palmas_reg_init *reg_init) { unsigned int reg; unsigned int addr; int ret; struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata; struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; addr = rinfo->ctrl_addr; ret = palmas_ldo_read(palmas, addr, ®); if (ret) return ret; if (reg_init->warm_reset) reg |= PALMAS_LDO1_CTRL_WR_S; else reg &= ~PALMAS_LDO1_CTRL_WR_S; if (reg_init->mode_sleep) reg |= PALMAS_LDO1_CTRL_MODE_SLEEP; else reg &= ~PALMAS_LDO1_CTRL_MODE_SLEEP; ret = palmas_ldo_write(palmas, addr, reg); if (ret) return ret; if (reg_init->roof_floor) { /* Enable externally controlled regulator */ ret = palmas_update_bits(palmas, PALMAS_LDO_BASE, addr, PALMAS_LDO1_CTRL_MODE_ACTIVE, PALMAS_LDO1_CTRL_MODE_ACTIVE); if (ret < 0) { dev_err(palmas->dev, "LDO Register 0x%02x update failed %d\n", addr, ret); return ret; } return palmas_regulator_config_external(palmas, id, reg_init); } return 0; }
static int palmas_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct palmas *palmas; struct palmas_platform_data *pdata; struct device_node *node = i2c->dev.of_node; int ret = 0, i; unsigned int reg, addr, *features; int slave; const struct of_device_id *match; pdata = dev_get_platdata(&i2c->dev); if (node && !pdata) { pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; palmas_dt_to_pdata(i2c, pdata); } if (!pdata) return -EINVAL; palmas = devm_kzalloc(&i2c->dev, sizeof(struct palmas), GFP_KERNEL); if (palmas == NULL) return -ENOMEM; i2c_set_clientdata(i2c, palmas); palmas->dev = &i2c->dev; palmas->irq = i2c->irq; match = of_match_device(of_match_ptr(of_palmas_match_tbl), &i2c->dev); if (!match) return -ENODATA; features = (unsigned int *)match->data; palmas->features = *features; for (i = 0; i < PALMAS_NUM_CLIENTS; i++) { if (i == 0) palmas->i2c_clients[i] = i2c; else { palmas->i2c_clients[i] = i2c_new_dummy(i2c->adapter, i2c->addr + i); if (!palmas->i2c_clients[i]) { dev_err(palmas->dev, "can't attach client %d\n", i); ret = -ENOMEM; goto err; } palmas->i2c_clients[i]->dev.of_node = of_node_get(node); } palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], &palmas_regmap_config[i]); if (IS_ERR(palmas->regmap[i])) { ret = PTR_ERR(palmas->regmap[i]); dev_err(palmas->dev, "Failed to allocate regmap %d, err: %d\n", i, ret); goto err; } } if (!palmas->irq) { dev_warn(palmas->dev, "IRQ missing: skipping irq request\n"); goto no_irq; } /* Change interrupt line output polarity */ if (pdata->irq_flags & IRQ_TYPE_LEVEL_HIGH) reg = PALMAS_POLARITY_CTRL_INT_POLARITY; else reg = 0; ret = palmas_update_bits(palmas, PALMAS_PU_PD_OD_BASE, PALMAS_POLARITY_CTRL, PALMAS_POLARITY_CTRL_INT_POLARITY, reg); if (ret < 0) { dev_err(palmas->dev, "POLARITY_CTRL updat failed: %d\n", ret); goto err; } /* Change IRQ into clear on read mode for efficiency */ slave = PALMAS_BASE_TO_SLAVE(PALMAS_INTERRUPT_BASE); addr = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, PALMAS_INT_CTRL); reg = PALMAS_INT_CTRL_INT_CLEAR; regmap_write(palmas->regmap[slave], addr, reg); ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq, IRQF_ONESHOT | pdata->irq_flags, 0, &palmas_irq_chip, &palmas->irq_data); if (ret < 0) goto err; no_irq: slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE); addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, PALMAS_PRIMARY_SECONDARY_PAD1); if (pdata->mux_from_pdata) { reg = pdata->pad1; ret = regmap_write(palmas->regmap[slave], addr, reg); if (ret) goto err_irq; } else { ret = regmap_read(palmas->regmap[slave], addr, ®); if (ret) goto err_irq; } if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0)) palmas->gpio_muxed |= PALMAS_GPIO_0_MUXED; if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK)) palmas->gpio_muxed |= PALMAS_GPIO_1_MUXED; else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) == (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT)) palmas->led_muxed |= PALMAS_LED1_MUXED; else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) == (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT)) palmas->pwm_muxed |= PALMAS_PWM1_MUXED; if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK)) palmas->gpio_muxed |= PALMAS_GPIO_2_MUXED; else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) == (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT)) palmas->led_muxed |= PALMAS_LED2_MUXED; else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) == (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT)) palmas->pwm_muxed |= PALMAS_PWM2_MUXED; if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3)) palmas->gpio_muxed |= PALMAS_GPIO_3_MUXED; addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, PALMAS_PRIMARY_SECONDARY_PAD2); if (pdata->mux_from_pdata) { reg = pdata->pad2; ret = regmap_write(palmas->regmap[slave], addr, reg); if (ret) goto err_irq; } else { ret = regmap_read(palmas->regmap[slave], addr, ®); if (ret) goto err_irq; } if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4)) palmas->gpio_muxed |= PALMAS_GPIO_4_MUXED; if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK)) palmas->gpio_muxed |= PALMAS_GPIO_5_MUXED; if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6)) palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED; if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK)) palmas->gpio_muxed |= PALMAS_GPIO_7_MUXED; dev_info(palmas->dev, "Muxing GPIO %x, PWM %x, LED %x\n", palmas->gpio_muxed, palmas->pwm_muxed, palmas->led_muxed); reg = pdata->power_ctrl; slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE); addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_POWER_CTRL); ret = regmap_write(palmas->regmap[slave], addr, reg); if (ret) goto err_irq; /* * If we are probing with DT do this the DT way and return here * otherwise continue and add devices using mfd helpers. */ if (node) { ret = of_platform_populate(node, NULL, NULL, &i2c->dev); if (ret < 0) goto err_irq; else return ret; } return ret; err_irq: regmap_del_irq_chip(palmas->irq, palmas->irq_data); err: return ret; }
static int palmas_gpadc_auto_conv_configure(struct palmas_gpadc *adc) { int adc_period, conv; int i; int ch0 = 0, ch1 = 0; int thres; int ret; if (!adc->auto_conv0_enable && !adc->auto_conv1_enable) return 0; adc_period = adc->auto_conversion_period; for (i = 0; i < 16; ++i) { if (((1000 * (1 << i))/32) > adc_period) break; } if (i > 0) i--; adc_period = i; ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE, PALMAS_GPADC_AUTO_CTRL, PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK, adc_period); if (ret < 0) { dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret); return ret; } conv = 0; if (adc->auto_conv0_enable) { int is_high; ch0 = adc->auto_conv0_data.adc_channel_number; conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN; conv |= (adc->auto_conv0_data.adc_shutdown ? PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0 : 0); if (adc->auto_conv0_data.adc_high_threshold > 0) { thres = adc->auto_conv0_data.adc_high_threshold; is_high = 0; } else { thres = adc->auto_conv0_data.adc_low_threshold; is_high = BIT(7); } ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE, PALMAS_GPADC_THRES_CONV0_LSB, thres & 0xFF); if (ret < 0) { dev_err(adc->dev, "THRES_CONV0_LSB write failed: %d\n", ret); return ret; } ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE, PALMAS_GPADC_THRES_CONV0_MSB, ((thres >> 8) & 0xF) | is_high); if (ret < 0) { dev_err(adc->dev, "THRES_CONV0_MSB write failed: %d\n", ret); return ret; } }
static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct palmas_gpadc *adc = iio_priv(indio_dev); int adc_chan = chan->channel; int ret = 0; if (adc_chan > PALMAS_ADC_CH_MAX) return -EINVAL; mutex_lock(&indio_dev->mlock); switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: ret = palmas_gpadc_read_prepare(adc, adc_chan); if (ret < 0) goto out; ret = palmas_gpadc_start_convertion(adc, adc_chan); if (ret < 0) { dev_err(adc->dev, "ADC start coversion failed\n"); goto out; } if (mask == IIO_CHAN_INFO_PROCESSED) ret = palmas_gpadc_get_calibrated_code( adc, adc_chan, ret); *val = ret; ret = IIO_VAL_INT; goto out; case IIO_CHAN_INFO_RAW_DUAL: case IIO_CHAN_INFO_PROCESSED_DUAL: ret = palmas_gpadc_read_prepare(adc, adc_chan); if (ret < 0) goto out; ret = palmas_gpadc_start_convertion(adc, adc_chan); if (ret < 0) { dev_err(adc->dev, "ADC start coversion failed\n"); goto out; } if (mask == IIO_CHAN_INFO_PROCESSED_DUAL) ret = palmas_gpadc_get_calibrated_code( adc, adc_chan, ret); *val = ret; if ((adc_chan == PALMAS_ADC_CH_IN3) && adc->ch3_dual_current && val2) { unsigned int reg_mask, reg_val; reg_mask = PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_MASK; reg_val = ((adc->ch3_current + 1) << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT); ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE, PALMAS_GPADC_CTRL1, reg_mask, reg_val); if (ret < 0) { dev_err(adc->dev, "CTRL1 update failed\n"); goto out; } ret = palmas_gpadc_start_convertion(adc, adc_chan); if (ret < 0) { dev_err(adc->dev, "ADC start coversion failed\n"); goto out; } if (mask == IIO_CHAN_INFO_PROCESSED_DUAL) ret = palmas_gpadc_get_calibrated_code( adc, adc_chan, ret); *val2 = ret; } ret = IIO_VAL_INT; goto out; } mutex_unlock(&indio_dev->mlock); return ret; out: palmas_gpadc_read_done(adc, adc_chan); mutex_unlock(&indio_dev->mlock); return ret; }
static int palmas_rtc_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_rtc *palmas_rtc = NULL; int ret; bool enable_bb_charging = false; bool high_bb_charging = false; if (pdev->dev.of_node) { enable_bb_charging = of_property_read_bool(pdev->dev.of_node, "ti,backup-battery-chargeable"); high_bb_charging = of_property_read_bool(pdev->dev.of_node, "ti,backup-battery-charge-high-current"); } palmas_rtc = devm_kzalloc(&pdev->dev, sizeof(struct palmas_rtc), GFP_KERNEL); if (!palmas_rtc) return -ENOMEM; /* Clear pending interrupts */ ret = palmas_clear_interrupts(&pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "clear RTC int failed, err = %d\n", ret); return ret; } palmas_rtc->dev = &pdev->dev; platform_set_drvdata(pdev, palmas_rtc); if (enable_bb_charging) { unsigned reg = PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG; if (high_bb_charging) reg = 0; ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_BACKUP_BATTERY_CTRL, PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG, reg); if (ret < 0) { dev_err(&pdev->dev, "BACKUP_BATTERY_CTRL update failed, %d\n", ret); return ret; } ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_BACKUP_BATTERY_CTRL, PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN, PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN); if (ret < 0) { dev_err(&pdev->dev, "BACKUP_BATTERY_CTRL update failed, %d\n", ret); return ret; } } /* Start RTC */ ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG, PALMAS_RTC_CTRL_REG_STOP_RTC, PALMAS_RTC_CTRL_REG_STOP_RTC); if (ret < 0) { dev_err(&pdev->dev, "RTC_CTRL write failed, err = %d\n", ret); return ret; } palmas_rtc->irq = platform_get_irq(pdev, 0); device_init_wakeup(&pdev->dev, 1); palmas_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &palmas_rtc_ops, THIS_MODULE); if (IS_ERR(palmas_rtc->rtc)) { ret = PTR_ERR(palmas_rtc->rtc); dev_err(&pdev->dev, "RTC register failed, err = %d\n", ret); return ret; } ret = devm_request_threaded_irq(&pdev->dev, palmas_rtc->irq, NULL, palmas_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, dev_name(&pdev->dev), palmas_rtc); if (ret < 0) { dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret); return ret; } return 0; }
static void palmas_power_off(void *drv_data) { struct palmas_pm *palmas_pm = drv_data; struct palmas *palmas = palmas_pm->palmas; unsigned int val; int i; int ret; unsigned int vbus_line_state, ldo_short_status2; palmas_allow_atomic_xfer(palmas); if (palmas_pm->need_rtc_power_on) palmas_auto_power_on(palmas_pm); for (i = 0; i < palmas_pm->num_int_mask_regs; ++i) { ret = palmas_write(palmas, PALMAS_INTERRUPT_BASE, palmas_pm->int_mask_reg_add[i], palmas_pm->int_mask_val[i]); if (ret < 0) dev_err(palmas_pm->dev, "register 0x%02x write failed: %d\n", palmas_pm->int_mask_reg_add[i], ret); ret = palmas_read(palmas, PALMAS_INTERRUPT_BASE, palmas_pm->int_status_reg_add[i], &val); if (ret < 0) dev_err(palmas_pm->dev, "register 0x%02x read failed: %d\n", palmas_pm->int_status_reg_add[i], ret); } if (palmas_pm->enable_boot_up_at_vbus || palmas_pm->need_usb_event_power_on) { ret = palmas_update_bits(palmas, PALMAS_INTERRUPT_BASE, PALMAS_INT3_MASK, PALMAS_INT3_MASK_VBUS | PALMAS_INT3_MASK_VBUS_OTG, 0); if (ret < 0) dev_err(palmas_pm->dev, "INT3_MASK update failed: %d\n", ret); } /* Mask all COLD RST condition */ palmas_write(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_SWOFF_COLDRST, 0x0); dev_info(palmas_pm->dev, "Powering off the device\n"); palmas_read(palmas, PALMAS_INTERRUPT_BASE, PALMAS_INT3_LINE_STATE, &vbus_line_state); if (palmas_pm->enable_boot_up_at_vbus && (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) { dev_info(palmas_pm->dev, "VBUS found, boot on system by timer interrupt\n"); ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_INTERRUPTS_REG, PALMAS_RTC_INTERRUPTS_REG_IT_TIMER, PALMAS_RTC_INTERRUPTS_REG_IT_TIMER); if (ret < 0) { dev_err(palmas_pm->dev, "RTC_INTERRUPTS update failed: %d\n", ret); goto poweroff_direct; } ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_INTERRUPTS_REG, PALMAS_RTC_INTERRUPTS_REG_EVERY_MASK, 0); if (ret < 0) { dev_err(palmas_pm->dev, "RTC_INTERRUPTS update failed: %d\n", ret); goto poweroff_direct; } ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG, PALMAS_RTC_CTRL_REG_STOP_RTC, PALMAS_RTC_CTRL_REG_STOP_RTC); if (ret < 0) { dev_err(palmas_pm->dev, "RTC_CTRL_REG update failed: %d\n", ret); goto poweroff_direct; } ret = palmas_update_bits(palmas, PALMAS_INTERRUPT_BASE, PALMAS_INT2_MASK, PALMAS_INT2_MASK_RTC_TIMER, 0); if (ret < 0) { dev_err(palmas_pm->dev, "INT2_MASK update failed: %d\n", ret); goto poweroff_direct; } } poweroff_direct: /* Errata * clear VANA short status before switch-off */ palmas_read(palmas, PALMAS_LDO_BASE, PALMAS_LDO_SHORT_STATUS2, &ldo_short_status2); /* Power off the device */ palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL, 1, 0); }
static void palmas_power_reset(void *drv_data) { struct palmas_pm *palmas_pm = drv_data; struct palmas *palmas = palmas_pm->palmas; unsigned int val; int i; int ret; palmas_allow_atomic_xfer(palmas); for (i = 0; i < palmas_pm->num_int_mask_regs; ++i) { ret = palmas_write(palmas, PALMAS_INTERRUPT_BASE, palmas_pm->int_mask_reg_add[i], palmas_pm->int_mask_val[i]); if (ret < 0) dev_err(palmas_pm->dev, "register 0x%02x write failed: %d\n", palmas_pm->int_mask_reg_add[i], ret); ret = palmas_read(palmas, PALMAS_INTERRUPT_BASE, palmas_pm->int_status_reg_add[i], &val); if (ret < 0) dev_err(palmas_pm->dev, "register 0x%02x read failed: %d\n", palmas_pm->int_status_reg_add[i], ret); } /* SW-WAR for ES Version 2.1, 2.0 and 1.0 */ if (palmas_is_es_version_or_less(palmas, 2, 1)) { dev_info(palmas_pm->dev, "Resetting Palmas through RTC\n"); ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL, PALMAS_DEV_CTRL_SW_RST, 0); if (ret < 0) { dev_err(palmas_pm->dev, "DEV_CTRL update failed: %d\n", ret); goto reset_direct; } ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_INTERRUPTS_REG, PALMAS_RTC_INTERRUPTS_REG_IT_TIMER, PALMAS_RTC_INTERRUPTS_REG_IT_TIMER); if (ret < 0) { dev_err(palmas_pm->dev, "RTC_INTERRUPTS update failed: %d\n", ret); goto reset_direct; } ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG, PALMAS_RTC_CTRL_REG_STOP_RTC, PALMAS_RTC_CTRL_REG_STOP_RTC); if (ret < 0) { dev_err(palmas_pm->dev, "RTC_CTRL_REG update failed: %d\n", ret); goto reset_direct; } ret = palmas_update_bits(palmas, PALMAS_INTERRUPT_BASE, PALMAS_INT2_MASK, PALMAS_INT2_MASK_RTC_TIMER, 0); if (ret < 0) { dev_err(palmas_pm->dev, "INT2_MASK update failed: %d\n", ret); goto reset_direct; } ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_SWOFF_COLDRST, PALMAS_SWOFF_COLDRST_SW_RST, PALMAS_SWOFF_COLDRST_SW_RST); if (ret < 0) { dev_err(palmas_pm->dev, "SWOFF_COLDRST update failed: %d\n", ret); goto reset_direct; } ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL, PALMAS_DEV_CTRL_SW_RST, PALMAS_DEV_CTRL_SW_RST); if (ret < 0) { dev_err(palmas_pm->dev, "DEV_CTRL update failed: %d\n", ret); goto reset_direct; } return; } reset_direct: dev_info(palmas_pm->dev, "Power reset the device\n"); palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_SWOFF_COLDRST, PALMAS_SWOFF_COLDRST_SW_RST, PALMAS_SWOFF_COLDRST_SW_RST); palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL, 0x2, 0x2); }
static int palmas_usb_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct palmas_usb *palmas_usb; int status; palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL); if (!palmas_usb) return -ENOMEM; if (node && !pdata) { palmas_usb->wakeup = of_property_read_bool(node, "ti,wakeup"); palmas_usb->enable_id_detection = of_property_read_bool(node, "ti,enable-id-detection"); palmas_usb->enable_vbus_detection = of_property_read_bool(node, "ti,enable-vbus-detection"); } else { palmas_usb->wakeup = true; palmas_usb->enable_id_detection = true; palmas_usb->enable_vbus_detection = true; if (pdata) palmas_usb->wakeup = pdata->wakeup; } palmas_usb->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id", GPIOD_IN); if (IS_ERR(palmas_usb->id_gpiod)) { dev_err(&pdev->dev, "failed to get id gpio\n"); return PTR_ERR(palmas_usb->id_gpiod); } palmas_usb->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus", GPIOD_IN); if (IS_ERR(palmas_usb->vbus_gpiod)) { dev_err(&pdev->dev, "failed to get vbus gpio\n"); return PTR_ERR(palmas_usb->vbus_gpiod); } if (palmas_usb->enable_id_detection && palmas_usb->id_gpiod) { palmas_usb->enable_id_detection = false; palmas_usb->enable_gpio_id_detection = true; } if (palmas_usb->enable_vbus_detection && palmas_usb->vbus_gpiod) { palmas_usb->enable_vbus_detection = false; palmas_usb->enable_gpio_vbus_detection = true; } if (palmas_usb->enable_gpio_id_detection) { u32 debounce; if (of_property_read_u32(node, "debounce-delay-ms", &debounce)) debounce = USB_GPIO_DEBOUNCE_MS; status = gpiod_set_debounce(palmas_usb->id_gpiod, debounce * 1000); if (status < 0) palmas_usb->sw_debounce_jiffies = msecs_to_jiffies(debounce); } INIT_DELAYED_WORK(&palmas_usb->wq_detectid, palmas_gpio_id_detect); palmas->usb = palmas_usb; palmas_usb->palmas = palmas; palmas_usb->dev = &pdev->dev; palmas_usb_wakeup(palmas, palmas_usb->wakeup); platform_set_drvdata(pdev, palmas_usb); palmas_usb->edev = devm_extcon_dev_allocate(&pdev->dev, palmas_extcon_cable); if (IS_ERR(palmas_usb->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); return -ENOMEM; } status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev); if (status) { dev_err(&pdev->dev, "failed to register extcon device\n"); return status; } if (palmas_usb->enable_id_detection) { palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_ID_OTG_IRQ); palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_ID_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq, NULL, palmas_id_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "palmas_usb_id", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->id_irq, status); return status; } } else if (palmas_usb->enable_gpio_id_detection) { palmas_usb->gpio_id_irq = gpiod_to_irq(palmas_usb->id_gpiod); if (palmas_usb->gpio_id_irq < 0) { dev_err(&pdev->dev, "failed to get id irq\n"); return palmas_usb->gpio_id_irq; } status = devm_request_threaded_irq(&pdev->dev, palmas_usb->gpio_id_irq, NULL, palmas_gpio_id_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "palmas_usb_id", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "failed to request handler for id irq\n"); return status; } } if (palmas_usb->enable_vbus_detection) { palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_OTG_IRQ); palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "palmas_usb_vbus", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->vbus_irq, status); return status; } } else if (palmas_usb->enable_gpio_vbus_detection) { /* remux GPIO_1 as VBUSDET */ status = palmas_update_bits(palmas, PALMAS_PU_PD_OD_BASE, PALMAS_PRIMARY_SECONDARY_PAD1, PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK, (1 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT)); if (status < 0) { dev_err(&pdev->dev, "can't remux GPIO1\n"); return status; } palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_OTG_IRQ); palmas_usb->gpio_vbus_irq = gpiod_to_irq(palmas_usb->vbus_gpiod); if (palmas_usb->gpio_vbus_irq < 0) { dev_err(&pdev->dev, "failed to get vbus irq\n"); return palmas_usb->gpio_vbus_irq; } status = devm_request_threaded_irq(&pdev->dev, palmas_usb->gpio_vbus_irq, NULL, palmas_vbus_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "palmas_usb_vbus", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "failed to request handler for vbus irq\n"); return status; } } palmas_enable_irq(palmas_usb); /* perform initial detection */ if (palmas_usb->enable_gpio_vbus_detection) palmas_vbus_irq_handler(palmas_usb->gpio_vbus_irq, palmas_usb); palmas_gpio_id_detect(&palmas_usb->wq_detectid.work); device_set_wakeup_capable(&pdev->dev, true); return 0; }