Received: by 10.192.165.156 with SMTP id m28csp1135900imm; Wed, 11 Apr 2018 13:06:28 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+jPfvBegR+qFVaK6Zl+8KaO2qMmzd9tUZyDAbnsOpi8X1c6WyL7HELhhBeR9Jp2BajAgtb X-Received: by 10.101.100.132 with SMTP id e4mr4491662pgv.240.1523477188419; Wed, 11 Apr 2018 13:06:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523477188; cv=none; d=google.com; s=arc-20160816; b=dlxsCfI/PTQwOiyl5XuhTSuvELFlIqWxEGoSIBQHzR5D8xVvIKvi1S4U1HGHwtChZF HP/HsczISP5c86Mrzu2xZjvcoOiD7SMFyYtsJ54yehPRPHLNnLaruw4DBgitKxyF54Rt Z3B92aLNKPDPMnDjU5M/3KeCz4Jdp7N6BP8LTQJR4OAErAG+7hfY/2pl9kjngkbywSKW Wq75OoBf/Hi/K6zvVDE776TP53zv2Kxnd2rFkSObegHCp/dYokW3KGhIcnekfKDJxvqf 2f+4CqR0tLnFoeYz55Ittz6xJ6GEkfDsopAhzPW3YkWYUprN4J/dKUqILxH3Bz0Nj2cs u+dA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=DV8klGqxTVnEZT8TTm7h1Ah3p8bNg/y/fj3FrnkjqUc=; b=YUxJuc4Zu/BKzyNSjBzYPwtceDkZDwdeo+ay0V05jpdYq+7wEHv8JcsjwKCNH5izA+ Y4B97ZZ1rgqEFjbbmxb1d9hvHfr6FyjOwStAeTWu4fTeUn2GneC/0c1Pm750Y8Fommxl 4opOzHjoUOdAjU6ZXj+PqstQhOPE+AzE4qJHY0+rYm8AGo30g26LFDV2gHaQVaPbhVeE aW7RYvLNDIVzWsYrjxPDXYrOCmjciXdxVp6//o+2bECK83WC9yET5ANXURS1ik+1StDv O6W/WQNzHut2xr9/5Ba6ckbfRXYrfE1L45sxFervSYNnkQWnF2TE8x3L8MXW4YMO4pzO ofeg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g5si1146347pgr.411.2018.04.11.13.05.50; Wed, 11 Apr 2018 13:06:28 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756949AbeDKT71 (ORCPT + 99 others); Wed, 11 Apr 2018 15:59:27 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:35914 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755667AbeDKS4q (ORCPT ); Wed, 11 Apr 2018 14:56:46 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 48579C06; Wed, 11 Apr 2018 18:56:45 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Aaron Lu , Hans de Goede , Andy Shevchenko , Linus Walleij , Sasha Levin Subject: [PATCH 4.9 094/310] gpio: crystalcove: Do not write regular gpio registers for virtual GPIOs Date: Wed, 11 Apr 2018 20:33:53 +0200 Message-Id: <20180411183626.280561563@linuxfoundation.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180411183622.305902791@linuxfoundation.org> References: <20180411183622.305902791@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Hans de Goede [ Upstream commit 9a752b4c9ab924033bfdb8784c680d50b2bd5684 ] The Crystal Cove PMIC has 16 real GPIOs but the ACPI code for devices with this PMIC may address up to 95 GPIOs, these extra GPIOs are called virtual GPIOs and are used by the ACPI code as a method of accessing various non GPIO bits of PMIC. Commit dcdc3018d635 ("gpio: crystalcove: support virtual GPIO") added dummy support for these to avoid a bunch of ACPI errors, but instead of ignoring writes / reads to them by doing: if (gpio >= CRYSTALCOVE_GPIO_NUM) return 0; It accidentally introduced the following wrong check: if (gpio > CRYSTALCOVE_VGPIO_NUM) return 0; Which means that attempts by the ACPI code to access these gpios causes some arbitrary gpio to get touched through for example GPIO1P0CTLO + gpionr % 8. Since we do support input/output (but not interrupts) on the 0x5e virtual GPIO, this commit makes to_reg return -ENOTSUPP for unsupported virtual GPIOs so as to not have to check for (gpio >= CRYSTALCOVE_GPIO_NUM && gpio != 0x5e) everywhere and to make it easier to add support for more virtual GPIOs in the future. It then adds a check for to_reg returning an error to all callers where this may happen fixing the ACPI code accessing virtual GPIOs accidentally causing changes to real GPIOs. Fixes: dcdc3018d635 ("gpio: crystalcove: support virtual GPIO") Cc: Aaron Lu Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-crystalcove.c | 54 ++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 18 deletions(-) --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -90,8 +90,18 @@ static inline int to_reg(int gpio, enum { int reg; - if (gpio == 94) - return GPIOPANELCTL; + if (gpio >= CRYSTALCOVE_GPIO_NUM) { + /* + * Virtual GPIO called from ACPI, for now we only support + * the panel ctl. + */ + switch (gpio) { + case 0x5e: + return GPIOPANELCTL; + default: + return -EOPNOTSUPP; + } + } if (reg_type == CTRL_IN) { if (gpio < 8) @@ -130,36 +140,36 @@ static void crystalcove_update_irq_ctrl( static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); + int reg = to_reg(gpio, CTRL_OUT); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return 0; - return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT), - CTLO_INPUT_SET); + return regmap_write(cg->regmap, reg, CTLO_INPUT_SET); } static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int value) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); + int reg = to_reg(gpio, CTRL_OUT); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return 0; - return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT), - CTLO_OUTPUT_SET | value); + return regmap_write(cg->regmap, reg, CTLO_OUTPUT_SET | value); } static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); - int ret; unsigned int val; + int ret, reg = to_reg(gpio, CTRL_IN); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return 0; - ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val); + ret = regmap_read(cg->regmap, reg, &val); if (ret) return ret; @@ -170,14 +180,15 @@ static void crystalcove_gpio_set(struct unsigned gpio, int value) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); + int reg = to_reg(gpio, CTRL_OUT); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return; if (value) - regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1); + regmap_update_bits(cg->regmap, reg, 1, 1); else - regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 0); + regmap_update_bits(cg->regmap, reg, 1, 0); } static int crystalcove_irq_type(struct irq_data *data, unsigned type) @@ -185,6 +196,9 @@ static int crystalcove_irq_type(struct i struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data)); + if (data->hwirq >= CRYSTALCOVE_GPIO_NUM) + return 0; + switch (type) { case IRQ_TYPE_NONE: cg->intcnt_value = CTLI_INTCNT_DIS; @@ -235,8 +249,10 @@ static void crystalcove_irq_unmask(struc struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data)); - cg->set_irq_mask = false; - cg->update |= UPDATE_IRQ_MASK; + if (data->hwirq < CRYSTALCOVE_GPIO_NUM) { + cg->set_irq_mask = false; + cg->update |= UPDATE_IRQ_MASK; + } } static void crystalcove_irq_mask(struct irq_data *data) @@ -244,8 +260,10 @@ static void crystalcove_irq_mask(struct struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data)); - cg->set_irq_mask = true; - cg->update |= UPDATE_IRQ_MASK; + if (data->hwirq < CRYSTALCOVE_GPIO_NUM) { + cg->set_irq_mask = true; + cg->update |= UPDATE_IRQ_MASK; + } } static struct irq_chip crystalcove_irqchip = {