18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * I2C multiplexer 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it> 68c2ecf20Sopenharmony_ci * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This module supports the PCA954x and PCA984x series of I2C multiplexer/switch 98c2ecf20Sopenharmony_ci * chips made by NXP Semiconductors. 108c2ecf20Sopenharmony_ci * This includes the: 118c2ecf20Sopenharmony_ci * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547, 128c2ecf20Sopenharmony_ci * PCA9548, PCA9846, PCA9847, PCA9848 and PCA9849. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * These chips are all controlled via the I2C bus itself, and all have a 158c2ecf20Sopenharmony_ci * single 8-bit register. The upstream "parent" bus fans out to two, 168c2ecf20Sopenharmony_ci * four, or eight downstream busses or channels; which of these 178c2ecf20Sopenharmony_ci * are selected is determined by the chip type and register contents. A 188c2ecf20Sopenharmony_ci * mux can select only one sub-bus at a time; a switch can select any 198c2ecf20Sopenharmony_ci * combination simultaneously. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Based on: 228c2ecf20Sopenharmony_ci * pca954x.c from Kumar Gala <galak@kernel.crashing.org> 238c2ecf20Sopenharmony_ci * Copyright (C) 2006 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Based on: 268c2ecf20Sopenharmony_ci * pca954x.c from Ken Harrenstien 278c2ecf20Sopenharmony_ci * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Based on: 308c2ecf20Sopenharmony_ci * i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com> 318c2ecf20Sopenharmony_ci * and 328c2ecf20Sopenharmony_ci * pca9540.c from Jean Delvare <jdelvare@suse.de>. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/device.h> 368c2ecf20Sopenharmony_ci#include <linux/delay.h> 378c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 388c2ecf20Sopenharmony_ci#include <linux/i2c.h> 398c2ecf20Sopenharmony_ci#include <linux/i2c-mux.h> 408c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 418c2ecf20Sopenharmony_ci#include <linux/irq.h> 428c2ecf20Sopenharmony_ci#include <linux/module.h> 438c2ecf20Sopenharmony_ci#include <linux/pm.h> 448c2ecf20Sopenharmony_ci#include <linux/property.h> 458c2ecf20Sopenharmony_ci#include <linux/slab.h> 468c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 478c2ecf20Sopenharmony_ci#include <dt-bindings/mux/mux.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define PCA954X_MAX_NCHANS 8 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define PCA954X_IRQ_OFFSET 4 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cienum pca_type { 548c2ecf20Sopenharmony_ci pca_9540, 558c2ecf20Sopenharmony_ci pca_9542, 568c2ecf20Sopenharmony_ci pca_9543, 578c2ecf20Sopenharmony_ci pca_9544, 588c2ecf20Sopenharmony_ci pca_9545, 598c2ecf20Sopenharmony_ci pca_9546, 608c2ecf20Sopenharmony_ci pca_9547, 618c2ecf20Sopenharmony_ci pca_9548, 628c2ecf20Sopenharmony_ci pca_9846, 638c2ecf20Sopenharmony_ci pca_9847, 648c2ecf20Sopenharmony_ci pca_9848, 658c2ecf20Sopenharmony_ci pca_9849, 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistruct chip_desc { 698c2ecf20Sopenharmony_ci u8 nchans; 708c2ecf20Sopenharmony_ci u8 enable; /* used for muxes only */ 718c2ecf20Sopenharmony_ci u8 has_irq; 728c2ecf20Sopenharmony_ci enum muxtype { 738c2ecf20Sopenharmony_ci pca954x_ismux = 0, 748c2ecf20Sopenharmony_ci pca954x_isswi 758c2ecf20Sopenharmony_ci } muxtype; 768c2ecf20Sopenharmony_ci struct i2c_device_identity id; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct pca954x { 808c2ecf20Sopenharmony_ci const struct chip_desc *chip; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci u8 last_chan; /* last register value */ 838c2ecf20Sopenharmony_ci /* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */ 848c2ecf20Sopenharmony_ci s32 idle_state; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci struct i2c_client *client; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci struct irq_domain *irq; 898c2ecf20Sopenharmony_ci unsigned int irq_mask; 908c2ecf20Sopenharmony_ci raw_spinlock_t lock; 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Provide specs for the PCA954x types we know about */ 948c2ecf20Sopenharmony_cistatic const struct chip_desc chips[] = { 958c2ecf20Sopenharmony_ci [pca_9540] = { 968c2ecf20Sopenharmony_ci .nchans = 2, 978c2ecf20Sopenharmony_ci .enable = 0x4, 988c2ecf20Sopenharmony_ci .muxtype = pca954x_ismux, 998c2ecf20Sopenharmony_ci .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, 1008c2ecf20Sopenharmony_ci }, 1018c2ecf20Sopenharmony_ci [pca_9542] = { 1028c2ecf20Sopenharmony_ci .nchans = 2, 1038c2ecf20Sopenharmony_ci .enable = 0x4, 1048c2ecf20Sopenharmony_ci .has_irq = 1, 1058c2ecf20Sopenharmony_ci .muxtype = pca954x_ismux, 1068c2ecf20Sopenharmony_ci .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci [pca_9543] = { 1098c2ecf20Sopenharmony_ci .nchans = 2, 1108c2ecf20Sopenharmony_ci .has_irq = 1, 1118c2ecf20Sopenharmony_ci .muxtype = pca954x_isswi, 1128c2ecf20Sopenharmony_ci .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, 1138c2ecf20Sopenharmony_ci }, 1148c2ecf20Sopenharmony_ci [pca_9544] = { 1158c2ecf20Sopenharmony_ci .nchans = 4, 1168c2ecf20Sopenharmony_ci .enable = 0x4, 1178c2ecf20Sopenharmony_ci .has_irq = 1, 1188c2ecf20Sopenharmony_ci .muxtype = pca954x_ismux, 1198c2ecf20Sopenharmony_ci .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, 1208c2ecf20Sopenharmony_ci }, 1218c2ecf20Sopenharmony_ci [pca_9545] = { 1228c2ecf20Sopenharmony_ci .nchans = 4, 1238c2ecf20Sopenharmony_ci .has_irq = 1, 1248c2ecf20Sopenharmony_ci .muxtype = pca954x_isswi, 1258c2ecf20Sopenharmony_ci .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, 1268c2ecf20Sopenharmony_ci }, 1278c2ecf20Sopenharmony_ci [pca_9546] = { 1288c2ecf20Sopenharmony_ci .nchans = 4, 1298c2ecf20Sopenharmony_ci .muxtype = pca954x_isswi, 1308c2ecf20Sopenharmony_ci .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, 1318c2ecf20Sopenharmony_ci }, 1328c2ecf20Sopenharmony_ci [pca_9547] = { 1338c2ecf20Sopenharmony_ci .nchans = 8, 1348c2ecf20Sopenharmony_ci .enable = 0x8, 1358c2ecf20Sopenharmony_ci .muxtype = pca954x_ismux, 1368c2ecf20Sopenharmony_ci .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, 1378c2ecf20Sopenharmony_ci }, 1388c2ecf20Sopenharmony_ci [pca_9548] = { 1398c2ecf20Sopenharmony_ci .nchans = 8, 1408c2ecf20Sopenharmony_ci .muxtype = pca954x_isswi, 1418c2ecf20Sopenharmony_ci .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, 1428c2ecf20Sopenharmony_ci }, 1438c2ecf20Sopenharmony_ci [pca_9846] = { 1448c2ecf20Sopenharmony_ci .nchans = 4, 1458c2ecf20Sopenharmony_ci .muxtype = pca954x_isswi, 1468c2ecf20Sopenharmony_ci .id = { 1478c2ecf20Sopenharmony_ci .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, 1488c2ecf20Sopenharmony_ci .part_id = 0x10b, 1498c2ecf20Sopenharmony_ci }, 1508c2ecf20Sopenharmony_ci }, 1518c2ecf20Sopenharmony_ci [pca_9847] = { 1528c2ecf20Sopenharmony_ci .nchans = 8, 1538c2ecf20Sopenharmony_ci .enable = 0x8, 1548c2ecf20Sopenharmony_ci .muxtype = pca954x_ismux, 1558c2ecf20Sopenharmony_ci .id = { 1568c2ecf20Sopenharmony_ci .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, 1578c2ecf20Sopenharmony_ci .part_id = 0x108, 1588c2ecf20Sopenharmony_ci }, 1598c2ecf20Sopenharmony_ci }, 1608c2ecf20Sopenharmony_ci [pca_9848] = { 1618c2ecf20Sopenharmony_ci .nchans = 8, 1628c2ecf20Sopenharmony_ci .muxtype = pca954x_isswi, 1638c2ecf20Sopenharmony_ci .id = { 1648c2ecf20Sopenharmony_ci .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, 1658c2ecf20Sopenharmony_ci .part_id = 0x10a, 1668c2ecf20Sopenharmony_ci }, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci [pca_9849] = { 1698c2ecf20Sopenharmony_ci .nchans = 4, 1708c2ecf20Sopenharmony_ci .enable = 0x4, 1718c2ecf20Sopenharmony_ci .muxtype = pca954x_ismux, 1728c2ecf20Sopenharmony_ci .id = { 1738c2ecf20Sopenharmony_ci .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, 1748c2ecf20Sopenharmony_ci .part_id = 0x109, 1758c2ecf20Sopenharmony_ci }, 1768c2ecf20Sopenharmony_ci }, 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic const struct i2c_device_id pca954x_id[] = { 1808c2ecf20Sopenharmony_ci { "pca9540", pca_9540 }, 1818c2ecf20Sopenharmony_ci { "pca9542", pca_9542 }, 1828c2ecf20Sopenharmony_ci { "pca9543", pca_9543 }, 1838c2ecf20Sopenharmony_ci { "pca9544", pca_9544 }, 1848c2ecf20Sopenharmony_ci { "pca9545", pca_9545 }, 1858c2ecf20Sopenharmony_ci { "pca9546", pca_9546 }, 1868c2ecf20Sopenharmony_ci { "pca9547", pca_9547 }, 1878c2ecf20Sopenharmony_ci { "pca9548", pca_9548 }, 1888c2ecf20Sopenharmony_ci { "pca9846", pca_9846 }, 1898c2ecf20Sopenharmony_ci { "pca9847", pca_9847 }, 1908c2ecf20Sopenharmony_ci { "pca9848", pca_9848 }, 1918c2ecf20Sopenharmony_ci { "pca9849", pca_9849 }, 1928c2ecf20Sopenharmony_ci { } 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pca954x_id); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic const struct of_device_id pca954x_of_match[] = { 1978c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9540", .data = &chips[pca_9540] }, 1988c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9542", .data = &chips[pca_9542] }, 1998c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9543", .data = &chips[pca_9543] }, 2008c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9544", .data = &chips[pca_9544] }, 2018c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9545", .data = &chips[pca_9545] }, 2028c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9546", .data = &chips[pca_9546] }, 2038c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9547", .data = &chips[pca_9547] }, 2048c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9548", .data = &chips[pca_9548] }, 2058c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9846", .data = &chips[pca_9846] }, 2068c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9847", .data = &chips[pca_9847] }, 2078c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9848", .data = &chips[pca_9848] }, 2088c2ecf20Sopenharmony_ci { .compatible = "nxp,pca9849", .data = &chips[pca_9849] }, 2098c2ecf20Sopenharmony_ci {} 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pca954x_of_match); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() 2148c2ecf20Sopenharmony_ci for this as they will try to lock adapter a second time */ 2158c2ecf20Sopenharmony_cistatic int pca954x_reg_write(struct i2c_adapter *adap, 2168c2ecf20Sopenharmony_ci struct i2c_client *client, u8 val) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci union i2c_smbus_data dummy; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return __i2c_smbus_xfer(adap, client->addr, client->flags, 2218c2ecf20Sopenharmony_ci I2C_SMBUS_WRITE, val, 2228c2ecf20Sopenharmony_ci I2C_SMBUS_BYTE, &dummy); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic u8 pca954x_regval(struct pca954x *data, u8 chan) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci /* We make switches look like muxes, not sure how to be smarter. */ 2288c2ecf20Sopenharmony_ci if (data->chip->muxtype == pca954x_ismux) 2298c2ecf20Sopenharmony_ci return chan | data->chip->enable; 2308c2ecf20Sopenharmony_ci else 2318c2ecf20Sopenharmony_ci return 1 << chan; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct pca954x *data = i2c_mux_priv(muxc); 2378c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 2388c2ecf20Sopenharmony_ci u8 regval; 2398c2ecf20Sopenharmony_ci int ret = 0; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci regval = pca954x_regval(data, chan); 2428c2ecf20Sopenharmony_ci /* Only select the channel if its different from the last channel */ 2438c2ecf20Sopenharmony_ci if (data->last_chan != regval) { 2448c2ecf20Sopenharmony_ci ret = pca954x_reg_write(muxc->parent, client, regval); 2458c2ecf20Sopenharmony_ci data->last_chan = ret < 0 ? 0 : regval; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct pca954x *data = i2c_mux_priv(muxc); 2548c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 2558c2ecf20Sopenharmony_ci s32 idle_state; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci idle_state = READ_ONCE(data->idle_state); 2588c2ecf20Sopenharmony_ci if (idle_state >= 0) 2598c2ecf20Sopenharmony_ci /* Set the mux back to a predetermined channel */ 2608c2ecf20Sopenharmony_ci return pca954x_select_chan(muxc, idle_state); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (idle_state == MUX_IDLE_DISCONNECT) { 2638c2ecf20Sopenharmony_ci /* Deselect active channel */ 2648c2ecf20Sopenharmony_ci data->last_chan = 0; 2658c2ecf20Sopenharmony_ci return pca954x_reg_write(muxc->parent, client, 2668c2ecf20Sopenharmony_ci data->last_chan); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* otherwise leave as-is */ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic ssize_t idle_state_show(struct device *dev, 2758c2ecf20Sopenharmony_ci struct device_attribute *attr, 2768c2ecf20Sopenharmony_ci char *buf) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 2798c2ecf20Sopenharmony_ci struct i2c_mux_core *muxc = i2c_get_clientdata(client); 2808c2ecf20Sopenharmony_ci struct pca954x *data = i2c_mux_priv(muxc); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", READ_ONCE(data->idle_state)); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic ssize_t idle_state_store(struct device *dev, 2868c2ecf20Sopenharmony_ci struct device_attribute *attr, 2878c2ecf20Sopenharmony_ci const char *buf, size_t count) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 2908c2ecf20Sopenharmony_ci struct i2c_mux_core *muxc = i2c_get_clientdata(client); 2918c2ecf20Sopenharmony_ci struct pca954x *data = i2c_mux_priv(muxc); 2928c2ecf20Sopenharmony_ci int val; 2938c2ecf20Sopenharmony_ci int ret; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &val); 2968c2ecf20Sopenharmony_ci if (ret < 0) 2978c2ecf20Sopenharmony_ci return ret; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (val != MUX_IDLE_AS_IS && val != MUX_IDLE_DISCONNECT && 3008c2ecf20Sopenharmony_ci (val < 0 || val >= data->chip->nchans)) 3018c2ecf20Sopenharmony_ci return -EINVAL; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci i2c_lock_bus(muxc->parent, I2C_LOCK_SEGMENT); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci WRITE_ONCE(data->idle_state, val); 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * Set the mux into a state consistent with the new 3088c2ecf20Sopenharmony_ci * idle_state. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci if (data->last_chan || val != MUX_IDLE_DISCONNECT) 3118c2ecf20Sopenharmony_ci ret = pca954x_deselect_mux(muxc, 0); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci i2c_unlock_bus(muxc->parent, I2C_LOCK_SEGMENT); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return ret < 0 ? ret : count; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(idle_state); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic irqreturn_t pca954x_irq_handler(int irq, void *dev_id) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct pca954x *data = dev_id; 3238c2ecf20Sopenharmony_ci unsigned long pending; 3248c2ecf20Sopenharmony_ci int ret, i; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ret = i2c_smbus_read_byte(data->client); 3278c2ecf20Sopenharmony_ci if (ret < 0) 3288c2ecf20Sopenharmony_ci return IRQ_NONE; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci pending = (ret >> PCA954X_IRQ_OFFSET) & (BIT(data->chip->nchans) - 1); 3318c2ecf20Sopenharmony_ci for_each_set_bit(i, &pending, data->chip->nchans) 3328c2ecf20Sopenharmony_ci handle_nested_irq(irq_linear_revmap(data->irq, i)); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return IRQ_RETVAL(pending); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW) 3408c2ecf20Sopenharmony_ci return -EINVAL; 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic struct irq_chip pca954x_irq_chip = { 3458c2ecf20Sopenharmony_ci .name = "i2c-mux-pca954x", 3468c2ecf20Sopenharmony_ci .irq_set_type = pca954x_irq_set_type, 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int pca954x_irq_setup(struct i2c_mux_core *muxc) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct pca954x *data = i2c_mux_priv(muxc); 3528c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 3538c2ecf20Sopenharmony_ci int c, irq; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (!data->chip->has_irq || client->irq <= 0) 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci raw_spin_lock_init(&data->lock); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci data->irq = irq_domain_add_linear(client->dev.of_node, 3618c2ecf20Sopenharmony_ci data->chip->nchans, 3628c2ecf20Sopenharmony_ci &irq_domain_simple_ops, data); 3638c2ecf20Sopenharmony_ci if (!data->irq) 3648c2ecf20Sopenharmony_ci return -ENODEV; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci for (c = 0; c < data->chip->nchans; c++) { 3678c2ecf20Sopenharmony_ci irq = irq_create_mapping(data->irq, c); 3688c2ecf20Sopenharmony_ci if (!irq) { 3698c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed irq create map\n"); 3708c2ecf20Sopenharmony_ci return -EINVAL; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci irq_set_chip_data(irq, data); 3738c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, &pca954x_irq_chip, 3748c2ecf20Sopenharmony_ci handle_simple_irq); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic void pca954x_cleanup(struct i2c_mux_core *muxc) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct pca954x *data = i2c_mux_priv(muxc); 3838c2ecf20Sopenharmony_ci int c, irq; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (data->irq) { 3868c2ecf20Sopenharmony_ci for (c = 0; c < data->chip->nchans; c++) { 3878c2ecf20Sopenharmony_ci irq = irq_find_mapping(data->irq, c); 3888c2ecf20Sopenharmony_ci irq_dispose_mapping(irq); 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci irq_domain_remove(data->irq); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci i2c_mux_del_adapters(muxc); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int pca954x_init(struct i2c_client *client, struct pca954x *data) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci int ret; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (data->idle_state >= 0) 4008c2ecf20Sopenharmony_ci data->last_chan = pca954x_regval(data, data->idle_state); 4018c2ecf20Sopenharmony_ci else 4028c2ecf20Sopenharmony_ci data->last_chan = 0; /* Disconnect multiplexer */ 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte(client, data->last_chan); 4058c2ecf20Sopenharmony_ci if (ret < 0) 4068c2ecf20Sopenharmony_ci data->last_chan = 0; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return ret; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci/* 4128c2ecf20Sopenharmony_ci * I2C init/probing/exit functions 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_cistatic int pca954x_probe(struct i2c_client *client, 4158c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct i2c_adapter *adap = client->adapter; 4188c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 4198c2ecf20Sopenharmony_ci struct gpio_desc *gpio; 4208c2ecf20Sopenharmony_ci struct i2c_mux_core *muxc; 4218c2ecf20Sopenharmony_ci struct pca954x *data; 4228c2ecf20Sopenharmony_ci int num; 4238c2ecf20Sopenharmony_ci int ret; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) 4268c2ecf20Sopenharmony_ci return -ENODEV; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci muxc = i2c_mux_alloc(adap, dev, PCA954X_MAX_NCHANS, sizeof(*data), 0, 4298c2ecf20Sopenharmony_ci pca954x_select_chan, pca954x_deselect_mux); 4308c2ecf20Sopenharmony_ci if (!muxc) 4318c2ecf20Sopenharmony_ci return -ENOMEM; 4328c2ecf20Sopenharmony_ci data = i2c_mux_priv(muxc); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci i2c_set_clientdata(client, muxc); 4358c2ecf20Sopenharmony_ci data->client = client; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* Reset the mux if a reset GPIO is specified. */ 4388c2ecf20Sopenharmony_ci gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 4398c2ecf20Sopenharmony_ci if (IS_ERR(gpio)) 4408c2ecf20Sopenharmony_ci return PTR_ERR(gpio); 4418c2ecf20Sopenharmony_ci if (gpio) { 4428c2ecf20Sopenharmony_ci udelay(1); 4438c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(gpio, 0); 4448c2ecf20Sopenharmony_ci /* Give the chip some time to recover. */ 4458c2ecf20Sopenharmony_ci udelay(1); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci data->chip = device_get_match_data(dev); 4498c2ecf20Sopenharmony_ci if (!data->chip) 4508c2ecf20Sopenharmony_ci data->chip = &chips[id->driver_data]; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) { 4538c2ecf20Sopenharmony_ci struct i2c_device_identity id; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci ret = i2c_get_device_id(client, &id); 4568c2ecf20Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) 4578c2ecf20Sopenharmony_ci return ret; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (!ret && 4608c2ecf20Sopenharmony_ci (id.manufacturer_id != data->chip->id.manufacturer_id || 4618c2ecf20Sopenharmony_ci id.part_id != data->chip->id.part_id)) { 4628c2ecf20Sopenharmony_ci dev_warn(dev, "unexpected device id %03x-%03x-%x\n", 4638c2ecf20Sopenharmony_ci id.manufacturer_id, id.part_id, 4648c2ecf20Sopenharmony_ci id.die_revision); 4658c2ecf20Sopenharmony_ci return -ENODEV; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci data->idle_state = MUX_IDLE_AS_IS; 4708c2ecf20Sopenharmony_ci if (device_property_read_u32(dev, "idle-state", &data->idle_state)) { 4718c2ecf20Sopenharmony_ci if (device_property_read_bool(dev, "i2c-mux-idle-disconnect")) 4728c2ecf20Sopenharmony_ci data->idle_state = MUX_IDLE_DISCONNECT; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* 4768c2ecf20Sopenharmony_ci * Write the mux register at addr to verify 4778c2ecf20Sopenharmony_ci * that the mux is in fact present. This also 4788c2ecf20Sopenharmony_ci * initializes the mux to a channel 4798c2ecf20Sopenharmony_ci * or disconnected state. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci ret = pca954x_init(client, data); 4828c2ecf20Sopenharmony_ci if (ret < 0) { 4838c2ecf20Sopenharmony_ci dev_warn(dev, "probe failed\n"); 4848c2ecf20Sopenharmony_ci return -ENODEV; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci ret = pca954x_irq_setup(muxc); 4888c2ecf20Sopenharmony_ci if (ret) 4898c2ecf20Sopenharmony_ci goto fail_cleanup; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Now create an adapter for each channel */ 4928c2ecf20Sopenharmony_ci for (num = 0; num < data->chip->nchans; num++) { 4938c2ecf20Sopenharmony_ci ret = i2c_mux_add_adapter(muxc, 0, num, 0); 4948c2ecf20Sopenharmony_ci if (ret) 4958c2ecf20Sopenharmony_ci goto fail_cleanup; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (data->irq) { 4998c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(dev, data->client->irq, 5008c2ecf20Sopenharmony_ci NULL, pca954x_irq_handler, 5018c2ecf20Sopenharmony_ci IRQF_ONESHOT | IRQF_SHARED, 5028c2ecf20Sopenharmony_ci "pca954x", data); 5038c2ecf20Sopenharmony_ci if (ret) 5048c2ecf20Sopenharmony_ci goto fail_cleanup; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* 5088c2ecf20Sopenharmony_ci * The attr probably isn't going to be needed in most cases, 5098c2ecf20Sopenharmony_ci * so don't fail completely on error. 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_ci device_create_file(dev, &dev_attr_idle_state); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci dev_info(dev, "registered %d multiplexed busses for I2C %s %s\n", 5148c2ecf20Sopenharmony_ci num, data->chip->muxtype == pca954x_ismux 5158c2ecf20Sopenharmony_ci ? "mux" : "switch", client->name); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cifail_cleanup: 5208c2ecf20Sopenharmony_ci pca954x_cleanup(muxc); 5218c2ecf20Sopenharmony_ci return ret; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic int pca954x_remove(struct i2c_client *client) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct i2c_mux_core *muxc = i2c_get_clientdata(client); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci device_remove_file(&client->dev, &dev_attr_idle_state); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci pca954x_cleanup(muxc); 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 5358c2ecf20Sopenharmony_cistatic int pca954x_resume(struct device *dev) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 5388c2ecf20Sopenharmony_ci struct i2c_mux_core *muxc = i2c_get_clientdata(client); 5398c2ecf20Sopenharmony_ci struct pca954x *data = i2c_mux_priv(muxc); 5408c2ecf20Sopenharmony_ci int ret; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci ret = pca954x_init(client, data); 5438c2ecf20Sopenharmony_ci if (ret < 0) 5448c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to verify mux presence\n"); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci return ret; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci#endif 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic struct i2c_driver pca954x_driver = { 5538c2ecf20Sopenharmony_ci .driver = { 5548c2ecf20Sopenharmony_ci .name = "pca954x", 5558c2ecf20Sopenharmony_ci .pm = &pca954x_pm, 5568c2ecf20Sopenharmony_ci .of_match_table = pca954x_of_match, 5578c2ecf20Sopenharmony_ci }, 5588c2ecf20Sopenharmony_ci .probe = pca954x_probe, 5598c2ecf20Sopenharmony_ci .remove = pca954x_remove, 5608c2ecf20Sopenharmony_ci .id_table = pca954x_id, 5618c2ecf20Sopenharmony_ci}; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cimodule_i2c_driver(pca954x_driver); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ciMODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 5668c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCA954x I2C mux/switch driver"); 5678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 568