1 /* 2 * Copyright (c) 2014 MediaTek Inc. 3 * Author: Flora Fu, MediaTek 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15 #include <linux/interrupt.h> 16 #include <linux/module.h> 17 #include <linux/of_device.h> 18 #include <linux/of_irq.h> 19 #include <linux/regmap.h> 20 #include <linux/mfd/core.h> 21 #include <linux/mfd/mt6397/core.h> 22 #include <linux/mfd/mt6397/registers.h> 23 24 #define MT6397_RTC_BASE 0xe000 25 #define MT6397_RTC_SIZE 0x3e 26 27 static const struct resource mt6397_rtc_resources[] = { 28 { 29 .start = MT6397_RTC_BASE, 30 .end = MT6397_RTC_BASE + MT6397_RTC_SIZE, 31 .flags = IORESOURCE_MEM, 32 }, 33 { 34 .start = MT6397_IRQ_RTC, 35 .end = MT6397_IRQ_RTC, 36 .flags = IORESOURCE_IRQ, 37 }, 38 }; 39 40 static const struct mfd_cell mt6397_devs[] = { 41 { 42 .name = "mt6397-rtc", 43 .num_resources = ARRAY_SIZE(mt6397_rtc_resources), 44 .resources = mt6397_rtc_resources, 45 .of_compatible = "mediatek,mt6397-rtc", 46 }, { 47 .name = "mt6397-regulator", 48 .of_compatible = "mediatek,mt6397-regulator", 49 }, { 50 .name = "mt6397-codec", 51 .of_compatible = "mediatek,mt6397-codec", 52 }, { 53 .name = "mt6397-clk", 54 .of_compatible = "mediatek,mt6397-clk", 55 }, { 56 .name = "mt6397-pinctrl", 57 .of_compatible = "mediatek,mt6397-pinctrl", 58 }, 59 }; 60 61 static void mt6397_irq_lock(struct irq_data *data) 62 { 63 struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq); 64 65 mutex_lock(&mt6397->irqlock); 66 } 67 68 static void mt6397_irq_sync_unlock(struct irq_data *data) 69 { 70 struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq); 71 72 regmap_write(mt6397->regmap, MT6397_INT_CON0, mt6397->irq_masks_cur[0]); 73 regmap_write(mt6397->regmap, MT6397_INT_CON1, mt6397->irq_masks_cur[1]); 74 75 mutex_unlock(&mt6397->irqlock); 76 } 77 78 static void mt6397_irq_disable(struct irq_data *data) 79 { 80 struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq); 81 int shift = data->hwirq & 0xf; 82 int reg = data->hwirq >> 4; 83 84 mt6397->irq_masks_cur[reg] &= ~BIT(shift); 85 } 86 87 static void mt6397_irq_enable(struct irq_data *data) 88 { 89 struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq); 90 int shift = data->hwirq & 0xf; 91 int reg = data->hwirq >> 4; 92 93 mt6397->irq_masks_cur[reg] |= BIT(shift); 94 } 95 96 static struct irq_chip mt6397_irq_chip = { 97 .name = "mt6397-irq", 98 .irq_bus_lock = mt6397_irq_lock, 99 .irq_bus_sync_unlock = mt6397_irq_sync_unlock, 100 .irq_enable = mt6397_irq_enable, 101 .irq_disable = mt6397_irq_disable, 102 }; 103 104 static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg, 105 int irqbase) 106 { 107 unsigned int status; 108 int i, irq, ret; 109 110 ret = regmap_read(mt6397->regmap, reg, &status); 111 if (ret) { 112 dev_err(mt6397->dev, "Failed to read irq status: %d\n", ret); 113 return; 114 } 115 116 for (i = 0; i < 16; i++) { 117 if (status & BIT(i)) { 118 irq = irq_find_mapping(mt6397->irq_domain, irqbase + i); 119 if (irq) 120 handle_nested_irq(irq); 121 } 122 } 123 124 regmap_write(mt6397->regmap, reg, status); 125 } 126 127 static irqreturn_t mt6397_irq_thread(int irq, void *data) 128 { 129 struct mt6397_chip *mt6397 = data; 130 131 mt6397_irq_handle_reg(mt6397, MT6397_INT_STATUS0, 0); 132 mt6397_irq_handle_reg(mt6397, MT6397_INT_STATUS1, 16); 133 134 return IRQ_HANDLED; 135 } 136 137 static int mt6397_irq_domain_map(struct irq_domain *d, unsigned int irq, 138 irq_hw_number_t hw) 139 { 140 struct mt6397_chip *mt6397 = d->host_data; 141 142 irq_set_chip_data(irq, mt6397); 143 irq_set_chip_and_handler(irq, &mt6397_irq_chip, handle_level_irq); 144 irq_set_nested_thread(irq, 1); 145 #ifdef CONFIG_ARM 146 set_irq_flags(irq, IRQF_VALID); 147 #else 148 irq_set_noprobe(irq); 149 #endif 150 151 return 0; 152 } 153 154 static const struct irq_domain_ops mt6397_irq_domain_ops = { 155 .map = mt6397_irq_domain_map, 156 }; 157 158 static int mt6397_irq_init(struct mt6397_chip *mt6397) 159 { 160 int ret; 161 162 mutex_init(&mt6397->irqlock); 163 164 /* Mask all interrupt sources */ 165 regmap_write(mt6397->regmap, MT6397_INT_CON0, 0x0); 166 regmap_write(mt6397->regmap, MT6397_INT_CON1, 0x0); 167 168 mt6397->irq_domain = irq_domain_add_linear(mt6397->dev->of_node, 169 MT6397_IRQ_NR, &mt6397_irq_domain_ops, mt6397); 170 if (!mt6397->irq_domain) { 171 dev_err(mt6397->dev, "could not create irq domain\n"); 172 return -ENOMEM; 173 } 174 175 ret = devm_request_threaded_irq(mt6397->dev, mt6397->irq, NULL, 176 mt6397_irq_thread, IRQF_ONESHOT, "mt6397-pmic", mt6397); 177 if (ret) { 178 dev_err(mt6397->dev, "failed to register irq=%d; err: %d\n", 179 mt6397->irq, ret); 180 return ret; 181 } 182 183 return 0; 184 } 185 186 static int mt6397_probe(struct platform_device *pdev) 187 { 188 int ret; 189 struct mt6397_chip *mt6397; 190 191 mt6397 = devm_kzalloc(&pdev->dev, sizeof(*mt6397), GFP_KERNEL); 192 if (!mt6397) 193 return -ENOMEM; 194 195 mt6397->dev = &pdev->dev; 196 /* 197 * mt6397 MFD is child device of soc pmic wrapper. 198 * Regmap is set from its parent. 199 */ 200 mt6397->regmap = dev_get_regmap(pdev->dev.parent, NULL); 201 if (!mt6397->regmap) 202 return -ENODEV; 203 204 platform_set_drvdata(pdev, mt6397); 205 206 mt6397->irq = platform_get_irq(pdev, 0); 207 if (mt6397->irq > 0) { 208 ret = mt6397_irq_init(mt6397); 209 if (ret) 210 return ret; 211 } 212 213 ret = mfd_add_devices(&pdev->dev, -1, mt6397_devs, 214 ARRAY_SIZE(mt6397_devs), NULL, 0, NULL); 215 if (ret) 216 dev_err(&pdev->dev, "failed to add child devices: %d\n", ret); 217 218 return ret; 219 } 220 221 static int mt6397_remove(struct platform_device *pdev) 222 { 223 mfd_remove_devices(&pdev->dev); 224 225 return 0; 226 } 227 228 static const struct of_device_id mt6397_of_match[] = { 229 { .compatible = "mediatek,mt6397" }, 230 { } 231 }; 232 MODULE_DEVICE_TABLE(of, mt6397_of_match); 233 234 static struct platform_driver mt6397_driver = { 235 .probe = mt6397_probe, 236 .remove = mt6397_remove, 237 .driver = { 238 .name = "mt6397", 239 .of_match_table = of_match_ptr(mt6397_of_match), 240 }, 241 }; 242 243 module_platform_driver(mt6397_driver); 244 245 MODULE_AUTHOR("Flora Fu, MediaTek"); 246 MODULE_DESCRIPTION("Driver for MediaTek MT6397 PMIC"); 247 MODULE_LICENSE("GPL"); 248 MODULE_ALIAS("platform:mt6397"); 249