1d50f8f33SHaojian Zhuang /* 2d50f8f33SHaojian Zhuang * Base driver for Maxim MAX8925 3d50f8f33SHaojian Zhuang * 41f1cf8f9SHaojian Zhuang * Copyright (C) 2009-2010 Marvell International Ltd. 5d50f8f33SHaojian Zhuang * Haojian Zhuang <haojian.zhuang@marvell.com> 6d50f8f33SHaojian Zhuang * 7d50f8f33SHaojian Zhuang * This program is free software; you can redistribute it and/or modify 8d50f8f33SHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 9d50f8f33SHaojian Zhuang * published by the Free Software Foundation. 10d50f8f33SHaojian Zhuang */ 11d50f8f33SHaojian Zhuang 12d50f8f33SHaojian Zhuang #include <linux/kernel.h> 13d50f8f33SHaojian Zhuang #include <linux/module.h> 14d50f8f33SHaojian Zhuang #include <linux/i2c.h> 151f1cf8f9SHaojian Zhuang #include <linux/irq.h> 16d50f8f33SHaojian Zhuang #include <linux/interrupt.h> 174e405ae2SQing Xu #include <linux/irqdomain.h> 18d50f8f33SHaojian Zhuang #include <linux/platform_device.h> 1951acdb61SHaojian Zhuang #include <linux/regulator/machine.h> 20d50f8f33SHaojian Zhuang #include <linux/mfd/core.h> 21d50f8f33SHaojian Zhuang #include <linux/mfd/max8925.h> 224e405ae2SQing Xu #include <linux/of.h> 234e405ae2SQing Xu #include <linux/of_platform.h> 24d50f8f33SHaojian Zhuang 25a9e9ce4cSBill Pemberton static struct resource bk_resources[] = { 2663b501e2SHaojian Zhuang { 0x84, 0x84, "mode control", IORESOURCE_REG, }, 2763b501e2SHaojian Zhuang { 0x85, 0x85, "control", IORESOURCE_REG, }, 281ad99893SHaojian Zhuang }; 291ad99893SHaojian Zhuang 30a9e9ce4cSBill Pemberton static struct mfd_cell bk_devs[] = { 311ad99893SHaojian Zhuang { 321ad99893SHaojian Zhuang .name = "max8925-backlight", 3363b501e2SHaojian Zhuang .num_resources = ARRAY_SIZE(bk_resources), 3463b501e2SHaojian Zhuang .resources = &bk_resources[0], 351ad99893SHaojian Zhuang .id = -1, 361ad99893SHaojian Zhuang }, 371ad99893SHaojian Zhuang }; 381ad99893SHaojian Zhuang 391ad99893SHaojian Zhuang static struct resource touch_resources[] = { 401ad99893SHaojian Zhuang { 411ad99893SHaojian Zhuang .name = "max8925-tsc", 421ad99893SHaojian Zhuang .start = MAX8925_TSC_IRQ, 431ad99893SHaojian Zhuang .end = MAX8925_ADC_RES_END, 44015625a2SMark Brown .flags = IORESOURCE_REG, 451ad99893SHaojian Zhuang }, 461ad99893SHaojian Zhuang }; 471ad99893SHaojian Zhuang 481ad99893SHaojian Zhuang static struct mfd_cell touch_devs[] = { 491ad99893SHaojian Zhuang { 501ad99893SHaojian Zhuang .name = "max8925-touch", 511ad99893SHaojian Zhuang .num_resources = 1, 521ad99893SHaojian Zhuang .resources = &touch_resources[0], 531ad99893SHaojian Zhuang .id = -1, 541ad99893SHaojian Zhuang }, 551ad99893SHaojian Zhuang }; 561ad99893SHaojian Zhuang 571f1cf8f9SHaojian Zhuang static struct resource power_supply_resources[] = { 581f1cf8f9SHaojian Zhuang { 591f1cf8f9SHaojian Zhuang .name = "max8925-power", 601f1cf8f9SHaojian Zhuang .start = MAX8925_CHG_IRQ1, 611f1cf8f9SHaojian Zhuang .end = MAX8925_CHG_IRQ1_MASK, 62015625a2SMark Brown .flags = IORESOURCE_REG, 631f1cf8f9SHaojian Zhuang }, 641f1cf8f9SHaojian Zhuang }; 651f1cf8f9SHaojian Zhuang 661f1cf8f9SHaojian Zhuang static struct mfd_cell power_devs[] = { 671f1cf8f9SHaojian Zhuang { 681f1cf8f9SHaojian Zhuang .name = "max8925-power", 691f1cf8f9SHaojian Zhuang .num_resources = 1, 701f1cf8f9SHaojian Zhuang .resources = &power_supply_resources[0], 711f1cf8f9SHaojian Zhuang .id = -1, 721f1cf8f9SHaojian Zhuang }, 731f1cf8f9SHaojian Zhuang }; 741f1cf8f9SHaojian Zhuang 751f1cf8f9SHaojian Zhuang static struct resource rtc_resources[] = { 761f1cf8f9SHaojian Zhuang { 771f1cf8f9SHaojian Zhuang .name = "max8925-rtc", 78c1a2f31dSHaojian Zhuang .start = MAX8925_IRQ_RTC_ALARM0, 79c1a2f31dSHaojian Zhuang .end = MAX8925_IRQ_RTC_ALARM0, 80c1a2f31dSHaojian Zhuang .flags = IORESOURCE_IRQ, 811f1cf8f9SHaojian Zhuang }, 821f1cf8f9SHaojian Zhuang }; 831f1cf8f9SHaojian Zhuang 841f1cf8f9SHaojian Zhuang static struct mfd_cell rtc_devs[] = { 851f1cf8f9SHaojian Zhuang { 861f1cf8f9SHaojian Zhuang .name = "max8925-rtc", 871f1cf8f9SHaojian Zhuang .num_resources = 1, 881f1cf8f9SHaojian Zhuang .resources = &rtc_resources[0], 891f1cf8f9SHaojian Zhuang .id = -1, 901f1cf8f9SHaojian Zhuang }, 911f1cf8f9SHaojian Zhuang }; 921f1cf8f9SHaojian Zhuang 93d0f7a6d6SHaojian Zhuang static struct resource onkey_resources[] = { 94d0f7a6d6SHaojian Zhuang { 95d0f7a6d6SHaojian Zhuang .name = "max8925-onkey", 962d95ae3bSHaojian Zhuang .start = MAX8925_IRQ_GPM_SW_R, 972d95ae3bSHaojian Zhuang .end = MAX8925_IRQ_GPM_SW_R, 982d95ae3bSHaojian Zhuang .flags = IORESOURCE_IRQ, 992d95ae3bSHaojian Zhuang }, { 1002d95ae3bSHaojian Zhuang .name = "max8925-onkey", 1012d95ae3bSHaojian Zhuang .start = MAX8925_IRQ_GPM_SW_F, 1022d95ae3bSHaojian Zhuang .end = MAX8925_IRQ_GPM_SW_F, 103d0f7a6d6SHaojian Zhuang .flags = IORESOURCE_IRQ, 104d0f7a6d6SHaojian Zhuang }, 105d0f7a6d6SHaojian Zhuang }; 106d0f7a6d6SHaojian Zhuang 107d0f7a6d6SHaojian Zhuang static struct mfd_cell onkey_devs[] = { 108d0f7a6d6SHaojian Zhuang { 109d0f7a6d6SHaojian Zhuang .name = "max8925-onkey", 1102d95ae3bSHaojian Zhuang .num_resources = 2, 111d0f7a6d6SHaojian Zhuang .resources = &onkey_resources[0], 112d0f7a6d6SHaojian Zhuang .id = -1, 113d0f7a6d6SHaojian Zhuang }, 114d0f7a6d6SHaojian Zhuang }; 115d0f7a6d6SHaojian Zhuang 116a9e9ce4cSBill Pemberton static struct resource sd1_resources[] = { 11751acdb61SHaojian Zhuang {0x06, 0x06, "sdv", IORESOURCE_REG, }, 1181ad99893SHaojian Zhuang }; 1191ad99893SHaojian Zhuang 120a9e9ce4cSBill Pemberton static struct resource sd2_resources[] = { 12151acdb61SHaojian Zhuang {0x09, 0x09, "sdv", IORESOURCE_REG, }, 12251acdb61SHaojian Zhuang }; 1231ad99893SHaojian Zhuang 124a9e9ce4cSBill Pemberton static struct resource sd3_resources[] = { 12551acdb61SHaojian Zhuang {0x0c, 0x0c, "sdv", IORESOURCE_REG, }, 12651acdb61SHaojian Zhuang }; 12751acdb61SHaojian Zhuang 128a9e9ce4cSBill Pemberton static struct resource ldo1_resources[] = { 12951acdb61SHaojian Zhuang {0x1a, 0x1a, "ldov", IORESOURCE_REG, }, 13051acdb61SHaojian Zhuang }; 13151acdb61SHaojian Zhuang 132a9e9ce4cSBill Pemberton static struct resource ldo2_resources[] = { 13351acdb61SHaojian Zhuang {0x1e, 0x1e, "ldov", IORESOURCE_REG, }, 13451acdb61SHaojian Zhuang }; 13551acdb61SHaojian Zhuang 136a9e9ce4cSBill Pemberton static struct resource ldo3_resources[] = { 13751acdb61SHaojian Zhuang {0x22, 0x22, "ldov", IORESOURCE_REG, }, 13851acdb61SHaojian Zhuang }; 13951acdb61SHaojian Zhuang 140a9e9ce4cSBill Pemberton static struct resource ldo4_resources[] = { 14151acdb61SHaojian Zhuang {0x26, 0x26, "ldov", IORESOURCE_REG, }, 14251acdb61SHaojian Zhuang }; 14351acdb61SHaojian Zhuang 144a9e9ce4cSBill Pemberton static struct resource ldo5_resources[] = { 14551acdb61SHaojian Zhuang {0x2a, 0x2a, "ldov", IORESOURCE_REG, }, 14651acdb61SHaojian Zhuang }; 14751acdb61SHaojian Zhuang 148a9e9ce4cSBill Pemberton static struct resource ldo6_resources[] = { 14951acdb61SHaojian Zhuang {0x2e, 0x2e, "ldov", IORESOURCE_REG, }, 15051acdb61SHaojian Zhuang }; 15151acdb61SHaojian Zhuang 152a9e9ce4cSBill Pemberton static struct resource ldo7_resources[] = { 15351acdb61SHaojian Zhuang {0x32, 0x32, "ldov", IORESOURCE_REG, }, 15451acdb61SHaojian Zhuang }; 15551acdb61SHaojian Zhuang 156a9e9ce4cSBill Pemberton static struct resource ldo8_resources[] = { 15751acdb61SHaojian Zhuang {0x36, 0x36, "ldov", IORESOURCE_REG, }, 15851acdb61SHaojian Zhuang }; 15951acdb61SHaojian Zhuang 160a9e9ce4cSBill Pemberton static struct resource ldo9_resources[] = { 16151acdb61SHaojian Zhuang {0x3a, 0x3a, "ldov", IORESOURCE_REG, }, 16251acdb61SHaojian Zhuang }; 16351acdb61SHaojian Zhuang 164a9e9ce4cSBill Pemberton static struct resource ldo10_resources[] = { 16551acdb61SHaojian Zhuang {0x3e, 0x3e, "ldov", IORESOURCE_REG, }, 16651acdb61SHaojian Zhuang }; 16751acdb61SHaojian Zhuang 168a9e9ce4cSBill Pemberton static struct resource ldo11_resources[] = { 16951acdb61SHaojian Zhuang {0x42, 0x42, "ldov", IORESOURCE_REG, }, 17051acdb61SHaojian Zhuang }; 17151acdb61SHaojian Zhuang 172a9e9ce4cSBill Pemberton static struct resource ldo12_resources[] = { 17351acdb61SHaojian Zhuang {0x46, 0x46, "ldov", IORESOURCE_REG, }, 17451acdb61SHaojian Zhuang }; 17551acdb61SHaojian Zhuang 176a9e9ce4cSBill Pemberton static struct resource ldo13_resources[] = { 17751acdb61SHaojian Zhuang {0x4a, 0x4a, "ldov", IORESOURCE_REG, }, 17851acdb61SHaojian Zhuang }; 17951acdb61SHaojian Zhuang 180a9e9ce4cSBill Pemberton static struct resource ldo14_resources[] = { 18151acdb61SHaojian Zhuang {0x4e, 0x4e, "ldov", IORESOURCE_REG, }, 18251acdb61SHaojian Zhuang }; 18351acdb61SHaojian Zhuang 184a9e9ce4cSBill Pemberton static struct resource ldo15_resources[] = { 18551acdb61SHaojian Zhuang {0x52, 0x52, "ldov", IORESOURCE_REG, }, 18651acdb61SHaojian Zhuang }; 18751acdb61SHaojian Zhuang 188a9e9ce4cSBill Pemberton static struct resource ldo16_resources[] = { 18951acdb61SHaojian Zhuang {0x12, 0x12, "ldov", IORESOURCE_REG, }, 19051acdb61SHaojian Zhuang }; 19151acdb61SHaojian Zhuang 192a9e9ce4cSBill Pemberton static struct resource ldo17_resources[] = { 19351acdb61SHaojian Zhuang {0x16, 0x16, "ldov", IORESOURCE_REG, }, 19451acdb61SHaojian Zhuang }; 19551acdb61SHaojian Zhuang 196a9e9ce4cSBill Pemberton static struct resource ldo18_resources[] = { 19751acdb61SHaojian Zhuang {0x74, 0x74, "ldov", IORESOURCE_REG, }, 19851acdb61SHaojian Zhuang }; 19951acdb61SHaojian Zhuang 200a9e9ce4cSBill Pemberton static struct resource ldo19_resources[] = { 20151acdb61SHaojian Zhuang {0x5e, 0x5e, "ldov", IORESOURCE_REG, }, 20251acdb61SHaojian Zhuang }; 20351acdb61SHaojian Zhuang 204a9e9ce4cSBill Pemberton static struct resource ldo20_resources[] = { 20551acdb61SHaojian Zhuang {0x9e, 0x9e, "ldov", IORESOURCE_REG, }, 20651acdb61SHaojian Zhuang }; 20751acdb61SHaojian Zhuang 208a9e9ce4cSBill Pemberton static struct mfd_cell reg_devs[] = { 20951acdb61SHaojian Zhuang { 21051acdb61SHaojian Zhuang .name = "max8925-regulator", 21151acdb61SHaojian Zhuang .id = 0, 21251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(sd1_resources), 21351acdb61SHaojian Zhuang .resources = sd1_resources, 21451acdb61SHaojian Zhuang }, { 21551acdb61SHaojian Zhuang .name = "max8925-regulator", 21651acdb61SHaojian Zhuang .id = 1, 21751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(sd2_resources), 21851acdb61SHaojian Zhuang .resources = sd2_resources, 21951acdb61SHaojian Zhuang }, { 22051acdb61SHaojian Zhuang .name = "max8925-regulator", 22151acdb61SHaojian Zhuang .id = 2, 22251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(sd3_resources), 22351acdb61SHaojian Zhuang .resources = sd3_resources, 22451acdb61SHaojian Zhuang }, { 22551acdb61SHaojian Zhuang .name = "max8925-regulator", 22651acdb61SHaojian Zhuang .id = 3, 22751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo1_resources), 22851acdb61SHaojian Zhuang .resources = ldo1_resources, 22951acdb61SHaojian Zhuang }, { 23051acdb61SHaojian Zhuang .name = "max8925-regulator", 23151acdb61SHaojian Zhuang .id = 4, 23251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo2_resources), 23351acdb61SHaojian Zhuang .resources = ldo2_resources, 23451acdb61SHaojian Zhuang }, { 23551acdb61SHaojian Zhuang .name = "max8925-regulator", 23651acdb61SHaojian Zhuang .id = 5, 23751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo3_resources), 23851acdb61SHaojian Zhuang .resources = ldo3_resources, 23951acdb61SHaojian Zhuang }, { 24051acdb61SHaojian Zhuang .name = "max8925-regulator", 24151acdb61SHaojian Zhuang .id = 6, 24251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo4_resources), 24351acdb61SHaojian Zhuang .resources = ldo4_resources, 24451acdb61SHaojian Zhuang }, { 24551acdb61SHaojian Zhuang .name = "max8925-regulator", 24651acdb61SHaojian Zhuang .id = 7, 24751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo5_resources), 24851acdb61SHaojian Zhuang .resources = ldo5_resources, 24951acdb61SHaojian Zhuang }, { 25051acdb61SHaojian Zhuang .name = "max8925-regulator", 25151acdb61SHaojian Zhuang .id = 8, 25251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo6_resources), 25351acdb61SHaojian Zhuang .resources = ldo6_resources, 25451acdb61SHaojian Zhuang }, { 25551acdb61SHaojian Zhuang .name = "max8925-regulator", 25651acdb61SHaojian Zhuang .id = 9, 25751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo7_resources), 25851acdb61SHaojian Zhuang .resources = ldo7_resources, 25951acdb61SHaojian Zhuang }, { 26051acdb61SHaojian Zhuang .name = "max8925-regulator", 26151acdb61SHaojian Zhuang .id = 10, 26251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo8_resources), 26351acdb61SHaojian Zhuang .resources = ldo8_resources, 26451acdb61SHaojian Zhuang }, { 26551acdb61SHaojian Zhuang .name = "max8925-regulator", 26651acdb61SHaojian Zhuang .id = 11, 26751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo9_resources), 26851acdb61SHaojian Zhuang .resources = ldo9_resources, 26951acdb61SHaojian Zhuang }, { 27051acdb61SHaojian Zhuang .name = "max8925-regulator", 27151acdb61SHaojian Zhuang .id = 12, 27251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo10_resources), 27351acdb61SHaojian Zhuang .resources = ldo10_resources, 27451acdb61SHaojian Zhuang }, { 27551acdb61SHaojian Zhuang .name = "max8925-regulator", 27651acdb61SHaojian Zhuang .id = 13, 27751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo11_resources), 27851acdb61SHaojian Zhuang .resources = ldo11_resources, 27951acdb61SHaojian Zhuang }, { 28051acdb61SHaojian Zhuang .name = "max8925-regulator", 28151acdb61SHaojian Zhuang .id = 14, 28251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo12_resources), 28351acdb61SHaojian Zhuang .resources = ldo12_resources, 28451acdb61SHaojian Zhuang }, { 28551acdb61SHaojian Zhuang .name = "max8925-regulator", 28651acdb61SHaojian Zhuang .id = 15, 28751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo13_resources), 28851acdb61SHaojian Zhuang .resources = ldo13_resources, 28951acdb61SHaojian Zhuang }, { 29051acdb61SHaojian Zhuang .name = "max8925-regulator", 29151acdb61SHaojian Zhuang .id = 16, 29251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo14_resources), 29351acdb61SHaojian Zhuang .resources = ldo14_resources, 29451acdb61SHaojian Zhuang }, { 29551acdb61SHaojian Zhuang .name = "max8925-regulator", 29651acdb61SHaojian Zhuang .id = 17, 29751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo15_resources), 29851acdb61SHaojian Zhuang .resources = ldo15_resources, 29951acdb61SHaojian Zhuang }, { 30051acdb61SHaojian Zhuang .name = "max8925-regulator", 30151acdb61SHaojian Zhuang .id = 18, 30251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo16_resources), 30351acdb61SHaojian Zhuang .resources = ldo16_resources, 30451acdb61SHaojian Zhuang }, { 30551acdb61SHaojian Zhuang .name = "max8925-regulator", 30651acdb61SHaojian Zhuang .id = 19, 30751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo17_resources), 30851acdb61SHaojian Zhuang .resources = ldo17_resources, 30951acdb61SHaojian Zhuang }, { 31051acdb61SHaojian Zhuang .name = "max8925-regulator", 31151acdb61SHaojian Zhuang .id = 20, 31251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo18_resources), 31351acdb61SHaojian Zhuang .resources = ldo18_resources, 31451acdb61SHaojian Zhuang }, { 31551acdb61SHaojian Zhuang .name = "max8925-regulator", 31651acdb61SHaojian Zhuang .id = 21, 31751acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo19_resources), 31851acdb61SHaojian Zhuang .resources = ldo19_resources, 31951acdb61SHaojian Zhuang }, { 32051acdb61SHaojian Zhuang .name = "max8925-regulator", 32151acdb61SHaojian Zhuang .id = 22, 32251acdb61SHaojian Zhuang .num_resources = ARRAY_SIZE(ldo20_resources), 32351acdb61SHaojian Zhuang .resources = ldo20_resources, 32451acdb61SHaojian Zhuang }, 3251ad99893SHaojian Zhuang }; 3261ad99893SHaojian Zhuang 3271f1cf8f9SHaojian Zhuang enum { 3281f1cf8f9SHaojian Zhuang FLAGS_ADC = 1, /* register in ADC component */ 3291f1cf8f9SHaojian Zhuang FLAGS_RTC, /* register in RTC component */ 3301f1cf8f9SHaojian Zhuang }; 3311f1cf8f9SHaojian Zhuang 3321f1cf8f9SHaojian Zhuang struct max8925_irq_data { 3331f1cf8f9SHaojian Zhuang int reg; 3341f1cf8f9SHaojian Zhuang int mask_reg; 3351f1cf8f9SHaojian Zhuang int enable; /* enable or not */ 3361f1cf8f9SHaojian Zhuang int offs; /* bit offset in mask register */ 3371f1cf8f9SHaojian Zhuang int flags; 3381f1cf8f9SHaojian Zhuang int tsc_irq; 3391f1cf8f9SHaojian Zhuang }; 3401f1cf8f9SHaojian Zhuang 3411f1cf8f9SHaojian Zhuang static struct max8925_irq_data max8925_irqs[] = { 3421f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_DC_OVP] = { 3431f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ1, 3441f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ1_MASK, 3451f1cf8f9SHaojian Zhuang .offs = 1 << 0, 3461f1cf8f9SHaojian Zhuang }, 3471f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_DC_F] = { 3481f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ1, 3491f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ1_MASK, 3501f1cf8f9SHaojian Zhuang .offs = 1 << 1, 3511f1cf8f9SHaojian Zhuang }, 3521f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_DC_R] = { 3531f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ1, 3541f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ1_MASK, 3551f1cf8f9SHaojian Zhuang .offs = 1 << 2, 3561f1cf8f9SHaojian Zhuang }, 3571f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_THM_OK_R] = { 3581f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3591f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3601f1cf8f9SHaojian Zhuang .offs = 1 << 0, 3611f1cf8f9SHaojian Zhuang }, 3621f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_THM_OK_F] = { 3631f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3641f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3651f1cf8f9SHaojian Zhuang .offs = 1 << 1, 3661f1cf8f9SHaojian Zhuang }, 3671f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_SYSLOW_F] = { 3681f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3691f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3701f1cf8f9SHaojian Zhuang .offs = 1 << 2, 3711f1cf8f9SHaojian Zhuang }, 3721f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_SYSLOW_R] = { 3731f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3741f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3751f1cf8f9SHaojian Zhuang .offs = 1 << 3, 3761f1cf8f9SHaojian Zhuang }, 3771f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_RST] = { 3781f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3791f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3801f1cf8f9SHaojian Zhuang .offs = 1 << 4, 3811f1cf8f9SHaojian Zhuang }, 3821f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_DONE] = { 3831f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3841f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3851f1cf8f9SHaojian Zhuang .offs = 1 << 5, 3861f1cf8f9SHaojian Zhuang }, 3871f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_TOPOFF] = { 3881f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3891f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3901f1cf8f9SHaojian Zhuang .offs = 1 << 6, 3911f1cf8f9SHaojian Zhuang }, 3921f1cf8f9SHaojian Zhuang [MAX8925_IRQ_VCHG_TMR_FAULT] = { 3931f1cf8f9SHaojian Zhuang .reg = MAX8925_CHG_IRQ2, 3941f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_CHG_IRQ2_MASK, 3951f1cf8f9SHaojian Zhuang .offs = 1 << 7, 3961f1cf8f9SHaojian Zhuang }, 3971f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_RSTIN] = { 3981f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 3991f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4001f1cf8f9SHaojian Zhuang .offs = 1 << 0, 4011f1cf8f9SHaojian Zhuang }, 4021f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_MPL] = { 4031f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4041f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4051f1cf8f9SHaojian Zhuang .offs = 1 << 1, 4061f1cf8f9SHaojian Zhuang }, 4071f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SW_3SEC] = { 4081f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4091f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4101f1cf8f9SHaojian Zhuang .offs = 1 << 2, 4111f1cf8f9SHaojian Zhuang }, 4121f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_EXTON_F] = { 4131f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4141f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4151f1cf8f9SHaojian Zhuang .offs = 1 << 3, 4161f1cf8f9SHaojian Zhuang }, 4171f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_EXTON_R] = { 4181f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4191f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4201f1cf8f9SHaojian Zhuang .offs = 1 << 4, 4211f1cf8f9SHaojian Zhuang }, 4221f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SW_1SEC] = { 4231f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4241f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4251f1cf8f9SHaojian Zhuang .offs = 1 << 5, 4261f1cf8f9SHaojian Zhuang }, 4271f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SW_F] = { 4281f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4291f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4301f1cf8f9SHaojian Zhuang .offs = 1 << 6, 4311f1cf8f9SHaojian Zhuang }, 4321f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SW_R] = { 4331f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ1, 4341f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, 4351f1cf8f9SHaojian Zhuang .offs = 1 << 7, 4361f1cf8f9SHaojian Zhuang }, 4371f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SYSCKEN_F] = { 4381f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ2, 4391f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ2_MASK, 4401f1cf8f9SHaojian Zhuang .offs = 1 << 0, 4411f1cf8f9SHaojian Zhuang }, 4421f1cf8f9SHaojian Zhuang [MAX8925_IRQ_GPM_SYSCKEN_R] = { 4431f1cf8f9SHaojian Zhuang .reg = MAX8925_ON_OFF_IRQ2, 4441f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_ON_OFF_IRQ2_MASK, 4451f1cf8f9SHaojian Zhuang .offs = 1 << 1, 4461f1cf8f9SHaojian Zhuang }, 4471f1cf8f9SHaojian Zhuang [MAX8925_IRQ_RTC_ALARM1] = { 4481f1cf8f9SHaojian Zhuang .reg = MAX8925_RTC_IRQ, 4491f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_RTC_IRQ_MASK, 4501f1cf8f9SHaojian Zhuang .offs = 1 << 2, 4511f1cf8f9SHaojian Zhuang .flags = FLAGS_RTC, 4521f1cf8f9SHaojian Zhuang }, 4531f1cf8f9SHaojian Zhuang [MAX8925_IRQ_RTC_ALARM0] = { 4541f1cf8f9SHaojian Zhuang .reg = MAX8925_RTC_IRQ, 4551f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_RTC_IRQ_MASK, 4561f1cf8f9SHaojian Zhuang .offs = 1 << 3, 4571f1cf8f9SHaojian Zhuang .flags = FLAGS_RTC, 4581f1cf8f9SHaojian Zhuang }, 4591f1cf8f9SHaojian Zhuang [MAX8925_IRQ_TSC_STICK] = { 4601f1cf8f9SHaojian Zhuang .reg = MAX8925_TSC_IRQ, 4611f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_TSC_IRQ_MASK, 4621f1cf8f9SHaojian Zhuang .offs = 1 << 0, 4631f1cf8f9SHaojian Zhuang .flags = FLAGS_ADC, 4641f1cf8f9SHaojian Zhuang .tsc_irq = 1, 4651f1cf8f9SHaojian Zhuang }, 4661f1cf8f9SHaojian Zhuang [MAX8925_IRQ_TSC_NSTICK] = { 4671f1cf8f9SHaojian Zhuang .reg = MAX8925_TSC_IRQ, 4681f1cf8f9SHaojian Zhuang .mask_reg = MAX8925_TSC_IRQ_MASK, 4691f1cf8f9SHaojian Zhuang .offs = 1 << 1, 4701f1cf8f9SHaojian Zhuang .flags = FLAGS_ADC, 4711f1cf8f9SHaojian Zhuang .tsc_irq = 1, 4721f1cf8f9SHaojian Zhuang }, 4731f1cf8f9SHaojian Zhuang }; 4741f1cf8f9SHaojian Zhuang 4751f1cf8f9SHaojian Zhuang static inline struct max8925_irq_data *irq_to_max8925(struct max8925_chip *chip, 4761f1cf8f9SHaojian Zhuang int irq) 477d50f8f33SHaojian Zhuang { 4781f1cf8f9SHaojian Zhuang return &max8925_irqs[irq - chip->irq_base]; 479d50f8f33SHaojian Zhuang } 480d50f8f33SHaojian Zhuang 4811f1cf8f9SHaojian Zhuang static irqreturn_t max8925_irq(int irq, void *data) 482d50f8f33SHaojian Zhuang { 483d50f8f33SHaojian Zhuang struct max8925_chip *chip = data; 4841f1cf8f9SHaojian Zhuang struct max8925_irq_data *irq_data; 4851f1cf8f9SHaojian Zhuang struct i2c_client *i2c; 4861f1cf8f9SHaojian Zhuang int read_reg = -1, value = 0; 4871f1cf8f9SHaojian Zhuang int i; 488d50f8f33SHaojian Zhuang 4891f1cf8f9SHaojian Zhuang for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { 4901f1cf8f9SHaojian Zhuang irq_data = &max8925_irqs[i]; 4911f1cf8f9SHaojian Zhuang /* TSC IRQ should be serviced in max8925_tsc_irq() */ 4921f1cf8f9SHaojian Zhuang if (irq_data->tsc_irq) 4931f1cf8f9SHaojian Zhuang continue; 4941f1cf8f9SHaojian Zhuang if (irq_data->flags == FLAGS_RTC) 4951f1cf8f9SHaojian Zhuang i2c = chip->rtc; 4961f1cf8f9SHaojian Zhuang else if (irq_data->flags == FLAGS_ADC) 4971f1cf8f9SHaojian Zhuang i2c = chip->adc; 4981f1cf8f9SHaojian Zhuang else 4991f1cf8f9SHaojian Zhuang i2c = chip->i2c; 5001f1cf8f9SHaojian Zhuang if (read_reg != irq_data->reg) { 5011f1cf8f9SHaojian Zhuang read_reg = irq_data->reg; 5021f1cf8f9SHaojian Zhuang value = max8925_reg_read(i2c, irq_data->reg); 503d50f8f33SHaojian Zhuang } 5041f1cf8f9SHaojian Zhuang if (value & irq_data->enable) 5051f1cf8f9SHaojian Zhuang handle_nested_irq(chip->irq_base + i); 506d50f8f33SHaojian Zhuang } 507d50f8f33SHaojian Zhuang return IRQ_HANDLED; 508d50f8f33SHaojian Zhuang } 509d50f8f33SHaojian Zhuang 5101f1cf8f9SHaojian Zhuang static irqreturn_t max8925_tsc_irq(int irq, void *data) 511d50f8f33SHaojian Zhuang { 5121f1cf8f9SHaojian Zhuang struct max8925_chip *chip = data; 5131f1cf8f9SHaojian Zhuang struct max8925_irq_data *irq_data; 5141f1cf8f9SHaojian Zhuang struct i2c_client *i2c; 5151f1cf8f9SHaojian Zhuang int read_reg = -1, value = 0; 5161f1cf8f9SHaojian Zhuang int i; 5171f1cf8f9SHaojian Zhuang 5181f1cf8f9SHaojian Zhuang for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { 5191f1cf8f9SHaojian Zhuang irq_data = &max8925_irqs[i]; 5201f1cf8f9SHaojian Zhuang /* non TSC IRQ should be serviced in max8925_irq() */ 5211f1cf8f9SHaojian Zhuang if (!irq_data->tsc_irq) 5221f1cf8f9SHaojian Zhuang continue; 5231f1cf8f9SHaojian Zhuang if (irq_data->flags == FLAGS_RTC) 5241f1cf8f9SHaojian Zhuang i2c = chip->rtc; 5251f1cf8f9SHaojian Zhuang else if (irq_data->flags == FLAGS_ADC) 5261f1cf8f9SHaojian Zhuang i2c = chip->adc; 5271f1cf8f9SHaojian Zhuang else 5281f1cf8f9SHaojian Zhuang i2c = chip->i2c; 5291f1cf8f9SHaojian Zhuang if (read_reg != irq_data->reg) { 5301f1cf8f9SHaojian Zhuang read_reg = irq_data->reg; 5311f1cf8f9SHaojian Zhuang value = max8925_reg_read(i2c, irq_data->reg); 5321f1cf8f9SHaojian Zhuang } 5331f1cf8f9SHaojian Zhuang if (value & irq_data->enable) 5341f1cf8f9SHaojian Zhuang handle_nested_irq(chip->irq_base + i); 5351f1cf8f9SHaojian Zhuang } 5361f1cf8f9SHaojian Zhuang return IRQ_HANDLED; 5371f1cf8f9SHaojian Zhuang } 5381f1cf8f9SHaojian Zhuang 53998d9bc13SMark Brown static void max8925_irq_lock(struct irq_data *data) 5401f1cf8f9SHaojian Zhuang { 54198d9bc13SMark Brown struct max8925_chip *chip = irq_data_get_irq_chip_data(data); 542d50f8f33SHaojian Zhuang 543d50f8f33SHaojian Zhuang mutex_lock(&chip->irq_lock); 544d50f8f33SHaojian Zhuang } 545d50f8f33SHaojian Zhuang 54698d9bc13SMark Brown static void max8925_irq_sync_unlock(struct irq_data *data) 547d50f8f33SHaojian Zhuang { 54898d9bc13SMark Brown struct max8925_chip *chip = irq_data_get_irq_chip_data(data); 5491f1cf8f9SHaojian Zhuang struct max8925_irq_data *irq_data; 5501f1cf8f9SHaojian Zhuang static unsigned char cache_chg[2] = {0xff, 0xff}; 5511f1cf8f9SHaojian Zhuang static unsigned char cache_on[2] = {0xff, 0xff}; 5521f1cf8f9SHaojian Zhuang static unsigned char cache_rtc = 0xff, cache_tsc = 0xff; 5531f1cf8f9SHaojian Zhuang unsigned char irq_chg[2], irq_on[2]; 5541f1cf8f9SHaojian Zhuang unsigned char irq_rtc, irq_tsc; 5551f1cf8f9SHaojian Zhuang int i; 556d50f8f33SHaojian Zhuang 5571f1cf8f9SHaojian Zhuang /* Load cached value. In initial, all IRQs are masked */ 5581f1cf8f9SHaojian Zhuang irq_chg[0] = cache_chg[0]; 5591f1cf8f9SHaojian Zhuang irq_chg[1] = cache_chg[1]; 5601f1cf8f9SHaojian Zhuang irq_on[0] = cache_on[0]; 5611f1cf8f9SHaojian Zhuang irq_on[1] = cache_on[1]; 5621f1cf8f9SHaojian Zhuang irq_rtc = cache_rtc; 5631f1cf8f9SHaojian Zhuang irq_tsc = cache_tsc; 5641f1cf8f9SHaojian Zhuang for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { 5651f1cf8f9SHaojian Zhuang irq_data = &max8925_irqs[i]; 56690182317SKevin Liu /* 1 -- disable, 0 -- enable */ 5671f1cf8f9SHaojian Zhuang switch (irq_data->mask_reg) { 5681f1cf8f9SHaojian Zhuang case MAX8925_CHG_IRQ1_MASK: 56990182317SKevin Liu irq_chg[0] &= ~irq_data->enable; 5701f1cf8f9SHaojian Zhuang break; 5711f1cf8f9SHaojian Zhuang case MAX8925_CHG_IRQ2_MASK: 57290182317SKevin Liu irq_chg[1] &= ~irq_data->enable; 5731f1cf8f9SHaojian Zhuang break; 5741f1cf8f9SHaojian Zhuang case MAX8925_ON_OFF_IRQ1_MASK: 57590182317SKevin Liu irq_on[0] &= ~irq_data->enable; 5761f1cf8f9SHaojian Zhuang break; 5771f1cf8f9SHaojian Zhuang case MAX8925_ON_OFF_IRQ2_MASK: 57890182317SKevin Liu irq_on[1] &= ~irq_data->enable; 5791f1cf8f9SHaojian Zhuang break; 5801f1cf8f9SHaojian Zhuang case MAX8925_RTC_IRQ_MASK: 58190182317SKevin Liu irq_rtc &= ~irq_data->enable; 5821f1cf8f9SHaojian Zhuang break; 5831f1cf8f9SHaojian Zhuang case MAX8925_TSC_IRQ_MASK: 58490182317SKevin Liu irq_tsc &= ~irq_data->enable; 5851f1cf8f9SHaojian Zhuang break; 5861f1cf8f9SHaojian Zhuang default: 5871f1cf8f9SHaojian Zhuang dev_err(chip->dev, "wrong IRQ\n"); 5881f1cf8f9SHaojian Zhuang break; 5891f1cf8f9SHaojian Zhuang } 5901f1cf8f9SHaojian Zhuang } 5911f1cf8f9SHaojian Zhuang /* update mask into registers */ 5921f1cf8f9SHaojian Zhuang if (cache_chg[0] != irq_chg[0]) { 5931f1cf8f9SHaojian Zhuang cache_chg[0] = irq_chg[0]; 5941f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK, 5951f1cf8f9SHaojian Zhuang irq_chg[0]); 5961f1cf8f9SHaojian Zhuang } 5971f1cf8f9SHaojian Zhuang if (cache_chg[1] != irq_chg[1]) { 5981f1cf8f9SHaojian Zhuang cache_chg[1] = irq_chg[1]; 5991f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ2_MASK, 6001f1cf8f9SHaojian Zhuang irq_chg[1]); 6011f1cf8f9SHaojian Zhuang } 6021f1cf8f9SHaojian Zhuang if (cache_on[0] != irq_on[0]) { 6031f1cf8f9SHaojian Zhuang cache_on[0] = irq_on[0]; 6041f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK, 6051f1cf8f9SHaojian Zhuang irq_on[0]); 6061f1cf8f9SHaojian Zhuang } 6071f1cf8f9SHaojian Zhuang if (cache_on[1] != irq_on[1]) { 6081f1cf8f9SHaojian Zhuang cache_on[1] = irq_on[1]; 6091f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK, 6101f1cf8f9SHaojian Zhuang irq_on[1]); 6111f1cf8f9SHaojian Zhuang } 6121f1cf8f9SHaojian Zhuang if (cache_rtc != irq_rtc) { 6131f1cf8f9SHaojian Zhuang cache_rtc = irq_rtc; 6141f1cf8f9SHaojian Zhuang max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, irq_rtc); 6151f1cf8f9SHaojian Zhuang } 6161f1cf8f9SHaojian Zhuang if (cache_tsc != irq_tsc) { 6171f1cf8f9SHaojian Zhuang cache_tsc = irq_tsc; 6181f1cf8f9SHaojian Zhuang max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, irq_tsc); 6191f1cf8f9SHaojian Zhuang } 6201f1cf8f9SHaojian Zhuang 621d50f8f33SHaojian Zhuang mutex_unlock(&chip->irq_lock); 6221f1cf8f9SHaojian Zhuang } 6231f1cf8f9SHaojian Zhuang 62498d9bc13SMark Brown static void max8925_irq_enable(struct irq_data *data) 6251f1cf8f9SHaojian Zhuang { 62698d9bc13SMark Brown struct max8925_chip *chip = irq_data_get_irq_chip_data(data); 62798d9bc13SMark Brown max8925_irqs[data->irq - chip->irq_base].enable 62898d9bc13SMark Brown = max8925_irqs[data->irq - chip->irq_base].offs; 6291f1cf8f9SHaojian Zhuang } 6301f1cf8f9SHaojian Zhuang 63198d9bc13SMark Brown static void max8925_irq_disable(struct irq_data *data) 6321f1cf8f9SHaojian Zhuang { 63398d9bc13SMark Brown struct max8925_chip *chip = irq_data_get_irq_chip_data(data); 63498d9bc13SMark Brown max8925_irqs[data->irq - chip->irq_base].enable = 0; 6351f1cf8f9SHaojian Zhuang } 6361f1cf8f9SHaojian Zhuang 6371f1cf8f9SHaojian Zhuang static struct irq_chip max8925_irq_chip = { 6381f1cf8f9SHaojian Zhuang .name = "max8925", 63998d9bc13SMark Brown .irq_bus_lock = max8925_irq_lock, 64098d9bc13SMark Brown .irq_bus_sync_unlock = max8925_irq_sync_unlock, 64198d9bc13SMark Brown .irq_enable = max8925_irq_enable, 64298d9bc13SMark Brown .irq_disable = max8925_irq_disable, 6431f1cf8f9SHaojian Zhuang }; 6441f1cf8f9SHaojian Zhuang 6454e405ae2SQing Xu static int max8925_irq_domain_map(struct irq_domain *d, unsigned int virq, 6464e405ae2SQing Xu irq_hw_number_t hw) 6474e405ae2SQing Xu { 6484e405ae2SQing Xu irq_set_chip_data(virq, d->host_data); 6494e405ae2SQing Xu irq_set_chip_and_handler(virq, &max8925_irq_chip, handle_edge_irq); 6504e405ae2SQing Xu irq_set_nested_thread(virq, 1); 6514e405ae2SQing Xu #ifdef CONFIG_ARM 6524e405ae2SQing Xu set_irq_flags(virq, IRQF_VALID); 6534e405ae2SQing Xu #else 6544e405ae2SQing Xu irq_set_noprobe(virq); 6554e405ae2SQing Xu #endif 6564e405ae2SQing Xu return 0; 6574e405ae2SQing Xu } 6584e405ae2SQing Xu 6594e405ae2SQing Xu static struct irq_domain_ops max8925_irq_domain_ops = { 6604e405ae2SQing Xu .map = max8925_irq_domain_map, 6614e405ae2SQing Xu .xlate = irq_domain_xlate_onetwocell, 6624e405ae2SQing Xu }; 6634e405ae2SQing Xu 6644e405ae2SQing Xu 6651f1cf8f9SHaojian Zhuang static int max8925_irq_init(struct max8925_chip *chip, int irq, 6661f1cf8f9SHaojian Zhuang struct max8925_platform_data *pdata) 6671f1cf8f9SHaojian Zhuang { 6681f1cf8f9SHaojian Zhuang unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; 6694e405ae2SQing Xu int ret; 6704e405ae2SQing Xu struct device_node *node = chip->dev->of_node; 6711f1cf8f9SHaojian Zhuang 6721f1cf8f9SHaojian Zhuang /* clear all interrupts */ 6731f1cf8f9SHaojian Zhuang max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ1); 6741f1cf8f9SHaojian Zhuang max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ2); 6751f1cf8f9SHaojian Zhuang max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ1); 6761f1cf8f9SHaojian Zhuang max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ2); 6771f1cf8f9SHaojian Zhuang max8925_reg_read(chip->rtc, MAX8925_RTC_IRQ); 6781f1cf8f9SHaojian Zhuang max8925_reg_read(chip->adc, MAX8925_TSC_IRQ); 67968e488d9SHaojian Zhuang /* mask all interrupts except for TSC */ 6801f1cf8f9SHaojian Zhuang max8925_reg_write(chip->rtc, MAX8925_ALARM0_CNTL, 0); 6811f1cf8f9SHaojian Zhuang max8925_reg_write(chip->rtc, MAX8925_ALARM1_CNTL, 0); 6821f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK, 0xff); 6831f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ2_MASK, 0xff); 6841f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff); 6851f1cf8f9SHaojian Zhuang max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK, 0xff); 6861f1cf8f9SHaojian Zhuang max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, 0xff); 6871f1cf8f9SHaojian Zhuang 6881f1cf8f9SHaojian Zhuang mutex_init(&chip->irq_lock); 6894e405ae2SQing Xu chip->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0); 6904e405ae2SQing Xu if (chip->irq_base < 0) { 6914e405ae2SQing Xu dev_err(chip->dev, "Failed to allocate interrupts, ret:%d\n", 6924e405ae2SQing Xu chip->irq_base); 6934e405ae2SQing Xu return -EBUSY; 6944e405ae2SQing Xu } 6954e405ae2SQing Xu 6964e405ae2SQing Xu irq_domain_add_legacy(node, MAX8925_NR_IRQS, chip->irq_base, 0, 6974e405ae2SQing Xu &max8925_irq_domain_ops, chip); 6984e405ae2SQing Xu 6994e405ae2SQing Xu /* request irq handler for pmic main irq*/ 7001f1cf8f9SHaojian Zhuang chip->core_irq = irq; 7014e405ae2SQing Xu if (!chip->core_irq) 7024e405ae2SQing Xu return -EBUSY; 703619a1e31SFengguang Wu ret = request_threaded_irq(irq, NULL, max8925_irq, flags | IRQF_ONESHOT, 7041f1cf8f9SHaojian Zhuang "max8925", chip); 7051f1cf8f9SHaojian Zhuang if (ret) { 7061f1cf8f9SHaojian Zhuang dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret); 7071f1cf8f9SHaojian Zhuang chip->core_irq = 0; 7084e405ae2SQing Xu return -EBUSY; 7091f1cf8f9SHaojian Zhuang } 71068e488d9SHaojian Zhuang 7114e405ae2SQing Xu /* request irq handler for pmic tsc irq*/ 7124e405ae2SQing Xu 71368e488d9SHaojian Zhuang /* mask TSC interrupt */ 71468e488d9SHaojian Zhuang max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0x0f); 71568e488d9SHaojian Zhuang 7161f1cf8f9SHaojian Zhuang if (!pdata->tsc_irq) { 7171f1cf8f9SHaojian Zhuang dev_warn(chip->dev, "No interrupt support on TSC IRQ\n"); 718d50f8f33SHaojian Zhuang return 0; 719d50f8f33SHaojian Zhuang } 7201f1cf8f9SHaojian Zhuang chip->tsc_irq = pdata->tsc_irq; 7211f1cf8f9SHaojian Zhuang ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq, 722619a1e31SFengguang Wu flags | IRQF_ONESHOT, "max8925-tsc", chip); 7231f1cf8f9SHaojian Zhuang if (ret) { 7241f1cf8f9SHaojian Zhuang dev_err(chip->dev, "Failed to request TSC IRQ: %d\n", ret); 7251f1cf8f9SHaojian Zhuang chip->tsc_irq = 0; 7261f1cf8f9SHaojian Zhuang } 7271f1cf8f9SHaojian Zhuang return 0; 7281f1cf8f9SHaojian Zhuang } 7291f1cf8f9SHaojian Zhuang 730f791be49SBill Pemberton static void init_regulator(struct max8925_chip *chip, 73151acdb61SHaojian Zhuang struct max8925_platform_data *pdata) 73251acdb61SHaojian Zhuang { 73351acdb61SHaojian Zhuang int ret; 73451acdb61SHaojian Zhuang 73551acdb61SHaojian Zhuang if (!pdata) 73651acdb61SHaojian Zhuang return; 73751acdb61SHaojian Zhuang if (pdata->sd1) { 73851acdb61SHaojian Zhuang reg_devs[0].platform_data = pdata->sd1; 73951acdb61SHaojian Zhuang reg_devs[0].pdata_size = sizeof(struct regulator_init_data); 74051acdb61SHaojian Zhuang } 74151acdb61SHaojian Zhuang if (pdata->sd2) { 74251acdb61SHaojian Zhuang reg_devs[1].platform_data = pdata->sd2; 74351acdb61SHaojian Zhuang reg_devs[1].pdata_size = sizeof(struct regulator_init_data); 74451acdb61SHaojian Zhuang } 74551acdb61SHaojian Zhuang if (pdata->sd3) { 74651acdb61SHaojian Zhuang reg_devs[2].platform_data = pdata->sd3; 74751acdb61SHaojian Zhuang reg_devs[2].pdata_size = sizeof(struct regulator_init_data); 74851acdb61SHaojian Zhuang } 74951acdb61SHaojian Zhuang if (pdata->ldo1) { 75051acdb61SHaojian Zhuang reg_devs[3].platform_data = pdata->ldo1; 75151acdb61SHaojian Zhuang reg_devs[3].pdata_size = sizeof(struct regulator_init_data); 75251acdb61SHaojian Zhuang } 75351acdb61SHaojian Zhuang if (pdata->ldo2) { 75451acdb61SHaojian Zhuang reg_devs[4].platform_data = pdata->ldo2; 75551acdb61SHaojian Zhuang reg_devs[4].pdata_size = sizeof(struct regulator_init_data); 75651acdb61SHaojian Zhuang } 75751acdb61SHaojian Zhuang if (pdata->ldo3) { 75851acdb61SHaojian Zhuang reg_devs[5].platform_data = pdata->ldo3; 75951acdb61SHaojian Zhuang reg_devs[5].pdata_size = sizeof(struct regulator_init_data); 76051acdb61SHaojian Zhuang } 76151acdb61SHaojian Zhuang if (pdata->ldo4) { 76251acdb61SHaojian Zhuang reg_devs[6].platform_data = pdata->ldo4; 76351acdb61SHaojian Zhuang reg_devs[6].pdata_size = sizeof(struct regulator_init_data); 76451acdb61SHaojian Zhuang } 76551acdb61SHaojian Zhuang if (pdata->ldo5) { 76651acdb61SHaojian Zhuang reg_devs[7].platform_data = pdata->ldo5; 76751acdb61SHaojian Zhuang reg_devs[7].pdata_size = sizeof(struct regulator_init_data); 76851acdb61SHaojian Zhuang } 76951acdb61SHaojian Zhuang if (pdata->ldo6) { 77051acdb61SHaojian Zhuang reg_devs[8].platform_data = pdata->ldo6; 77151acdb61SHaojian Zhuang reg_devs[8].pdata_size = sizeof(struct regulator_init_data); 77251acdb61SHaojian Zhuang } 77351acdb61SHaojian Zhuang if (pdata->ldo7) { 77451acdb61SHaojian Zhuang reg_devs[9].platform_data = pdata->ldo7; 77551acdb61SHaojian Zhuang reg_devs[9].pdata_size = sizeof(struct regulator_init_data); 77651acdb61SHaojian Zhuang } 77751acdb61SHaojian Zhuang if (pdata->ldo8) { 77851acdb61SHaojian Zhuang reg_devs[10].platform_data = pdata->ldo8; 77951acdb61SHaojian Zhuang reg_devs[10].pdata_size = sizeof(struct regulator_init_data); 78051acdb61SHaojian Zhuang } 78151acdb61SHaojian Zhuang if (pdata->ldo9) { 78251acdb61SHaojian Zhuang reg_devs[11].platform_data = pdata->ldo9; 78351acdb61SHaojian Zhuang reg_devs[11].pdata_size = sizeof(struct regulator_init_data); 78451acdb61SHaojian Zhuang } 78551acdb61SHaojian Zhuang if (pdata->ldo10) { 78651acdb61SHaojian Zhuang reg_devs[12].platform_data = pdata->ldo10; 78751acdb61SHaojian Zhuang reg_devs[12].pdata_size = sizeof(struct regulator_init_data); 78851acdb61SHaojian Zhuang } 78951acdb61SHaojian Zhuang if (pdata->ldo11) { 79051acdb61SHaojian Zhuang reg_devs[13].platform_data = pdata->ldo11; 79151acdb61SHaojian Zhuang reg_devs[13].pdata_size = sizeof(struct regulator_init_data); 79251acdb61SHaojian Zhuang } 79351acdb61SHaojian Zhuang if (pdata->ldo12) { 79451acdb61SHaojian Zhuang reg_devs[14].platform_data = pdata->ldo12; 79551acdb61SHaojian Zhuang reg_devs[14].pdata_size = sizeof(struct regulator_init_data); 79651acdb61SHaojian Zhuang } 79751acdb61SHaojian Zhuang if (pdata->ldo13) { 79851acdb61SHaojian Zhuang reg_devs[15].platform_data = pdata->ldo13; 79951acdb61SHaojian Zhuang reg_devs[15].pdata_size = sizeof(struct regulator_init_data); 80051acdb61SHaojian Zhuang } 80151acdb61SHaojian Zhuang if (pdata->ldo14) { 80251acdb61SHaojian Zhuang reg_devs[16].platform_data = pdata->ldo14; 80351acdb61SHaojian Zhuang reg_devs[16].pdata_size = sizeof(struct regulator_init_data); 80451acdb61SHaojian Zhuang } 80551acdb61SHaojian Zhuang if (pdata->ldo15) { 80651acdb61SHaojian Zhuang reg_devs[17].platform_data = pdata->ldo15; 80751acdb61SHaojian Zhuang reg_devs[17].pdata_size = sizeof(struct regulator_init_data); 80851acdb61SHaojian Zhuang } 80951acdb61SHaojian Zhuang if (pdata->ldo16) { 81051acdb61SHaojian Zhuang reg_devs[18].platform_data = pdata->ldo16; 81151acdb61SHaojian Zhuang reg_devs[18].pdata_size = sizeof(struct regulator_init_data); 81251acdb61SHaojian Zhuang } 81351acdb61SHaojian Zhuang if (pdata->ldo17) { 81451acdb61SHaojian Zhuang reg_devs[19].platform_data = pdata->ldo17; 81551acdb61SHaojian Zhuang reg_devs[19].pdata_size = sizeof(struct regulator_init_data); 81651acdb61SHaojian Zhuang } 81751acdb61SHaojian Zhuang if (pdata->ldo18) { 81851acdb61SHaojian Zhuang reg_devs[20].platform_data = pdata->ldo18; 81951acdb61SHaojian Zhuang reg_devs[20].pdata_size = sizeof(struct regulator_init_data); 82051acdb61SHaojian Zhuang } 82151acdb61SHaojian Zhuang if (pdata->ldo19) { 82251acdb61SHaojian Zhuang reg_devs[21].platform_data = pdata->ldo19; 82351acdb61SHaojian Zhuang reg_devs[21].pdata_size = sizeof(struct regulator_init_data); 82451acdb61SHaojian Zhuang } 82551acdb61SHaojian Zhuang if (pdata->ldo20) { 82651acdb61SHaojian Zhuang reg_devs[22].platform_data = pdata->ldo20; 82751acdb61SHaojian Zhuang reg_devs[22].pdata_size = sizeof(struct regulator_init_data); 82851acdb61SHaojian Zhuang } 82951acdb61SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, reg_devs, ARRAY_SIZE(reg_devs), 83051acdb61SHaojian Zhuang NULL, 0, NULL); 83151acdb61SHaojian Zhuang if (ret < 0) { 83251acdb61SHaojian Zhuang dev_err(chip->dev, "Failed to add regulator subdev\n"); 83351acdb61SHaojian Zhuang return; 83451acdb61SHaojian Zhuang } 83551acdb61SHaojian Zhuang } 83651acdb61SHaojian Zhuang 837f791be49SBill Pemberton int max8925_device_init(struct max8925_chip *chip, 838d50f8f33SHaojian Zhuang struct max8925_platform_data *pdata) 839d50f8f33SHaojian Zhuang { 840d50f8f33SHaojian Zhuang int ret; 841d50f8f33SHaojian Zhuang 8421f1cf8f9SHaojian Zhuang max8925_irq_init(chip, chip->i2c->irq, pdata); 843d50f8f33SHaojian Zhuang 8441f1cf8f9SHaojian Zhuang if (pdata && (pdata->power || pdata->touch)) { 8451f1cf8f9SHaojian Zhuang /* enable ADC to control internal reference */ 8461f1cf8f9SHaojian Zhuang max8925_set_bits(chip->i2c, MAX8925_RESET_CNFG, 1, 1); 8471f1cf8f9SHaojian Zhuang /* enable internal reference for ADC */ 8481f1cf8f9SHaojian Zhuang max8925_set_bits(chip->adc, MAX8925_TSC_CNFG1, 3, 2); 8491f1cf8f9SHaojian Zhuang /* check for internal reference IRQ */ 8501f1cf8f9SHaojian Zhuang do { 8511f1cf8f9SHaojian Zhuang ret = max8925_reg_read(chip->adc, MAX8925_TSC_IRQ); 8521f1cf8f9SHaojian Zhuang } while (ret & MAX8925_NREF_OK); 8531f1cf8f9SHaojian Zhuang /* enaable ADC scheduler, interval is 1 second */ 8541f1cf8f9SHaojian Zhuang max8925_set_bits(chip->adc, MAX8925_ADC_SCHED, 3, 2); 8551f1cf8f9SHaojian Zhuang } 8561f1cf8f9SHaojian Zhuang 8571f1cf8f9SHaojian Zhuang /* enable Momentary Power Loss */ 8581f1cf8f9SHaojian Zhuang max8925_set_bits(chip->rtc, MAX8925_MPL_CNTL, 1 << 4, 1 << 4); 8591f1cf8f9SHaojian Zhuang 8601f1cf8f9SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], 8611f1cf8f9SHaojian Zhuang ARRAY_SIZE(rtc_devs), 862f9ed1431SQing Xu NULL, chip->irq_base, NULL); 863d50f8f33SHaojian Zhuang if (ret < 0) { 8641f1cf8f9SHaojian Zhuang dev_err(chip->dev, "Failed to add rtc subdev\n"); 865d50f8f33SHaojian Zhuang goto out; 866d50f8f33SHaojian Zhuang } 867d0f7a6d6SHaojian Zhuang 868d0f7a6d6SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], 869d0f7a6d6SHaojian Zhuang ARRAY_SIZE(onkey_devs), 870678e8cb5SQing Xu NULL, chip->irq_base, NULL); 871d0f7a6d6SHaojian Zhuang if (ret < 0) { 872d0f7a6d6SHaojian Zhuang dev_err(chip->dev, "Failed to add onkey subdev\n"); 873d0f7a6d6SHaojian Zhuang goto out_dev; 874d0f7a6d6SHaojian Zhuang } 875d0f7a6d6SHaojian Zhuang 87651acdb61SHaojian Zhuang init_regulator(chip, pdata); 8771ad99893SHaojian Zhuang 8781ad99893SHaojian Zhuang if (pdata && pdata->backlight) { 87963b501e2SHaojian Zhuang bk_devs[0].platform_data = &pdata->backlight; 88063b501e2SHaojian Zhuang bk_devs[0].pdata_size = sizeof(struct max8925_backlight_pdata); 88163b501e2SHaojian Zhuang } 88263b501e2SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, bk_devs, ARRAY_SIZE(bk_devs), 88363b501e2SHaojian Zhuang NULL, 0, NULL); 8841ad99893SHaojian Zhuang if (ret < 0) { 8851ad99893SHaojian Zhuang dev_err(chip->dev, "Failed to add backlight subdev\n"); 8861ad99893SHaojian Zhuang goto out_dev; 8871ad99893SHaojian Zhuang } 888d50f8f33SHaojian Zhuang 8891f1cf8f9SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 8901f1cf8f9SHaojian Zhuang ARRAY_SIZE(power_devs), 891f9ed1431SQing Xu NULL, 0, NULL); 892d50f8f33SHaojian Zhuang if (ret < 0) { 8934e405ae2SQing Xu dev_err(chip->dev, 894f9ed1431SQing Xu "Failed to add power supply subdev, err = %d\n", ret); 8951f1cf8f9SHaojian Zhuang goto out_dev; 896d50f8f33SHaojian Zhuang } 8971ad99893SHaojian Zhuang 8981ad99893SHaojian Zhuang if (pdata && pdata->touch) { 8991ad99893SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], 9001ad99893SHaojian Zhuang ARRAY_SIZE(touch_devs), 901f9ed1431SQing Xu NULL, chip->tsc_irq, NULL); 9021ad99893SHaojian Zhuang if (ret < 0) { 9031ad99893SHaojian Zhuang dev_err(chip->dev, "Failed to add touch subdev\n"); 9041f1cf8f9SHaojian Zhuang goto out_dev; 9051ad99893SHaojian Zhuang } 9061ad99893SHaojian Zhuang } 9071f1cf8f9SHaojian Zhuang 9081ad99893SHaojian Zhuang return 0; 9091f1cf8f9SHaojian Zhuang out_dev: 9101f1cf8f9SHaojian Zhuang mfd_remove_devices(chip->dev); 911d50f8f33SHaojian Zhuang out: 912d50f8f33SHaojian Zhuang return ret; 913d50f8f33SHaojian Zhuang } 914d50f8f33SHaojian Zhuang 9154740f73fSBill Pemberton void max8925_device_exit(struct max8925_chip *chip) 916d50f8f33SHaojian Zhuang { 9171f1cf8f9SHaojian Zhuang if (chip->core_irq) 9181f1cf8f9SHaojian Zhuang free_irq(chip->core_irq, chip); 9191f1cf8f9SHaojian Zhuang if (chip->tsc_irq) 9201f1cf8f9SHaojian Zhuang free_irq(chip->tsc_irq, chip); 9211ad99893SHaojian Zhuang mfd_remove_devices(chip->dev); 922d50f8f33SHaojian Zhuang } 923d50f8f33SHaojian Zhuang 9241f1cf8f9SHaojian Zhuang 925d50f8f33SHaojian Zhuang MODULE_DESCRIPTION("PMIC Driver for Maxim MAX8925"); 926d50f8f33SHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com"); 927d50f8f33SHaojian Zhuang MODULE_LICENSE("GPL"); 928