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