| /* |
| * Copyright (c) 2015 LGE Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * 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. |
| */ |
| |
| #define pr_fmt(fmt) "%s: " fmt, __func__ |
| |
| #include <linux/init.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/regulator/of_regulator.h> |
| #include <linux/regulator/driver.h> |
| #include <linux/regulator/machine.h> |
| #include <linux/i2c.h> |
| #include <linux/of_gpio.h> |
| #include <linux/regmap.h> |
| #include <linux/delay.h> |
| |
| #ifdef DW8768_DEBUG |
| #define dw_info(...) pr_info(__VA_ARGS__) |
| #else |
| #define dw_info(...) do { } while (0) |
| #endif |
| |
| struct dw8768_regulator { |
| struct device *dev; |
| struct regulator_desc rdesc; |
| struct regulator_dev *rdev; |
| struct regulator_init_data *init_data; |
| struct regmap *i2c_regmap; |
| struct device_node *reg_node; |
| int ena_gpio; |
| int enm_gpio; |
| int pre_on_usleep; |
| int post_on_usleep; |
| int pre_off_usleep; |
| int post_off_usleep; |
| bool is_enabled; |
| int curr_uV; |
| u8 vol_set_val; |
| bool vol_set_postponed; |
| }; |
| |
| #define DW8768_REG_VPOS_ADDR 0x00 |
| #define DW8768_REG_VNEG_ADDR 0x01 |
| #define DW8768_REG_V_MASK 0x1f |
| #define DW8768_REG_EN_ADDR 0x05 /* when no enm*/ |
| |
| #define DW8768_VOLTAGE_MIN 4000000 |
| #define DW8768_VOLTAGE_MAX 6000000 |
| #define DW8768_VOLTAGE_STEP 100000 |
| #define DW8768_VOLTAGE_LEVELS \ |
| ((DW8768_VOLTAGE_MAX - DW8768_VOLTAGE_MIN) \ |
| / DW8768_VOLTAGE_STEP + 1) |
| |
| #define DW8768_VOLTAGE_DEFAULT 5500000 |
| |
| static struct of_regulator_match dw8768_reg_matches[] = { |
| { .name = "dw8768-dsv", .driver_data = (void *)0 }, |
| }; |
| |
| static int dw8768_regulator_enable(struct regulator_dev *rdev) |
| { |
| struct dw8768_regulator *reg_data = rdev_get_drvdata(rdev); |
| int rc = 0; |
| |
| if (!rdev->regmap) { |
| pr_err("invalid regmap\n"); |
| return -EINVAL; |
| } |
| |
| dw_info("enable, postponed:%d\n", reg_data->vol_set_postponed); |
| |
| if (reg_data->pre_on_usleep) |
| usleep(reg_data->pre_on_usleep); |
| |
| if (gpio_is_valid(reg_data->ena_gpio)) { |
| gpio_set_value(reg_data->ena_gpio, 1); |
| if (gpio_is_valid(reg_data->enm_gpio)) { |
| gpio_set_value(reg_data->enm_gpio, 1); |
| } else { |
| rc = regmap_write(rdev->regmap, |
| DW8768_REG_EN_ADDR, 0x0F); |
| if (rc) |
| pr_err("Failed to write i2c. rc=%d\n", rc); |
| } |
| reg_data->is_enabled = true; |
| } else { |
| pr_err("gpio ena is not configured\n"); |
| rc = -EINVAL; |
| } |
| |
| if (reg_data->vol_set_postponed) { |
| rc = regmap_write(rdev->regmap, DW8768_REG_VPOS_ADDR, |
| reg_data->vol_set_val); |
| if (rc) { |
| pr_err("failed to write postponed +V(%d)\n", |
| reg_data->vol_set_val); |
| return rc; |
| } |
| rc = regmap_write(rdev->regmap, DW8768_REG_VNEG_ADDR, |
| reg_data->vol_set_val); |
| if (rc) { |
| pr_err("failed to write postponed -V(%d)\n", |
| reg_data->vol_set_val); |
| return rc; |
| } |
| reg_data->vol_set_postponed = false; |
| } |
| |
| if (reg_data->post_on_usleep) |
| usleep(reg_data->post_on_usleep); |
| return rc; |
| } |
| |
| static int dw8768_regulator_disable(struct regulator_dev *rdev) |
| { |
| struct dw8768_regulator *reg_data = rdev_get_drvdata(rdev); |
| int rc = 0; |
| |
| if (!rdev->regmap) { |
| pr_err("invalid regmap\n"); |
| return -EINVAL; |
| } |
| |
| dw_info("disable, postponed:%d\n", reg_data->vol_set_postponed); |
| |
| if (reg_data->pre_off_usleep) |
| usleep(reg_data->pre_off_usleep); |
| |
| if (gpio_is_valid(reg_data->ena_gpio)) { |
| if (gpio_is_valid(reg_data->enm_gpio)) { |
| gpio_set_value(reg_data->enm_gpio, 0); |
| } else { |
| rc = regmap_write(rdev->regmap, |
| DW8768_REG_EN_ADDR, 0x07); |
| if (rc) |
| pr_err("Failed to write i2c. rc=%d\n", rc); |
| } |
| gpio_set_value(reg_data->ena_gpio, 0); |
| reg_data->is_enabled = false; |
| } else { |
| pr_err("gpio ena is not configured\n"); |
| rc = -EINVAL; |
| } |
| |
| if (reg_data->post_off_usleep) |
| usleep(reg_data->post_off_usleep); |
| return rc; |
| } |
| |
| static int dw8768_regulator_is_enabled(struct regulator_dev *rdev) |
| { |
| struct dw8768_regulator *reg_data = rdev_get_drvdata(rdev); |
| |
| return reg_data->is_enabled ? 1 : 0; |
| } |
| |
| static int dw8768_regulator_set_voltage(struct regulator_dev *rdev, |
| int min_uV, int max_uV, unsigned *selector) |
| { |
| struct dw8768_regulator *reg_data = rdev_get_drvdata(rdev); |
| int rc, val, new_uV; |
| |
| if (!rdev->regmap) { |
| pr_err("invalid regmap\n"); |
| return -EINVAL; |
| } |
| |
| val = DIV_ROUND_UP(min_uV - DW8768_VOLTAGE_MIN, DW8768_VOLTAGE_STEP); |
| val = val & DW8768_REG_V_MASK; |
| new_uV = DW8768_VOLTAGE_MIN + (val * DW8768_VOLTAGE_STEP); |
| if (new_uV == reg_data->curr_uV) { |
| dw_info("curV and newV are same\n"); |
| return 0; |
| } |
| if (new_uV > max_uV) { |
| pr_err("failed to set voltage (%d %d)\n", min_uV, max_uV); |
| return -EINVAL; |
| } |
| |
| reg_data->vol_set_val = val; |
| if (!reg_data->is_enabled) { |
| reg_data->vol_set_postponed = true; |
| } else { |
| rc = regmap_write(rdev->regmap, DW8768_REG_VPOS_ADDR, val); |
| if (rc) { |
| pr_err("failed to write +V(%d %d)\n", min_uV, max_uV); |
| return rc; |
| } |
| rc = regmap_write(rdev->regmap, DW8768_REG_VNEG_ADDR, val); |
| if (rc) { |
| pr_err("failed to write -V(%d %d)\n", min_uV, max_uV); |
| return rc; |
| } |
| } |
| |
| reg_data->curr_uV = new_uV; |
| *selector = val; |
| |
| dw_info("uV:%d reg:%x postponed:%d\n", new_uV, val, |
| reg_data->vol_set_postponed); |
| return 0; |
| } |
| |
| static int dw8768_regulator_get_voltage(struct regulator_dev *rdev) |
| { |
| struct dw8768_regulator *reg_data = rdev_get_drvdata(rdev); |
| int rc, posval, negval; |
| |
| if (!rdev->regmap) { |
| pr_err("invalid regmap\n"); |
| return -EINVAL; |
| } |
| |
| if (!reg_data->is_enabled) { |
| dw_info("curr_uV:%d (no_enabled)\n", reg_data->curr_uV); |
| return reg_data->curr_uV; |
| } |
| |
| rc = regmap_read(rdev->regmap, DW8768_REG_VPOS_ADDR, &posval); |
| if (rc) { |
| pr_err("failed to read +V\n"); |
| return rc; |
| } |
| rc = regmap_read(rdev->regmap, DW8768_REG_VNEG_ADDR, &negval); |
| if (rc) { |
| pr_err("failed to read -V\n"); |
| return rc; |
| } |
| if (posval != negval) { |
| pr_err("mismatch between +V(%d) and -V(%d)\n", |
| posval, negval); |
| return -EINVAL; |
| } |
| reg_data->curr_uV = (posval & DW8768_REG_V_MASK)* DW8768_VOLTAGE_STEP |
| + DW8768_VOLTAGE_MIN; |
| |
| dw_info("curr_uV:%d\n", reg_data->curr_uV); |
| |
| return reg_data->curr_uV; |
| } |
| |
| static int dw8768_regulator_list_voltage(struct regulator_dev *rdev, |
| unsigned selector) |
| { |
| if (selector >= DW8768_VOLTAGE_LEVELS) |
| return 0; |
| return selector * DW8768_VOLTAGE_STEP + DW8768_VOLTAGE_MIN; |
| } |
| |
| static struct regulator_ops dw8768_ops = { |
| .set_voltage = dw8768_regulator_set_voltage, |
| .get_voltage = dw8768_regulator_get_voltage, |
| .list_voltage = dw8768_regulator_list_voltage, |
| .enable = dw8768_regulator_enable, |
| .disable = dw8768_regulator_disable, |
| .is_enabled = dw8768_regulator_is_enabled, |
| }; |
| |
| static int dw8768_parse_dt_reg(struct dw8768_regulator *reg_data, |
| struct device_node *node) |
| { |
| int temp; |
| |
| reg_data->ena_gpio = of_get_named_gpio(node, "dw,ena-gpio", 0); |
| if (!gpio_is_valid(reg_data->ena_gpio)) { |
| pr_err("ena-gpio not specified. rd=%d\n", |
| reg_data->ena_gpio); |
| return -EINVAL; |
| } |
| |
| reg_data->enm_gpio = of_get_named_gpio(node, "dw,enm-gpio", 0); |
| if (!gpio_is_valid(reg_data->enm_gpio)) { |
| pr_err("enm-gpio not specified. rd=%d\n", |
| reg_data->enm_gpio); |
| } |
| |
| if (!of_property_read_u32(node, "dw,pre-on-sleep-us", &temp)) |
| reg_data->pre_on_usleep = temp; |
| if (!of_property_read_u32(node, "dw,post-on-sleep-us", &temp)) |
| reg_data->post_on_usleep = temp; |
| else |
| reg_data->post_on_usleep = 3700; |
| if (!of_property_read_u32(node, "dw,pre-off-sleep-us", &temp)) |
| reg_data->pre_off_usleep = temp; |
| if (!of_property_read_u32(node, "dw,post-off-sleep-us", &temp)) |
| reg_data->post_off_usleep = temp; |
| |
| dw_info("pre-on:%d post-on:%d pre-off:%d post-off:%d\n", |
| reg_data->pre_on_usleep, reg_data->post_on_usleep, |
| reg_data->pre_off_usleep, reg_data->post_off_usleep); |
| |
| return 0; |
| } |
| |
| static int dw8768_parse_dt(struct dw8768_regulator *reg_data, |
| struct i2c_client *client) |
| { |
| struct device_node *node; |
| struct regulation_constraints *constraints; |
| int rc; |
| |
| if (!client->dev.of_node) { |
| pr_err("Can't find device tree\n"); |
| return -ENOTSUPP; |
| } |
| node = of_find_node_by_name(client->dev.of_node, |
| "regulators"); |
| if (!node) { |
| pr_err("Can't find regulator node\n"); |
| return -EINVAL; |
| } |
| |
| rc = of_regulator_match(&client->dev, node, dw8768_reg_matches, |
| ARRAY_SIZE(dw8768_reg_matches)); |
| if (IS_ERR_VALUE(rc)) { |
| pr_err("Can't match regulator. rc=%d\n", rc); |
| return rc; |
| } |
| if (!dw8768_reg_matches[0].init_data) { |
| pr_err("Failed to match regulator\n"); |
| return -EINVAL; |
| } |
| constraints = &dw8768_reg_matches[0].init_data->constraints; |
| if (!constraints) { |
| pr_err("Failed to init constraints\n"); |
| return -EINVAL; |
| } |
| constraints->input_uV = constraints->max_uV; |
| constraints->valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | |
| REGULATOR_CHANGE_STATUS; |
| |
| reg_data->init_data = dw8768_reg_matches[0].init_data; |
| reg_data->reg_node = dw8768_reg_matches[0].of_node; |
| reg_data->rdesc.name = constraints->name; |
| |
| rc = dw8768_parse_dt_reg(reg_data, |
| dw8768_reg_matches[0].of_node); |
| return rc; |
| } |
| |
| static struct regmap_config dw8768_i2c_regmap = { |
| .reg_bits = 8, |
| .val_bits = 8, |
| }; |
| |
| static int dw8768_regulator_probe(struct i2c_client *client, |
| const struct i2c_device_id *id) |
| { |
| struct dw8768_regulator *reg_data; |
| struct regulator_config config = {}; |
| struct regulator_desc *rdesc; |
| int rc; |
| |
| reg_data = devm_kzalloc(&client->dev, |
| sizeof(struct dw8768_regulator), |
| GFP_KERNEL); |
| if (!reg_data) { |
| pr_err("Can't allocate dw8768_regulator memory\n"); |
| return -ENOMEM; |
| } |
| |
| rc = dw8768_parse_dt(reg_data, client); |
| if (rc) { |
| pr_err("Failed to parse device tree. rc=%d\n", rc); |
| goto error; |
| } |
| |
| if (!gpio_is_valid(reg_data->ena_gpio)) { |
| pr_err("Invalid gpio ena\n"); |
| goto error; |
| } |
| rc = gpio_request_one(reg_data->ena_gpio, |
| GPIOF_OUT_INIT_HIGH, "dw8768_ena"); |
| if (rc) { |
| pr_err("Failed to request gpio ena. rc=%d\n", rc); |
| goto error; |
| } |
| |
| if (gpio_is_valid(reg_data->enm_gpio)) { |
| rc = gpio_request_one(reg_data->enm_gpio, |
| GPIOF_OUT_INIT_HIGH, "dw8768_enm"); |
| if (rc) { |
| pr_err("Failed to request gpio enm. rc=%d\n", rc); |
| goto error_enm; |
| } |
| } |
| |
| reg_data->i2c_regmap = devm_regmap_init_i2c(client, |
| &dw8768_i2c_regmap); |
| if (IS_ERR(reg_data->i2c_regmap)) { |
| rc = PTR_ERR(reg_data->i2c_regmap); |
| pr_err("Failed to init i2c. rc=%d\n", rc); |
| goto error_i2c; |
| } |
| |
| i2c_set_clientdata(client, reg_data); |
| |
| reg_data->dev = &client->dev; |
| |
| config.dev = &client->dev; |
| config.init_data = reg_data->init_data; |
| config.driver_data = reg_data; |
| config.of_node = reg_data->reg_node; |
| config.regmap = reg_data->i2c_regmap; |
| |
| rdesc = ®_data->rdesc; |
| rdesc->type = REGULATOR_VOLTAGE; |
| rdesc->owner = THIS_MODULE; |
| rdesc->n_voltages = DW8768_VOLTAGE_LEVELS; |
| rdesc->ops = &dw8768_ops; |
| |
| reg_data->curr_uV = DW8768_VOLTAGE_DEFAULT; |
| reg_data->rdev = regulator_register(rdesc, &config); |
| if (IS_ERR(reg_data->rdev)) { |
| rc = PTR_ERR(reg_data->rdev); |
| pr_err("Failed to register regulator. rc=%d\n", rc); |
| goto error_i2c; |
| } |
| |
| return rc; |
| |
| error_i2c: |
| if (gpio_is_valid(reg_data->enm_gpio)) |
| gpio_free(reg_data->enm_gpio); |
| error_enm: |
| if (gpio_is_valid(reg_data->ena_gpio)) |
| gpio_free(reg_data->ena_gpio); |
| error: |
| if (reg_data) { |
| devm_kfree(&client->dev, reg_data); |
| } |
| return rc; |
| } |
| |
| static int dw8768_regulator_remove(struct i2c_client *client) |
| { |
| struct dw8768_regulator *reg_data = |
| i2c_get_clientdata(client); |
| |
| regulator_unregister(reg_data->rdev); |
| if (gpio_is_valid(reg_data->ena_gpio)) |
| gpio_free(reg_data->ena_gpio); |
| if (gpio_is_valid(reg_data->enm_gpio)) |
| gpio_free(reg_data->enm_gpio); |
| |
| return 0; |
| } |
| |
| static struct of_device_id dw8768_match_table[] = { |
| { .compatible = "dw,dw8768", }, |
| {}, |
| }; |
| |
| static const struct i2c_device_id dw8768_id[] = { |
| { "dw8768", 0 }, |
| { }, |
| }; |
| MODULE_DEVICE_TABLE(i2c, dw8768_id); |
| |
| static struct i2c_driver dw8768_regulator_driver = { |
| .driver = { |
| .name = "dw8768", |
| .owner = THIS_MODULE, |
| .of_match_table = dw8768_match_table, |
| }, |
| .probe = dw8768_regulator_probe, |
| .remove = dw8768_regulator_remove, |
| .id_table = dw8768_id, |
| }; |
| |
| static int __init dw8768_init(void) |
| { |
| return i2c_add_driver(&dw8768_regulator_driver); |
| } |
| subsys_initcall(dw8768_init); |
| |
| static void __exit dw8768_exit(void) |
| { |
| i2c_del_driver(&dw8768_regulator_driver); |
| } |
| module_exit(dw8768_exit); |
| |
| MODULE_DESCRIPTION("DONGWOON DW8768 regulator driver"); |
| MODULE_LICENSE("GPL v2"); |