1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d50f8f33SHaojian Zhuang /* 3d50f8f33SHaojian Zhuang * Base driver for Maxim MAX8925 4d50f8f33SHaojian Zhuang * 51f1cf8f9SHaojian Zhuang * Copyright (C) 2009-2010 Marvell International Ltd. 6d50f8f33SHaojian Zhuang * Haojian Zhuang <haojian.zhuang@marvell.com> 7d50f8f33SHaojian Zhuang */ 8d50f8f33SHaojian Zhuang 9d50f8f33SHaojian Zhuang #include <linux/kernel.h> 10b51bf15cSPaul Gortmaker #include <linux/init.h> 11d50f8f33SHaojian Zhuang #include <linux/i2c.h> 121f1cf8f9SHaojian Zhuang #include <linux/irq.h> 13d50f8f33SHaojian Zhuang #include <linux/interrupt.h> 144e405ae2SQing Xu #include <linux/irqdomain.h> 15d50f8f33SHaojian Zhuang #include <linux/platform_device.h> 1651acdb61SHaojian Zhuang #include <linux/regulator/machine.h> 17d50f8f33SHaojian Zhuang #include <linux/mfd/core.h> 18d50f8f33SHaojian Zhuang #include <linux/mfd/max8925.h> 194e405ae2SQing Xu #include <linux/of.h> 204e405ae2SQing Xu #include <linux/of_platform.h> 21d50f8f33SHaojian Zhuang 22a9e9ce4cSBill Pemberton static struct resource bk_resources[] = { 2363b501e2SHaojian Zhuang { 0x84, 0x84, "mode control", IORESOURCE_REG, }, 2463b501e2SHaojian Zhuang { 0x85, 0x85, "control", IORESOURCE_REG, }, 251ad99893SHaojian Zhuang }; 261ad99893SHaojian Zhuang 27a9e9ce4cSBill Pemberton static struct mfd_cell bk_devs[] = { 281ad99893SHaojian Zhuang { 291ad99893SHaojian Zhuang .name = "max8925-backlight", 3063b501e2SHaojian Zhuang .num_resources = ARRAY_SIZE(bk_resources), 3163b501e2SHaojian Zhuang .resources = &bk_resources[0], 321ad99893SHaojian Zhuang .id = -1, 331ad99893SHaojian Zhuang }, 341ad99893SHaojian Zhuang }; 351ad99893SHaojian Zhuang 361ad99893SHaojian Zhuang static struct resource touch_resources[] = { 371ad99893SHaojian Zhuang { 381ad99893SHaojian Zhuang .name = "max8925-tsc", 391ad99893SHaojian Zhuang .start = MAX8925_TSC_IRQ, 401ad99893SHaojian Zhuang .end = MAX8925_ADC_RES_END, 41015625a2SMark Brown .flags = IORESOURCE_REG, 421ad99893SHaojian Zhuang }, 431ad99893SHaojian Zhuang }; 441ad99893SHaojian Zhuang 457c0517b1SGeert Uytterhoeven static const struct mfd_cell touch_devs[] = { 461ad99893SHaojian Zhuang { 471ad99893SHaojian Zhuang .name = "max8925-touch", 481ad99893SHaojian Zhuang .num_resources = 1, 491ad99893SHaojian Zhuang .resources = &touch_resources[0], 501ad99893SHaojian Zhuang .id = -1, 511ad99893SHaojian Zhuang }, 521ad99893SHaojian Zhuang }; 531ad99893SHaojian Zhuang 541f1cf8f9SHaojian Zhuang static struct resource power_supply_resources[] = { 551f1cf8f9SHaojian Zhuang { 561f1cf8f9SHaojian Zhuang .name = "max8925-power", 571f1cf8f9SHaojian Zhuang .start = MAX8925_CHG_IRQ1, 581f1cf8f9SHaojian Zhuang .end = MAX8925_CHG_IRQ1_MASK, 59015625a2SMark Brown .flags = IORESOURCE_REG, 601f1cf8f9SHaojian Zhuang }, 611f1cf8f9SHaojian Zhuang }; 621f1cf8f9SHaojian Zhuang 637c0517b1SGeert Uytterhoeven static const struct mfd_cell power_devs[] = { 641f1cf8f9SHaojian Zhuang { 651f1cf8f9SHaojian Zhuang .name = "max8925-power", 661f1cf8f9SHaojian Zhuang .num_resources = 1, 671f1cf8f9SHaojian Zhuang .resources = &power_supply_resources[0], 681f1cf8f9SHaojian Zhuang .id = -1, 691f1cf8f9SHaojian Zhuang }, 701f1cf8f9SHaojian Zhuang }; 711f1cf8f9SHaojian Zhuang 721f1cf8f9SHaojian Zhuang static struct resource rtc_resources[] = { 731f1cf8f9SHaojian Zhuang { 741f1cf8f9SHaojian Zhuang .name = "max8925-rtc", 75c1a2f31dSHaojian Zhuang .start = MAX8925_IRQ_RTC_ALARM0, 76c1a2f31dSHaojian Zhuang .end = MAX8925_IRQ_RTC_ALARM0, 77c1a2f31dSHaojian Zhuang .flags = IORESOURCE_IRQ, 781f1cf8f9SHaojian Zhuang }, 791f1cf8f9SHaojian Zhuang }; 801f1cf8f9SHaojian Zhuang 817c0517b1SGeert Uytterhoeven static const struct mfd_cell rtc_devs[] = { 821f1cf8f9SHaojian Zhuang { 831f1cf8f9SHaojian Zhuang .name = "max8925-rtc", 841f1cf8f9SHaojian Zhuang .num_resources = 1, 851f1cf8f9SHaojian Zhuang .resources = &rtc_resources[0], 861f1cf8f9SHaojian Zhuang .id = -1, 871f1cf8f9SHaojian Zhuang }, 881f1cf8f9SHaojian Zhuang }; 891f1cf8f9SHaojian Zhuang 90d0f7a6d6SHaojian Zhuang static struct resource onkey_resources[] = { 91d0f7a6d6SHaojian Zhuang { 92d0f7a6d6SHaojian Zhuang .name = "max8925-onkey", 932d95ae3bSHaojian Zhuang .start = MAX8925_IRQ_GPM_SW_R, 942d95ae3bSHaojian Zhuang .end = MAX8925_IRQ_GPM_SW_R, 952d95ae3bSHaojian Zhuang .flags = IORESOURCE_IRQ, 962d95ae3bSHaojian Zhuang }, { 972d95ae3bSHaojian Zhuang .name = "max8925-onkey", 982d95ae3bSHaojian Zhuang .start = MAX8925_IRQ_GPM_SW_F, 992d95ae3bSHaojian Zhuang .end = MAX8925_IRQ_GPM_SW_F, 100d0f7a6d6SHaojian Zhuang .flags = IORESOURCE_IRQ, 101d0f7a6d6SHaojian Zhuang }, 102d0f7a6d6SHaojian Zhuang }; 103d0f7a6d6SHaojian Zhuang 1047c0517b1SGeert Uytterhoeven static const struct mfd_cell onkey_devs[] = { 105d0f7a6d6SHaojian Zhuang { 106d0f7a6d6SHaojian Zhuang .name = "max8925-onkey", 1072d95ae3bSHaojian Zhuang .num_resources = 2, 108d0f7a6d6SHaojian Zhuang .resources = &onkey_resources[0], 109d0f7a6d6SHaojian Zhuang .id = -1, 110d0f7a6d6SHaojian Zhuang }, 111d0f7a6d6SHaojian Zhuang }; 112d0f7a6d6SHaojian Zhuang 113a9e9ce4cSBill Pemberton static struct resource sd1_resources[] = { 11451acdb61SHaojian Zhuang {0x06, 0x06, "sdv", IORESOURCE_REG, }, 1151ad99893SHaojian Zhuang }; 1161ad99893SHaojian Zhuang 117a9e9ce4cSBill Pemberton static struct resource sd2_resources[] = { 11851acdb61SHaojian Zhuang {0x09, 0x09, "sdv", IORESOURCE_REG, }, 11951acdb61SHaojian Zhuang }; 1201ad99893SHaojian Zhuang 121a9e9ce4cSBill Pemberton static struct resource sd3_resources[] = { 12251acdb61SHaojian Zhuang {0x0c, 0x0c, "sdv", IORESOURCE_REG, }, 12351acdb61SHaojian Zhuang }; 12451acdb61SHaojian Zhuang 125a9e9ce4cSBill Pemberton static struct resource ldo1_resources[] = { 12651acdb61SHaojian Zhuang {0x1a, 0x1a, "ldov", IORESOURCE_REG, }, 12751acdb61SHaojian Zhuang }; 12851acdb61SHaojian Zhuang 129a9e9ce4cSBill Pemberton static struct resource ldo2_resources[] = { 13051acdb61SHaojian Zhuang {0x1e, 0x1e, "ldov", IORESOURCE_REG, }, 13151acdb61SHaojian Zhuang }; 13251acdb61SHaojian Zhuang 133a9e9ce4cSBill Pemberton static struct resource ldo3_resources[] = { 13451acdb61SHaojian Zhuang {0x22, 0x22, "ldov", IORESOURCE_REG, }, 13551acdb61SHaojian Zhuang }; 13651acdb61SHaojian Zhuang 137a9e9ce4cSBill Pemberton static struct resource ldo4_resources[] = { 13851acdb61SHaojian Zhuang {0x26, 0x26, "ldov", IORESOURCE_REG, }, 13951acdb61SHaojian Zhuang }; 14051acdb61SHaojian Zhuang 141a9e9ce4cSBill Pemberton static struct resource ldo5_resources[] = { 14251acdb61SHaojian Zhuang {0x2a, 0x2a, "ldov", IORESOURCE_REG, }, 14351acdb61SHaojian Zhuang }; 14451acdb61SHaojian Zhuang 145a9e9ce4cSBill Pemberton static struct resource ldo6_resources[] = { 14651acdb61SHaojian Zhuang {0x2e, 0x2e, "ldov", IORESOURCE_REG, }, 14751acdb61SHaojian Zhuang }; 14851acdb61SHaojian Zhuang 149a9e9ce4cSBill Pemberton static struct resource ldo7_resources[] = { 15051acdb61SHaojian Zhuang {0x32, 0x32, "ldov", IORESOURCE_REG, }, 15151acdb61SHaojian Zhuang }; 15251acdb61SHaojian Zhuang 153a9e9ce4cSBill Pemberton static struct resource ldo8_resources[] = { 15451acdb61SHaojian Zhuang {0x36, 0x36, "ldov", IORESOURCE_REG, }, 15551acdb61SHaojian Zhuang }; 15651acdb61SHaojian Zhuang 157a9e9ce4cSBill Pemberton static struct resource ldo9_resources[] = { 15851acdb61SHaojian Zhuang {0x3a, 0x3a, "ldov", IORESOURCE_REG, }, 15951acdb61SHaojian Zhuang }; 16051acdb61SHaojian Zhuang 161a9e9ce4cSBill Pemberton static struct resource ldo10_resources[] = { 16251acdb61SHaojian Zhuang {0x3e, 0x3e, "ldov", IORESOURCE_REG, }, 16351acdb61SHaojian Zhuang }; 16451acdb61SHaojian Zhuang 165a9e9ce4cSBill Pemberton static struct resource ldo11_resources[] = { 16651acdb61SHaojian Zhuang {0x42, 0x42, "ldov", IORESOURCE_REG, }, 16751acdb61SHaojian Zhuang }; 16851acdb61SHaojian Zhuang 169a9e9ce4cSBill Pemberton static struct resource ldo12_resources[] = { 17051acdb61SHaojian Zhuang {0x46, 0x46, "ldov", IORESOURCE_REG, }, 17151acdb61SHaojian Zhuang }; 17251acdb61SHaojian Zhuang 173a9e9ce4cSBill Pemberton static struct resource ldo13_resources[] = { 17451acdb61SHaojian Zhuang {0x4a, 0x4a, "ldov", IORESOURCE_REG, }, 17551acdb61SHaojian Zhuang }; 17651acdb61SHaojian Zhuang 177a9e9ce4cSBill Pemberton static struct resource ldo14_resources[] = { 17851acdb61SHaojian Zhuang {0x4e, 0x4e, "ldov", IORESOURCE_REG, }, 17951acdb61SHaojian Zhuang }; 18051acdb61SHaojian Zhuang 181a9e9ce4cSBill Pemberton static struct resource ldo15_resources[] = { 18251acdb61SHaojian Zhuang {0x52, 0x52, "ldov", IORESOURCE_REG, }, 18351acdb61SHaojian Zhuang }; 18451acdb61SHaojian Zhuang 185a9e9ce4cSBill Pemberton static struct resource ldo16_resources[] = { 18651acdb61SHaojian Zhuang {0x12, 0x12, "ldov", IORESOURCE_REG, }, 18751acdb61SHaojian Zhuang }; 18851acdb61SHaojian Zhuang 189a9e9ce4cSBill Pemberton static struct resource ldo17_resources[] = { 19051acdb61SHaojian Zhuang {0x16, 0x16, "ldov", IORESOURCE_REG, }, 19151acdb61SHaojian Zhuang }; 19251acdb61SHaojian Zhuang 193a9e9ce4cSBill Pemberton static struct resource ldo18_resources[] = { 19451acdb61SHaojian Zhuang {0x74, 0x74, "ldov", IORESOURCE_REG, }, 19551acdb61SHaojian Zhuang }; 19651acdb61SHaojian Zhuang 197a9e9ce4cSBill Pemberton static struct resource ldo19_resources[] = { 19851acdb61SHaojian Zhuang {0x5e, 0x5e, "ldov", IORESOURCE_REG, }, 19951acdb61SHaojian Zhuang }; 20051acdb61SHaojian Zhuang 201a9e9ce4cSBill Pemberton static struct resource ldo20_resources[] = { 20251acdb61SHaojian Zhuang {0x9e, 0x9e, "ldov", IORESOURCE_REG, }, 20351acdb61SHaojian Zhuang }; 20451acdb61SHaojian Zhuang 205a9e9ce4cSBill Pemberton static struct mfd_cell reg_devs[] = { 20651acdb61SHaojian Zhuang { 20751acdb61SHaojian Zhuang .name = "max8925-regulator", 20851acdb61SHaojian Zhuang .id = 0, 20951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(sd1_resources), 21051acdb61SHaojian Zhuang .resources = sd1_resources, 21151acdb61SHaojian Zhuang }, { 21251acdb61SHaojian Zhuang .name = "max8925-regulator", 21351acdb61SHaojian Zhuang .id = 1, 21451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(sd2_resources), 21551acdb61SHaojian Zhuang .resources = sd2_resources, 21651acdb61SHaojian Zhuang }, { 21751acdb61SHaojian Zhuang .name = "max8925-regulator", 21851acdb61SHaojian Zhuang .id = 2, 21951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(sd3_resources), 22051acdb61SHaojian Zhuang .resources = sd3_resources, 22151acdb61SHaojian Zhuang }, { 22251acdb61SHaojian Zhuang .name = "max8925-regulator", 22351acdb61SHaojian Zhuang .id = 3, 22451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo1_resources), 22551acdb61SHaojian Zhuang .resources = ldo1_resources, 22651acdb61SHaojian Zhuang }, { 22751acdb61SHaojian Zhuang .name = "max8925-regulator", 22851acdb61SHaojian Zhuang .id = 4, 22951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo2_resources), 23051acdb61SHaojian Zhuang .resources = ldo2_resources, 23151acdb61SHaojian Zhuang }, { 23251acdb61SHaojian Zhuang .name = "max8925-regulator", 23351acdb61SHaojian Zhuang .id = 5, 23451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo3_resources), 23551acdb61SHaojian Zhuang .resources = ldo3_resources, 23651acdb61SHaojian Zhuang }, { 23751acdb61SHaojian Zhuang .name = "max8925-regulator", 23851acdb61SHaojian Zhuang .id = 6, 23951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo4_resources), 24051acdb61SHaojian Zhuang .resources = ldo4_resources, 24151acdb61SHaojian Zhuang }, { 24251acdb61SHaojian Zhuang .name = "max8925-regulator", 24351acdb61SHaojian Zhuang .id = 7, 24451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo5_resources), 24551acdb61SHaojian Zhuang .resources = ldo5_resources, 24651acdb61SHaojian Zhuang }, { 24751acdb61SHaojian Zhuang .name = "max8925-regulator", 24851acdb61SHaojian Zhuang .id = 8, 24951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo6_resources), 25051acdb61SHaojian Zhuang .resources = ldo6_resources, 25151acdb61SHaojian Zhuang }, { 25251acdb61SHaojian Zhuang .name = "max8925-regulator", 25351acdb61SHaojian Zhuang .id = 9, 25451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo7_resources), 25551acdb61SHaojian Zhuang .resources = ldo7_resources, 25651acdb61SHaojian Zhuang }, { 25751acdb61SHaojian Zhuang .name = "max8925-regulator", 25851acdb61SHaojian Zhuang .id = 10, 25951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo8_resources), 26051acdb61SHaojian Zhuang .resources = ldo8_resources, 26151acdb61SHaojian Zhuang }, { 26251acdb61SHaojian Zhuang .name = "max8925-regulator", 26351acdb61SHaojian Zhuang .id = 11, 26451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo9_resources), 26551acdb61SHaojian Zhuang .resources = ldo9_resources, 26651acdb61SHaojian Zhuang }, { 26751acdb61SHaojian Zhuang .name = "max8925-regulator", 26851acdb61SHaojian Zhuang .id = 12, 26951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo10_resources), 27051acdb61SHaojian Zhuang .resources = ldo10_resources, 27151acdb61SHaojian Zhuang }, { 27251acdb61SHaojian Zhuang .name = "max8925-regulator", 27351acdb61SHaojian Zhuang .id = 13, 27451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo11_resources), 27551acdb61SHaojian Zhuang .resources = ldo11_resources, 27651acdb61SHaojian Zhuang }, { 27751acdb61SHaojian Zhuang .name = "max8925-regulator", 27851acdb61SHaojian Zhuang .id = 14, 27951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo12_resources), 28051acdb61SHaojian Zhuang .resources = ldo12_resources, 28151acdb61SHaojian Zhuang }, { 28251acdb61SHaojian Zhuang .name = "max8925-regulator", 28351acdb61SHaojian Zhuang .id = 15, 28451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo13_resources), 28551acdb61SHaojian Zhuang .resources = ldo13_resources, 28651acdb61SHaojian Zhuang }, { 28751acdb61SHaojian Zhuang .name = "max8925-regulator", 28851acdb61SHaojian Zhuang .id = 16, 28951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo14_resources), 29051acdb61SHaojian Zhuang .resources = ldo14_resources, 29151acdb61SHaojian Zhuang }, { 29251acdb61SHaojian Zhuang .name = "max8925-regulator", 29351acdb61SHaojian Zhuang .id = 17, 29451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo15_resources), 29551acdb61SHaojian Zhuang .resources = ldo15_resources, 29651acdb61SHaojian Zhuang }, { 29751acdb61SHaojian Zhuang .name = "max8925-regulator", 29851acdb61SHaojian Zhuang .id = 18, 29951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo16_resources), 30051acdb61SHaojian Zhuang .resources = ldo16_resources, 30151acdb61SHaojian Zhuang }, { 30251acdb61SHaojian Zhuang .name = "max8925-regulator", 30351acdb61SHaojian Zhuang .id = 19, 30451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo17_resources), 30551acdb61SHaojian Zhuang .resources = ldo17_resources, 30651acdb61SHaojian Zhuang }, { 30751acdb61SHaojian Zhuang .name = "max8925-regulator", 30851acdb61SHaojian Zhuang .id = 20, 30951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo18_resources), 31051acdb61SHaojian Zhuang .resources = ldo18_resources, 31151acdb61SHaojian Zhuang }, { 31251acdb61SHaojian Zhuang .name = "max8925-regulator", 31351acdb61SHaojian Zhuang .id = 21, 31451acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo19_resources), 31551acdb61SHaojian Zhuang .resources = ldo19_resources, 31651acdb61SHaojian Zhuang }, { 31751acdb61SHaojian Zhuang .name = "max8925-regulator", 31851acdb61SHaojian Zhuang .id = 22, 31951acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo20_resources), 32051acdb61SHaojian Zhuang .resources = ldo20_resources, 32151acdb61SHaojian Zhuang }, 3221ad99893SHaojian Zhuang }; 3231ad99893SHaojian Zhuang 3241f1cf8f9SHaojian Zhuang enum { 3251f1cf8f9SHaojian Zhuang FLAGS_ADC = 1, /* register in ADC component */ 3261f1cf8f9SHaojian Zhuang FLAGS_RTC, /* register in RTC component */ 3271f1cf8f9SHaojian Zhuang }; 3281f1cf8f9SHaojian Zhuang 3291f1cf8f9SHaojian Zhuang struct max8925_irq_data { 3301f1cf8f9SHaojian Zhuang int reg; 3311f1cf8f9SHaojian Zhuang int mask_reg; 3321f1cf8f9SHaojian Zhuang int enable; /* enable or not */ 3331f1cf8f9SHaojian Zhuang int offs; /* bit offset in mask register */ 3341f1cf8f9SHaojian Zhuang int flags; 3351f1cf8f9SHaojian Zhuang int tsc_irq; 3361f1cf8f9SHaojian Zhuang }; 3371f1cf8f9SHaojian Zhuang 3381f1cf8f9SHaojian Zhuang static struct max8925_irq_data max8925_irqs[] = { 3391f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_DC_OVP] = { 3401f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ1, 3411f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ1_MASK, 3421f1cf8f9SHaojian Zhuang .offs = 1 << 0, 3431f1cf8f9SHaojian Zhuang }, 3441f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_DC_F] = { 3451f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ1, 3461f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ1_MASK, 3471f1cf8f9SHaojian Zhuang .offs = 1 << 1, 3481f1cf8f9SHaojian Zhuang }, 3491f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_DC_R] = { 3501f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ1, 3511f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ1_MASK, 3521f1cf8f9SHaojian Zhuang .offs = 1 << 2, 3531f1cf8f9SHaojian Zhuang }, 3541f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_THM_OK_R] = { 3551f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3561f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3571f1cf8f9SHaojian Zhuang .offs = 1 << 0, 3581f1cf8f9SHaojian Zhuang }, 3591f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_THM_OK_F] = { 3601f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3611f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3621f1cf8f9SHaojian Zhuang .offs = 1 << 1, 3631f1cf8f9SHaojian Zhuang }, 3641f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_SYSLOW_F] = { 3651f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3661f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3671f1cf8f9SHaojian Zhuang .offs = 1 << 2, 3681f1cf8f9SHaojian Zhuang }, 3691f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_SYSLOW_R] = { 3701f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3711f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3721f1cf8f9SHaojian Zhuang .offs = 1 << 3, 3731f1cf8f9SHaojian Zhuang }, 3741f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_RST] = { 3751f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3761f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3771f1cf8f9SHaojian Zhuang .offs = 1 << 4, 3781f1cf8f9SHaojian Zhuang }, 3791f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_DONE] = { 3801f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3811f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3821f1cf8f9SHaojian Zhuang .offs = 1 << 5, 3831f1cf8f9SHaojian Zhuang }, 3841f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_TOPOFF] = { 3851f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3861f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3871f1cf8f9SHaojian Zhuang .offs = 1 << 6, 3881f1cf8f9SHaojian Zhuang }, 3891f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_TMR_FAULT] = { 3901f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3911f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3921f1cf8f9SHaojian Zhuang .offs = 1 << 7, 3931f1cf8f9SHaojian Zhuang }, 3941f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_RSTIN] = { 3951f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 3961f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 3971f1cf8f9SHaojian Zhuang .offs = 1 << 0, 3981f1cf8f9SHaojian Zhuang }, 3991f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_MPL] = { 4001f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4011f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4021f1cf8f9SHaojian Zhuang .offs = 1 << 1, 4031f1cf8f9SHaojian Zhuang }, 4041f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SW_3SEC] = { 4051f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4061f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4071f1cf8f9SHaojian Zhuang .offs = 1 << 2, 4081f1cf8f9SHaojian Zhuang }, 4091f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_EXTON_F] = { 4101f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4111f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4121f1cf8f9SHaojian Zhuang .offs = 1 << 3, 4131f1cf8f9SHaojian Zhuang }, 4141f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_EXTON_R] = { 4151f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4161f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4171f1cf8f9SHaojian Zhuang .offs = 1 << 4, 4181f1cf8f9SHaojian Zhuang }, 4191f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SW_1SEC] = { 4201f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4211f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4221f1cf8f9SHaojian Zhuang .offs = 1 << 5, 4231f1cf8f9SHaojian Zhuang }, 4241f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SW_F] = { 4251f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4261f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4271f1cf8f9SHaojian Zhuang .offs = 1 << 6, 4281f1cf8f9SHaojian Zhuang }, 4291f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SW_R] = { 4301f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4311f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4321f1cf8f9SHaojian Zhuang .offs = 1 << 7, 4331f1cf8f9SHaojian Zhuang }, 4341f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SYSCKEN_F] = { 4351f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ2, 4361f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ2_MASK, 4371f1cf8f9SHaojian Zhuang .offs = 1 << 0, 4381f1cf8f9SHaojian Zhuang }, 4391f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SYSCKEN_R] = { 4401f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ2, 4411f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ2_MASK, 4421f1cf8f9SHaojian Zhuang .offs = 1 << 1, 4431f1cf8f9SHaojian Zhuang }, 4441f1cf8f9SHaojian Zhuang [MAX8925_IRQ_RTC_ALARM1] = { 4451f1cf8f9SHaojian Zhuang .reg = MAX8925_RTC_IRQ, 4461f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_RTC_IRQ_MASK, 4471f1cf8f9SHaojian Zhuang .offs = 1 << 2, 4481f1cf8f9SHaojian Zhuang .flags = FLAGS_RTC, 4491f1cf8f9SHaojian Zhuang }, 4501f1cf8f9SHaojian Zhuang [MAX8925_IRQ_RTC_ALARM0] = { 4511f1cf8f9SHaojian Zhuang .reg = MAX8925_RTC_IRQ, 4521f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_RTC_IRQ_MASK, 4531f1cf8f9SHaojian Zhuang .offs = 1 << 3, 4541f1cf8f9SHaojian Zhuang .flags = FLAGS_RTC, 4551f1cf8f9SHaojian Zhuang }, 4561f1cf8f9SHaojian Zhuang [MAX8925_IRQ_TSC_STICK] = { 4571f1cf8f9SHaojian Zhuang .reg = MAX8925_TSC_IRQ, 4581f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_TSC_IRQ_MASK, 4591f1cf8f9SHaojian Zhuang .offs = 1 << 0, 4601f1cf8f9SHaojian Zhuang .flags = FLAGS_ADC, 4611f1cf8f9SHaojian Zhuang .tsc_irq = 1, 4621f1cf8f9SHaojian Zhuang }, 4631f1cf8f9SHaojian Zhuang [MAX8925_IRQ_TSC_NSTICK] = { 4641f1cf8f9SHaojian Zhuang .reg = MAX8925_TSC_IRQ, 4651f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_TSC_IRQ_MASK, 4661f1cf8f9SHaojian Zhuang .offs = 1 << 1, 4671f1cf8f9SHaojian Zhuang .flags = FLAGS_ADC, 4681f1cf8f9SHaojian Zhuang .tsc_irq = 1, 4691f1cf8f9SHaojian Zhuang }, 4701f1cf8f9SHaojian Zhuang }; 4711f1cf8f9SHaojian Zhuang 4721f1cf8f9SHaojian Zhuang static inline struct max8925_irq_data *irq_to_max8925(struct max8925_chip *chip, 4731f1cf8f9SHaojian Zhuang int irq) 474d50f8f33SHaojian Zhuang { 4751f1cf8f9SHaojian Zhuang return &max8925_irqs[irq - chip->irq_base]; 476d50f8f33SHaojian Zhuang } 477d50f8f33SHaojian Zhuang 4781f1cf8f9SHaojian Zhuang static irqreturn_t max8925_irq(int irq, void *data) 479d50f8f33SHaojian Zhuang { 480d50f8f33SHaojian Zhuang struct max8925_chip *chip = data; 4811f1cf8f9SHaojian Zhuang struct max8925_irq_data *irq_data; 4821f1cf8f9SHaojian Zhuang struct i2c_client *i2c; 4831f1cf8f9SHaojian Zhuang int read_reg = -1, value = 0; 4841f1cf8f9SHaojian Zhuang int i; 485d50f8f33SHaojian Zhuang 4861f1cf8f9SHaojian Zhuang for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { 4871f1cf8f9SHaojian Zhuang irq_data = &max8925_irqs[i]; 4881f1cf8f9SHaojian Zhuang /* TSC IRQ should be serviced in max8925_tsc_irq() */ 4891f1cf8f9SHaojian Zhuang if (irq_data->tsc_irq) 4901f1cf8f9SHaojian Zhuang continue; 4911f1cf8f9SHaojian Zhuang if (irq_data->flags == FLAGS_RTC) 4921f1cf8f9SHaojian Zhuang i2c = chip->rtc; 4931f1cf8f9SHaojian Zhuang else if (irq_data->flags == FLAGS_ADC) 4941f1cf8f9SHaojian Zhuang i2c = chip->adc; 4951f1cf8f9SHaojian Zhuang else 4961f1cf8f9SHaojian Zhuang i2c = chip->i2c; 4971f1cf8f9SHaojian Zhuang if (read_reg != irq_data->reg) { 4981f1cf8f9SHaojian Zhuang read_reg = irq_data->reg; 4991f1cf8f9SHaojian Zhuang value = max8925_reg_read(i2c, irq_data->reg); 500d50f8f33SHaojian Zhuang } 5011f1cf8f9SHaojian Zhuang if (value & irq_data->enable) 5021f1cf8f9SHaojian Zhuang handle_nested_irq(chip->irq_base + i); 503d50f8f33SHaojian Zhuang } 504d50f8f33SHaojian Zhuang return IRQ_HANDLED; 505d50f8f33SHaojian Zhuang } 506d50f8f33SHaojian Zhuang 5071f1cf8f9SHaojian Zhuang static irqreturn_t max8925_tsc_irq(int irq, void *data) 508d50f8f33SHaojian Zhuang { 5091f1cf8f9SHaojian Zhuang struct max8925_chip *chip = data; 5101f1cf8f9SHaojian Zhuang struct max8925_irq_data *irq_data; 5111f1cf8f9SHaojian Zhuang struct i2c_client *i2c; 5121f1cf8f9SHaojian Zhuang int read_reg = -1, value = 0; 5131f1cf8f9SHaojian Zhuang int i; 5141f1cf8f9SHaojian Zhuang 5151f1cf8f9SHaojian Zhuang for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { 5161f1cf8f9SHaojian Zhuang irq_data = &max8925_irqs[i]; 5171f1cf8f9SHaojian Zhuang /* non TSC IRQ should be serviced in max8925_irq() */ 5181f1cf8f9SHaojian Zhuang if (!irq_data->tsc_irq) 5191f1cf8f9SHaojian Zhuang continue; 5201f1cf8f9SHaojian Zhuang if (irq_data->flags == FLAGS_RTC) 5211f1cf8f9SHaojian Zhuang i2c = chip->rtc; 5221f1cf8f9SHaojian Zhuang else if (irq_data->flags == FLAGS_ADC) 5231f1cf8f9SHaojian Zhuang i2c = chip->adc; 5241f1cf8f9SHaojian Zhuang else 5251f1cf8f9SHaojian Zhuang i2c = chip->i2c; 5261f1cf8f9SHaojian Zhuang if (read_reg != irq_data->reg) { 5271f1cf8f9SHaojian Zhuang read_reg = irq_data->reg; 5281f1cf8f9SHaojian Zhuang value = max8925_reg_read(i2c, irq_data->reg); 5291f1cf8f9SHaojian Zhuang } 5301f1cf8f9SHaojian Zhuang if (value & irq_data->enable) 5311f1cf8f9SHaojian Zhuang handle_nested_irq(chip->irq_base + i); 5321f1cf8f9SHaojian Zhuang } 5331f1cf8f9SHaojian Zhuang return IRQ_HANDLED; 5341f1cf8f9SHaojian Zhuang } 5351f1cf8f9SHaojian Zhuang 53698d9bc13SMark Brown static void max8925_irq_lock(struct irq_data *data) 5371f1cf8f9SHaojian Zhuang { 53898d9bc13SMark Brown struct max8925_chip *chip = irq_data_get_irq_chip_data(data); 539d50f8f33SHaojian Zhuang 540d50f8f33SHaojian Zhuang mutex_lock(&chip->irq_lock); 541d50f8f33SHaojian Zhuang } 542d50f8f33SHaojian Zhuang 54398d9bc13SMark Brown static void max8925_irq_sync_unlock(struct irq_data *data) 544d50f8f33SHaojian Zhuang { 54598d9bc13SMark Brown struct max8925_chip *chip = irq_data_get_irq_chip_data(data); 5461f1cf8f9SHaojian Zhuang struct max8925_irq_data *irq_data; 5471f1cf8f9SHaojian Zhuang static unsigned char cache_chg[2] = {0xff, 0xff}; 5481f1cf8f9SHaojian Zhuang static unsigned char cache_on[2] = {0xff, 0xff}; 5491f1cf8f9SHaojian Zhuang static unsigned char cache_rtc = 0xff, cache_tsc = 0xff; 5501f1cf8f9SHaojian Zhuang unsigned char irq_chg[2], irq_on[2]; 5511f1cf8f9SHaojian Zhuang unsigned char irq_rtc, irq_tsc; 5521f1cf8f9SHaojian Zhuang int i; 553d50f8f33SHaojian Zhuang 5541f1cf8f9SHaojian Zhuang /* Load cached value. In initial, all IRQs are masked */ 5551f1cf8f9SHaojian Zhuang irq_chg[0] = cache_chg[0]; 5561f1cf8f9SHaojian Zhuang irq_chg[1] = cache_chg[1]; 5571f1cf8f9SHaojian Zhuang irq_on[0] = cache_on[0]; 5581f1cf8f9SHaojian Zhuang irq_on[1] = cache_on[1]; 5591f1cf8f9SHaojian Zhuang irq_rtc = cache_rtc; 5601f1cf8f9SHaojian Zhuang irq_tsc = cache_tsc; 5611f1cf8f9SHaojian Zhuang for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { 5621f1cf8f9SHaojian Zhuang irq_data = &max8925_irqs[i]; 56390182317SKevin Liu /* 1 -- disable, 0 -- enable */ 5641f1cf8f9SHaojian Zhuang switch (irq_data->mask_reg) { 5651f1cf8f9SHaojian Zhuang case MAX8925_CHG_IRQ1_MASK: 56690182317SKevin Liu irq_chg[0] &= ~irq_data->enable; 5671f1cf8f9SHaojian Zhuang break; 5681f1cf8f9SHaojian Zhuang case MAX8925_CHG_IRQ2_MASK: 56990182317SKevin Liu irq_chg[1] &= ~irq_data->enable; 5701f1cf8f9SHaojian Zhuang break; 5711f1cf8f9SHaojian Zhuang case MAX8925_ON_OFF_IRQ1_MASK: 57290182317SKevin Liu irq_on[0] &= ~irq_data->enable; 5731f1cf8f9SHaojian Zhuang break; 5741f1cf8f9SHaojian Zhuang case MAX8925_ON_OFF_IRQ2_MASK: 57590182317SKevin Liu irq_on[1] &= ~irq_data->enable; 5761f1cf8f9SHaojian Zhuang break; 5771f1cf8f9SHaojian Zhuang case MAX8925_RTC_IRQ_MASK: 57890182317SKevin Liu irq_rtc &= ~irq_data->enable; 5791f1cf8f9SHaojian Zhuang break; 5801f1cf8f9SHaojian Zhuang case MAX8925_TSC_IRQ_MASK: 58190182317SKevin Liu irq_tsc &= ~irq_data->enable; 5821f1cf8f9SHaojian Zhuang break; 5831f1cf8f9SHaojian Zhuang default: 5841f1cf8f9SHaojian Zhuang dev_err(chip->dev, "wrong IRQ\n"); 5851f1cf8f9SHaojian Zhuang break; 5861f1cf8f9SHaojian Zhuang } 5871f1cf8f9SHaojian Zhuang } 5881f1cf8f9SHaojian Zhuang /* update mask into registers */ 5891f1cf8f9SHaojian Zhuang if (cache_chg[0] != irq_chg[0]) { 5901f1cf8f9SHaojian Zhuang cache_chg[0] = irq_chg[0]; 5911f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK, 5921f1cf8f9SHaojian Zhuang irq_chg[0]); 5931f1cf8f9SHaojian Zhuang } 5941f1cf8f9SHaojian Zhuang if (cache_chg[1] != irq_chg[1]) { 5951f1cf8f9SHaojian Zhuang cache_chg[1] = irq_chg[1]; 5961f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ2_MASK, 5971f1cf8f9SHaojian Zhuang irq_chg[1]); 5981f1cf8f9SHaojian Zhuang } 5991f1cf8f9SHaojian Zhuang if (cache_on[0] != irq_on[0]) { 6001f1cf8f9SHaojian Zhuang cache_on[0] = irq_on[0]; 6011f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK, 6021f1cf8f9SHaojian Zhuang irq_on[0]); 6031f1cf8f9SHaojian Zhuang } 6041f1cf8f9SHaojian Zhuang if (cache_on[1] != irq_on[1]) { 6051f1cf8f9SHaojian Zhuang cache_on[1] = irq_on[1]; 6061f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK, 6071f1cf8f9SHaojian Zhuang irq_on[1]); 6081f1cf8f9SHaojian Zhuang } 6091f1cf8f9SHaojian Zhuang if (cache_rtc != irq_rtc) { 6101f1cf8f9SHaojian Zhuang cache_rtc = irq_rtc; 6111f1cf8f9SHaojian Zhuang max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, irq_rtc); 6121f1cf8f9SHaojian Zhuang } 6131f1cf8f9SHaojian Zhuang if (cache_tsc != irq_tsc) { 6141f1cf8f9SHaojian Zhuang cache_tsc = irq_tsc; 6151f1cf8f9SHaojian Zhuang max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, irq_tsc); 6161f1cf8f9SHaojian Zhuang } 6171f1cf8f9SHaojian Zhuang 618d50f8f33SHaojian Zhuang mutex_unlock(&chip->irq_lock); 6191f1cf8f9SHaojian Zhuang } 6201f1cf8f9SHaojian Zhuang 62198d9bc13SMark Brown static void max8925_irq_enable(struct irq_data *data) 6221f1cf8f9SHaojian Zhuang { 62398d9bc13SMark Brown struct max8925_chip *chip = irq_data_get_irq_chip_data(data); 624a5c5accfSLee Jones 62598d9bc13SMark Brown max8925_irqs[data->irq - chip->irq_base].enable 62698d9bc13SMark Brown = max8925_irqs[data->irq - chip->irq_base].offs; 6271f1cf8f9SHaojian Zhuang } 6281f1cf8f9SHaojian Zhuang 62998d9bc13SMark Brown static void max8925_irq_disable(struct irq_data *data) 6301f1cf8f9SHaojian Zhuang { 63198d9bc13SMark Brown struct max8925_chip *chip = irq_data_get_irq_chip_data(data); 632a5c5accfSLee Jones 63398d9bc13SMark Brown max8925_irqs[data->irq - chip->irq_base].enable = 0; 6341f1cf8f9SHaojian Zhuang } 6351f1cf8f9SHaojian Zhuang 6361f1cf8f9SHaojian Zhuang static struct irq_chip max8925_irq_chip = { 6371f1cf8f9SHaojian Zhuang .name = "max8925", 63898d9bc13SMark Brown .irq_bus_lock = max8925_irq_lock, 63998d9bc13SMark Brown .irq_bus_sync_unlock = max8925_irq_sync_unlock, 64098d9bc13SMark Brown .irq_enable = max8925_irq_enable, 64198d9bc13SMark Brown .irq_disable = max8925_irq_disable, 6421f1cf8f9SHaojian Zhuang }; 6431f1cf8f9SHaojian Zhuang 6444e405ae2SQing Xu static int max8925_irq_domain_map(struct irq_domain *d, unsigned int virq, 6454e405ae2SQing Xu irq_hw_number_t hw) 6464e405ae2SQing Xu { 6474e405ae2SQing Xu irq_set_chip_data(virq, d->host_data); 6484e405ae2SQing Xu irq_set_chip_and_handler(virq, &max8925_irq_chip, handle_edge_irq); 6494e405ae2SQing Xu irq_set_nested_thread(virq, 1); 6504e405ae2SQing Xu irq_set_noprobe(virq); 6519bd09f34SRob Herring 6524e405ae2SQing Xu return 0; 6534e405ae2SQing Xu } 6544e405ae2SQing Xu 6557ce7b26fSKrzysztof Kozlowski static const struct irq_domain_ops max8925_irq_domain_ops = { 6564e405ae2SQing Xu .map = max8925_irq_domain_map, 6574e405ae2SQing Xu .xlate = irq_domain_xlate_onetwocell, 6584e405ae2SQing Xu }; 6594e405ae2SQing Xu 6604e405ae2SQing Xu 6611f1cf8f9SHaojian Zhuang static int max8925_irq_init(struct max8925_chip *chip, int irq, 6621f1cf8f9SHaojian Zhuang struct max8925_platform_data *pdata) 6631f1cf8f9SHaojian Zhuang { 6641f1cf8f9SHaojian Zhuang unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; 6654e405ae2SQing Xu int ret; 6664e405ae2SQing Xu struct device_node *node = chip->dev->of_node; 6671f1cf8f9SHaojian Zhuang 6681f1cf8f9SHaojian Zhuang /* clear all interrupts */ 6691f1cf8f9SHaojian Zhuang max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ1); 6701f1cf8f9SHaojian Zhuang max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ2); 6711f1cf8f9SHaojian Zhuang max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ1); 6721f1cf8f9SHaojian Zhuang max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ2); 6731f1cf8f9SHaojian Zhuang max8925_reg_read(chip->rtc, MAX8925_RTC_IRQ); 6741f1cf8f9SHaojian Zhuang max8925_reg_read(chip->adc, MAX8925_TSC_IRQ); 67568e488d9SHaojian Zhuang /* mask all interrupts except for TSC */ 6761f1cf8f9SHaojian Zhuang max8925_reg_write(chip->rtc, MAX8925_ALARM0_CNTL, 0); 6771f1cf8f9SHaojian Zhuang max8925_reg_write(chip->rtc, MAX8925_ALARM1_CNTL, 0); 6781f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK, 0xff); 6791f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ2_MASK, 0xff); 6801f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff); 6811f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK, 0xff); 6821f1cf8f9SHaojian Zhuang max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, 0xff); 6831f1cf8f9SHaojian Zhuang 6841f1cf8f9SHaojian Zhuang mutex_init(&chip->irq_lock); 6854e405ae2SQing Xu chip->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0); 6864e405ae2SQing Xu if (chip->irq_base < 0) { 6874e405ae2SQing Xu dev_err(chip->dev, "Failed to allocate interrupts, ret:%d\n", 6884e405ae2SQing Xu chip->irq_base); 6894e405ae2SQing Xu return -EBUSY; 6904e405ae2SQing Xu } 6914e405ae2SQing Xu 6924e405ae2SQing Xu irq_domain_add_legacy(node, MAX8925_NR_IRQS, chip->irq_base, 0, 6934e405ae2SQing Xu &max8925_irq_domain_ops, chip); 6944e405ae2SQing Xu 6954e405ae2SQing Xu /* request irq handler for pmic main irq*/ 6961f1cf8f9SHaojian Zhuang chip->core_irq = irq; 6974e405ae2SQing Xu if (!chip->core_irq) 6984e405ae2SQing Xu return -EBUSY; 699619a1e31SFengguang Wu ret = request_threaded_irq(irq, NULL, max8925_irq, flags | IRQF_ONESHOT, 7001f1cf8f9SHaojian Zhuang "max8925", chip); 7011f1cf8f9SHaojian Zhuang if (ret) { 7021f1cf8f9SHaojian Zhuang dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret); 7031f1cf8f9SHaojian Zhuang chip->core_irq = 0; 7044e405ae2SQing Xu return -EBUSY; 7051f1cf8f9SHaojian Zhuang } 70668e488d9SHaojian Zhuang 7074e405ae2SQing Xu /* request irq handler for pmic tsc irq*/ 7084e405ae2SQing Xu 70968e488d9SHaojian Zhuang /* mask TSC interrupt */ 71068e488d9SHaojian Zhuang max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0x0f); 71168e488d9SHaojian Zhuang 7121f1cf8f9SHaojian Zhuang if (!pdata->tsc_irq) { 7131f1cf8f9SHaojian Zhuang dev_warn(chip->dev, "No interrupt support on TSC IRQ\n"); 714d50f8f33SHaojian Zhuang return 0; 715d50f8f33SHaojian Zhuang } 7161f1cf8f9SHaojian Zhuang chip->tsc_irq = pdata->tsc_irq; 7171f1cf8f9SHaojian Zhuang ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq, 718619a1e31SFengguang Wu flags | IRQF_ONESHOT, "max8925-tsc", chip); 7191f1cf8f9SHaojian Zhuang if (ret) { 7201f1cf8f9SHaojian Zhuang dev_err(chip->dev, "Failed to request TSC IRQ: %d\n", ret); 7211f1cf8f9SHaojian Zhuang chip->tsc_irq = 0; 7221f1cf8f9SHaojian Zhuang } 7231f1cf8f9SHaojian Zhuang return 0; 7241f1cf8f9SHaojian Zhuang } 7251f1cf8f9SHaojian Zhuang 726f791be49SBill Pemberton static void init_regulator(struct max8925_chip *chip, 72751acdb61SHaojian Zhuang struct max8925_platform_data *pdata) 72851acdb61SHaojian Zhuang { 72951acdb61SHaojian Zhuang int ret; 73051acdb61SHaojian Zhuang 73151acdb61SHaojian Zhuang if (!pdata) 73251acdb61SHaojian Zhuang return; 73351acdb61SHaojian Zhuang if (pdata->sd1) { 73451acdb61SHaojian Zhuang reg_devs[0].platform_data = pdata->sd1; 73551acdb61SHaojian Zhuang reg_devs[0].pdata_size = sizeof(struct regulator_init_data); 73651acdb61SHaojian Zhuang } 73751acdb61SHaojian Zhuang if (pdata->sd2) { 73851acdb61SHaojian Zhuang reg_devs[1].platform_data = pdata->sd2; 73951acdb61SHaojian Zhuang reg_devs[1].pdata_size = sizeof(struct regulator_init_data); 74051acdb61SHaojian Zhuang } 74151acdb61SHaojian Zhuang if (pdata->sd3) { 74251acdb61SHaojian Zhuang reg_devs[2].platform_data = pdata->sd3; 74351acdb61SHaojian Zhuang reg_devs[2].pdata_size = sizeof(struct regulator_init_data); 74451acdb61SHaojian Zhuang } 74551acdb61SHaojian Zhuang if (pdata->ldo1) { 74651acdb61SHaojian Zhuang reg_devs[3].platform_data = pdata->ldo1; 74751acdb61SHaojian Zhuang reg_devs[3].pdata_size = sizeof(struct regulator_init_data); 74851acdb61SHaojian Zhuang } 74951acdb61SHaojian Zhuang if (pdata->ldo2) { 75051acdb61SHaojian Zhuang reg_devs[4].platform_data = pdata->ldo2; 75151acdb61SHaojian Zhuang reg_devs[4].pdata_size = sizeof(struct regulator_init_data); 75251acdb61SHaojian Zhuang } 75351acdb61SHaojian Zhuang if (pdata->ldo3) { 75451acdb61SHaojian Zhuang reg_devs[5].platform_data = pdata->ldo3; 75551acdb61SHaojian Zhuang reg_devs[5].pdata_size = sizeof(struct regulator_init_data); 75651acdb61SHaojian Zhuang } 75751acdb61SHaojian Zhuang if (pdata->ldo4) { 75851acdb61SHaojian Zhuang reg_devs[6].platform_data = pdata->ldo4; 75951acdb61SHaojian Zhuang reg_devs[6].pdata_size = sizeof(struct regulator_init_data); 76051acdb61SHaojian Zhuang } 76151acdb61SHaojian Zhuang if (pdata->ldo5) { 76251acdb61SHaojian Zhuang reg_devs[7].platform_data = pdata->ldo5; 76351acdb61SHaojian Zhuang reg_devs[7].pdata_size = sizeof(struct regulator_init_data); 76451acdb61SHaojian Zhuang } 76551acdb61SHaojian Zhuang if (pdata->ldo6) { 76651acdb61SHaojian Zhuang reg_devs[8].platform_data = pdata->ldo6; 76751acdb61SHaojian Zhuang reg_devs[8].pdata_size = sizeof(struct regulator_init_data); 76851acdb61SHaojian Zhuang } 76951acdb61SHaojian Zhuang if (pdata->ldo7) { 77051acdb61SHaojian Zhuang reg_devs[9].platform_data = pdata->ldo7; 77151acdb61SHaojian Zhuang reg_devs[9].pdata_size = sizeof(struct regulator_init_data); 77251acdb61SHaojian Zhuang } 77351acdb61SHaojian Zhuang if (pdata->ldo8) { 77451acdb61SHaojian Zhuang reg_devs[10].platform_data = pdata->ldo8; 77551acdb61SHaojian Zhuang reg_devs[10].pdata_size = sizeof(struct regulator_init_data); 77651acdb61SHaojian Zhuang } 77751acdb61SHaojian Zhuang if (pdata->ldo9) { 77851acdb61SHaojian Zhuang reg_devs[11].platform_data = pdata->ldo9; 77951acdb61SHaojian Zhuang reg_devs[11].pdata_size = sizeof(struct regulator_init_data); 78051acdb61SHaojian Zhuang } 78151acdb61SHaojian Zhuang if (pdata->ldo10) { 78251acdb61SHaojian Zhuang reg_devs[12].platform_data = pdata->ldo10; 78351acdb61SHaojian Zhuang reg_devs[12].pdata_size = sizeof(struct regulator_init_data); 78451acdb61SHaojian Zhuang } 78551acdb61SHaojian Zhuang if (pdata->ldo11) { 78651acdb61SHaojian Zhuang reg_devs[13].platform_data = pdata->ldo11; 78751acdb61SHaojian Zhuang reg_devs[13].pdata_size = sizeof(struct regulator_init_data); 78851acdb61SHaojian Zhuang } 78951acdb61SHaojian Zhuang if (pdata->ldo12) { 79051acdb61SHaojian Zhuang reg_devs[14].platform_data = pdata->ldo12; 79151acdb61SHaojian Zhuang reg_devs[14].pdata_size = sizeof(struct regulator_init_data); 79251acdb61SHaojian Zhuang } 79351acdb61SHaojian Zhuang if (pdata->ldo13) { 79451acdb61SHaojian Zhuang reg_devs[15].platform_data = pdata->ldo13; 79551acdb61SHaojian Zhuang reg_devs[15].pdata_size = sizeof(struct regulator_init_data); 79651acdb61SHaojian Zhuang } 79751acdb61SHaojian Zhuang if (pdata->ldo14) { 79851acdb61SHaojian Zhuang reg_devs[16].platform_data = pdata->ldo14; 79951acdb61SHaojian Zhuang reg_devs[16].pdata_size = sizeof(struct regulator_init_data); 80051acdb61SHaojian Zhuang } 80151acdb61SHaojian Zhuang if (pdata->ldo15) { 80251acdb61SHaojian Zhuang reg_devs[17].platform_data = pdata->ldo15; 80351acdb61SHaojian Zhuang reg_devs[17].pdata_size = sizeof(struct regulator_init_data); 80451acdb61SHaojian Zhuang } 80551acdb61SHaojian Zhuang if (pdata->ldo16) { 80651acdb61SHaojian Zhuang reg_devs[18].platform_data = pdata->ldo16; 80751acdb61SHaojian Zhuang reg_devs[18].pdata_size = sizeof(struct regulator_init_data); 80851acdb61SHaojian Zhuang } 80951acdb61SHaojian Zhuang if (pdata->ldo17) { 81051acdb61SHaojian Zhuang reg_devs[19].platform_data = pdata->ldo17; 81151acdb61SHaojian Zhuang reg_devs[19].pdata_size = sizeof(struct regulator_init_data); 81251acdb61SHaojian Zhuang } 81351acdb61SHaojian Zhuang if (pdata->ldo18) { 81451acdb61SHaojian Zhuang reg_devs[20].platform_data = pdata->ldo18; 81551acdb61SHaojian Zhuang reg_devs[20].pdata_size = sizeof(struct regulator_init_data); 81651acdb61SHaojian Zhuang } 81751acdb61SHaojian Zhuang if (pdata->ldo19) { 81851acdb61SHaojian Zhuang reg_devs[21].platform_data = pdata->ldo19; 81951acdb61SHaojian Zhuang reg_devs[21].pdata_size = sizeof(struct regulator_init_data); 82051acdb61SHaojian Zhuang } 82151acdb61SHaojian Zhuang if (pdata->ldo20) { 82251acdb61SHaojian Zhuang reg_devs[22].platform_data = pdata->ldo20; 82351acdb61SHaojian Zhuang reg_devs[22].pdata_size = sizeof(struct regulator_init_data); 82451acdb61SHaojian Zhuang } 82551acdb61SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, reg_devs, ARRAY_SIZE(reg_devs), 82651acdb61SHaojian Zhuang NULL, 0, NULL); 82751acdb61SHaojian Zhuang if (ret < 0) { 82851acdb61SHaojian Zhuang dev_err(chip->dev, "Failed to add regulator subdev\n"); 82951acdb61SHaojian Zhuang return; 83051acdb61SHaojian Zhuang } 83151acdb61SHaojian Zhuang } 83251acdb61SHaojian Zhuang 833f791be49SBill Pemberton int max8925_device_init(struct max8925_chip *chip, 834d50f8f33SHaojian Zhuang struct max8925_platform_data *pdata) 835d50f8f33SHaojian Zhuang { 836d50f8f33SHaojian Zhuang int ret; 837d50f8f33SHaojian Zhuang 8381f1cf8f9SHaojian Zhuang max8925_irq_init(chip, chip->i2c->irq, pdata); 839d50f8f33SHaojian Zhuang 8401f1cf8f9SHaojian Zhuang if (pdata && (pdata->power || pdata->touch)) { 8411f1cf8f9SHaojian Zhuang /* enable ADC to control internal reference */ 8421f1cf8f9SHaojian Zhuang max8925_set_bits(chip->i2c, MAX8925_RESET_CNFG, 1, 1); 8431f1cf8f9SHaojian Zhuang /* enable internal reference for ADC */ 8441f1cf8f9SHaojian Zhuang max8925_set_bits(chip->adc, MAX8925_TSC_CNFG1, 3, 2); 8451f1cf8f9SHaojian Zhuang /* check for internal reference IRQ */ 8461f1cf8f9SHaojian Zhuang do { 8471f1cf8f9SHaojian Zhuang ret = max8925_reg_read(chip->adc, MAX8925_TSC_IRQ); 8481f1cf8f9SHaojian Zhuang } while (ret & MAX8925_NREF_OK); 8491f1cf8f9SHaojian Zhuang /* enaable ADC scheduler, interval is 1 second */ 8501f1cf8f9SHaojian Zhuang max8925_set_bits(chip->adc, MAX8925_ADC_SCHED, 3, 2); 8511f1cf8f9SHaojian Zhuang } 8521f1cf8f9SHaojian Zhuang 8531f1cf8f9SHaojian Zhuang /* enable Momentary Power Loss */ 8541f1cf8f9SHaojian Zhuang max8925_set_bits(chip->rtc, MAX8925_MPL_CNTL, 1 << 4, 1 << 4); 8551f1cf8f9SHaojian Zhuang 8561f1cf8f9SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], 8571f1cf8f9SHaojian Zhuang ARRAY_SIZE(rtc_devs), 858f9ed1431SQing Xu NULL, chip->irq_base, NULL); 859d50f8f33SHaojian Zhuang if (ret < 0) { 8601f1cf8f9SHaojian Zhuang dev_err(chip->dev, "Failed to add rtc subdev\n"); 861d50f8f33SHaojian Zhuang goto out; 862d50f8f33SHaojian Zhuang } 863d0f7a6d6SHaojian Zhuang 864d0f7a6d6SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], 865d0f7a6d6SHaojian Zhuang ARRAY_SIZE(onkey_devs), 866678e8cb5SQing Xu NULL, chip->irq_base, NULL); 867d0f7a6d6SHaojian Zhuang if (ret < 0) { 868d0f7a6d6SHaojian Zhuang dev_err(chip->dev, "Failed to add onkey subdev\n"); 869d0f7a6d6SHaojian Zhuang goto out_dev; 870d0f7a6d6SHaojian Zhuang } 871d0f7a6d6SHaojian Zhuang 87251acdb61SHaojian Zhuang init_regulator(chip, pdata); 8731ad99893SHaojian Zhuang 8741ad99893SHaojian Zhuang if (pdata && pdata->backlight) { 87563b501e2SHaojian Zhuang bk_devs[0].platform_data = &pdata->backlight; 87663b501e2SHaojian Zhuang bk_devs[0].pdata_size = sizeof(struct max8925_backlight_pdata); 87763b501e2SHaojian Zhuang } 87863b501e2SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, bk_devs, ARRAY_SIZE(bk_devs), 87963b501e2SHaojian Zhuang NULL, 0, NULL); 8801ad99893SHaojian Zhuang if (ret < 0) { 8811ad99893SHaojian Zhuang dev_err(chip->dev, "Failed to add backlight subdev\n"); 8821ad99893SHaojian Zhuang goto out_dev; 8831ad99893SHaojian Zhuang } 884d50f8f33SHaojian Zhuang 8851f1cf8f9SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 8861f1cf8f9SHaojian Zhuang ARRAY_SIZE(power_devs), 887f9ed1431SQing Xu NULL, 0, NULL); 888d50f8f33SHaojian Zhuang if (ret < 0) { 8894e405ae2SQing Xu dev_err(chip->dev, 890f9ed1431SQing Xu "Failed to add power supply subdev, err = %d\n", ret); 8911f1cf8f9SHaojian Zhuang goto out_dev; 892d50f8f33SHaojian Zhuang } 8931ad99893SHaojian Zhuang 8941ad99893SHaojian Zhuang if (pdata && pdata->touch) { 8951ad99893SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], 8961ad99893SHaojian Zhuang ARRAY_SIZE(touch_devs), 897f9ed1431SQing Xu NULL, chip->tsc_irq, NULL); 8981ad99893SHaojian Zhuang if (ret < 0) { 8991ad99893SHaojian Zhuang dev_err(chip->dev, "Failed to add touch subdev\n"); 9001f1cf8f9SHaojian Zhuang goto out_dev; 9011ad99893SHaojian Zhuang } 9021ad99893SHaojian Zhuang } 9031f1cf8f9SHaojian Zhuang 9041ad99893SHaojian Zhuang return 0; 9051f1cf8f9SHaojian Zhuang out_dev: 9061f1cf8f9SHaojian Zhuang mfd_remove_devices(chip->dev); 907d50f8f33SHaojian Zhuang out: 908d50f8f33SHaojian Zhuang return ret; 909d50f8f33SHaojian Zhuang } 910d50f8f33SHaojian Zhuang 9114740f73fSBill Pemberton void max8925_device_exit(struct max8925_chip *chip) 912d50f8f33SHaojian Zhuang { 9131f1cf8f9SHaojian Zhuang if (chip->core_irq) 9141f1cf8f9SHaojian Zhuang free_irq(chip->core_irq, chip); 9151f1cf8f9SHaojian Zhuang if (chip->tsc_irq) 9161f1cf8f9SHaojian Zhuang free_irq(chip->tsc_irq, chip); 9171ad99893SHaojian Zhuang mfd_remove_devices(chip->dev); 918d50f8f33SHaojian Zhuang } 919