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
|
// SPDX-License-Identifier: GPL-2.0
/*
* Analog Devices AD7768 GPIO auxiliary driver
*
* Copyright 2026 Analog Devices Inc.
*/
#include <linux/auxiliary_bus.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/regmap.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h>
#define AD7768_REG_GPIO_CONTROL 0x0E
#define AD7768_GPIO_UGPIO_ENABLE BIT(7)
#define AD7768_REG_GPIO_WRITE 0x0F
#define AD7768_REG_GPIO_READ 0x10
#define AD7768_NUM_GPIOS 5
#define AD7768_FILTER_GPIO 4
static int ad7768_gpio_init_valid_mask(struct gpio_chip *gc,
unsigned long *valid_mask,
unsigned int ngpios)
{
if (ngpios > AD7768_FILTER_GPIO &&
fwnode_property_match_string(gc->fwnode, "clock-names", "mclk") < 0)
__clear_bit(AD7768_FILTER_GPIO, valid_mask);
return 0;
}
static int ad7768_gpio_reg_mask_xlate(struct gpio_regmap *gpio,
enum gpio_regmap_operation op,
unsigned int base, unsigned int offset,
unsigned int *reg, unsigned int *mask)
{
struct regmap *regmap = gpio_regmap_get_drvdata(gpio);
int ret;
*reg = base;
*mask = BIT(offset);
if (op != GPIO_REGMAP_GET_OP)
return 0;
/*
* AD7768 has separate input-state and output-latch registers. For an
* output line, report the programmed value from the output latch;
* input lines continue to use the input-state register.
*/
ret = regmap_test_bits(regmap, AD7768_REG_GPIO_CONTROL, *mask);
if (ret < 0)
return ret;
if (ret)
*reg = AD7768_REG_GPIO_WRITE;
return 0;
}
static int ad7768_gpio_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct gpio_regmap_config config;
struct device *dev = &adev->dev;
struct device *parent = dev->parent;
struct regmap *map;
int ret;
map = dev_get_regmap(parent, NULL);
if (!map)
return -ENODEV;
PM_RUNTIME_ACQUIRE_AUTOSUSPEND(parent, pm);
ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret)
return ret;
ret = regmap_set_bits(map, AD7768_REG_GPIO_CONTROL, AD7768_GPIO_UGPIO_ENABLE);
if (ret)
return ret;
config = (struct gpio_regmap_config) {
.parent = dev,
.regmap = map,
.label = dev_name(parent),
.ngpio = AD7768_NUM_GPIOS,
.reg_dat_base = AD7768_REG_GPIO_READ,
.reg_set_base = AD7768_REG_GPIO_WRITE,
.reg_dir_out_base = AD7768_REG_GPIO_CONTROL,
.pm_dev = parent,
.fwnode = dev_fwnode(parent),
.reg_mask_xlate = ad7768_gpio_reg_mask_xlate,
.init_valid_mask = ad7768_gpio_init_valid_mask,
.drvdata = map,
};
return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &config));
}
static const struct auxiliary_device_id ad7768_gpio_ids[] = {
{ .name = "ad7768.gpio" },
{ }
};
MODULE_DEVICE_TABLE(auxiliary, ad7768_gpio_ids);
static struct auxiliary_driver ad7768_gpio_driver = {
.probe = ad7768_gpio_probe,
.id_table = ad7768_gpio_ids,
};
module_auxiliary_driver(ad7768_gpio_driver);
MODULE_AUTHOR("Janani Sunil <janani.sunil@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7768 GPIO auxiliary driver");
MODULE_LICENSE("GPL");
|