// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #define RT9490_REG_CHG_IRQ_FLAG0 0x22 #define RT9490_REG_CHG_IRQ_MASK0 0x28 #define RT9490_REG_DEVICE_INFO 0x48 #define RT9490_REG_ADD_IRQ_FLAG 0x4D #define RT9490_REG_ADD_IRQ_MASK 0x4E #define RT9490_NUM_IRQ_REGS 7 #define RT9490_ADD_IRQ_OFFSET 6 #define RT9490_DEVICE_ID_MASK GENMASK(6, 3) #define RT9490_VENDOR_ID 0x60 //#define RT9490_VENDOR_ID 0x00 struct rt9490_data { struct i2c_client *i2c; struct device *dev; struct regmap *regmap; struct irq_domain *irq_domain; struct mutex lock; struct mutex hidden_mode_lock; struct irq_chip irq_chip; u8 mask_buf[RT9490_NUM_IRQ_REGS]; int hidden_mode_cnt; }; static const struct mfd_cell rt9490_devs[] = { MFD_CELL_OF("rt9490-adc", NULL, NULL, 0, 0, "richtek,rt9490-adc"), MFD_CELL_OF("rt9490-chg", NULL, NULL, 0, 0, "richtek,rt9490-chg") }; static void rt9490_irq_bus_lock(struct irq_data *irq_data) { struct rt9490_data *data = irq_data_get_irq_chip_data(irq_data); mutex_lock(&data->lock); } static void rt9490_irq_bus_unlock(struct irq_data *irq_data) { struct rt9490_data *data = irq_data_get_irq_chip_data(irq_data); unsigned int reg_offset = irq_data->hwirq / 8; unsigned int reg_addr; int ret; if (reg_offset == RT9490_ADD_IRQ_OFFSET) reg_addr = RT9490_REG_ADD_IRQ_MASK; else reg_addr = RT9490_REG_CHG_IRQ_MASK0 + reg_offset; ret = regmap_write(data->regmap, reg_addr, data->mask_buf[reg_offset]); if (ret) dev_err(data->dev, "Failed to write mask [%d]\n", reg_offset); mutex_unlock(&data->lock); } static void rt9490_irq_enable(struct irq_data *irq_data) { struct rt9490_data *data = irq_data_get_irq_chip_data(irq_data); data->mask_buf[irq_data->hwirq / 8] &= ~BIT(irq_data->hwirq % 8); } static void rt9490_irq_disable(struct irq_data *irq_data) { struct rt9490_data *data = irq_data_get_irq_chip_data(irq_data); data->mask_buf[irq_data->hwirq / 8] |= BIT(irq_data->hwirq % 8); } static int rt9490_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { struct rt9490_data *data = h->host_data; struct i2c_client *i2c = to_i2c_client(data->dev); irq_set_chip_data(virq, data); irq_set_chip(virq, &data->irq_chip); irq_set_nested_thread(virq, true); irq_set_parent(virq, i2c->irq); irq_set_noprobe(virq); return 0; } static const struct irq_domain_ops rt9490_irq_domain_ops = { .map = rt9490_irq_map, .xlate = irq_domain_xlate_onetwocell, }; static irqreturn_t rt9490_irq_handler(int irq, void *priv) { struct rt9490_data *data = priv; u8 status_buf[RT9490_NUM_IRQ_REGS], evts; unsigned int add_event; bool handled = false; int i, j, ret; ret = regmap_raw_read(data->regmap, RT9490_REG_CHG_IRQ_FLAG0, status_buf, RT9490_ADD_IRQ_OFFSET); ret |= regmap_read(data->regmap, RT9490_REG_ADD_IRQ_FLAG, &add_event); if (ret) { dev_err(data->dev, "Failed to read irq flag\n"); return IRQ_NONE; } status_buf[RT9490_ADD_IRQ_OFFSET] = add_event; for (i = 0; i < RT9490_NUM_IRQ_REGS; i++) { evts = status_buf[i] & ~data->mask_buf[i]; if (!evts) continue; for (j = 0; j < 8; j++) { if (!(evts & BIT(j))) continue; handle_nested_irq(irq_find_mapping(data->irq_domain, i * 8 + j)); handled = true; } } return handled ? IRQ_HANDLED : IRQ_NONE; } static int rt9490_add_irq_chip(struct rt9490_data *data) { struct i2c_client *i2c = to_i2c_client(data->dev); u8 status_buf[RT9490_ADD_IRQ_OFFSET]; unsigned int add_event; int ret; mutex_init(&data->lock); data->irq_chip.name = dev_name(data->dev); data->irq_chip.irq_bus_lock = rt9490_irq_bus_lock; data->irq_chip.irq_bus_sync_unlock = rt9490_irq_bus_unlock; data->irq_chip.irq_enable = rt9490_irq_enable; data->irq_chip.irq_disable = rt9490_irq_disable; /* Mask and read clear all events by default */ memset(data->mask_buf, 0xff, RT9490_NUM_IRQ_REGS); ret = regmap_raw_write(data->regmap, RT9490_REG_CHG_IRQ_MASK0, data->mask_buf, RT9490_ADD_IRQ_OFFSET); ret |= regmap_write(data->regmap, RT9490_REG_ADD_IRQ_MASK, data->mask_buf[RT9490_ADD_IRQ_OFFSET]); if (ret) { dev_err(data->dev, "Failed to write irq mask\n"); return ret; } ret = regmap_raw_read(data->regmap, RT9490_REG_CHG_IRQ_FLAG0, status_buf, RT9490_ADD_IRQ_OFFSET); ret |= regmap_read(data->regmap, RT9490_REG_ADD_IRQ_FLAG, &add_event); if (ret) { dev_err(data->dev, "Failed to read clear irq flag\n"); return ret; } data->irq_domain = irq_domain_add_linear(data->dev->of_node, RT9490_NUM_IRQ_REGS * 8, &rt9490_irq_domain_ops, data); if (!data->irq_domain) { dev_err(data->dev, "Failed to create irq domain\n"); return -ENOMEM; } ret = request_threaded_irq(i2c->irq, NULL, rt9490_irq_handler, IRQF_ONESHOT, dev_name(data->dev), data); if (ret) { dev_err(data->dev, "Failed to request irq(%d)\n", ret); irq_domain_remove(data->irq_domain); return ret; } device_init_wakeup(data->dev, true); return 0; } static void rt9490_del_irq_chip(struct rt9490_data *data) { struct i2c_client *i2c = to_i2c_client(data->dev); device_init_wakeup(data->dev, false); free_irq(i2c->irq, data); irq_domain_remove(data->irq_domain); mutex_destroy(&data->lock); } static const struct regmap_config rt9490_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = RT9490_REG_ADD_IRQ_MASK, }; static int rt9490_check_vendor_info(struct rt9490_data *data) { unsigned int devid; int ret; ret = regmap_read(data->regmap, RT9490_REG_DEVICE_INFO, &devid); if (ret) return ret; if ((devid & RT9490_DEVICE_ID_MASK) != RT9490_VENDOR_ID) { dev_err(data->dev, "VID not correct [0x%02x]\n", devid); return -ENODEV; } return 0; } static int rt9490_probe(struct i2c_client *i2c) { struct rt9490_data *data; int ret; data = devm_kzalloc(&i2c->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; mutex_init(&data->hidden_mode_lock); data->hidden_mode_cnt = 0; data->dev = &i2c->dev; data->i2c = i2c; i2c_set_clientdata(i2c, data); data->regmap = devm_regmap_init_i2c(i2c, &rt9490_regmap_config); if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); ret = rt9490_check_vendor_info(data); if (ret) { dev_err(&i2c->dev, "Failed to check vendor info\n"); return ret; } ret = rt9490_add_irq_chip(data); if (ret) return ret; ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, rt9490_devs, ARRAY_SIZE(rt9490_devs), NULL, 0, data->irq_domain); if (ret) { dev_err(&i2c->dev, "Failed to add sub devices\n"); rt9490_del_irq_chip(data); } return 0; } static int rt9490_remove(struct i2c_client *i2c) { struct rt9490_data *data = i2c_get_clientdata(i2c); rt9490_del_irq_chip(data); return 0; } static int __maybe_unused rt9490_suspend(struct device *dev) { struct i2c_client *i2c = to_i2c_client(dev); if (device_may_wakeup(dev)) enable_irq_wake(i2c->irq); return 0; } static int __maybe_unused rt9490_resume(struct device *dev) { struct i2c_client *i2c = to_i2c_client(dev); if (device_may_wakeup(dev)) disable_irq_wake(i2c->irq); return 0; } static SIMPLE_DEV_PM_OPS(rt9490_pm_ops, rt9490_suspend, rt9490_resume); static const struct of_device_id rt9490_of_match_table[] = { { .compatible = "richtek,rt9490", }, { } }; MODULE_DEVICE_TABLE(of, rt9490_of_match_table); static struct i2c_driver rt9490_driver = { .driver = { .name = "rt9490", .of_match_table = rt9490_of_match_table, .pm = &rt9490_pm_ops, }, .probe_new = rt9490_probe, .remove = rt9490_remove, }; module_i2c_driver(rt9490_driver); MODULE_DESCRIPTION("Richtek RT9490 MFD driver"); MODULE_AUTHOR("ChiYuan Huang "); MODULE_LICENSE("GPL");