blob: 8faeabab035e5603b53bfcbed8ecdde581c6d837 [file] [log] [blame]
/*
* Copyright 2016-2017 Google, Inc
*
* 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 <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
struct tps61099 {
struct device *dev;
struct regulator_dev *rdev;
struct regulator_desc rdesc;
struct regulator_ops *reg_ops;
struct pinctrl *pinctrl;
struct pinctrl_state *pinctrl_active_state;
struct pinctrl_state *pinctrl_sleep_state;
struct gpio_desc *enable_gpio;
bool enabled;
};
static int tps61099_regulator_enable_pinctrl(struct regulator_dev *rdev)
{
struct tps61099 *tps61099 = rdev_get_drvdata(rdev);
int rc;
rc = pinctrl_select_state(tps61099->pinctrl,
tps61099->pinctrl_active_state);
if (rc < 0) {
dev_err(tps61099->dev, "cannot select active state rc=%d\n",
rc);
return rc;
}
tps61099->enabled = true;
return rc;
}
static int tps61099_regulator_disable_pinctrl(struct regulator_dev *rdev)
{
struct tps61099 *tps61099 = rdev_get_drvdata(rdev);
int rc = 0;
rc = pinctrl_select_state(tps61099->pinctrl,
tps61099->pinctrl_sleep_state);
if (rc < 0) {
dev_err(tps61099->dev, "cannot select sleep state rc=%d\n", rc);
return rc;
}
tps61099->enabled = false;
return rc;
}
static int tps61099_regulator_enable_gpio(struct regulator_dev *rdev)
{
struct tps61099 *tps61099 = rdev_get_drvdata(rdev);
gpiod_set_value(tps61099->enable_gpio, true);
tps61099->enabled = true;
return 0;
}
static int tps61099_regulator_disable_gpio(struct regulator_dev *rdev)
{
struct tps61099 *tps61099 = rdev_get_drvdata(rdev);
gpiod_set_value(tps61099->enable_gpio, false);
tps61099->enabled = false;
return 0;
}
static int tps61099_regulator_is_enabled(struct regulator_dev *rdev)
{
struct tps61099 *tps61099 = rdev_get_drvdata(rdev);
return tps61099->enabled ? 1 : 0;
}
static struct regulator_ops tps61099_reg_ops_pinctrl = {
.enable = tps61099_regulator_enable_pinctrl,
.disable = tps61099_regulator_disable_pinctrl,
.is_enabled = tps61099_regulator_is_enabled,
};
static struct regulator_ops tps61099_reg_ops_gpio = {
.enable = tps61099_regulator_enable_gpio,
.disable = tps61099_regulator_disable_gpio,
.is_enabled = tps61099_regulator_is_enabled,
};
static struct tps61099 *tps61099_init_pinctrl(struct platform_device *pdev)
{
struct tps61099 *tps61099;
struct pinctrl *pinctrl;
struct pinctrl_state *pinctrl_active_state;
struct pinctrl_state *pinctrl_sleep_state;
int rc = 0;
pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(pinctrl)) {
rc = PTR_ERR(pinctrl);
dev_err(&pdev->dev, "cannot get pinctrl rc=%d\n", rc);
return ERR_PTR(rc);
}
pinctrl_active_state = pinctrl_lookup_state(pinctrl, "tps61099_active");
if (IS_ERR(pinctrl_active_state)) {
rc = PTR_ERR(pinctrl_active_state);
dev_err(&pdev->dev,
"cannot lookup pinctrl active state rc=%d\n",
rc);
return ERR_PTR(rc);
}
pinctrl_sleep_state = pinctrl_lookup_state(pinctrl, "tps61099_sleep");
if (IS_ERR(pinctrl_sleep_state)) {
rc = PTR_ERR(pinctrl_sleep_state);
dev_err(&pdev->dev,
"cannot lookup pinctrl sleep state rc=%d\n",
rc);
return ERR_PTR(rc);
}
rc = pinctrl_select_state(pinctrl, pinctrl_sleep_state);
if (rc < 0) {
dev_err(&pdev->dev,
"cannot select sleep pinctrl during driver probe rc=%d\n",
rc);
return ERR_PTR(rc);
}
tps61099 = devm_kzalloc(&pdev->dev, sizeof(*tps61099),
GFP_KERNEL);
if (!tps61099)
return ERR_PTR(-ENOMEM);
tps61099->dev = &pdev->dev;
tps61099->pinctrl = pinctrl;
tps61099->pinctrl_active_state = pinctrl_active_state;
tps61099->pinctrl_sleep_state = pinctrl_sleep_state;
tps61099->reg_ops = &tps61099_reg_ops_pinctrl;
return tps61099;
}
static void tps61099_deinit_pinctrl(struct tps61099 *tps61099)
{}
static struct tps61099 *tps61099_init_gpio(struct platform_device *pdev)
{
struct tps61099 *tps61099;
struct gpio_desc *enable_gpio;
int rc = 0;
enable_gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(enable_gpio)) {
rc = PTR_ERR(enable_gpio);
dev_err(&pdev->dev, "cannot get gpio rc=%d\n", rc);
return ERR_PTR(rc);
}
tps61099 = devm_kzalloc(&pdev->dev, sizeof(*tps61099),
GFP_KERNEL);
if (!tps61099)
return ERR_PTR(-ENOMEM);
tps61099->dev = &pdev->dev;
tps61099->enable_gpio = enable_gpio;
tps61099->reg_ops = &tps61099_reg_ops_gpio;
return tps61099;
}
static void tps61099_deinit_gpio(struct tps61099 *tps61099)
{}
static struct tps61099 *tps61099_init(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
bool uses_gpio = of_property_read_bool(node, "uses_gpio");
if (uses_gpio)
return tps61099_init_gpio(pdev);
else
return tps61099_init_pinctrl(pdev);
}
static void tps61099_deinit(struct tps61099 *tps61099)
{
struct device_node *node = tps61099->dev->of_node;
bool uses_gpio = of_property_read_bool(node, "uses_gpio");
if (uses_gpio)
tps61099_deinit_gpio(tps61099);
else
tps61099_deinit_pinctrl(tps61099);
}
static int tps61099_probe(struct platform_device *pdev)
{
struct tps61099 *tps61099;
struct regulator_config cfg = {};
int rc = 0;
tps61099 = tps61099_init(pdev);
if (IS_ERR(tps61099))
return PTR_ERR(tps61099);
cfg.dev = tps61099->dev;
cfg.driver_data = tps61099;
tps61099->rdesc.owner = THIS_MODULE;
tps61099->rdesc.type = REGULATOR_VOLTAGE;
tps61099->rdesc.ops = tps61099->reg_ops;
tps61099->rdesc.of_match = "ti,tps61099";
tps61099->rdesc.name = "ti,tps61099";
tps61099->rdev = devm_regulator_register(tps61099->dev,
&tps61099->rdesc,
&cfg);
if (IS_ERR(tps61099->rdev)) {
rc = PTR_ERR(tps61099->rdev);
tps61099->rdev = NULL;
dev_err(tps61099->dev, "cannot register regulator rc=%d\n", rc);
goto deinit_tps;
}
platform_set_drvdata(pdev, tps61099);
dev_dbg(tps61099->dev, "TPS61099 driver successfully probed\n");
return rc;
deinit_tps:
tps61099_deinit(tps61099);
return rc;
}
static int tps61099_remove(struct platform_device *pdev)
{
struct tps61099 *tps61099 = platform_get_drvdata(pdev);
regulator_unregister(tps61099->rdev);
platform_set_drvdata(pdev, NULL);
return 0;
}
static void tps61099_shutdown(struct platform_device *pdev)
{
}
static const struct of_device_id match_table[] = {
{ .compatible = "ti,tps61099", },
{ },
};
static struct platform_driver tps61099_driver = {
.driver = {
.name = "ti,tps61099",
.owner = THIS_MODULE,
.of_match_table = match_table,
},
.probe = tps61099_probe,
.remove = tps61099_remove,
.shutdown = tps61099_shutdown,
};
module_platform_driver(tps61099_driver);