244 lines
5.0 KiB
C
244 lines
5.0 KiB
C
#include <linux/io.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/pinctrl/consumer.h>
|
|
#include <linux/pinctrl/machine.h>
|
|
#include <linux/pinctrl/pinctrl.h>
|
|
#include <linux/pinctrl/pinconf-generic.h>
|
|
#include <linux/pinctrl/pinmux.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/sunxi-gpio.h>
|
|
#include <linux/mfd/core.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/i2c.h>
|
|
#include "../../../../pinctrl/core.h"
|
|
#include "../axp-core.h"
|
|
#include "../axp-gpio.h"
|
|
#include "pmu1736-gpio.h"
|
|
|
|
static int pmu1736_gpio_get_data(struct axp_dev *axp_dev, int gpio)
|
|
{
|
|
u8 ret;
|
|
struct axp_regmap *map;
|
|
|
|
map = axp_dev->regmap;
|
|
if (NULL == map) {
|
|
pr_err("%s: axp regmap is null\n", __func__);
|
|
return -ENXIO;
|
|
}
|
|
|
|
switch (gpio) {
|
|
case 1:
|
|
axp_regmap_read(map, AXP_GPIO1_CFG, &ret); ret &= 0x80; break;
|
|
case 2:
|
|
default:
|
|
pr_err("This IO is not an input\n");
|
|
return -ENXIO;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int pmu1736_gpio_set_data(struct axp_dev *axp_dev, int gpio, int value)
|
|
{
|
|
struct axp_regmap *map;
|
|
|
|
if ((0 < gpio) && (3 > gpio)) {
|
|
map = axp_dev->regmap;
|
|
if (NULL == map) {
|
|
pr_err("%s: %d axp regmap is null\n",
|
|
__func__, __LINE__);
|
|
return -ENXIO;
|
|
}
|
|
} else {
|
|
return -ENXIO;
|
|
}
|
|
|
|
if (value) {
|
|
/* high */
|
|
switch (gpio) {
|
|
case 1:
|
|
return axp_regmap_update_sync(map,
|
|
AXP_GPIO1_CFG, 0x40, 0x60);
|
|
case 2:
|
|
return axp_regmap_update_sync(map,
|
|
AXP_GPIO2_CFG, 0x02, 0x07);
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
/* low */
|
|
switch (gpio) {
|
|
case 1:
|
|
return axp_regmap_update_sync(map,
|
|
AXP_GPIO1_CFG, 0x20, 0x60);
|
|
case 2:
|
|
return axp_regmap_update_sync(map,
|
|
AXP_GPIO2_CFG, 0x01, 0x07);
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return -ENXIO;
|
|
}
|
|
|
|
static int pmu1736_pmx_set(struct axp_dev *axp_dev, int gpio, int mux)
|
|
{
|
|
struct axp_regmap *map;
|
|
|
|
map = axp_dev->regmap;
|
|
if (NULL == map) {
|
|
pr_err("%s: %d axp regmap is null\n", __func__, __LINE__);
|
|
return -ENXIO;
|
|
}
|
|
|
|
if (mux == 1) {
|
|
/* output */
|
|
switch (gpio) {
|
|
case 1:
|
|
return axp_regmap_update_sync(map,
|
|
AXP_GPIO1_CFG, 0x20, 0x60);
|
|
case 2:
|
|
return axp_regmap_update_sync(map,
|
|
AXP_GPIO2_CFG, 0x02, 0x07);
|
|
default:
|
|
return -ENXIO;
|
|
}
|
|
} else if (mux == 0) {
|
|
/* input */
|
|
switch (gpio) {
|
|
case 1:
|
|
return axp_regmap_update_sync(map,
|
|
AXP_GPIO1_CFG, 0x60, 0x60);
|
|
case 2:
|
|
return axp_regmap_update_sync(map,
|
|
AXP_GPIO2_CFG, 0x03, 0x07);
|
|
default:
|
|
pr_err("This IO can not config as input!");
|
|
return -ENXIO;
|
|
}
|
|
}
|
|
|
|
return -ENXIO;
|
|
}
|
|
|
|
static int pmu1736_pmx_get(struct axp_dev *axp_dev, int gpio)
|
|
{
|
|
u8 ret;
|
|
struct axp_regmap *map;
|
|
|
|
map = axp_dev->regmap;
|
|
if (NULL == map) {
|
|
pr_err("%s: %d axp regmap is null\n",
|
|
__func__, __LINE__);
|
|
return -ENXIO;
|
|
}
|
|
|
|
switch (gpio) {
|
|
case 1:
|
|
axp_regmap_read(map, AXP_GPIO1_CFG, &ret);
|
|
if (0x40 == (ret & 0x60))
|
|
return 1;
|
|
else if (0x60 == (ret & 0x60))
|
|
return 0;
|
|
else
|
|
return -ENXIO;
|
|
case 2:
|
|
axp_regmap_read(map, AXP_GPIO2_CFG, &ret);
|
|
if (0x02 == (ret & 0x07))
|
|
return 1;
|
|
else if (0x03 == (ret & 0x07))
|
|
return 0;
|
|
else
|
|
return -ENXIO;
|
|
default:
|
|
return -ENXIO;
|
|
}
|
|
}
|
|
|
|
static const struct axp_desc_pin pmu1736_pins[] = {
|
|
AXP_PIN_DESC(AXP_PINCTRL_GPIO(1),
|
|
AXP_FUNCTION(0x0, "gpio_in"),
|
|
AXP_FUNCTION(0x1, "gpio_out")),
|
|
AXP_PIN_DESC(AXP_PINCTRL_GPIO(2),
|
|
AXP_FUNCTION(0x0, "gpio_in"),
|
|
AXP_FUNCTION(0x1, "gpio_out")),
|
|
};
|
|
|
|
static struct axp_pinctrl_desc pmu1736_pinctrl_pins_desc = {
|
|
.pins = pmu1736_pins,
|
|
.npins = ARRAY_SIZE(pmu1736_pins),
|
|
};
|
|
|
|
static struct axp_gpio_ops pmu1736_gpio_ops = {
|
|
.gpio_get_data = pmu1736_gpio_get_data,
|
|
.gpio_set_data = pmu1736_gpio_set_data,
|
|
.pmx_set = pmu1736_pmx_set,
|
|
.pmx_get = pmu1736_pmx_get,
|
|
};
|
|
|
|
static int pmu1736_gpio_probe(struct platform_device *pdev)
|
|
{
|
|
|
|
struct axp_dev *axp_dev = dev_get_drvdata(pdev->dev.parent);
|
|
struct axp_pinctrl *pmu1736_pin;
|
|
|
|
pmu1736_pin = axp_pinctrl_register(&pdev->dev,
|
|
axp_dev, &pmu1736_pinctrl_pins_desc,
|
|
&pmu1736_gpio_ops);
|
|
if (IS_ERR_OR_NULL(pmu1736_pin))
|
|
goto fail;
|
|
|
|
platform_set_drvdata(pdev, pmu1736_pin);
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
return -1;
|
|
}
|
|
|
|
static int pmu1736_gpio_remove(struct platform_device *pdev)
|
|
{
|
|
struct axp_pinctrl *pmu1736_pin = platform_get_drvdata(pdev);
|
|
return axp_pinctrl_unregister(pmu1736_pin);
|
|
}
|
|
|
|
static const struct of_device_id pmu1736_gpio_dt_ids[] = {
|
|
{ .compatible = "pmu1736-gpio", },
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, pmu1736_gpio_dt_ids);
|
|
|
|
static struct platform_driver pmu1736_gpio_driver = {
|
|
.driver = {
|
|
.name = "pmu1736-gpio",
|
|
.of_match_table = pmu1736_gpio_dt_ids,
|
|
},
|
|
.probe = pmu1736_gpio_probe,
|
|
.remove = pmu1736_gpio_remove,
|
|
};
|
|
|
|
static int __init pmu1736_gpio_initcall(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = platform_driver_register(&pmu1736_gpio_driver);
|
|
if (IS_ERR_VALUE(ret)) {
|
|
pr_err("%s: failed, errno %d\n", __func__, ret);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
fs_initcall(pmu1736_gpio_initcall);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("gpio Driver for pmu1736");
|
|
MODULE_AUTHOR("Qin <qinyongshen@allwinnertech.com>");
|