1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (C) 2018 BayLibre SAS
// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
//
// GPIO driver for MAXIM 77650/77651 charger/power-supply.
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/mfd/max77650.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define MAX77650_GPIO_DIR_MASK BIT(0)
#define MAX77650_GPIO_INVAL_MASK BIT(1)
#define MAX77650_GPIO_DRV_MASK BIT(2)
#define MAX77650_GPIO_OUTVAL_MASK BIT(3)
#define MAX77650_GPIO_DEBOUNCE_MASK BIT(4)
#define MAX77650_GPIO_DIR_OUT 0x00
#define MAX77650_GPIO_DIR_IN BIT(0)
#define MAX77650_GPIO_OUT_LOW 0x00
#define MAX77650_GPIO_OUT_HIGH BIT(3)
#define MAX77650_GPIO_DRV_OPEN_DRAIN 0x00
#define MAX77650_GPIO_DRV_PUSH_PULL BIT(2)
#define MAX77650_GPIO_DEBOUNCE BIT(4)
#define MAX77650_GPIO_DIR_BITS(_reg) \
((_reg) & MAX77650_GPIO_DIR_MASK)
#define MAX77650_GPIO_INVAL_BITS(_reg) \
(((_reg) & MAX77650_GPIO_INVAL_MASK) >> 1)
struct max77650_gpio_chip {
struct regmap *map;
struct gpio_chip gc;
int irq;
};
static int max77650_gpio_direction_input(struct gpio_chip *gc,
unsigned int offset)
{
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
return regmap_update_bits(chip->map,
MAX77650_REG_CNFG_GPIO,
MAX77650_GPIO_DIR_MASK,
MAX77650_GPIO_DIR_IN);
}
static int max77650_gpio_direction_output(struct gpio_chip *gc,
unsigned int offset, int value)
{
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
int mask, regval;
mask = MAX77650_GPIO_DIR_MASK | MAX77650_GPIO_OUTVAL_MASK;
regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW;
regval |= MAX77650_GPIO_DIR_OUT;
return regmap_update_bits(chip->map,
MAX77650_REG_CNFG_GPIO, mask, regval);
}
static void max77650_gpio_set_value(struct gpio_chip *gc,
unsigned int offset, int value)
{
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
int rv, regval;
regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW;
rv = regmap_update_bits(chip->map, MAX77650_REG_CNFG_GPIO,
MAX77650_GPIO_OUTVAL_MASK, regval);
if (rv)
dev_err(gc->parent, "cannot set GPIO value: %d\n", rv);
}
static int max77650_gpio_get_value(struct gpio_chip *gc,
unsigned int offset)
{
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
unsigned int val;
int rv;
rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val);
if (rv)
return rv;
return MAX77650_GPIO_INVAL_BITS(val);
}
static int max77650_gpio_get_direction(struct gpio_chip *gc,
unsigned int offset)
{
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
unsigned int val;
int rv;
rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val);
if (rv)
return rv;
return MAX77650_GPIO_DIR_BITS(val);
}
static int max77650_gpio_set_config(struct gpio_chip *gc,
unsigned int offset, unsigned long cfg)
{
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
switch (pinconf_to_config_param(cfg)) {
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
return regmap_update_bits(chip->map,
MAX77650_REG_CNFG_GPIO,
MAX77650_GPIO_DRV_MASK,
MAX77650_GPIO_DRV_OPEN_DRAIN);
case PIN_CONFIG_DRIVE_PUSH_PULL:
return regmap_update_bits(chip->map,
MAX77650_REG_CNFG_GPIO,
MAX77650_GPIO_DRV_MASK,
MAX77650_GPIO_DRV_PUSH_PULL);
case PIN_CONFIG_INPUT_DEBOUNCE:
return regmap_update_bits(chip->map,
MAX77650_REG_CNFG_GPIO,
MAX77650_GPIO_DEBOUNCE_MASK,
MAX77650_GPIO_DEBOUNCE);
default:
return -ENOTSUPP;
}
}
static int max77650_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
{
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
return chip->irq;
}
static int max77650_gpio_probe(struct platform_device *pdev)
{
struct max77650_gpio_chip *chip;
struct device *dev, *parent;
struct i2c_client *i2c;
dev = &pdev->dev;
parent = dev->parent;
i2c = to_i2c_client(parent);
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->map = dev_get_regmap(parent, NULL);
if (!chip->map)
return -ENODEV;
chip->irq = platform_get_irq_byname(pdev, "GPI");
if (chip->irq < 0)
return chip->irq;
chip->gc.base = -1;
chip->gc.ngpio = 1;
chip->gc.label = i2c->name;
chip->gc.parent = dev;
chip->gc.owner = THIS_MODULE;
chip->gc.can_sleep = true;
chip->gc.direction_input = max77650_gpio_direction_input;
chip->gc.direction_output = max77650_gpio_direction_output;
chip->gc.set = max77650_gpio_set_value;
chip->gc.get = max77650_gpio_get_value;
chip->gc.get_direction = max77650_gpio_get_direction;
chip->gc.set_config = max77650_gpio_set_config;
chip->gc.to_irq = max77650_gpio_to_irq;
return devm_gpiochip_add_data(dev, &chip->gc, chip);
}
static struct platform_driver max77650_gpio_driver = {
.driver = {
.name = "max77650-gpio",
},
.probe = max77650_gpio_probe,
};
module_platform_driver(max77650_gpio_driver);
MODULE_DESCRIPTION("MAXIM 77650/77651 GPIO driver");
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:max77650-gpio");
|