1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2014 MediaTek Inc. 4 * Author: Flora Fu, MediaTek 5 */ 6 7 #include <linux/interrupt.h> 8 #include <linux/ioport.h> 9 #include <linux/module.h> 10 #include <linux/of_device.h> 11 #include <linux/of_irq.h> 12 #include <linux/regmap.h> 13 #include <linux/mfd/core.h> 14 #include <linux/mfd/mt6323/core.h> 15 #include <linux/mfd/mt6358/core.h> 16 #include <linux/mfd/mt6359/core.h> 17 #include <linux/mfd/mt6397/core.h> 18 #include <linux/mfd/mt6323/registers.h> 19 #include <linux/mfd/mt6358/registers.h> 20 #include <linux/mfd/mt6359/registers.h> 21 #include <linux/mfd/mt6397/registers.h> 22 23 #define MT6323_RTC_BASE 0x8000 24 #define MT6323_RTC_SIZE 0x40 25 26 #define MT6358_RTC_BASE 0x0588 27 #define MT6358_RTC_SIZE 0x3c 28 29 #define MT6397_RTC_BASE 0xe000 30 #define MT6397_RTC_SIZE 0x3e 31 32 #define MT6323_PWRC_BASE 0x8000 33 #define MT6323_PWRC_SIZE 0x40 34 35 static const struct resource mt6323_rtc_resources[] = { 36 DEFINE_RES_MEM(MT6323_RTC_BASE, MT6323_RTC_SIZE), 37 DEFINE_RES_IRQ(MT6323_IRQ_STATUS_RTC), 38 }; 39 40 static const struct resource mt6358_rtc_resources[] = { 41 DEFINE_RES_MEM(MT6358_RTC_BASE, MT6358_RTC_SIZE), 42 DEFINE_RES_IRQ(MT6358_IRQ_RTC), 43 }; 44 45 static const struct resource mt6397_rtc_resources[] = { 46 DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE), 47 DEFINE_RES_IRQ(MT6397_IRQ_RTC), 48 }; 49 50 static const struct resource mt6323_keys_resources[] = { 51 DEFINE_RES_IRQ(MT6323_IRQ_STATUS_PWRKEY), 52 DEFINE_RES_IRQ(MT6323_IRQ_STATUS_FCHRKEY), 53 }; 54 55 static const struct resource mt6397_keys_resources[] = { 56 DEFINE_RES_IRQ(MT6397_IRQ_PWRKEY), 57 DEFINE_RES_IRQ(MT6397_IRQ_HOMEKEY), 58 }; 59 60 static const struct resource mt6323_pwrc_resources[] = { 61 DEFINE_RES_MEM(MT6323_PWRC_BASE, MT6323_PWRC_SIZE), 62 }; 63 64 static const struct mfd_cell mt6323_devs[] = { 65 { 66 .name = "mt6323-rtc", 67 .num_resources = ARRAY_SIZE(mt6323_rtc_resources), 68 .resources = mt6323_rtc_resources, 69 .of_compatible = "mediatek,mt6323-rtc", 70 }, { 71 .name = "mt6323-regulator", 72 .of_compatible = "mediatek,mt6323-regulator" 73 }, { 74 .name = "mt6323-led", 75 .of_compatible = "mediatek,mt6323-led" 76 }, { 77 .name = "mtk-pmic-keys", 78 .num_resources = ARRAY_SIZE(mt6323_keys_resources), 79 .resources = mt6323_keys_resources, 80 .of_compatible = "mediatek,mt6323-keys" 81 }, { 82 .name = "mt6323-pwrc", 83 .num_resources = ARRAY_SIZE(mt6323_pwrc_resources), 84 .resources = mt6323_pwrc_resources, 85 .of_compatible = "mediatek,mt6323-pwrc" 86 }, 87 }; 88 89 static const struct mfd_cell mt6358_devs[] = { 90 { 91 .name = "mt6358-regulator", 92 .of_compatible = "mediatek,mt6358-regulator" 93 }, { 94 .name = "mt6358-rtc", 95 .num_resources = ARRAY_SIZE(mt6358_rtc_resources), 96 .resources = mt6358_rtc_resources, 97 .of_compatible = "mediatek,mt6358-rtc", 98 }, { 99 .name = "mt6358-sound", 100 .of_compatible = "mediatek,mt6358-sound" 101 }, 102 }; 103 104 static const struct mfd_cell mt6359_devs[] = { 105 { .name = "mt6359-regulator", }, 106 { 107 .name = "mt6359-rtc", 108 .num_resources = ARRAY_SIZE(mt6358_rtc_resources), 109 .resources = mt6358_rtc_resources, 110 .of_compatible = "mediatek,mt6358-rtc", 111 }, 112 { .name = "mt6359-sound", }, 113 }; 114 115 static const struct mfd_cell mt6397_devs[] = { 116 { 117 .name = "mt6397-rtc", 118 .num_resources = ARRAY_SIZE(mt6397_rtc_resources), 119 .resources = mt6397_rtc_resources, 120 .of_compatible = "mediatek,mt6397-rtc", 121 }, { 122 .name = "mt6397-regulator", 123 .of_compatible = "mediatek,mt6397-regulator", 124 }, { 125 .name = "mt6397-codec", 126 .of_compatible = "mediatek,mt6397-codec", 127 }, { 128 .name = "mt6397-clk", 129 .of_compatible = "mediatek,mt6397-clk", 130 }, { 131 .name = "mt6397-pinctrl", 132 .of_compatible = "mediatek,mt6397-pinctrl", 133 }, { 134 .name = "mtk-pmic-keys", 135 .num_resources = ARRAY_SIZE(mt6397_keys_resources), 136 .resources = mt6397_keys_resources, 137 .of_compatible = "mediatek,mt6397-keys" 138 } 139 }; 140 141 struct chip_data { 142 u32 cid_addr; 143 u32 cid_shift; 144 const struct mfd_cell *cells; 145 int cell_size; 146 int (*irq_init)(struct mt6397_chip *chip); 147 }; 148 149 static const struct chip_data mt6323_core = { 150 .cid_addr = MT6323_CID, 151 .cid_shift = 0, 152 .cells = mt6323_devs, 153 .cell_size = ARRAY_SIZE(mt6323_devs), 154 .irq_init = mt6397_irq_init, 155 }; 156 157 static const struct chip_data mt6358_core = { 158 .cid_addr = MT6358_SWCID, 159 .cid_shift = 8, 160 .cells = mt6358_devs, 161 .cell_size = ARRAY_SIZE(mt6358_devs), 162 .irq_init = mt6358_irq_init, 163 }; 164 165 static const struct chip_data mt6359_core = { 166 .cid_addr = MT6359_SWCID, 167 .cid_shift = 8, 168 .cells = mt6359_devs, 169 .cell_size = ARRAY_SIZE(mt6359_devs), 170 .irq_init = mt6358_irq_init, 171 }; 172 173 static const struct chip_data mt6397_core = { 174 .cid_addr = MT6397_CID, 175 .cid_shift = 0, 176 .cells = mt6397_devs, 177 .cell_size = ARRAY_SIZE(mt6397_devs), 178 .irq_init = mt6397_irq_init, 179 }; 180 181 static int mt6397_probe(struct platform_device *pdev) 182 { 183 int ret; 184 unsigned int id = 0; 185 struct mt6397_chip *pmic; 186 const struct chip_data *pmic_core; 187 188 pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); 189 if (!pmic) 190 return -ENOMEM; 191 192 pmic->dev = &pdev->dev; 193 194 /* 195 * mt6397 MFD is child device of soc pmic wrapper. 196 * Regmap is set from its parent. 197 */ 198 pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL); 199 if (!pmic->regmap) 200 return -ENODEV; 201 202 pmic_core = of_device_get_match_data(&pdev->dev); 203 if (!pmic_core) 204 return -ENODEV; 205 206 ret = regmap_read(pmic->regmap, pmic_core->cid_addr, &id); 207 if (ret) { 208 dev_err(&pdev->dev, "Failed to read chip id: %d\n", ret); 209 return ret; 210 } 211 212 pmic->chip_id = (id >> pmic_core->cid_shift) & 0xff; 213 214 platform_set_drvdata(pdev, pmic); 215 216 pmic->irq = platform_get_irq(pdev, 0); 217 if (pmic->irq <= 0) 218 return pmic->irq; 219 220 ret = pmic_core->irq_init(pmic); 221 if (ret) 222 return ret; 223 224 ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, 225 pmic_core->cells, pmic_core->cell_size, 226 NULL, 0, pmic->irq_domain); 227 if (ret) { 228 irq_domain_remove(pmic->irq_domain); 229 dev_err(&pdev->dev, "failed to add child devices: %d\n", ret); 230 } 231 232 return ret; 233 } 234 235 static const struct of_device_id mt6397_of_match[] = { 236 { 237 .compatible = "mediatek,mt6323", 238 .data = &mt6323_core, 239 }, { 240 .compatible = "mediatek,mt6358", 241 .data = &mt6358_core, 242 }, { 243 .compatible = "mediatek,mt6359", 244 .data = &mt6359_core, 245 }, { 246 .compatible = "mediatek,mt6397", 247 .data = &mt6397_core, 248 }, { 249 /* sentinel */ 250 } 251 }; 252 MODULE_DEVICE_TABLE(of, mt6397_of_match); 253 254 static const struct platform_device_id mt6397_id[] = { 255 { "mt6397", 0 }, 256 { }, 257 }; 258 MODULE_DEVICE_TABLE(platform, mt6397_id); 259 260 static struct platform_driver mt6397_driver = { 261 .probe = mt6397_probe, 262 .driver = { 263 .name = "mt6397", 264 .of_match_table = mt6397_of_match, 265 }, 266 .id_table = mt6397_id, 267 }; 268 269 module_platform_driver(mt6397_driver); 270 271 MODULE_AUTHOR("Flora Fu, MediaTek"); 272 MODULE_DESCRIPTION("Driver for MediaTek MT6397 PMIC"); 273 MODULE_LICENSE("GPL"); 274