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), ®_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