0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/interrupt.h>
0012 #include <linux/irq.h>
0013 #include <linux/irqdomain.h>
0014 #include <linux/mfd/intel_soc_pmic.h>
0015 #include <linux/module.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/regmap.h>
0018
0019 #define CHGRIRQ_REG 0x0a
0020 #define MCHGRIRQ_REG 0x17
0021
0022 struct crystal_cove_charger_data {
0023 struct mutex buslock;
0024 struct irq_chip irqchip;
0025 struct regmap *regmap;
0026 struct irq_domain *irq_domain;
0027 int irq;
0028 int charger_irq;
0029 u8 mask;
0030 u8 new_mask;
0031 };
0032
0033 static irqreturn_t crystal_cove_charger_irq(int irq, void *data)
0034 {
0035 struct crystal_cove_charger_data *charger = data;
0036
0037
0038 handle_nested_irq(charger->charger_irq);
0039
0040
0041 regmap_write(charger->regmap, CHGRIRQ_REG, BIT(0));
0042
0043 return IRQ_HANDLED;
0044 }
0045
0046 static void crystal_cove_charger_irq_bus_lock(struct irq_data *data)
0047 {
0048 struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
0049
0050 mutex_lock(&charger->buslock);
0051 }
0052
0053 static void crystal_cove_charger_irq_bus_sync_unlock(struct irq_data *data)
0054 {
0055 struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
0056
0057 if (charger->mask != charger->new_mask) {
0058 regmap_write(charger->regmap, MCHGRIRQ_REG, charger->new_mask);
0059 charger->mask = charger->new_mask;
0060 }
0061
0062 mutex_unlock(&charger->buslock);
0063 }
0064
0065 static void crystal_cove_charger_irq_unmask(struct irq_data *data)
0066 {
0067 struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
0068
0069 charger->new_mask &= ~BIT(data->hwirq);
0070 }
0071
0072 static void crystal_cove_charger_irq_mask(struct irq_data *data)
0073 {
0074 struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
0075
0076 charger->new_mask |= BIT(data->hwirq);
0077 }
0078
0079 static void crystal_cove_charger_rm_irq_domain(void *data)
0080 {
0081 struct crystal_cove_charger_data *charger = data;
0082
0083 irq_domain_remove(charger->irq_domain);
0084 }
0085
0086 static int crystal_cove_charger_probe(struct platform_device *pdev)
0087 {
0088 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
0089 struct crystal_cove_charger_data *charger;
0090 int ret;
0091
0092 charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
0093 if (!charger)
0094 return -ENOMEM;
0095
0096 charger->regmap = pmic->regmap;
0097 mutex_init(&charger->buslock);
0098
0099 charger->irq = platform_get_irq(pdev, 0);
0100 if (charger->irq < 0)
0101 return charger->irq;
0102
0103 charger->irq_domain = irq_domain_create_linear(dev_fwnode(pdev->dev.parent), 1,
0104 &irq_domain_simple_ops, NULL);
0105 if (!charger->irq_domain)
0106 return -ENOMEM;
0107
0108
0109 irq_domain_update_bus_token(charger->irq_domain, DOMAIN_BUS_WAKEUP);
0110
0111 ret = devm_add_action_or_reset(&pdev->dev, crystal_cove_charger_rm_irq_domain, charger);
0112 if (ret)
0113 return ret;
0114
0115 charger->charger_irq = irq_create_mapping(charger->irq_domain, 0);
0116 if (!charger->charger_irq)
0117 return -ENOMEM;
0118
0119 charger->irqchip.name = KBUILD_MODNAME;
0120 charger->irqchip.irq_unmask = crystal_cove_charger_irq_unmask;
0121 charger->irqchip.irq_mask = crystal_cove_charger_irq_mask;
0122 charger->irqchip.irq_bus_lock = crystal_cove_charger_irq_bus_lock;
0123 charger->irqchip.irq_bus_sync_unlock = crystal_cove_charger_irq_bus_sync_unlock;
0124
0125 irq_set_chip_data(charger->charger_irq, charger);
0126 irq_set_chip_and_handler(charger->charger_irq, &charger->irqchip, handle_simple_irq);
0127 irq_set_nested_thread(charger->charger_irq, true);
0128 irq_set_noprobe(charger->charger_irq);
0129
0130
0131 charger->mask = charger->new_mask = BIT(0);
0132 regmap_write(charger->regmap, MCHGRIRQ_REG, charger->mask);
0133
0134 ret = devm_request_threaded_irq(&pdev->dev, charger->irq, NULL,
0135 crystal_cove_charger_irq,
0136 IRQF_ONESHOT, KBUILD_MODNAME, charger);
0137 if (ret)
0138 return dev_err_probe(&pdev->dev, ret, "requesting irq\n");
0139
0140 return 0;
0141 }
0142
0143 static struct platform_driver crystal_cove_charger_driver = {
0144 .probe = crystal_cove_charger_probe,
0145 .driver = {
0146 .name = "crystal_cove_charger",
0147 },
0148 };
0149 module_platform_driver(crystal_cove_charger_driver);
0150
0151 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
0152 MODULE_DESCRIPTION("Intel Bay Trail Crystal Cove external charger IRQ pass-through");
0153 MODULE_LICENSE("GPL");