^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Intel CHT Whiskey Cove PMIC I2C Master driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2011 - 2014 Intel Corporation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/completion.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/irqdomain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/mfd/intel_soc_pmic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/power/bq24190_charger.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define CHT_WC_I2C_CTRL 0x5e24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define CHT_WC_I2C_CTRL_WR BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define CHT_WC_I2C_CTRL_RD BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define CHT_WC_I2C_CLIENT_ADDR 0x5e25
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define CHT_WC_I2C_REG_OFFSET 0x5e26
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define CHT_WC_I2C_WRDATA 0x5e27
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define CHT_WC_I2C_RDDATA 0x5e28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define CHT_WC_EXTCHGRIRQ 0x6e0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define CHT_WC_EXTCHGRIRQ_CLIENT_IRQ BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define CHT_WC_EXTCHGRIRQ_WRITE_IRQ BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define CHT_WC_EXTCHGRIRQ_READ_IRQ BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define CHT_WC_EXTCHGRIRQ_NACK_IRQ BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK ((u8)GENMASK(3, 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define CHT_WC_EXTCHGRIRQ_MSK 0x6e17
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct cht_wc_i2c_adap {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct i2c_adapter adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) wait_queue_head_t wait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct irq_chip irqchip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct mutex adap_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct mutex irqchip_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct irq_domain *irq_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int client_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) u8 irq_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) u8 old_irq_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int read_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) bool io_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) bool done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct cht_wc_i2c_adap *adap = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int ret, reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) mutex_lock(&adap->adap_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* Read IRQs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ret = regmap_read(adap->regmap, CHT_WC_EXTCHGRIRQ, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) dev_err(&adap->adapter.dev, "Error reading extchgrirq reg\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) mutex_unlock(&adap->adap_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) reg &= ~adap->irq_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* Reads must be acked after reading the received data. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA, &adap->read_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) adap->io_error = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * Immediately ack IRQs, so that if new IRQs arrives while we're
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * handling the previous ones our irq will re-trigger when we're done.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) dev_err(&adap->adapter.dev, "Error writing extchgrirq reg\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) adap->io_error |= !!(reg & CHT_WC_EXTCHGRIRQ_NACK_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) adap->done = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) mutex_unlock(&adap->adap_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) wake_up(&adap->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * Do NOT use handle_nested_irq here, the client irq handler will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * likely want to do i2c transfers and the i2c controller uses this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * interrupt handler as well, so running the client irq handler from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * this thread will cause things to lock up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * generic_handle_irq expects local IRQs to be disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * as normally it is called from interrupt context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) local_irq_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) generic_handle_irq(adap->client_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) local_irq_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static u32 cht_wc_i2c_adap_master_func(struct i2c_adapter *adap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /* This i2c adapter only supports SMBUS byte transfers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return I2C_FUNC_SMBUS_BYTE_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static int cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16 addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) unsigned short flags, char read_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) u8 command, int size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) union i2c_smbus_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct cht_wc_i2c_adap *adap = i2c_get_adapdata(_adap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) mutex_lock(&adap->adap_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) adap->io_error = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) adap->done = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) mutex_unlock(&adap->adap_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) ret = regmap_write(adap->regmap, CHT_WC_I2C_CLIENT_ADDR, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (read_write == I2C_SMBUS_WRITE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ret = regmap_write(adap->regmap, CHT_WC_I2C_WRDATA, data->byte);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ret = regmap_write(adap->regmap, CHT_WC_I2C_REG_OFFSET, command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) ret = regmap_write(adap->regmap, CHT_WC_I2C_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) (read_write == I2C_SMBUS_WRITE) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) CHT_WC_I2C_CTRL_WR : CHT_WC_I2C_CTRL_RD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) ret = wait_event_timeout(adap->wait, adap->done, msecs_to_jiffies(30));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * The CHT GPIO controller serializes all IRQs, sometimes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * causing significant delays, check status manually.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) cht_wc_i2c_adap_thread_handler(0, adap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (!adap->done)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) mutex_lock(&adap->adap_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (adap->io_error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) ret = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) else if (read_write == I2C_SMBUS_READ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) data->byte = adap->read_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) mutex_unlock(&adap->adap_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static const struct i2c_algorithm cht_wc_i2c_adap_algo = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .functionality = cht_wc_i2c_adap_master_func,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) .smbus_xfer = cht_wc_i2c_adap_smbus_xfer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * We are an i2c-adapter which itself is part of an i2c-client. This means that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * transfers done through us take adapter->bus_lock twice, once for our parent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * i2c-adapter and once to take our own bus_lock. Lockdep does not like this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * nested locking, to make lockdep happy in the case of busses with muxes, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * i2c-core's i2c_adapter_lock_bus function calls:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * But i2c_adapter_depth only works when the direct parent of the adapter is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * another adapter, as it is only meant for muxes. In our case there is an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * i2c-client and MFD instantiated platform_device in the parent->child chain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * between the 2 devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * So we override the default i2c_lock_operations and pass a hardcoded
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * depth of 1 to rt_mutex_lock_nested, to make lockdep happy.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * Note that if there were to be a mux attached to our adapter, this would
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * break things again since the i2c-mux code expects the root-adapter to have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * a locking depth of 0. But we always have only 1 client directly attached
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * in the form of the Charger IC paired with the CHT Whiskey Cove PMIC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static void cht_wc_i2c_adap_lock_bus(struct i2c_adapter *adapter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) unsigned int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) rt_mutex_lock_nested(&adapter->bus_lock, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static int cht_wc_i2c_adap_trylock_bus(struct i2c_adapter *adapter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) unsigned int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return rt_mutex_trylock(&adapter->bus_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) static void cht_wc_i2c_adap_unlock_bus(struct i2c_adapter *adapter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) unsigned int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) rt_mutex_unlock(&adapter->bus_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static const struct i2c_lock_operations cht_wc_i2c_adap_lock_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .lock_bus = cht_wc_i2c_adap_lock_bus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .trylock_bus = cht_wc_i2c_adap_trylock_bus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .unlock_bus = cht_wc_i2c_adap_unlock_bus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /**** irqchip for the client connected to the extchgr i2c adapter ****/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static void cht_wc_i2c_irq_lock(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) mutex_lock(&adap->irqchip_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static void cht_wc_i2c_irq_sync_unlock(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (adap->irq_mask != adap->old_irq_mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) adap->irq_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) adap->old_irq_mask = adap->irq_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) dev_err(&adap->adapter.dev, "Error writing EXTCHGRIRQ_MSK\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) mutex_unlock(&adap->irqchip_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) static void cht_wc_i2c_irq_enable(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) adap->irq_mask &= ~CHT_WC_EXTCHGRIRQ_CLIENT_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static void cht_wc_i2c_irq_disable(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) adap->irq_mask |= CHT_WC_EXTCHGRIRQ_CLIENT_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static const struct irq_chip cht_wc_i2c_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) .irq_bus_lock = cht_wc_i2c_irq_lock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) .irq_bus_sync_unlock = cht_wc_i2c_irq_sync_unlock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) .irq_disable = cht_wc_i2c_irq_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) .irq_enable = cht_wc_i2c_irq_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) .name = "cht_wc_ext_chrg_irq_chip",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static const char * const bq24190_suppliers[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) "tcpm-source-psy-i2c-fusb302" };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static const struct property_entry bq24190_props[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_suppliers),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) PROPERTY_ENTRY_BOOL("omit-battery-class"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) PROPERTY_ENTRY_BOOL("disable-reset"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) static struct regulator_consumer_supply fusb302_consumer = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) .supply = "vbus",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /* Must match fusb302 dev_name in intel_cht_int33fe.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) .dev_name = "i2c-fusb302",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static const struct regulator_init_data bq24190_vbus_init_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) .constraints = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* The name is used in intel_cht_int33fe.c do not change. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) .name = "cht_wc_usb_typec_vbus",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) .valid_ops_mask = REGULATOR_CHANGE_STATUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) .consumer_supplies = &fusb302_consumer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .num_consumer_supplies = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static struct bq24190_platform_data bq24190_pdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) .regulator_init_data = &bq24190_vbus_init_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) struct cht_wc_i2c_adap *adap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct i2c_board_info board_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) .type = "bq24190",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) .addr = 0x6b,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .dev_name = "bq24190",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .properties = bq24190_props,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .platform_data = &bq24190_pdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) int ret, reg, irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) adap = devm_kzalloc(&pdev->dev, sizeof(*adap), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (!adap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) init_waitqueue_head(&adap->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) mutex_init(&adap->adap_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) mutex_init(&adap->irqchip_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) adap->irqchip = cht_wc_i2c_irq_chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) adap->regmap = pmic->regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) adap->adapter.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) adap->adapter.class = I2C_CLASS_HWMON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) adap->adapter.algo = &cht_wc_i2c_adap_algo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) adap->adapter.lock_ops = &cht_wc_i2c_adap_lock_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) strlcpy(adap->adapter.name, "PMIC I2C Adapter",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) sizeof(adap->adapter.name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) adap->adapter.dev.parent = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /* Clear and activate i2c-adapter interrupts, disable client IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) adap->old_irq_mask = adap->irq_mask = ~CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, ~adap->irq_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK, adap->irq_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) /* Alloc and register client IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) adap->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) &irq_domain_simple_ops, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (!adap->irq_domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) adap->client_irq = irq_create_mapping(adap->irq_domain, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (!adap->client_irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) goto remove_irq_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) irq_set_chip_data(adap->client_irq, adap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) irq_set_chip_and_handler(adap->client_irq, &adap->irqchip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) handle_simple_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) cht_wc_i2c_adap_thread_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) IRQF_ONESHOT, "PMIC I2C Adapter", adap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) goto remove_irq_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) i2c_set_adapdata(&adap->adapter, adap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) ret = i2c_add_adapter(&adap->adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) goto remove_irq_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * Normally the Whiskey Cove PMIC is paired with a TI bq24292i charger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * connected to this i2c bus, and a max17047 fuel-gauge and a fusb302
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * USB Type-C controller connected to another i2c bus. In this setup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * the max17047 and fusb302 devices are enumerated through an INT33FE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * ACPI device. If this device is present register an i2c-client for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * the TI bq24292i charger.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (acpi_dev_present("INT33FE", NULL, -1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) board_info.irq = adap->client_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) adap->client = i2c_new_client_device(&adap->adapter, &board_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (IS_ERR(adap->client)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) ret = PTR_ERR(adap->client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) goto del_adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) platform_set_drvdata(pdev, adap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) del_adapter:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) i2c_del_adapter(&adap->adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) remove_irq_domain:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) irq_domain_remove(adap->irq_domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) i2c_unregister_device(adap->client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) i2c_del_adapter(&adap->adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) irq_domain_remove(adap->irq_domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) static const struct platform_device_id cht_wc_i2c_adap_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) { .name = "cht_wcove_ext_chgr" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) MODULE_DEVICE_TABLE(platform, cht_wc_i2c_adap_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) static struct platform_driver cht_wc_i2c_adap_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) .probe = cht_wc_i2c_adap_i2c_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) .remove = cht_wc_i2c_adap_i2c_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) .name = "cht_wcove_ext_chgr",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) .id_table = cht_wc_i2c_adap_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) module_platform_driver(cht_wc_i2c_adap_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC I2C Master driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) MODULE_LICENSE("GPL");