From patchwork Sun Mar 10 20:55:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Billy Laws X-Patchwork-Id: 1054056 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="WyF2j5Du"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44HYR16pK7z9s70 for ; Mon, 11 Mar 2019 07:55:25 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726687AbfCJUzX (ORCPT ); Sun, 10 Mar 2019 16:55:23 -0400 Received: from mail-io1-f66.google.com ([209.85.166.66]:33454 "EHLO mail-io1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726651AbfCJUzW (ORCPT ); Sun, 10 Mar 2019 16:55:22 -0400 Received: by mail-io1-f66.google.com with SMTP id b6so2300850iog.0 for ; Sun, 10 Mar 2019 13:55:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to :content-transfer-encoding; bh=ltfFoF6DyhCdMXEg9mjDvf1TS2+Ndul5ejIqWMkd6YU=; b=WyF2j5DuJDOPssTaG/dxSNqLad0eO4LjZLWBedbdIk/PcXfXa9b6Rs2eiMDNhU/y1E 7j3LxfQqNY8FTI+2/aZJdFg8CWLsde7uIllONmXANNaEI/AUAQisbLbAXlNY5iMi21P+ +pEP6TJTipn+YQsowOHKVbt7G4Pm+fK3VoyNetQ8HDq7aNXKnJ0fVc0Mtb5MWCDIJYD0 170AtQr7mLR2DysfhR8QM6xMxy2MKfFvA7YHyx4uK2vUSmgJ/EtnfZm7oi4Cwiz8QOec tUPlExZUv62XxYTP6BQYkgTMcctoGCRH67UyVIBKzvCDandQb3/X7PPjO68v0BT0GuMb V07w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to :content-transfer-encoding; bh=ltfFoF6DyhCdMXEg9mjDvf1TS2+Ndul5ejIqWMkd6YU=; b=QPmz28qx+uXUM1hsXesDvYmLkvtb0541NDQp/LPLsjQNvqVsZJeb/WP8vJJGfcO8At ADLFyGmFWWhXy6PGINL/diP7Zr9X7w0D6nN4K9EUGQZhZZtz3Zf9JEVbA4I5BpjMyrSL lDQ6xsimmf4M2iXXJ8mXcnHOZ8x3PPVjDqfCPQWtocgIZv2yKXp3FM0sNWetjG97PgRE xgliEFRZibH6erVhNI4IYuGSO2lHGI0aqMY3p1Vmm2unhkDRH5tSARj8YnoWTI9zKOch 4RPaCw+YNdFA4o7kdZoW6Dux9YwU01rmckR24bzCMIP7mv6FpkK78R0ekNTdRE4Wx1A5 0Y2Q== X-Gm-Message-State: APjAAAW7zy49zaDJlTqEfzJsuotVSTpVMbAogmlP4LEY7OVM480WX1n5 X/Gb9Di0GHA97GVf0Fiyep3Xtx0En9eSQv74Y5/2un61 X-Google-Smtp-Source: APXvYqwsjVxz7LF5SUeGkQhjnP2valFlDDpRxEoZj4P02epjR02nNMku8bm2s0VUPg4J60+MI0tJu3iXloc7vKhLV9k= X-Received: by 2002:a5d:8c98:: with SMTP id g24mr16004430ion.103.1552251321020; Sun, 10 Mar 2019 13:55:21 -0700 (PDT) MIME-Version: 1.0 From: Billy Laws Date: Sun, 10 Mar 2019 20:55:10 +0000 Message-ID: Subject: Max77620 ONOFF To: linux-tegra@vger.kernel.org Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org I'm currently working of a driver for the onoff block of the max77620 for the nintendo switches powerkey basing my work off of https://datasheets.maximintegrated.com/en/ds/MAX77714.pdf which seems to be a similar chip. However I don't seem to ever get the rising interrupt, just the falling one and i get that only once. Another issue i had is that the mask register is at a different offset to the top mask register than the status is to the top status register, i had to hack a mask_offset property to regmap-irq to fix this. If anyone here with access to the real datasheet can confirm if my code is correct that would be very helpful :) Attached below is my diff: -------------- .resources = gpio_resources, .num_resources = ARRAY_SIZE(gpio_resources), @@ -183,12 +196,19 @@ static int max77620_irq_global_mask(void *irq_drv_data) { struct max77620_chip *chip = irq_drv_data; int ret; + unsigned int val; ret = regmap_update_bits(chip->rmap, MAX77620_REG_INTENLBT, MAX77620_GLBLM_MASK, MAX77620_GLBLM_MASK); if (ret < 0) dev_err(chip->dev, "Failed to set GLBLM: %d\n", ret); + regmap_read(chip->rmap, MAX77620_REG_IRQTOP, &val); + dev_err(chip->dev, "1top status reg %x", val); + regmap_read(chip->rmap, MAX77620_REG_ONOFFIRQ, &val); + dev_err(chip->dev, "status reg %x", val); + regmap_read(chip->rmap, MAX77620_REG_ONOFFIRQM, &val); + dev_err(chip->dev, "mask reg %x", val); return ret; } @@ -196,12 +216,19 @@ static int max77620_irq_global_unmask(void *irq_drv_data) { struct max77620_chip *chip = irq_drv_data; int ret; + unsigned int val; ret = regmap_update_bits(chip->rmap, MAX77620_REG_INTENLBT, MAX77620_GLBLM_MASK, 0); if (ret < 0) dev_err(chip->dev, "Failed to reset GLBLM: %d\n", ret); + regmap_read(chip->rmap, MAX77620_REG_IRQTOP, &val); + dev_err(chip->dev, "1top status reg %x", val); + regmap_read(chip->rmap, MAX77620_REG_ONOFFIRQ, &val); + dev_err(chip->dev, "1status reg %x", val); + regmap_read(chip->rmap, MAX77620_REG_ONOFFIRQM, &val); + dev_err(chip->dev, "1mask reg %x", val); return ret; } @@ -209,7 +236,7 @@ static struct regmap_irq_chip max77620_top_irq_chip = { .name = "max77620-top", .irqs = max77620_top_irqs, .num_irqs = ARRAY_SIZE(max77620_top_irqs), - .num_regs = 2, + .num_regs = 7, .status_base = MAX77620_REG_IRQTOP, .mask_base = MAX77620_REG_IRQTOPM, .handle_pre_irq = max77620_irq_global_mask, @@ -431,6 +458,7 @@ static int max77620_probe(struct i2c_client *client, const struct mfd_cell *mfd_cells; int n_mfd_cells; int ret; + unsigned int val; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -478,7 +506,7 @@ static int max77620_probe(struct i2c_client *client, dev_err(chip->dev, "Failed to add regmap irq: %d\n", ret); return ret; } - + ret = max77620_initialise_fps(chip); if (ret < 0) return ret; @@ -491,6 +519,34 @@ static int max77620_probe(struct i2c_client *client, return ret; } + regmap_read(chip->rmap, MAX77620_REG_IRQTOP, &val); + dev_err(chip->dev, "2top status reg %x", val); + regmap_read(chip->rmap, MAX77620_REG_ONOFFIRQ, &val); + dev_err(chip->dev, "1status reg %x", val); + regmap_read(chip->rmap, MAX77620_REG_ONOFFIRQM, &val); + dev_err(chip->dev, "1mask reg %x", val); + + ret = regmap_update_bits(chip->rmap, MAX77620_REG_INTENLBT, + MAX77620_GLBLM_MASK, MAX77620_GLBLM_MASK); + if (ret < 0) + dev_err(chip->dev, "Failed to set GLBLM: %d\n", ret); + + udelay(1000); + ret = regmap_update_bits(chip->rmap, MAX77620_REG_INTENLBT, + MAX77620_GLBLM_MASK, 0); + if (ret < 0) + dev_err(chip->dev, "Failed to set GLBLM: %d\n", ret); + + regmap_read(chip->rmap, MAX77620_REG_IRQTOP, &val); + dev_err(chip->dev, "2top status reg %x", val); + regmap_read(chip->rmap, MAX77620_REG_ONOFFIRQ, &val); + dev_err(chip->dev, "1status reg %x", val); + regmap_read(chip->rmap, MAX77620_REG_ONOFFIRQM, &val); + dev_err(chip->dev, "1mask reg %x", val); + + + + return 0; } diff --git a/arch/arm64/boot/dts/nvidia/tegra210-nintendo-switch.dts b/arch/arm64/boot/dts/nvidia/tegra210-nintendo-switch.dts index bfe4f4b1e091..19d189b58d91 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-nintendo-switch.dts +++ b/arch/arm64/boot/dts/nvidia/tegra210-nintendo-switch.dts @@ -1656,7 +1656,7 @@ max77620: max77620@3c { compatible = "maxim,max77620"; reg = <0x3c>; - interrupts = ; + interrupts = ; #interrupt-cells = <2>; interrupt-controller; @@ -1945,8 +1945,8 @@ max77621_cpu: pmic@1b { compatible = "maxim,max77621"; reg = <0x1b>; - interrupt-parent = <&gpio>; - interrupts = ; + interrupt-parent = <&gpio>; + interrupts = ; regulator-name = "PPVAR_CPU"; // smaug: 800000..1231250 regulator-min-microvolt = <800000>; @@ -1969,8 +1969,8 @@ max77621_gpu: pmic@1c { compatible = "maxim,max77621"; reg = <0x1c>; - interrupt-parent = <&gpio>; - interrupts = ; + interrupt-parent = <&gpio>; + interrupts = ; regulator-name = "PPVAR_GPU"; regulator-min-microvolt = <840000>; regulator-max-microvolt = <1150000>; diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 330c1f7e9665..45f61660e1b4 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -240,7 +240,10 @@ static void regmap_irq_enable(struct irq_data *data) if (d->chip->clear_on_unmask) d->clear_status = true; - d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~mask; + if (!irq_data->mask_offset) + d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~mask; + else + d->mask_buf[irq_data->mask_offset / map->reg_stride] &= ~mask; } static void regmap_irq_disable(struct irq_data *data) @@ -249,7 +252,10 @@ static void regmap_irq_disable(struct irq_data *data) struct regmap *map = d->map; const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); - d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; + if (!irq_data->mask_offset) + d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; + else + d->mask_buf[irq_data->mask_offset / map->reg_stride] |= irq_data->mask; } static int regmap_irq_set_type(struct irq_data *data, unsigned int type) me@archlinux  ~/Development/tegra/linux   switch-5.0 ●✚  git diff HEAD drivers/ diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 330c1f7e9665..45f61660e1b4 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -240,7 +240,10 @@ static void regmap_irq_enable(struct irq_data *data) if (d->chip->clear_on_unmask) d->clear_status = true; - d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~mask; + if (!irq_data->mask_offset) + d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~mask; + else + d->mask_buf[irq_data->mask_offset / map->reg_stride] &= ~mask; } static void regmap_irq_disable(struct irq_data *data) @@ -249,7 +252,10 @@ static void regmap_irq_disable(struct irq_data *data) struct regmap *map = d->map; const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); - d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; + if (!irq_data->mask_offset) + d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; + else + d->mask_buf[irq_data->mask_offset / map->reg_stride] |= irq_data->mask; } static int regmap_irq_set_type(struct irq_data *data, unsigned int type) @@ -585,8 +591,10 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, mutex_init(&d->lock); for (i = 0; i < chip->num_irqs; i++) - d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride] - |= chip->irqs[i].mask; + if (!chip->irqs[i].mask_offset) + d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride] |= chip->irqs[i].mask; + else + d->mask_buf_def[chip->irqs[i].mask_offset / map->reg_stride] |= chip->irqs[i].mask; /* Mask all the interrupts by default */ for (i = 0; i < chip->num_regs; i++) { diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index ca59a2be9bc5..1cac5eb0aad1 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -191,6 +191,17 @@ config INPUT_MAX77693_HAPTIC To compile this driver as module, choose M here: the module will be called max77693-haptic. +config INPUT_MAX77620_ONOFF + tristate "MAX77620 ONOFF support" + depends on MFD_MAX77620 + help + Support the ONOFF block of MAX77620 PMICs as an input device + reporting power button status. + + To compile this driver as a module, choose M here: the module + will be called max77620_onoff. + + config INPUT_MAX8925_ONKEY tristate "MAX8925 ONKEY support" depends on MFD_MAX8925 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 9d0f9d1ff68f..47f0eaf8b370 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o +obj-$(CONFIG_INPUT_MAX77620_ONOFF) += max77620-onoff.o obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o diff --git a/drivers/input/misc/max77620-onoff.c b/drivers/input/misc/max77620-onoff.c new file mode 100644 index 000000000000..932536bc5680 --- /dev/null +++ b/drivers/input/misc/max77620-onoff.c @@ -0,0 +1,149 @@ +/**re-- + * MAX77620 ONKEY driver + *ore-- + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + *ore-- + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + *ore-- + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *ore-- + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */re-- + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define POWERKEY_PRESSED (1 << 2) /* 0/1 -- up/down */ + +struct max77620_onoff_info { + struct input_dev *input; + struct regmap *regmap; + unsigned int code; +}; + +/* + * MAX77620 gives us an interrupt when ONKEY is pressed or released. + * max77620_set_bits() operates I2C bus and may sleep. So implement + * it in thread IRQ handler. + */ +static irqreturn_t max77620_onoff_handler(int irq, void *data) +{ + struct max77620_onoff_info *info = data; + u32 state; + + regmap_read(info->regmap, MAX77620_REG_ONOFFSTAT, &state); + + input_report_key(info->input, info->code, state & POWERKEY_PRESSED); + input_sync(info->input); + + return IRQ_HANDLED; +} + +static int max77620_onoff_probe(struct platform_device *pdev) +{ + struct max77620_onoff_info *info; + int irq[2], error; + + irq[0] = platform_get_irq(pdev, 0); + if (irq[0] < 0) { + dev_err(&pdev->dev, "No IRQ resource!\n"); + return -EINVAL; + } + + irq[1] = platform_get_irq(pdev, 1); + if (irq[1] < 0) { + dev_err(&pdev->dev, "No IRQ resource!\n"); + return -EINVAL; + } + + info = devm_kzalloc(&pdev->dev, sizeof(struct max77620_onoff_info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!info->regmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + error = device_property_read_u32(&pdev->dev, "linux,code", &info->code); + if (error) + info->code = KEY_POWER; + + info->input = devm_input_allocate_device(&pdev->dev); + if (!info->input) + return -ENOMEM; + + info->input->name = "max77620_onoff"; + info->input->phys = "max77620_onoff/input0"; + info->input->id.bustype = BUS_I2C; + info->input->dev.parent = &pdev->dev; + input_set_capability(info->input, EV_KEY, info->code); + + error = devm_request_threaded_irq(&pdev->dev, irq[0], NULL, + max77620_onoff_handler, IRQF_ONESHOT, + "en0-up", info); + if (error < 0) { + dev_err(&pdev->dev, "Failed to request IRQ: #%d: %d\n", + irq[0], error); + return error; + } + + error = devm_request_threaded_irq(&pdev->dev, irq[1], NULL, + max77620_onoff_handler, IRQF_ONESHOT, + "en0-down", info); + if (error < 0) { + dev_err(&pdev->dev, "Failed to request IRQ: #%d: %d\n", + irq[1], error); + return error; + } + + error = input_register_device(info->input); + if (error) { + dev_err(&pdev->dev, "Can't register input device: %d\n", error); + return error; + } + + platform_set_drvdata(pdev, info); +// device_init_wakeup(&pdev->dev, 1); + + return 0; +} + +static int max77620_onoff_remove(struct platform_device *pdev) +{ + device_init_wakeup(&pdev->dev, 0); + + return 0; +} + +static struct platform_driver max77620_onoff_driver = { + .driver = { + .name = "max77620-onoff", + }, + .probe = max77620_onoff_probe, + .remove = max77620_onoff_remove, +}; +module_platform_driver(max77620_onoff_driver); + +MODULE_DESCRIPTION("Maxim MAX77620 ONOFF driver"); +MODULE_AUTHOR("Billy Laws "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c index d8ddd1a6f304..ef908af95a80 100644 --- a/drivers/mfd/max77620.c +++ b/drivers/mfd/max77620.c @@ -36,6 +36,12 @@ #include #include #include +#include + +static const struct resource onoff_resources[] = { + DEFINE_RES_IRQ(MAX77620_IRQ_ONOFF_EN0_R), + DEFINE_RES_IRQ(MAX77620_IRQ_ONOFF_EN0_F), +}; static const struct resource gpio_resources[] = { DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO), @@ -65,14 +71,21 @@ static const struct regmap_irq max77620_top_irqs[] = { REGMAP_IRQ_REG(MAX77620_IRQ_LBT_MBATLOW, 1, MAX77620_IRQ_LBM_MASK), REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM1, 1, MAX77620_IRQ_TJALRM1_MASK), REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM2, 1, MAX77620_IRQ_TJALRM2_MASK), + REGMAP_IRQ_REG2(MAX77620_IRQ_ONOFF_EN0_R, 6, 5, MAX77620_IRQ_ONOFF_EN0_R_MASK), + REGMAP_IRQ_REG2(MAX77620_IRQ_ONOFF_EN0_F, 6, 5, MAX77620_IRQ_ONOFF_EN0_F_MASK), }; + static const struct mfd_cell max77620_children[] = { { .name = "max77620-pinctrl", }, { .name = "max77620-clock", }, { .name = "max77620-pmic", }, { .name = "max77620-watchdog", }, { + .name = "max77620-onoff", + .resources = onoff_resources, + .num_resources = ARRAY_SIZE(onoff_resources), + }, { .name = "max77620-gpio",