/* * Driver for TI,TP61280 DC/DC Boost Converter * * Copyright (c) 2014-2016, NVIDIA Corporation. All rights reserved. * * Author: Venkat Reddy Talla * Author: Laxman Dewangan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TPS61280_CONFIG 0x01 #define TPS61280_VOUTFLOORSET 0x02 #define TPS61280_VOUTROOFSET 0x03 #define TPS61280_ILIMSET 0x04 #define TPS61280_STATUS 0x05 #define TPS61280_E2PROMCTRL 0xFF #define TPS61280_ILIM_BASE 0x08 #define TPS61280_ILIM_OFFSET 1500 #define TPS61280_ILIM_STEP 500 #define TPS61280_ENABLE_ILIM 0x0 #define TPS61280_DISABLE_ILIM 0x20 #define TPS61280_VOUT_OFFSET 2850 #define TPS61280_VOUT_STEP 50 #define TPS61280_HOTDIE_TEMP 120 #define TPS61280_NORMAL_OPTEMP 40 #define TPS61280_CONFIG_MODE_MASK 0x03 #define TPS61280_CONFIG_MODE_VSEL 0x03 #define TPS61280_CONFIG_MODE_FORCE_PWM 0x02 #define TPS61280_CONFIG_MODE_AUTO_PWM 0x01 #define TPS61280_CONFIG_MODE_DEVICE 0x00 #define TPS61280_ILIM_MASK 0x0F #define TPS61280_VOUT_MASK 0x1F #define TPS61280_CONFIG_ENABLE_MASK 0x60 #define TPS61280_CONFIG_BYPASS_HW_CONTRL 0x00 #define TPS61280_CONFIG_BYPASS_AUTO_TRANS 0x20 #define TPS61280_CONFIG_BYPASS_PASS_TROUGH 0x40 #define TPS61280_CONFIG_BYPASS_SHUTDOWN 0x60 #define TPS61280_PGOOD_MASK BIT(0) #define TPS61280_FAULT_MASK BIT(1) #define TPS61280_ILIMBST_MASK BIT(2) #define TPS61280_ILIMPT_MASK BIT(3) #define TPS61280_OPMODE_MASK BIT(4) #define TPS61280_DCDCMODE_MASK BIT(5) #define TPS61280_HOTDIE_MASK BIT(6) #define TPS61280_THERMALSD_MASK BIT(7) #define TPS61280_MAX_VOUT_REG 2 #define TPS61280_VOUT_MASK 0x1F #define TPS61280_VOUT_VMIN 2850000 #define TPS61280_VOUT_VMAX 4400000 #define TPS61280_VOUT_VSTEP 50000 struct tps61280_platform_data { bool bypass_pin_ctrl; int bypass_gpio; bool vsel_controlled_mode; bool vsel_controlled_dvs; bool vsel_controlled_sleep; int vsel_gpio; int vsel_pin_default_state; bool enable_pin_ctrl; int enable_gpio; }; struct tps61280_chip { struct device *dev; struct i2c_client *client; struct regulator_dev *rdev; struct regmap *rmap; struct regulator_desc rdesc; struct tps61280_platform_data pdata; int lru_index[TPS61280_MAX_VOUT_REG]; int curr_vout_val[TPS61280_MAX_VOUT_REG]; int curr_vout_reg; int curr_vsel_gpio_val; int sleep_vout_reg; struct thermal_zone_device *tz_device; struct mutex mutex; struct regulator_init_data *rinit_data; int bypass_state; int current_mode; int enable_state; }; static const struct regmap_config tps61280_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 5, }; /* * find_voltage_set_register: Find new voltage configuration register (VOUT). * The finding of the new VOUT register will be based on the LRU mechanism. * Each VOUT register will have different voltage configured . This * Function will look if any of the VOUT register have requested voltage set * or not. * - If it is already there then it will make that register as most * recently used and return as found so that caller need not to set * the VOUT register but need to set the proper gpios to select this * VOUT register. * - If requested voltage is not found then it will use the least * recently mechanism to get new VOUT register for new configuration * and will return not_found so that caller need to set new VOUT * register and then gpios (both). */ static bool find_voltage_set_register(struct tps61280_chip *tps, int req_vsel, int *vout_reg, int *gpio_val) { int i; bool found = false; int new_vout_reg = tps->lru_index[TPS61280_MAX_VOUT_REG - 1]; int found_index = TPS61280_MAX_VOUT_REG - 1; for (i = 0; i < TPS61280_MAX_VOUT_REG; ++i) { if (tps->curr_vout_val[tps->lru_index[i]] == req_vsel) { new_vout_reg = tps->lru_index[i]; found_index = i; found = true; goto update_lru_index; } } update_lru_index: for (i = found_index; i > 0; i--) tps->lru_index[i] = tps->lru_index[i - 1]; tps->lru_index[0] = new_vout_reg; *gpio_val = new_vout_reg; *vout_reg = TPS61280_VOUTFLOORSET + new_vout_reg; return found; } static int tps61280_dcdc_get_voltage_sel(struct regulator_dev *rdev) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); unsigned int data; int ret; ret = regmap_read(tps->rmap, tps->curr_vout_reg, &data); if (ret < 0) { dev_err(tps->dev, "register %d read failed: %d\n", tps->curr_vout_reg, ret); return ret; } return data & TPS61280_VOUT_MASK; } static int tps61280_dcdc_set_voltage_sel(struct regulator_dev *rdev, unsigned vsel) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); int ret; bool found = false; int vout_reg = tps->curr_vout_reg; int gpio_val = tps->curr_vsel_gpio_val; /* * If gpios are available to select the VOUT register then least * recently used register for new configuration. */ if (tps->pdata.vsel_controlled_dvs && gpio_is_valid(tps->pdata.vsel_gpio)) found = find_voltage_set_register(tps, vsel, &vout_reg, &gpio_val); if (!found) { ret = regmap_update_bits(tps->rmap, vout_reg, TPS61280_VOUT_MASK, vsel); if (ret < 0) { dev_err(tps->dev, "register %d update failed: %d\n", vout_reg, ret); return ret; } tps->curr_vout_reg = vout_reg; tps->curr_vout_val[gpio_val] = vsel; } /* Select proper VOUT register vio gpios */ if (tps->pdata.vsel_controlled_dvs && gpio_is_valid(tps->pdata.vsel_gpio)) { gpio_set_value_cansleep(tps->pdata.vsel_gpio, gpio_val & 0x1); tps->curr_vsel_gpio_val = gpio_val; } return 0; } static int tps61280_dcdc_set_sleep_voltage_sel(struct regulator_dev *rdev, unsigned sel) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); int ret; if (!tps->pdata.vsel_controlled_sleep || gpio_is_valid(tps->pdata.vsel_gpio)) { dev_err(tps->dev, "Regulator has invalid configuration\n"); return -EINVAL; } ret = regmap_update_bits(tps->rmap, tps->sleep_vout_reg, TPS61280_VOUT_MASK, sel); if (ret < 0) { dev_err(tps->dev, "register %d update failed: %d\n", tps->sleep_vout_reg, ret); return ret; } return 0; } static int tps61280_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); unsigned int val; int ret = 0; int curr_mode; switch (mode) { case REGULATOR_MODE_FAST: case REGULATOR_MODE_NORMAL: break; default: dev_err(tps->dev, "Mode is not supported\n"); return -EINVAL; } if (tps->current_mode == mode) return 0; curr_mode = mode; if (curr_mode != REGULATOR_MODE_FAST) curr_mode = REGULATOR_MODE_NORMAL; if (tps->pdata.vsel_controlled_mode) { if (!gpio_is_valid(tps->pdata.vsel_gpio)) return 0; if (curr_mode == REGULATOR_MODE_FAST) gpio_set_value_cansleep(tps->pdata.vsel_gpio, 1); else gpio_set_value_cansleep(tps->pdata.vsel_gpio, 0); tps->current_mode = curr_mode; return 0; } val = TPS61280_CONFIG_MODE_AUTO_PWM; if (curr_mode != REGULATOR_MODE_FAST) val = TPS61280_CONFIG_MODE_FORCE_PWM; ret = regmap_update_bits(tps->rmap, TPS61280_CONFIG, TPS61280_CONFIG_MODE_MASK, val); if (ret < 0) { dev_err(tps->dev, "CONFIG update failed %d\n", ret); return ret; } tps->current_mode = curr_mode; return 0; } static unsigned int tps61280_get_mode(struct regulator_dev *rdev) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); return tps->current_mode; } static int tps61280_val_to_reg(int val, int offset, int div, int nbits, bool roundup) { int max_val = offset + (BIT(nbits) - 1) * div; if (val <= offset) return 0; if (val >= max_val) return BIT(nbits) - 1; if (roundup) return DIV_ROUND_UP(val - offset, div); else return (val - offset) / div; } static int tps61280_set_current_limit(struct regulator_dev *rdev, int min_ua, int max_ua) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); int val; int ret = 0; if (!max_ua) return -EINVAL; dev_info(tps->dev, "Setting current limit %d\n", max_ua/1000); val = tps61280_val_to_reg(max_ua/1000, TPS61280_ILIM_OFFSET, TPS61280_ILIM_STEP, 3, 0); if (val < 0) return -EINVAL; ret = regmap_update_bits(tps->rmap, TPS61280_ILIMSET, TPS61280_ILIM_MASK, (val | TPS61280_ILIM_BASE)); if (ret < 0) { dev_err(tps->dev, "ILIM REG update failed %d\n", ret); return ret; } return ret; } static int tps61280_get_current_limit(struct regulator_dev *rdev) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); u32 val; int ret; ret = regmap_read(tps->rmap, TPS61280_ILIMSET, &val); if (ret < 0) { dev_err(tps->dev, "ILIM REG read failed %d\n", ret); return ret; } val &= (TPS61280_ILIM_MASK & ~TPS61280_ILIM_BASE); val = val * TPS61280_ILIM_STEP + TPS61280_ILIM_OFFSET; return val; } static int tps61280_regulator_enable(struct regulator_dev *rdev) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); u32 val; int ret; if (tps->pdata.enable_pin_ctrl) { gpio_set_value_cansleep(tps->pdata.enable_gpio, 1); return 0; } val = TPS61280_CONFIG_BYPASS_PASS_TROUGH; if (tps->bypass_state) val = TPS61280_CONFIG_BYPASS_AUTO_TRANS; ret = regmap_update_bits(tps->rmap, TPS61280_CONFIG, TPS61280_CONFIG_ENABLE_MASK, val); if (ret < 0) { dev_err(tps->dev, "CONFIG update failed %d\n", ret); return ret; } tps->enable_state = true; return 0; } static int tps61280_regulator_disable(struct regulator_dev *rdev) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); int ret; if (tps->pdata.enable_pin_ctrl) { gpio_set_value_cansleep(tps->pdata.enable_gpio, 0); return 0; } ret = regmap_update_bits(tps->rmap, TPS61280_CONFIG, TPS61280_CONFIG_ENABLE_MASK, TPS61280_CONFIG_BYPASS_SHUTDOWN); if (ret < 0) { dev_err(tps->dev, "CONFIG update failed %d\n", ret); return ret; } tps->enable_state = false; return 0; } static int tps61280_regulator_is_enabled(struct regulator_dev *rdev) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); return tps->enable_state; } static int tps61280_set_bypass(struct regulator_dev *rdev, bool enable) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); u32 val; int ret; if (tps->pdata.bypass_pin_ctrl) { if (!gpio_is_valid(tps->pdata.bypass_gpio)) return 0; if (enable) gpio_set_value_cansleep(tps->pdata.bypass_gpio, 1); else gpio_set_value_cansleep(tps->pdata.bypass_gpio, 0); tps->bypass_state = enable; return 0; } if (!tps->enable_state) { tps->bypass_state = enable; return 0; } val = TPS61280_CONFIG_BYPASS_PASS_TROUGH; if (enable) val = TPS61280_CONFIG_BYPASS_AUTO_TRANS; ret = regmap_update_bits(tps->rmap, TPS61280_CONFIG, TPS61280_CONFIG_ENABLE_MASK, val); if (ret < 0) { dev_err(tps->dev, "CONFIG update failed %d\n", ret); return ret; } tps->bypass_state = enable; return 0; } static int tps61280_get_bypass(struct regulator_dev *rdev, bool *enable) { struct tps61280_chip *tps = rdev_get_drvdata(rdev); *enable = tps->bypass_state; return 0; } static struct regulator_ops tps61280_ops = { .set_voltage_sel = tps61280_dcdc_set_voltage_sel, .get_voltage_sel = tps61280_dcdc_get_voltage_sel, .list_voltage = regulator_list_voltage_linear, .set_mode = tps61280_set_mode, .get_mode = tps61280_get_mode, .set_current_limit = tps61280_set_current_limit, .get_current_limit = tps61280_get_current_limit, .set_bypass = tps61280_set_bypass, .get_bypass = tps61280_get_bypass, .enable = tps61280_regulator_enable, .disable = tps61280_regulator_disable, .is_enabled = tps61280_regulator_is_enabled, .set_sleep_voltage_sel = tps61280_dcdc_set_sleep_voltage_sel, }; static int tps61280_thermal_read_temp(void *data, int *temp) { struct tps61280_chip *tps = data; u32 val; int ret; ret = regmap_read(tps->rmap, TPS61280_STATUS, &val); if (ret < 0) { dev_err(tps->dev, "STATUS REG read failed %d\n", ret); return -EINVAL; } if (val & TPS61280_HOTDIE_MASK) *temp = TPS61280_HOTDIE_TEMP * 1000; else *temp = TPS61280_NORMAL_OPTEMP * 1000; return 0; } static irqreturn_t tps61280_irq(int irq, void *dev) { struct tps61280_chip *tps = dev; struct i2c_client *client = tps->client; int val; int ret; ret = regmap_read(tps->rmap, TPS61280_STATUS, &val); if (ret < 0) { dev_err(&client->dev, "%s() STATUS REG read failed %d\n", __func__, ret); return -EINVAL; } dev_info(&client->dev, "%s() Irq %d status 0x%02x\n", __func__, irq, val); if (val & TPS61280_PGOOD_MASK) dev_info(&client->dev, "PG Status:output voltage is within normal range\n"); if (val & TPS61280_FAULT_MASK) dev_err(&client->dev, "FAULT condition has occurred\n"); if (val & TPS61280_ILIMBST_MASK) dev_err(&client->dev, "Input current triggered for 1.5ms in boost mode\n"); if (val & TPS61280_ILIMPT_MASK) dev_err(&client->dev, "Bypass FET Current has triggered\n"); if (val & TPS61280_OPMODE_MASK) dev_err(&client->dev, "Device operates in dc/dc mode\n"); else dev_err(&client->dev, "Device operates in pass-through mode\n"); if (val & TPS61280_DCDCMODE_MASK) dev_err(&client->dev, "Device operates in PFM mode\n"); else dev_err(&client->dev, "Device operates in PWM mode\n"); if (val & TPS61280_HOTDIE_MASK) { dev_info(&client->dev, "TPS61280 in thermal regulation\n"); if (tps->tz_device) thermal_zone_device_update(tps->tz_device, THERMAL_EVENT_UNSPECIFIED); } if (val & TPS61280_THERMALSD_MASK) dev_err(&client->dev, "Thermal shutdown tripped\n"); return IRQ_HANDLED; } static int tps61280_bypass_init(struct tps61280_chip *tps61280) { struct device *dev = tps61280->dev; unsigned int val; int ret; if (!tps61280->rinit_data) return 0; tps61280->rinit_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_BYPASS; if (tps61280->pdata.bypass_pin_ctrl) { int gpio_flag; ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG, TPS61280_CONFIG_ENABLE_MASK, TPS61280_CONFIG_BYPASS_HW_CONTRL); if (ret < 0) { dev_err(dev, "CONFIG update failed %d\n", ret); return ret; } if (!gpio_is_valid(tps61280->pdata.bypass_gpio)) return 0; if (tps61280->rinit_data->constraints.bypass_on) gpio_flag = GPIOF_OUT_INIT_HIGH; else gpio_flag = GPIOF_OUT_INIT_LOW; ret = devm_gpio_request_one(tps61280->dev, tps61280->pdata.bypass_gpio, gpio_flag, "tps61280-bypass-pin-gpio"); if (ret < 0) { dev_err(dev, "Bypass GPIO request failed: %d\n", ret); return ret; } tps61280->bypass_state = tps61280->rinit_data->constraints.bypass_on; return 0; } if (!tps61280->enable_state) { tps61280->bypass_state = tps61280->rinit_data->constraints.bypass_on; return 0; } val = TPS61280_CONFIG_BYPASS_PASS_TROUGH; if (tps61280->rinit_data->constraints.bypass_on) val = TPS61280_CONFIG_BYPASS_AUTO_TRANS; ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG, TPS61280_CONFIG_ENABLE_MASK, val); if (ret < 0) { dev_err(dev, "CONFIG update failed %d\n", ret); return ret; } tps61280->bypass_state = tps61280->rinit_data->constraints.bypass_on; return 0; } static int tps61280_mode_init(struct tps61280_chip *tps61280) { struct device *dev = tps61280->dev; unsigned int val; int ret; int curr_mode; if (!tps61280->rinit_data) return 0; tps61280->rinit_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE; tps61280->rinit_data->constraints.valid_modes_mask |= REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL; curr_mode = tps61280->rinit_data->constraints.initial_mode; if (curr_mode != REGULATOR_MODE_FAST) curr_mode = REGULATOR_MODE_NORMAL; if (tps61280->pdata.vsel_controlled_mode) { int gpio_flag; ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG, TPS61280_CONFIG_MODE_MASK, TPS61280_CONFIG_MODE_VSEL); if (ret < 0) { dev_err(dev, "CONFIG update failed %d\n", ret); return ret; } if (!gpio_is_valid(tps61280->pdata.vsel_gpio)) return 0; if (curr_mode == REGULATOR_MODE_FAST) gpio_flag = GPIOF_OUT_INIT_HIGH; else gpio_flag = GPIOF_OUT_INIT_LOW; ret = devm_gpio_request_one(tps61280->dev, tps61280->pdata.vsel_gpio, gpio_flag, "tps61280-mode-vsel-gpio"); if (ret < 0) { dev_err(dev, "VSEL-MODE GPIO request failed: %d\n", ret); return ret; } tps61280->current_mode = curr_mode; return 0; } val = TPS61280_CONFIG_MODE_AUTO_PWM; if (curr_mode != REGULATOR_MODE_FAST) val = TPS61280_CONFIG_MODE_FORCE_PWM; ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG, TPS61280_CONFIG_MODE_MASK, val); if (ret < 0) { dev_err(dev, "CONFIG update failed %d\n", ret); return ret; } tps61280->current_mode = curr_mode; return 0; } static int tps61280_regulator_enable_init(struct tps61280_chip *tps61280) { struct device *dev = tps61280->dev; int ret; int enable_state = 0; if (!tps61280->rinit_data) return 0; tps61280->rinit_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS; if (tps61280->rinit_data->constraints.always_on || tps61280->rinit_data->constraints.boot_on) enable_state = 1; if (tps61280->pdata.enable_pin_ctrl) { int gpio_flag = GPIOF_OUT_INIT_LOW; if (!gpio_is_valid(tps61280->pdata.enable_gpio)) return 0; if (enable_state) gpio_flag = GPIOF_OUT_INIT_HIGH; ret = devm_gpio_request_one(tps61280->dev, tps61280->pdata.enable_gpio, gpio_flag, "tps61280-en-pin-gpio"); if (ret < 0) { dev_err(dev, "Enable GPIO request failed: %d\n", ret); return ret; } tps61280->enable_state = enable_state; return 0; } if (!enable_state) { ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG, TPS61280_CONFIG_ENABLE_MASK, TPS61280_CONFIG_BYPASS_SHUTDOWN); if (ret < 0) { dev_err(dev, "CONFIG update failed %d\n", ret); return ret; } } tps61280->enable_state = enable_state; return 0; } static int tps61280_dvs_init(struct tps61280_chip *tps61280) { struct device *dev = tps61280->dev; unsigned int init_uv; unsigned int vsel; int ret; if (!tps61280->rinit_data) return 0; tps61280->rinit_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE; tps61280->curr_vsel_gpio_val = tps61280->pdata.vsel_pin_default_state; tps61280->curr_vout_reg = TPS61280_VOUTFLOORSET + tps61280->pdata.vsel_pin_default_state; tps61280->lru_index[0] = tps61280->curr_vout_reg; tps61280->sleep_vout_reg = TPS61280_VOUTFLOORSET; if (!tps61280->pdata.vsel_pin_default_state) tps61280->sleep_vout_reg += 1; if (tps61280->pdata.vsel_controlled_dvs && gpio_is_valid(tps61280->pdata.vsel_gpio)) { int gpio_flags; int i; gpio_flags = (tps61280->pdata.vsel_pin_default_state) ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ret = devm_gpio_request_one(dev, tps61280->pdata.vsel_gpio, gpio_flags, "tps61280-vsel-dvs"); if (ret) { dev_err(dev, "VSEL GPIO request failed: %d\n", ret); return ret; } /* * Initialize the lru index with vout_reg id * The index 0 will be most recently used and * set with the max->curr_vout_reg */ for (i = 0; i < TPS61280_MAX_VOUT_REG; ++i) tps61280->lru_index[i] = i; tps61280->lru_index[0] = tps61280->curr_vout_reg; tps61280->lru_index[tps61280->curr_vout_reg] = 0; } init_uv = tps61280->rinit_data->constraints.min_uV; if ((init_uv >= TPS61280_VOUT_VMIN) && (init_uv <= TPS61280_VOUT_VMAX)) { vsel = DIV_ROUND_UP((init_uv - TPS61280_VOUT_VMIN), TPS61280_VOUT_VSTEP); ret = regmap_update_bits(tps61280->rmap, TPS61280_VOUTFLOORSET, TPS61280_VOUT_MASK, vsel); if (ret < 0) { dev_err(dev, "VOUTFLOORSET update failed: %d\n", ret); return ret; } ret = regmap_update_bits(tps61280->rmap, TPS61280_VOUTROOFSET, TPS61280_VOUT_MASK, vsel); if (ret < 0) { dev_err(dev, "VOUTROOFSET update failed: %d\n", ret); return ret; } } return 0; } static const struct thermal_zone_of_device_ops tps61280_of_thermal_ops = { .get_temp = tps61280_thermal_read_temp, }; static int tps61280_parse_dt_data(struct i2c_client *client, struct tps61280_platform_data *pdata) { struct device_node *np = client->dev.of_node; u32 pval; int ret; pdata->vsel_controlled_mode = of_property_read_bool(np, "ti,enable-vsel-controlled-mode"); pdata->vsel_controlled_dvs = of_property_read_bool(np, "ti,enable-vsel-controlled-dvs"); pdata->vsel_controlled_sleep = of_property_read_bool(np, "ti,enable-vsel-controlled-sleep"); pdata->vsel_gpio = -EINVAL; if (pdata->vsel_controlled_mode || pdata->vsel_controlled_dvs) { pdata->vsel_gpio = of_get_named_gpio(np, "ti,vsel-pin-gpio", 0); if ((pdata->vsel_gpio < 0) && (pdata->vsel_gpio != -EINVAL)) { dev_err(&client->dev, "VSEL GPIO not available: %d\n", pdata->vsel_gpio); return pdata->vsel_gpio; } } if (pdata->vsel_controlled_dvs || pdata->vsel_controlled_sleep) { ret = of_property_read_u32(np, "ti,vsel-pin-default-state", &pval); if (ret < 0) { dev_err(&client->dev, "VSEL default state not found\n"); return ret; } pdata->vsel_pin_default_state = pval; } pdata->enable_pin_ctrl = of_property_read_bool(np, "ti,enable-en-pin-control"); if (pdata->enable_pin_ctrl) { pdata->enable_gpio = of_get_named_gpio(np, "ti,en-pin-gpio", 0); if ((pdata->enable_gpio < 0) && (pdata->enable_gpio != -EINVAL)) { dev_err(&client->dev, "EN GPIO not available: ^%d\n", pdata->enable_gpio); return pdata->enable_gpio; } } pdata->bypass_pin_ctrl = of_property_read_bool(np, "ti,enable-bypass-pin-control"); if (pdata->bypass_pin_ctrl) { pdata->bypass_gpio = of_get_named_gpio(np, "ti,bypass-pin-gpio", 0); if ((pdata->bypass_gpio < 0) && (pdata->bypass_gpio != -EINVAL)) { dev_err(&client->dev, "BYPASS GPIO not available: %d\n", pdata->bypass_gpio); return pdata->bypass_gpio; } } return 0; } static int tps61280_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tps61280_chip *tps61280; struct regulator_config rconfig = { }; int ret; if (!client->dev.of_node) { dev_err(&client->dev, "Only Supporting DT\n"); return -ENODEV; } tps61280 = devm_kzalloc(&client->dev, sizeof(*tps61280), GFP_KERNEL); if (!tps61280) return -ENOMEM; ret = tps61280_parse_dt_data(client, &tps61280->pdata); if (ret < 0) { dev_err(&client->dev, "Platform data pasring failed: %d\n", ret); return ret; } tps61280->rmap = devm_regmap_init_i2c(client, &tps61280_regmap_config); if (IS_ERR(tps61280->rmap)) { ret = PTR_ERR(tps61280->rmap); dev_err(&client->dev, "regmap init failed with err%d\n", ret); return ret; } tps61280->client = client; tps61280->dev = &client->dev; i2c_set_clientdata(client, tps61280); mutex_init(&tps61280->mutex); tps61280->rdesc.name = "tps61280-dcdc"; tps61280->rdesc.ops = &tps61280_ops; tps61280->rdesc.type = REGULATOR_VOLTAGE; tps61280->rdesc.owner = THIS_MODULE; tps61280->rdesc.linear_min_sel = 0; tps61280->rdesc.min_uV = TPS61280_VOUT_VMIN; tps61280->rdesc.uV_step = TPS61280_VOUT_VSTEP; tps61280->rdesc.n_voltages = 0x20; tps61280->rinit_data = of_get_regulator_init_data(tps61280->dev, tps61280->dev->of_node, &tps61280->rdesc); if (!tps61280->rinit_data) { dev_err(&client->dev, "No Regulator init data\n"); return -EINVAL; } ret = tps61280_regulator_enable_init(tps61280); if (ret < 0) { dev_err(&client->dev, "Enable init failed: %d\n", ret); return ret; } ret = tps61280_dvs_init(tps61280); if (ret < 0) { dev_err(&client->dev, "DVS init failed: %d\n", ret); return ret; } ret = tps61280_bypass_init(tps61280); if (ret < 0) { dev_err(&client->dev, "Bypass init failed: %d\n", ret); return ret; } ret = tps61280_mode_init(tps61280); if (ret < 0) { dev_err(&client->dev, "Mode init failed: %d\n", ret); return ret; } rconfig.dev = tps61280->dev; rconfig.of_node = tps61280->dev->of_node; rconfig.driver_data = tps61280; rconfig.regmap = tps61280->rmap; rconfig.init_data = tps61280->rinit_data; tps61280->rdev = devm_regulator_register(tps61280->dev, &tps61280->rdesc, &rconfig); if (IS_ERR(tps61280->rdev)) { ret = PTR_ERR(tps61280->rdev); dev_err(&client->dev, "regulator register failed %d\n", ret); return ret; } if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, tps61280_irq, IRQF_ONESHOT | IRQF_TRIGGER_FALLING, dev_name(&client->dev), tps61280); if (ret < 0) { dev_err(&client->dev, "Request irq %d failed: %d\n", client->irq, ret); return ret; } } device_set_wakeup_capable(&client->dev, 1); device_wakeup_enable(&client->dev); tps61280->tz_device = devm_thermal_zone_of_sensor_register(tps61280->dev, 0, tps61280, &tps61280_of_thermal_ops); if (IS_ERR(tps61280->tz_device)) { ret = PTR_ERR(tps61280->tz_device); dev_err(&client->dev, "TZ device register failed: %d\n", ret); return ret; } dev_info(&client->dev, "DC-Boost probe successful\n"); return 0; } #ifdef CONFIG_PM_SLEEP static int tps61280_suspend(struct device *dev) { struct tps61280_chip *tps = dev_get_drvdata(dev); if (device_may_wakeup(&tps->client->dev) && tps->client->irq) enable_irq_wake(tps->client->irq); return 0; } static int tps61280_resume(struct device *dev) { struct tps61280_chip *tps = dev_get_drvdata(dev); if (device_may_wakeup(&tps->client->dev) && tps->client->irq) disable_irq_wake(tps->client->irq); return 0; } #endif /* CONFIG_PM */ static SIMPLE_DEV_PM_OPS(tps61280_pm_ops, tps61280_suspend, tps61280_resume); static const struct of_device_id tps61280_dt_match[] = { { .compatible = "tps61280" }, { }, }; MODULE_DEVICE_TABLE(of, tps61280_dt_match); static const struct i2c_device_id tps61280_i2c_id[] = { { "tps61280", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, tps61280_i2c_id); static struct i2c_driver tps61280_driver = { .driver = { .name = "tps61280", .owner = THIS_MODULE, .of_match_table = of_match_ptr(tps61280_dt_match), .pm = &tps61280_pm_ops, }, .probe = tps61280_probe, .id_table = tps61280_i2c_id, }; static int __init tps61280_init(void) { return i2c_add_driver(&tps61280_driver); } fs_initcall_sync(tps61280_init); static void __exit tps61280_exit(void) { i2c_del_driver(&tps61280_driver); } module_exit(tps61280_exit); MODULE_DESCRIPTION("tps61280 driver"); MODULE_AUTHOR("Venkat Reddy Talla "); MODULE_AUTHOR("Laxman Dewangan "); MODULE_ALIAS("i2c:tps61280"); MODULE_LICENSE("GPL v2");