mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
Replace the #include of <linux/mod_devicetable.h> by the more specific <linux/device-id/*.h> where applicable. For most cases the include can be dropped completely, only a few drivers need one or two headers added. Acked-by: Danilo Krummrich <dakr@kernel.org> Acked-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Link: https://patch.msgid.link/1a3f2007c5c5dcf555c09a4035ce3ae8ef1b6c49.1782808461.git.u.kleine-koenig@baylibre.com Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
218 lines
5.4 KiB
C
218 lines
5.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Analog Devices LTC4283 GPIO driver
|
|
*
|
|
* Copyright 2025 Analog Devices Inc.
|
|
*/
|
|
|
|
#include <linux/auxiliary_bus.h>
|
|
#include <linux/bitfield.h>
|
|
#include <linux/bitmap.h>
|
|
#include <linux/bits.h>
|
|
#include <linux/device.h>
|
|
#include <linux/gpio/driver.h>
|
|
#include <linux/module.h>
|
|
#include <linux/regmap.h>
|
|
|
|
#define LTC4283_PINS_MAX 8
|
|
#define LTC4283_PGIOX_START_NR 4
|
|
#define LTC4283_INPUT_STATUS 0x02
|
|
#define LTC4283_PGIO_CONFIG 0x10
|
|
#define LTC4283_PGIO_CFG_MASK(pin) \
|
|
GENMASK(((pin) - LTC4283_PGIOX_START_NR) * 2 + 1, (((pin) - LTC4283_PGIOX_START_NR) * 2))
|
|
#define LTC4283_PGIO_CONFIG_2 0x11
|
|
|
|
#define LTC4283_ADIO_CONFIG 0x12
|
|
/* starts at bit 4 */
|
|
#define LTC4283_ADIOX_CONFIG_MASK(pin) BIT((pin) + 4)
|
|
#define LTC4283_PGIO_DIR_IN 3
|
|
#define LTC4283_PGIO_DIR_OUT 2
|
|
|
|
struct ltc4283_gpio {
|
|
struct gpio_chip gpio_chip;
|
|
struct regmap *regmap;
|
|
};
|
|
|
|
static int ltc4283_pgio_get_direction(const struct ltc4283_gpio *st, unsigned int off)
|
|
{
|
|
unsigned int val;
|
|
int ret;
|
|
|
|
ret = regmap_read(st->regmap, LTC4283_PGIO_CONFIG, &val);
|
|
if (ret)
|
|
return ret;
|
|
|
|
val = field_get(LTC4283_PGIO_CFG_MASK(off), val);
|
|
if (val == LTC4283_PGIO_DIR_IN)
|
|
return GPIO_LINE_DIRECTION_IN;
|
|
|
|
return GPIO_LINE_DIRECTION_OUT;
|
|
}
|
|
|
|
static int ltc4283_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
|
|
{
|
|
struct ltc4283_gpio *st = gpiochip_get_data(gc);
|
|
unsigned int val;
|
|
int ret;
|
|
|
|
if (off >= LTC4283_PGIOX_START_NR)
|
|
return ltc4283_pgio_get_direction(st, off);
|
|
|
|
ret = regmap_read(st->regmap, LTC4283_ADIO_CONFIG, &val);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (val & LTC4283_ADIOX_CONFIG_MASK(off))
|
|
return GPIO_LINE_DIRECTION_IN;
|
|
|
|
return GPIO_LINE_DIRECTION_OUT;
|
|
}
|
|
|
|
static int ltc4283_gpio_direction_set(const struct ltc4283_gpio *st,
|
|
unsigned int off, bool input)
|
|
{
|
|
if (off >= LTC4283_PGIOX_START_NR) {
|
|
unsigned int val = LTC4283_PGIO_DIR_OUT;
|
|
|
|
if (input)
|
|
val = LTC4283_PGIO_DIR_IN;
|
|
|
|
val = field_prep(LTC4283_PGIO_CFG_MASK(off), val);
|
|
return regmap_update_bits(st->regmap, LTC4283_PGIO_CONFIG,
|
|
LTC4283_PGIO_CFG_MASK(off), val);
|
|
}
|
|
|
|
return regmap_update_bits(st->regmap, LTC4283_ADIO_CONFIG,
|
|
LTC4283_ADIOX_CONFIG_MASK(off),
|
|
field_prep(LTC4283_ADIOX_CONFIG_MASK(off), input));
|
|
}
|
|
|
|
static int __ltc4283_gpio_set_value(const struct ltc4283_gpio *st,
|
|
unsigned int off, int val)
|
|
{
|
|
u32 reg = off < LTC4283_PGIOX_START_NR ? LTC4283_ADIO_CONFIG : LTC4283_PGIO_CONFIG_2;
|
|
|
|
return regmap_update_bits(st->regmap, reg, BIT(off),
|
|
field_prep(BIT(off), !!val));
|
|
}
|
|
|
|
static int ltc4283_gpio_direction_input(struct gpio_chip *gc, unsigned int off)
|
|
{
|
|
struct ltc4283_gpio *st = gpiochip_get_data(gc);
|
|
|
|
return ltc4283_gpio_direction_set(st, off, true);
|
|
}
|
|
|
|
static int ltc4283_gpio_direction_output(struct gpio_chip *gc, unsigned int off, int val)
|
|
{
|
|
struct ltc4283_gpio *st = gpiochip_get_data(gc);
|
|
int ret;
|
|
|
|
ret = ltc4283_gpio_direction_set(st, off, false);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return __ltc4283_gpio_set_value(st, off, val);
|
|
}
|
|
|
|
static int ltc4283_gpio_get_value(struct gpio_chip *gc, unsigned int off)
|
|
{
|
|
struct ltc4283_gpio *st = gpiochip_get_data(gc);
|
|
unsigned int val, reg;
|
|
int ret, dir;
|
|
|
|
dir = ltc4283_gpio_get_direction(gc, off);
|
|
if (dir < 0)
|
|
return dir;
|
|
|
|
if (dir == GPIO_LINE_DIRECTION_IN) {
|
|
ret = regmap_read(st->regmap, LTC4283_INPUT_STATUS, &val);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* ADIO1 is at bit 3. */
|
|
if (off < LTC4283_PGIOX_START_NR)
|
|
return !!(val & BIT(3 - off));
|
|
|
|
/* PGIO1 is at bit 7. */
|
|
return !!(val & BIT(7 - (off - LTC4283_PGIOX_START_NR)));
|
|
}
|
|
|
|
if (off < LTC4283_PGIOX_START_NR)
|
|
reg = LTC4283_ADIO_CONFIG;
|
|
else
|
|
reg = LTC4283_PGIO_CONFIG_2;
|
|
|
|
ret = regmap_read(st->regmap, reg, &val);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return !!(val & BIT(off));
|
|
}
|
|
|
|
static int ltc4283_gpio_set_value(struct gpio_chip *gc, unsigned int off, int val)
|
|
{
|
|
struct ltc4283_gpio *st = gpiochip_get_data(gc);
|
|
|
|
return __ltc4283_gpio_set_value(st, off, val);
|
|
}
|
|
|
|
static int ltc4283_init_valid_mask(struct gpio_chip *gc, unsigned long *valid_mask,
|
|
unsigned int ngpios)
|
|
{
|
|
unsigned long *mask = dev_get_platdata(gc->parent);
|
|
|
|
bitmap_copy(valid_mask, mask, ngpios);
|
|
return 0;
|
|
}
|
|
|
|
static int ltc4283_gpio_probe(struct auxiliary_device *adev,
|
|
const struct auxiliary_device_id *id)
|
|
{
|
|
struct device *dev = &adev->dev;
|
|
struct ltc4283_gpio *st;
|
|
struct gpio_chip *gc;
|
|
|
|
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
|
|
if (!st)
|
|
return -ENOMEM;
|
|
|
|
st->regmap = dev_get_regmap(dev->parent, NULL);
|
|
if (!st->regmap)
|
|
return dev_err_probe(dev, -ENODEV,
|
|
"Failed to get regmap\n");
|
|
|
|
gc = &st->gpio_chip;
|
|
gc->parent = dev;
|
|
gc->get_direction = ltc4283_gpio_get_direction;
|
|
gc->direction_input = ltc4283_gpio_direction_input;
|
|
gc->direction_output = ltc4283_gpio_direction_output;
|
|
gc->get = ltc4283_gpio_get_value;
|
|
gc->set = ltc4283_gpio_set_value;
|
|
gc->init_valid_mask = ltc4283_init_valid_mask;
|
|
gc->can_sleep = true;
|
|
|
|
gc->base = -1;
|
|
gc->ngpio = LTC4283_PINS_MAX;
|
|
gc->label = adev->name;
|
|
gc->owner = THIS_MODULE;
|
|
|
|
return devm_gpiochip_add_data(dev, &st->gpio_chip, st);
|
|
}
|
|
|
|
static const struct auxiliary_device_id ltc4283_aux_id_table[] = {
|
|
{ "ltc4283.gpio" },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(auxiliary, ltc4283_aux_id_table);
|
|
|
|
static struct auxiliary_driver ltc4283_gpio_driver = {
|
|
.probe = ltc4283_gpio_probe,
|
|
.id_table = ltc4283_aux_id_table,
|
|
};
|
|
module_auxiliary_driver(ltc4283_gpio_driver);
|
|
|
|
MODULE_AUTHOR("Nuno Sá <nuno.sa@analog.com>");
|
|
MODULE_DESCRIPTION("GPIO LTC4283 Driver");
|
|
MODULE_LICENSE("GPL");
|