Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions Documentation/devicetree/bindings/gpio/adi,adg1414-gpio.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/adi,adg1414-gpio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: ADG1414 Serially-Controlled Octal SPST Switches

maintainers:
- Kim Seer Paller <kimseer.paller@analog.com>

description:
The ADG1414 is a 9.5 Ω RON ±15 V/+12 V/±5 V iCMOS serially-controlled octal
SPST switches.

properties:
compatible:
enum:
- adi,adg14140-gpio

reg:
maxItems: 1

gpio-controller: true

'#gpio-cells':
const: 2

spi-cpha: true

reset-gpios:
description: RESET/Logic Power Supply Input (VL). When the RESET/VL pin is
low, all switches are off and the appropriate registers are cleared to 0.
maxItems: 1

'#daisy-chained-devices':
description: The number of daisy-chained devices.
$ref: /schemas/types.yaml#/definitions/uint32
default: 1
minimum: 1
maximum: 4

required:
- compatible
- reg
- spi-cpha

allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#

unevaluatedProperties: false

examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;

gpio@0 {
compatible = "adi,adg14140-gpio";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpha;
reset-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
};
};
...
1 change: 1 addition & 0 deletions Kconfig.adi
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ config KERNEL_ALL_ADI_DRIVERS
imply REGULATOR_MAX77857
imply REGULATOR_MAX77541
imply MFD_MAX77541
imply GPIO_ADG1414

source "drivers/clk/Kconfig.adi"
source "drivers/hwmon/Kconfig.adi"
Expand Down
10 changes: 10 additions & 0 deletions drivers/gpio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1708,6 +1708,16 @@ config GPIO_74X164
shift registers. This driver can be used to provide access
to more GPIO outputs.

config GPIO_ADG1414
tristate "ADG1414 SPST Switch Driver"
depends on GPIOLIB && SPI
help
Say yes here to build support for Analog Devices ADG1414 SPST
Switch Driver

To compile this driver as a module, choose M here: the
module will be called gpio-adg1414.

config GPIO_ADI_DAQ1
tristate "Analog Devices AD-FMCDAQ1-EBZ SPI-GPIO expander driver"
help
Expand Down
1 change: 1 addition & 0 deletions drivers/gpio/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o
obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
obj-$(CONFIG_GPIO_ADG1414) += gpio-adg1414.o
obj-$(CONFIG_GPIO_ADI_DAQ1) += gpio-adi-daq1.o
obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
Expand Down
155 changes: 155 additions & 0 deletions drivers/gpio/gpio-adg1414.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ADG1414 Serially-Controlled Octal SPST Switches Driver
*
* Copyright 2025 Analog Devices Inc.
*/

#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/spi/spi.h>

#define ADG1414_MAX_DEVICES 4

struct adg1414_state {
struct spi_device *spi;
struct gpio_chip chip;
/* lock to protect against multiple access to the device and shared data */
struct mutex lock;

u8 buffer[];
};

static int adg1414_write_config(struct adg1414_state *st)
{
return spi_write(st->spi, st->buffer, st->chip.ngpio / 8);
}

static int adg1414_get_value(struct gpio_chip *chip, unsigned int offset)
{
struct adg1414_state *st = gpiochip_get_data(chip);
u8 bank, pin;

guard(mutex)(&st->lock);
bank = (chip->ngpio / 8) - 1 - offset / 8;
pin = offset % 8;

return (st->buffer[bank] >> pin) & 0x1;
}

static void adg1414_set_value(struct gpio_chip *chip, unsigned int offset,
int val)
{
struct adg1414_state *st = gpiochip_get_data(chip);
u8 bank, pin;

guard(mutex)(&st->lock);
bank = (chip->ngpio / 8) - 1 - offset / 8;
pin = offset % 8;

if (val)
st->buffer[bank] |= BIT(pin);
else
st->buffer[bank] &= ~BIT(pin);

adg1414_write_config(st);
}

static void adg1414_set_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct adg1414_state *st = gpiochip_get_data(chip);
unsigned long offset, bankmask, bitmask;
size_t bank;

guard(mutex)(&st->lock);
for_each_set_clump8(offset, bankmask, mask, chip->ngpio) {
bank = (chip->ngpio / 8) - 1 - offset / 8;
bitmask = bitmap_get_value8(bits, offset) & bankmask;

st->buffer[bank] &= ~bankmask;
st->buffer[bank] |= bitmask;
}

adg1414_write_config(st);
}

static int adg1414_direction_output(struct gpio_chip *chip, unsigned int offset,
int val)
{
adg1414_set_value(chip, offset, val);
return 0;
}

static int adg1414_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct adg1414_state *st;
struct gpio_desc *reset;
u32 num_devices;
int ret;

num_devices = 1;
ret = device_property_read_u32(dev, "#daisy-chained-devices",
&num_devices);
if (!ret) {
if (!num_devices || num_devices > ADG1414_MAX_DEVICES)
return dev_err_probe(dev, ret,
"Failed to get daisy-chained-devices property\n");
}

st = devm_kzalloc(dev, sizeof(*st) + num_devices, GFP_KERNEL);
if (!st)
return -ENOMEM;

st->spi = spi;

/* Use reset pin to reset the device */
reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset))
return dev_err_probe(dev, PTR_ERR(reset),
"Failed to get reset gpio");

if (reset) {
fsleep(1);
gpiod_set_value_cansleep(reset, 0);
}

st->chip.label = "adg1414";
st->chip.parent = dev;
st->chip.direction_output = adg1414_direction_output;
st->chip.set = adg1414_set_value;
st->chip.get = adg1414_get_value;
st->chip.set_multiple = adg1414_set_multiple;
st->chip.base = -1;
st->chip.ngpio = num_devices * 8;
st->chip.can_sleep = true;

ret = devm_mutex_init(dev, &st->lock);
if (ret)
return ret;

return devm_gpiochip_add_data(dev, &st->chip, st);
}

static const struct of_device_id adg1414_of_match[] = {
{ .compatible = "adi,adg1414-gpio" },
{ }
};
MODULE_DEVICE_TABLE(of, adg1414_of_match);

static struct spi_driver adg1414_driver = {
.driver = {
.name = "adg1414-gpio",
.of_match_table = adg1414_of_match,
},
.probe = adg1414_probe,
};
module_spi_driver(adg1414_driver);

MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>");
MODULE_DESCRIPTION("ADG1414 Serially-Controlled Octal SPST Switches Driver");
MODULE_LICENSE("GPL");