18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  MAX732x I2C Port Expander with 8/16 I/O
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2007 Marvell International Ltd.
68c2ecf20Sopenharmony_ci *  Copyright (C) 2008 Jack Ren <jack.ren@marvell.com>
78c2ecf20Sopenharmony_ci *  Copyright (C) 2008 Eric Miao <eric.miao@marvell.com>
88c2ecf20Sopenharmony_ci *  Copyright (C) 2015 Linus Walleij <linus.walleij@linaro.org>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  Derived from drivers/gpio/pca953x.c
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/string.h>
178c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
188c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
198c2ecf20Sopenharmony_ci#include <linux/i2c.h>
208c2ecf20Sopenharmony_ci#include <linux/platform_data/max732x.h>
218c2ecf20Sopenharmony_ci#include <linux/of.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * Each port of MAX732x (including MAX7319) falls into one of the
268c2ecf20Sopenharmony_ci * following three types:
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci *   - Push Pull Output
298c2ecf20Sopenharmony_ci *   - Input
308c2ecf20Sopenharmony_ci *   - Open Drain I/O
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * designated by 'O', 'I' and 'P' individually according to MAXIM's
338c2ecf20Sopenharmony_ci * datasheets. 'I' and 'P' ports are interrupt capables, some with
348c2ecf20Sopenharmony_ci * a dedicated interrupt mask.
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * There are two groups of I/O ports, each group usually includes
378c2ecf20Sopenharmony_ci * up to 8 I/O ports, and is accessed by a specific I2C address:
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci *   - Group A : by I2C address 0b'110xxxx
408c2ecf20Sopenharmony_ci *   - Group B : by I2C address 0b'101xxxx
418c2ecf20Sopenharmony_ci *
428c2ecf20Sopenharmony_ci * where 'xxxx' is decided by the connections of pin AD2/AD0.  The
438c2ecf20Sopenharmony_ci * address used also affects the initial state of output signals.
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci * Within each group of ports, there are five known combinations of
468c2ecf20Sopenharmony_ci * I/O ports: 4I4O, 4P4O, 8I, 8P, 8O, see the definitions below for
478c2ecf20Sopenharmony_ci * the detailed organization of these ports. Only Goup A is interrupt
488c2ecf20Sopenharmony_ci * capable.
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci * GPIO numbers start from 'gpio_base + 0' to 'gpio_base + 8/16',
518c2ecf20Sopenharmony_ci * and GPIOs from GROUP_A are numbered before those from GROUP_B
528c2ecf20Sopenharmony_ci * (if there are two groups).
538c2ecf20Sopenharmony_ci *
548c2ecf20Sopenharmony_ci * NOTE: MAX7328/MAX7329 are drop-in replacements for PCF8574/a, so
558c2ecf20Sopenharmony_ci * they are not supported by this driver.
568c2ecf20Sopenharmony_ci */
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define PORT_NONE	0x0	/* '/' No Port */
598c2ecf20Sopenharmony_ci#define PORT_OUTPUT	0x1	/* 'O' Push-Pull, Output Only */
608c2ecf20Sopenharmony_ci#define PORT_INPUT	0x2	/* 'I' Input Only */
618c2ecf20Sopenharmony_ci#define PORT_OPENDRAIN	0x3	/* 'P' Open-Drain, I/O */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define IO_4I4O		0x5AA5	/* O7 O6 I5 I4 I3 I2 O1 O0 */
648c2ecf20Sopenharmony_ci#define IO_4P4O		0x5FF5	/* O7 O6 P5 P4 P3 P2 O1 O0 */
658c2ecf20Sopenharmony_ci#define IO_8I		0xAAAA	/* I7 I6 I5 I4 I3 I2 I1 I0 */
668c2ecf20Sopenharmony_ci#define IO_8P		0xFFFF	/* P7 P6 P5 P4 P3 P2 P1 P0 */
678c2ecf20Sopenharmony_ci#define IO_8O		0x5555	/* O7 O6 O5 O4 O3 O2 O1 O0 */
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define GROUP_A(x)	((x) & 0xffff)	/* I2C Addr: 0b'110xxxx */
708c2ecf20Sopenharmony_ci#define GROUP_B(x)	((x) << 16)	/* I2C Addr: 0b'101xxxx */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#define INT_NONE	0x0	/* No interrupt capability */
738c2ecf20Sopenharmony_ci#define INT_NO_MASK	0x1	/* Has interrupts, no mask */
748c2ecf20Sopenharmony_ci#define INT_INDEP_MASK	0x2	/* Has interrupts, independent mask */
758c2ecf20Sopenharmony_ci#define INT_MERGED_MASK 0x3	/* Has interrupts, merged mask */
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define INT_CAPS(x)	(((uint64_t)(x)) << 32)
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cienum {
808c2ecf20Sopenharmony_ci	MAX7319,
818c2ecf20Sopenharmony_ci	MAX7320,
828c2ecf20Sopenharmony_ci	MAX7321,
838c2ecf20Sopenharmony_ci	MAX7322,
848c2ecf20Sopenharmony_ci	MAX7323,
858c2ecf20Sopenharmony_ci	MAX7324,
868c2ecf20Sopenharmony_ci	MAX7325,
878c2ecf20Sopenharmony_ci	MAX7326,
888c2ecf20Sopenharmony_ci	MAX7327,
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic uint64_t max732x_features[] = {
928c2ecf20Sopenharmony_ci	[MAX7319] = GROUP_A(IO_8I) | INT_CAPS(INT_MERGED_MASK),
938c2ecf20Sopenharmony_ci	[MAX7320] = GROUP_B(IO_8O),
948c2ecf20Sopenharmony_ci	[MAX7321] = GROUP_A(IO_8P) | INT_CAPS(INT_NO_MASK),
958c2ecf20Sopenharmony_ci	[MAX7322] = GROUP_A(IO_4I4O) | INT_CAPS(INT_MERGED_MASK),
968c2ecf20Sopenharmony_ci	[MAX7323] = GROUP_A(IO_4P4O) | INT_CAPS(INT_INDEP_MASK),
978c2ecf20Sopenharmony_ci	[MAX7324] = GROUP_A(IO_8I) | GROUP_B(IO_8O) | INT_CAPS(INT_MERGED_MASK),
988c2ecf20Sopenharmony_ci	[MAX7325] = GROUP_A(IO_8P) | GROUP_B(IO_8O) | INT_CAPS(INT_NO_MASK),
998c2ecf20Sopenharmony_ci	[MAX7326] = GROUP_A(IO_4I4O) | GROUP_B(IO_8O) | INT_CAPS(INT_MERGED_MASK),
1008c2ecf20Sopenharmony_ci	[MAX7327] = GROUP_A(IO_4P4O) | GROUP_B(IO_8O) | INT_CAPS(INT_NO_MASK),
1018c2ecf20Sopenharmony_ci};
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic const struct i2c_device_id max732x_id[] = {
1048c2ecf20Sopenharmony_ci	{ "max7319", MAX7319 },
1058c2ecf20Sopenharmony_ci	{ "max7320", MAX7320 },
1068c2ecf20Sopenharmony_ci	{ "max7321", MAX7321 },
1078c2ecf20Sopenharmony_ci	{ "max7322", MAX7322 },
1088c2ecf20Sopenharmony_ci	{ "max7323", MAX7323 },
1098c2ecf20Sopenharmony_ci	{ "max7324", MAX7324 },
1108c2ecf20Sopenharmony_ci	{ "max7325", MAX7325 },
1118c2ecf20Sopenharmony_ci	{ "max7326", MAX7326 },
1128c2ecf20Sopenharmony_ci	{ "max7327", MAX7327 },
1138c2ecf20Sopenharmony_ci	{ },
1148c2ecf20Sopenharmony_ci};
1158c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max732x_id);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
1188c2ecf20Sopenharmony_cistatic const struct of_device_id max732x_of_table[] = {
1198c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max7319" },
1208c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max7320" },
1218c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max7321" },
1228c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max7322" },
1238c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max7323" },
1248c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max7324" },
1258c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max7325" },
1268c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max7326" },
1278c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max7327" },
1288c2ecf20Sopenharmony_ci	{ }
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, max732x_of_table);
1318c2ecf20Sopenharmony_ci#endif
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistruct max732x_chip {
1348c2ecf20Sopenharmony_ci	struct gpio_chip gpio_chip;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	struct i2c_client *client;	/* "main" client */
1378c2ecf20Sopenharmony_ci	struct i2c_client *client_dummy;
1388c2ecf20Sopenharmony_ci	struct i2c_client *client_group_a;
1398c2ecf20Sopenharmony_ci	struct i2c_client *client_group_b;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	unsigned int	mask_group_a;
1428c2ecf20Sopenharmony_ci	unsigned int	dir_input;
1438c2ecf20Sopenharmony_ci	unsigned int	dir_output;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	struct mutex	lock;
1468c2ecf20Sopenharmony_ci	uint8_t		reg_out[2];
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIO_MAX732X_IRQ
1498c2ecf20Sopenharmony_ci	struct mutex		irq_lock;
1508c2ecf20Sopenharmony_ci	uint8_t			irq_mask;
1518c2ecf20Sopenharmony_ci	uint8_t			irq_mask_cur;
1528c2ecf20Sopenharmony_ci	uint8_t			irq_trig_raise;
1538c2ecf20Sopenharmony_ci	uint8_t			irq_trig_fall;
1548c2ecf20Sopenharmony_ci	uint8_t			irq_features;
1558c2ecf20Sopenharmony_ci#endif
1568c2ecf20Sopenharmony_ci};
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic int max732x_writeb(struct max732x_chip *chip, int group_a, uint8_t val)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	struct i2c_client *client;
1618c2ecf20Sopenharmony_ci	int ret;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	client = group_a ? chip->client_group_a : chip->client_group_b;
1648c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte(client, val);
1658c2ecf20Sopenharmony_ci	if (ret < 0) {
1668c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed writing\n");
1678c2ecf20Sopenharmony_ci		return ret;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int max732x_readb(struct max732x_chip *chip, int group_a, uint8_t *val)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct i2c_client *client;
1768c2ecf20Sopenharmony_ci	int ret;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	client = group_a ? chip->client_group_a : chip->client_group_b;
1798c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte(client);
1808c2ecf20Sopenharmony_ci	if (ret < 0) {
1818c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed reading\n");
1828c2ecf20Sopenharmony_ci		return ret;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	*val = (uint8_t)ret;
1868c2ecf20Sopenharmony_ci	return 0;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic inline int is_group_a(struct max732x_chip *chip, unsigned off)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	return (1u << off) & chip->mask_group_a;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct max732x_chip *chip = gpiochip_get_data(gc);
1978c2ecf20Sopenharmony_ci	uint8_t reg_val;
1988c2ecf20Sopenharmony_ci	int ret;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	ret = max732x_readb(chip, is_group_a(chip, off), &reg_val);
2018c2ecf20Sopenharmony_ci	if (ret < 0)
2028c2ecf20Sopenharmony_ci		return ret;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return !!(reg_val & (1u << (off & 0x7)));
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic void max732x_gpio_set_mask(struct gpio_chip *gc, unsigned off, int mask,
2088c2ecf20Sopenharmony_ci				  int val)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct max732x_chip *chip = gpiochip_get_data(gc);
2118c2ecf20Sopenharmony_ci	uint8_t reg_out;
2128c2ecf20Sopenharmony_ci	int ret;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	mutex_lock(&chip->lock);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	reg_out = (off > 7) ? chip->reg_out[1] : chip->reg_out[0];
2178c2ecf20Sopenharmony_ci	reg_out = (reg_out & ~mask) | (val & mask);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	ret = max732x_writeb(chip, is_group_a(chip, off), reg_out);
2208c2ecf20Sopenharmony_ci	if (ret < 0)
2218c2ecf20Sopenharmony_ci		goto out;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	/* update the shadow register then */
2248c2ecf20Sopenharmony_ci	if (off > 7)
2258c2ecf20Sopenharmony_ci		chip->reg_out[1] = reg_out;
2268c2ecf20Sopenharmony_ci	else
2278c2ecf20Sopenharmony_ci		chip->reg_out[0] = reg_out;
2288c2ecf20Sopenharmony_ciout:
2298c2ecf20Sopenharmony_ci	mutex_unlock(&chip->lock);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	unsigned base = off & ~0x7;
2358c2ecf20Sopenharmony_ci	uint8_t mask = 1u << (off & 0x7);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	max732x_gpio_set_mask(gc, base, mask, val << (off & 0x7));
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic void max732x_gpio_set_multiple(struct gpio_chip *gc,
2418c2ecf20Sopenharmony_ci				      unsigned long *mask, unsigned long *bits)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	unsigned mask_lo = mask[0] & 0xff;
2448c2ecf20Sopenharmony_ci	unsigned mask_hi = (mask[0] >> 8) & 0xff;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (mask_lo)
2478c2ecf20Sopenharmony_ci		max732x_gpio_set_mask(gc, 0, mask_lo, bits[0] & 0xff);
2488c2ecf20Sopenharmony_ci	if (mask_hi)
2498c2ecf20Sopenharmony_ci		max732x_gpio_set_mask(gc, 8, mask_hi, (bits[0] >> 8) & 0xff);
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct max732x_chip *chip = gpiochip_get_data(gc);
2558c2ecf20Sopenharmony_ci	unsigned int mask = 1u << off;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if ((mask & chip->dir_input) == 0) {
2588c2ecf20Sopenharmony_ci		dev_dbg(&chip->client->dev, "%s port %d is output only\n",
2598c2ecf20Sopenharmony_ci			chip->client->name, off);
2608c2ecf20Sopenharmony_ci		return -EACCES;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/*
2648c2ecf20Sopenharmony_ci	 * Open-drain pins must be set to high impedance (which is
2658c2ecf20Sopenharmony_ci	 * equivalent to output-high) to be turned into an input.
2668c2ecf20Sopenharmony_ci	 */
2678c2ecf20Sopenharmony_ci	if ((mask & chip->dir_output))
2688c2ecf20Sopenharmony_ci		max732x_gpio_set_value(gc, off, 1);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return 0;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int max732x_gpio_direction_output(struct gpio_chip *gc,
2748c2ecf20Sopenharmony_ci		unsigned off, int val)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct max732x_chip *chip = gpiochip_get_data(gc);
2778c2ecf20Sopenharmony_ci	unsigned int mask = 1u << off;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if ((mask & chip->dir_output) == 0) {
2808c2ecf20Sopenharmony_ci		dev_dbg(&chip->client->dev, "%s port %d is input only\n",
2818c2ecf20Sopenharmony_ci			chip->client->name, off);
2828c2ecf20Sopenharmony_ci		return -EACCES;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	max732x_gpio_set_value(gc, off, val);
2868c2ecf20Sopenharmony_ci	return 0;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIO_MAX732X_IRQ
2908c2ecf20Sopenharmony_cistatic int max732x_writew(struct max732x_chip *chip, uint16_t val)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	int ret;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	val = cpu_to_le16(val);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	ret = i2c_master_send(chip->client_group_a, (char *)&val, 2);
2978c2ecf20Sopenharmony_ci	if (ret < 0) {
2988c2ecf20Sopenharmony_ci		dev_err(&chip->client_group_a->dev, "failed writing\n");
2998c2ecf20Sopenharmony_ci		return ret;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	return 0;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic int max732x_readw(struct max732x_chip *chip, uint16_t *val)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	int ret;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	ret = i2c_master_recv(chip->client_group_a, (char *)val, 2);
3108c2ecf20Sopenharmony_ci	if (ret < 0) {
3118c2ecf20Sopenharmony_ci		dev_err(&chip->client_group_a->dev, "failed reading\n");
3128c2ecf20Sopenharmony_ci		return ret;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	*val = le16_to_cpu(*val);
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic void max732x_irq_update_mask(struct max732x_chip *chip)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	uint16_t msg;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (chip->irq_mask == chip->irq_mask_cur)
3248c2ecf20Sopenharmony_ci		return;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	chip->irq_mask = chip->irq_mask_cur;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (chip->irq_features == INT_NO_MASK)
3298c2ecf20Sopenharmony_ci		return;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	mutex_lock(&chip->lock);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	switch (chip->irq_features) {
3348c2ecf20Sopenharmony_ci	case INT_INDEP_MASK:
3358c2ecf20Sopenharmony_ci		msg = (chip->irq_mask << 8) | chip->reg_out[0];
3368c2ecf20Sopenharmony_ci		max732x_writew(chip, msg);
3378c2ecf20Sopenharmony_ci		break;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	case INT_MERGED_MASK:
3408c2ecf20Sopenharmony_ci		msg = chip->irq_mask | chip->reg_out[0];
3418c2ecf20Sopenharmony_ci		max732x_writeb(chip, 1, (uint8_t)msg);
3428c2ecf20Sopenharmony_ci		break;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	mutex_unlock(&chip->lock);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic void max732x_irq_mask(struct irq_data *d)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3518c2ecf20Sopenharmony_ci	struct max732x_chip *chip = gpiochip_get_data(gc);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	chip->irq_mask_cur &= ~(1 << d->hwirq);
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic void max732x_irq_unmask(struct irq_data *d)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3598c2ecf20Sopenharmony_ci	struct max732x_chip *chip = gpiochip_get_data(gc);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	chip->irq_mask_cur |= 1 << d->hwirq;
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic void max732x_irq_bus_lock(struct irq_data *d)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3678c2ecf20Sopenharmony_ci	struct max732x_chip *chip = gpiochip_get_data(gc);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	mutex_lock(&chip->irq_lock);
3708c2ecf20Sopenharmony_ci	chip->irq_mask_cur = chip->irq_mask;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic void max732x_irq_bus_sync_unlock(struct irq_data *d)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3768c2ecf20Sopenharmony_ci	struct max732x_chip *chip = gpiochip_get_data(gc);
3778c2ecf20Sopenharmony_ci	uint16_t new_irqs;
3788c2ecf20Sopenharmony_ci	uint16_t level;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	max732x_irq_update_mask(chip);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	new_irqs = chip->irq_trig_fall | chip->irq_trig_raise;
3838c2ecf20Sopenharmony_ci	while (new_irqs) {
3848c2ecf20Sopenharmony_ci		level = __ffs(new_irqs);
3858c2ecf20Sopenharmony_ci		max732x_gpio_direction_input(&chip->gpio_chip, level);
3868c2ecf20Sopenharmony_ci		new_irqs &= ~(1 << level);
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	mutex_unlock(&chip->irq_lock);
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic int max732x_irq_set_type(struct irq_data *d, unsigned int type)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3958c2ecf20Sopenharmony_ci	struct max732x_chip *chip = gpiochip_get_data(gc);
3968c2ecf20Sopenharmony_ci	uint16_t off = d->hwirq;
3978c2ecf20Sopenharmony_ci	uint16_t mask = 1 << off;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (!(mask & chip->dir_input)) {
4008c2ecf20Sopenharmony_ci		dev_dbg(&chip->client->dev, "%s port %d is output only\n",
4018c2ecf20Sopenharmony_ci			chip->client->name, off);
4028c2ecf20Sopenharmony_ci		return -EACCES;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if (!(type & IRQ_TYPE_EDGE_BOTH)) {
4068c2ecf20Sopenharmony_ci		dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
4078c2ecf20Sopenharmony_ci			d->irq, type);
4088c2ecf20Sopenharmony_ci		return -EINVAL;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_EDGE_FALLING)
4128c2ecf20Sopenharmony_ci		chip->irq_trig_fall |= mask;
4138c2ecf20Sopenharmony_ci	else
4148c2ecf20Sopenharmony_ci		chip->irq_trig_fall &= ~mask;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_EDGE_RISING)
4178c2ecf20Sopenharmony_ci		chip->irq_trig_raise |= mask;
4188c2ecf20Sopenharmony_ci	else
4198c2ecf20Sopenharmony_ci		chip->irq_trig_raise &= ~mask;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	return 0;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic int max732x_irq_set_wake(struct irq_data *data, unsigned int on)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	struct max732x_chip *chip = irq_data_get_irq_chip_data(data);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	irq_set_irq_wake(chip->client->irq, on);
4298c2ecf20Sopenharmony_ci	return 0;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic struct irq_chip max732x_irq_chip = {
4338c2ecf20Sopenharmony_ci	.name			= "max732x",
4348c2ecf20Sopenharmony_ci	.irq_mask		= max732x_irq_mask,
4358c2ecf20Sopenharmony_ci	.irq_unmask		= max732x_irq_unmask,
4368c2ecf20Sopenharmony_ci	.irq_bus_lock		= max732x_irq_bus_lock,
4378c2ecf20Sopenharmony_ci	.irq_bus_sync_unlock	= max732x_irq_bus_sync_unlock,
4388c2ecf20Sopenharmony_ci	.irq_set_type		= max732x_irq_set_type,
4398c2ecf20Sopenharmony_ci	.irq_set_wake		= max732x_irq_set_wake,
4408c2ecf20Sopenharmony_ci};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic uint8_t max732x_irq_pending(struct max732x_chip *chip)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	uint8_t cur_stat;
4458c2ecf20Sopenharmony_ci	uint8_t old_stat;
4468c2ecf20Sopenharmony_ci	uint8_t trigger;
4478c2ecf20Sopenharmony_ci	uint8_t pending;
4488c2ecf20Sopenharmony_ci	uint16_t status;
4498c2ecf20Sopenharmony_ci	int ret;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	ret = max732x_readw(chip, &status);
4528c2ecf20Sopenharmony_ci	if (ret)
4538c2ecf20Sopenharmony_ci		return 0;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	trigger = status >> 8;
4568c2ecf20Sopenharmony_ci	trigger &= chip->irq_mask;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (!trigger)
4598c2ecf20Sopenharmony_ci		return 0;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	cur_stat = status & 0xFF;
4628c2ecf20Sopenharmony_ci	cur_stat &= chip->irq_mask;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	old_stat = cur_stat ^ trigger;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	pending = (old_stat & chip->irq_trig_fall) |
4678c2ecf20Sopenharmony_ci		  (cur_stat & chip->irq_trig_raise);
4688c2ecf20Sopenharmony_ci	pending &= trigger;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	return pending;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic irqreturn_t max732x_irq_handler(int irq, void *devid)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct max732x_chip *chip = devid;
4768c2ecf20Sopenharmony_ci	uint8_t pending;
4778c2ecf20Sopenharmony_ci	uint8_t level;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	pending = max732x_irq_pending(chip);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (!pending)
4828c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	do {
4858c2ecf20Sopenharmony_ci		level = __ffs(pending);
4868c2ecf20Sopenharmony_ci		handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain,
4878c2ecf20Sopenharmony_ci						   level));
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci		pending &= ~(1 << level);
4908c2ecf20Sopenharmony_ci	} while (pending);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic int max732x_irq_setup(struct max732x_chip *chip,
4968c2ecf20Sopenharmony_ci			     const struct i2c_device_id *id)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	struct i2c_client *client = chip->client;
4998c2ecf20Sopenharmony_ci	struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
5008c2ecf20Sopenharmony_ci	int has_irq = max732x_features[id->driver_data] >> 32;
5018c2ecf20Sopenharmony_ci	int irq_base = 0;
5028c2ecf20Sopenharmony_ci	int ret;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	if (((pdata && pdata->irq_base) || client->irq)
5058c2ecf20Sopenharmony_ci			&& has_irq != INT_NONE) {
5068c2ecf20Sopenharmony_ci		struct gpio_irq_chip *girq;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		if (pdata)
5098c2ecf20Sopenharmony_ci			irq_base = pdata->irq_base;
5108c2ecf20Sopenharmony_ci		chip->irq_features = has_irq;
5118c2ecf20Sopenharmony_ci		mutex_init(&chip->irq_lock);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(&client->dev, client->irq,
5148c2ecf20Sopenharmony_ci				NULL, max732x_irq_handler, IRQF_ONESHOT |
5158c2ecf20Sopenharmony_ci				IRQF_TRIGGER_FALLING | IRQF_SHARED,
5168c2ecf20Sopenharmony_ci				dev_name(&client->dev), chip);
5178c2ecf20Sopenharmony_ci		if (ret) {
5188c2ecf20Sopenharmony_ci			dev_err(&client->dev, "failed to request irq %d\n",
5198c2ecf20Sopenharmony_ci				client->irq);
5208c2ecf20Sopenharmony_ci			return ret;
5218c2ecf20Sopenharmony_ci		}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		girq = &chip->gpio_chip.irq;
5248c2ecf20Sopenharmony_ci		girq->chip = &max732x_irq_chip;
5258c2ecf20Sopenharmony_ci		/* This will let us handle the parent IRQ in the driver */
5268c2ecf20Sopenharmony_ci		girq->parent_handler = NULL;
5278c2ecf20Sopenharmony_ci		girq->num_parents = 0;
5288c2ecf20Sopenharmony_ci		girq->parents = NULL;
5298c2ecf20Sopenharmony_ci		girq->default_type = IRQ_TYPE_NONE;
5308c2ecf20Sopenharmony_ci		girq->handler = handle_simple_irq;
5318c2ecf20Sopenharmony_ci		girq->threaded = true;
5328c2ecf20Sopenharmony_ci		girq->first = irq_base; /* FIXME: get rid of this */
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	return 0;
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci#else /* CONFIG_GPIO_MAX732X_IRQ */
5398c2ecf20Sopenharmony_cistatic int max732x_irq_setup(struct max732x_chip *chip,
5408c2ecf20Sopenharmony_ci			     const struct i2c_device_id *id)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	struct i2c_client *client = chip->client;
5438c2ecf20Sopenharmony_ci	struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
5448c2ecf20Sopenharmony_ci	int has_irq = max732x_features[id->driver_data] >> 32;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (((pdata && pdata->irq_base) || client->irq) && has_irq != INT_NONE)
5478c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "interrupt support not compiled in\n");
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	return 0;
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci#endif
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic int max732x_setup_gpio(struct max732x_chip *chip,
5548c2ecf20Sopenharmony_ci					const struct i2c_device_id *id,
5558c2ecf20Sopenharmony_ci					unsigned gpio_start)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	struct gpio_chip *gc = &chip->gpio_chip;
5588c2ecf20Sopenharmony_ci	uint32_t id_data = (uint32_t)max732x_features[id->driver_data];
5598c2ecf20Sopenharmony_ci	int i, port = 0;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++, id_data >>= 2) {
5628c2ecf20Sopenharmony_ci		unsigned int mask = 1 << port;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		switch (id_data & 0x3) {
5658c2ecf20Sopenharmony_ci		case PORT_OUTPUT:
5668c2ecf20Sopenharmony_ci			chip->dir_output |= mask;
5678c2ecf20Sopenharmony_ci			break;
5688c2ecf20Sopenharmony_ci		case PORT_INPUT:
5698c2ecf20Sopenharmony_ci			chip->dir_input |= mask;
5708c2ecf20Sopenharmony_ci			break;
5718c2ecf20Sopenharmony_ci		case PORT_OPENDRAIN:
5728c2ecf20Sopenharmony_ci			chip->dir_output |= mask;
5738c2ecf20Sopenharmony_ci			chip->dir_input |= mask;
5748c2ecf20Sopenharmony_ci			break;
5758c2ecf20Sopenharmony_ci		default:
5768c2ecf20Sopenharmony_ci			continue;
5778c2ecf20Sopenharmony_ci		}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		if (i < 8)
5808c2ecf20Sopenharmony_ci			chip->mask_group_a |= mask;
5818c2ecf20Sopenharmony_ci		port++;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	if (chip->dir_input)
5858c2ecf20Sopenharmony_ci		gc->direction_input = max732x_gpio_direction_input;
5868c2ecf20Sopenharmony_ci	if (chip->dir_output) {
5878c2ecf20Sopenharmony_ci		gc->direction_output = max732x_gpio_direction_output;
5888c2ecf20Sopenharmony_ci		gc->set = max732x_gpio_set_value;
5898c2ecf20Sopenharmony_ci		gc->set_multiple = max732x_gpio_set_multiple;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci	gc->get = max732x_gpio_get_value;
5928c2ecf20Sopenharmony_ci	gc->can_sleep = true;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	gc->base = gpio_start;
5958c2ecf20Sopenharmony_ci	gc->ngpio = port;
5968c2ecf20Sopenharmony_ci	gc->label = chip->client->name;
5978c2ecf20Sopenharmony_ci	gc->parent = &chip->client->dev;
5988c2ecf20Sopenharmony_ci	gc->owner = THIS_MODULE;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	return port;
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic struct max732x_platform_data *of_gpio_max732x(struct device *dev)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	struct max732x_platform_data *pdata;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
6088c2ecf20Sopenharmony_ci	if (!pdata)
6098c2ecf20Sopenharmony_ci		return NULL;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	pdata->gpio_base = -1;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	return pdata;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic int max732x_probe(struct i2c_client *client,
6178c2ecf20Sopenharmony_ci				   const struct i2c_device_id *id)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	struct max732x_platform_data *pdata;
6208c2ecf20Sopenharmony_ci	struct device_node *node;
6218c2ecf20Sopenharmony_ci	struct max732x_chip *chip;
6228c2ecf20Sopenharmony_ci	struct i2c_client *c;
6238c2ecf20Sopenharmony_ci	uint16_t addr_a, addr_b;
6248c2ecf20Sopenharmony_ci	int ret, nr_port;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	pdata = dev_get_platdata(&client->dev);
6278c2ecf20Sopenharmony_ci	node = client->dev.of_node;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (!pdata && node)
6308c2ecf20Sopenharmony_ci		pdata = of_gpio_max732x(&client->dev);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	if (!pdata) {
6338c2ecf20Sopenharmony_ci		dev_dbg(&client->dev, "no platform data\n");
6348c2ecf20Sopenharmony_ci		return -EINVAL;
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
6388c2ecf20Sopenharmony_ci	if (chip == NULL)
6398c2ecf20Sopenharmony_ci		return -ENOMEM;
6408c2ecf20Sopenharmony_ci	chip->client = client;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	nr_port = max732x_setup_gpio(chip, id, pdata->gpio_base);
6438c2ecf20Sopenharmony_ci	chip->gpio_chip.parent = &client->dev;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	addr_a = (client->addr & 0x0f) | 0x60;
6468c2ecf20Sopenharmony_ci	addr_b = (client->addr & 0x0f) | 0x50;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	switch (client->addr & 0x70) {
6498c2ecf20Sopenharmony_ci	case 0x60:
6508c2ecf20Sopenharmony_ci		chip->client_group_a = client;
6518c2ecf20Sopenharmony_ci		if (nr_port > 8) {
6528c2ecf20Sopenharmony_ci			c = devm_i2c_new_dummy_device(&client->dev,
6538c2ecf20Sopenharmony_ci						      client->adapter, addr_b);
6548c2ecf20Sopenharmony_ci			if (IS_ERR(c)) {
6558c2ecf20Sopenharmony_ci				dev_err(&client->dev,
6568c2ecf20Sopenharmony_ci					"Failed to allocate I2C device\n");
6578c2ecf20Sopenharmony_ci				return PTR_ERR(c);
6588c2ecf20Sopenharmony_ci			}
6598c2ecf20Sopenharmony_ci			chip->client_group_b = chip->client_dummy = c;
6608c2ecf20Sopenharmony_ci		}
6618c2ecf20Sopenharmony_ci		break;
6628c2ecf20Sopenharmony_ci	case 0x50:
6638c2ecf20Sopenharmony_ci		chip->client_group_b = client;
6648c2ecf20Sopenharmony_ci		if (nr_port > 8) {
6658c2ecf20Sopenharmony_ci			c = devm_i2c_new_dummy_device(&client->dev,
6668c2ecf20Sopenharmony_ci						      client->adapter, addr_a);
6678c2ecf20Sopenharmony_ci			if (IS_ERR(c)) {
6688c2ecf20Sopenharmony_ci				dev_err(&client->dev,
6698c2ecf20Sopenharmony_ci					"Failed to allocate I2C device\n");
6708c2ecf20Sopenharmony_ci				return PTR_ERR(c);
6718c2ecf20Sopenharmony_ci			}
6728c2ecf20Sopenharmony_ci			chip->client_group_a = chip->client_dummy = c;
6738c2ecf20Sopenharmony_ci		}
6748c2ecf20Sopenharmony_ci		break;
6758c2ecf20Sopenharmony_ci	default:
6768c2ecf20Sopenharmony_ci		dev_err(&client->dev, "invalid I2C address specified %02x\n",
6778c2ecf20Sopenharmony_ci				client->addr);
6788c2ecf20Sopenharmony_ci		return -EINVAL;
6798c2ecf20Sopenharmony_ci	}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (nr_port > 8 && !chip->client_dummy) {
6828c2ecf20Sopenharmony_ci		dev_err(&client->dev,
6838c2ecf20Sopenharmony_ci			"Failed to allocate second group I2C device\n");
6848c2ecf20Sopenharmony_ci		return -ENODEV;
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	mutex_init(&chip->lock);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	ret = max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]);
6908c2ecf20Sopenharmony_ci	if (ret)
6918c2ecf20Sopenharmony_ci		return ret;
6928c2ecf20Sopenharmony_ci	if (nr_port > 8) {
6938c2ecf20Sopenharmony_ci		ret = max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]);
6948c2ecf20Sopenharmony_ci		if (ret)
6958c2ecf20Sopenharmony_ci			return ret;
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	ret = max732x_irq_setup(chip, id);
6998c2ecf20Sopenharmony_ci	if (ret)
7008c2ecf20Sopenharmony_ci		return ret;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
7038c2ecf20Sopenharmony_ci	if (ret)
7048c2ecf20Sopenharmony_ci		return ret;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	if (pdata->setup) {
7078c2ecf20Sopenharmony_ci		ret = pdata->setup(client, chip->gpio_chip.base,
7088c2ecf20Sopenharmony_ci				chip->gpio_chip.ngpio, pdata->context);
7098c2ecf20Sopenharmony_ci		if (ret < 0)
7108c2ecf20Sopenharmony_ci			dev_warn(&client->dev, "setup failed, %d\n", ret);
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, chip);
7148c2ecf20Sopenharmony_ci	return 0;
7158c2ecf20Sopenharmony_ci}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic int max732x_remove(struct i2c_client *client)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
7208c2ecf20Sopenharmony_ci	struct max732x_chip *chip = i2c_get_clientdata(client);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	if (pdata && pdata->teardown) {
7238c2ecf20Sopenharmony_ci		int ret;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		ret = pdata->teardown(client, chip->gpio_chip.base,
7268c2ecf20Sopenharmony_ci				chip->gpio_chip.ngpio, pdata->context);
7278c2ecf20Sopenharmony_ci		if (ret < 0) {
7288c2ecf20Sopenharmony_ci			dev_err(&client->dev, "%s failed, %d\n",
7298c2ecf20Sopenharmony_ci					"teardown", ret);
7308c2ecf20Sopenharmony_ci			return ret;
7318c2ecf20Sopenharmony_ci		}
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	return 0;
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_cistatic struct i2c_driver max732x_driver = {
7388c2ecf20Sopenharmony_ci	.driver = {
7398c2ecf20Sopenharmony_ci		.name		= "max732x",
7408c2ecf20Sopenharmony_ci		.of_match_table	= of_match_ptr(max732x_of_table),
7418c2ecf20Sopenharmony_ci	},
7428c2ecf20Sopenharmony_ci	.probe		= max732x_probe,
7438c2ecf20Sopenharmony_ci	.remove		= max732x_remove,
7448c2ecf20Sopenharmony_ci	.id_table	= max732x_id,
7458c2ecf20Sopenharmony_ci};
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_cistatic int __init max732x_init(void)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	return i2c_add_driver(&max732x_driver);
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci/* register after i2c postcore initcall and before
7528c2ecf20Sopenharmony_ci * subsys initcalls that may rely on these GPIOs
7538c2ecf20Sopenharmony_ci */
7548c2ecf20Sopenharmony_cisubsys_initcall(max732x_init);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic void __exit max732x_exit(void)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	i2c_del_driver(&max732x_driver);
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_cimodule_exit(max732x_exit);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
7638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GPIO expander driver for MAX732X");
7648c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
765