From patchwork Thu May 30 20:12:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 165462 Delivered-To: patch@linaro.org Received: by 2002:a92:9e1a:0:0:0:0:0 with SMTP id q26csp1427068ili; Thu, 30 May 2019 13:13:02 -0700 (PDT) X-Google-Smtp-Source: APXvYqz36q9tkwOqs0DUnR9oil509rMoWQjdwz5qDMDYhF2vO48v0Bt3GvX2cU9/R253yaz27ERz X-Received: by 2002:a17:90a:c583:: with SMTP id l3mr4806661pjt.55.1559247182611; Thu, 30 May 2019 13:13:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1559247182; cv=none; d=google.com; s=arc-20160816; b=Omy/jwI3szsuEo1g1FLudtlVyp9jqdWsfoYnXzvVmT3Z0shXjepNsRE96tGDSVgrqc WEYM2y0xZTn3VcLR0fQQ8nu5axhErZLFUkmUq6CU3h6f2d3RBkeynntx80bdeQFClDpj wIC/jfxxSKItuFG+M4e72ZI1NlTky36n74uHuTm5UK1/z0SePdOEoJFqPcWXx29beZrS Ttm36sixQF+ftvXxUxglYyc87Z++4B+wZyqpLjLUPbgheFaoz3vDmuz+yQQxXuY4sli+ mtu+G6V4Yt8GkmVk0doVsHwo1nbnWIVD2i5IVp3/KQ0BHyNKOMDLsqPzxe1U+6vBabg1 tPTQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=ViFMQAf2WDsJwO1vElsDb0JkszfiO6AKCi1zDV0EetY=; b=rxwOOW8xCL63ZMHuhGkGpFq7S5H3VX7UCq92sVwUAw2uBQ2XOPvQQvQXQw4C6jI+fZ ghbpG989P0ZCW/iUpFJVH5Kx75j38cluh6+C+MQwmP51zpj0XRw3tOHO4//7962s7R2l aLYIRs2p4gxaZ34hpCx2L6UGWZmjeV8P7t1ylIKMwSTKlwtjbraujb3mSPgfljR3xRy0 PzAxE6b8X0hBeUb/HXVH7a1mxCLoeX+KCgL0ZG0jOrnrVUz5v0fUpwIIQ3tfEnmjJDSF sR7t/2NJ+C+RrR2j8emhUGpslSZR2iWxDQRaApxvLojXfMFZN8VQiypWvoEaUoTSfeLZ ehjQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=gsLyxpGM; spf=pass (google.com: best guess record for domain of linux-i2c-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-i2c-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i36si3553918pgl.491.2019.05.30.13.13.02; Thu, 30 May 2019 13:13:02 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-i2c-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=gsLyxpGM; spf=pass (google.com: best guess record for domain of linux-i2c-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-i2c-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726125AbfE3UNB (ORCPT + 2 others); Thu, 30 May 2019 16:13:01 -0400 Received: from mail-wr1-f65.google.com ([209.85.221.65]:35968 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726045AbfE3UNB (ORCPT ); Thu, 30 May 2019 16:13:01 -0400 Received: by mail-wr1-f65.google.com with SMTP id n4so1947424wrs.3 for ; Thu, 30 May 2019 13:13:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=ViFMQAf2WDsJwO1vElsDb0JkszfiO6AKCi1zDV0EetY=; b=gsLyxpGM8cOdinX926XsdnIW+zXTbSiKsExJuzkkiGluymjM0M98lKCgtuQ2j2uCO1 r6CrlrqNUPqotrC/cchLuI1VsVfIw1AprGx0Y+08us6yE1Q7CoxYiGwysDQe550IJKVc LDFF7kav4ooF2u2+rh1pgGp9iEXqszV+crv7+n/bJP5cXgOLA3Q8LwYVjVtoD1yag2dR LujEyJ4eRVKanmj+czOJesoWjjnONIup02JqnLpTZR9nHc1tO+MKu0iiN0aYMCFj1J/m uYIXDr0zgpOSMU0vBnyWXAlkWnVnqBoL2evglncWFVFX2/xV4VZPkCcJTgleqLQZ9MwD sElQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=ViFMQAf2WDsJwO1vElsDb0JkszfiO6AKCi1zDV0EetY=; b=bwGUzYZ+qru2fTqguFcqxMWFQ6OhwV/rfXT4v+L1uv+RH65HIazBus3VO7o+I6btqi z6+LACaZAfWBWV8N0lhrQD2h/7zqTsQSLsQm7C+V9WIAK36kEjPpPz+cwjvdmWGBG6ET y9G+LKVIfEkzstfNEbschknwCFL6STklx6ImGxsHDHBCmr2XJS0s+flRCdZb7PRQi4ZL v/sguh16yOiMIexjAosdlawMthEzJ6v02AtfVbjACWalIn0/vuih/dfKFCysf+8+aqj+ PfuDbca5mph8nzgAQN3jHS+VswkzzTjdf9s/OxJqLbTHCffrmOKuElYHeWJfJY6/MJxF P4CA== X-Gm-Message-State: APjAAAXxqBLbDVKehpnYbat6YEn4/2/SvQiY2mq3Fiw6X7+mNiuo7OaV FBDq6C5tHwGAsCbA0/MYvKiETQ== X-Received: by 2002:adf:db8e:: with SMTP id u14mr3967158wri.190.1559247179285; Thu, 30 May 2019 13:12:59 -0700 (PDT) Received: from localhost.localdomain (catv-89-135-96-219.catv.broadband.hu. [89.135.96.219]) by smtp.gmail.com with ESMTPSA id 3sm2280554wmj.21.2019.05.30.13.12.57 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Thu, 30 May 2019 13:12:57 -0700 (PDT) From: Linus Walleij To: Wolfram Sang , linux-i2c@vger.kernel.org Cc: Linus Walleij , Mika Westerberg , Andy Shevchenko , Peter Rosin , Jean Delvare Subject: [PATCH] i2c: mux/i801: Switch to use descriptor passing Date: Thu, 30 May 2019 22:12:52 +0200 Message-Id: <20190530201252.11922-1-linus.walleij@linaro.org> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org This switches the i801 GPIO mux to use GPIO descriptors for handling the GPIO lines. The previous hack which was reaching inside the GPIO chips etc cannot live on. We pass descriptors along with the GPIO mux device at creation instead. The GPIO mux was only used by way of platform data with a platform device from one place in the kernel: the i801 i2c bus driver. Let's just associate the GPIO descriptor table with the actual device like everyone else and dynamically create a descriptor table passed along with the GPIO i2c mux. This enables simplification of the GPIO i2c mux driver to use only the descriptor API and the OF probe path gets simplified in the process. The i801 driver was registering the GPIO i2c mux with PLATFORM_DEVID_AUTO which would make it hard to predict the device name and assign the descriptor table properly, but this seems to be a mistake to begin with: all of the GPIO mux devices are hardcoded to look up GPIO lines from the "gpio_ich" GPIO chip. If there are more than one mux, there is certainly more than one gpio chip as well, and then we have more serious problems. Switch to PLATFORM_DEVID_NONE instead. There can be only one. Cc: Mika Westerberg Cc: Andy Shevchenko Cc: Peter Rosin Cc: Jean Delvare Signed-off-by: Linus Walleij --- Folks, you surely see what I am trying to do. Would appreciate help fixing any bugs (it compiles). --- drivers/i2c/busses/i2c-i801.c | 31 ++++-- drivers/i2c/muxes/i2c-mux-gpio.c | 109 +++++---------------- include/linux/platform_data/i2c-mux-gpio.h | 7 -- 3 files changed, 51 insertions(+), 96 deletions(-) -- 2.20.1 diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 679c6c41f64b..5bf5e16df888 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -107,7 +107,7 @@ #include #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI -#include +#include #include #endif @@ -1259,6 +1259,8 @@ static int i801_add_mux(struct i801_priv *priv) const struct i801_mux_config *mux_config; struct i2c_mux_gpio_platform_data gpio_data; int err; + struct gpiod_lookup_table *lookup; + int i; if (!priv->mux_drvdata) return 0; @@ -1270,14 +1272,31 @@ static int i801_add_mux(struct i801_priv *priv) gpio_data.values = mux_config->values; gpio_data.n_values = mux_config->n_values; gpio_data.classes = mux_config->classes; - gpio_data.gpio_chip = mux_config->gpio_chip; - gpio_data.gpios = mux_config->gpios; - gpio_data.n_gpios = mux_config->n_gpios; gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; - /* Register the mux device */ + /* Register GPIO descriptor lookup table */ + lookup = devm_kzalloc(dev, + struct_size(lookup, table, mux_config->n_gpios), + GFP_KERNEL); + if (!lookup) + return -ENOMEM; + lookup->dev_id = "i2c-mux-gpio"; + for (i = 0; i < mux_config->n_gpios; i++) { + lookup->table[i].chip_label = mux_config->gpio_chip; + lookup->table[i].chip_hwnum = mux_config->gpios[i]; + lookup->table[i].con_id = NULL; + } + gpiod_add_lookup_table(lookup); + + /* + * Register the mux device, we use PLATFORM_DEVID_NONE here + * because since we are referring to the GPIO chip by name we are + * anyways in deep trouble if there is more than one of these + * devices, and there should likely only be one platform controller + * hub. + */ priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio", - PLATFORM_DEVID_AUTO, &gpio_data, + PLATFORM_DEVID_NONE, &gpio_data, sizeof(struct i2c_mux_gpio_platform_data)); if (IS_ERR(priv->mux_pdev)) { err = PTR_ERR(priv->mux_pdev); diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 13882a2a4f60..044d44807fdd 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -14,13 +14,13 @@ #include #include #include -#include +#include +#include #include "../../gpio/gpiolib.h" -#include struct gpiomux { struct i2c_mux_gpio_platform_data data; - unsigned gpio_base; + int ngpios; struct gpio_desc **gpios; }; @@ -30,7 +30,7 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) values[0] = val; - gpiod_set_array_value_cansleep(mux->data.n_gpios, mux->gpios, NULL, + gpiod_set_array_value_cansleep(mux->ngpios, mux->gpios, NULL, values); } @@ -52,12 +52,6 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan) return 0; } -static int match_gpio_chip_by_label(struct gpio_chip *chip, - void *data) -{ - return !strcmp(chip->label, data); -} - #ifdef CONFIG_OF static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, struct platform_device *pdev) @@ -103,29 +97,6 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, if (of_property_read_u32(np, "idle-state", &mux->data.idle)) mux->data.idle = I2C_MUX_GPIO_NO_IDLE; - mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios"); - if (mux->data.n_gpios < 0) { - dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n"); - return -EINVAL; - } - - gpios = devm_kcalloc(&pdev->dev, - mux->data.n_gpios, sizeof(*mux->data.gpios), - GFP_KERNEL); - if (!gpios) { - dev_err(&pdev->dev, "Cannot allocate gpios array"); - return -ENOMEM; - } - - for (i = 0; i < mux->data.n_gpios; i++) { - ret = of_get_named_gpio(np, "mux-gpios", i); - if (ret < 0) - return ret; - gpios[i] = ret; - } - - mux->data.gpios = gpios; - return 0; } #else @@ -142,8 +113,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) struct gpiomux *mux; struct i2c_adapter *parent; struct i2c_adapter *root; - unsigned initial_state, gpio_base; - int i, ret; + unsigned initial_state; + int i, ngpios, ret; mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); if (!mux) @@ -158,29 +129,19 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) sizeof(mux->data)); } - /* - * If a GPIO chip name is provided, the GPIO pin numbers provided are - * relative to its base GPIO number. Otherwise they are absolute. - */ - if (mux->data.gpio_chip) { - struct gpio_chip *gpio; - - gpio = gpiochip_find(mux->data.gpio_chip, - match_gpio_chip_by_label); - if (!gpio) - return -EPROBE_DEFER; - - gpio_base = gpio->base; - } else { - gpio_base = 0; + ngpios = gpiod_count(&pdev->dev, NULL); + if (!ngpios) { + dev_err(&pdev->dev, "no gpios provided\n"); + return -EINVAL; } + mux->ngpios = ngpios; parent = i2c_get_adapter(mux->data.parent); if (!parent) return -EPROBE_DEFER; muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, - mux->data.n_gpios * sizeof(*mux->gpios), 0, + ngpios * sizeof(*mux->gpios), 0, i2c_mux_gpio_select, NULL); if (!muxc) { ret = -ENOMEM; @@ -194,7 +155,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) root = i2c_root_adapter(&parent->dev); muxc->mux_locked = true; - mux->gpio_base = gpio_base; if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) { initial_state = mux->data.idle; @@ -203,34 +163,27 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) initial_state = mux->data.values[0]; } - for (i = 0; i < mux->data.n_gpios; i++) { + for (i = 0; i < ngpios; i++) { struct device *gpio_dev; - struct gpio_desc *gpio_desc; - - ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio"); - if (ret) { - dev_err(&pdev->dev, "Failed to request GPIO %d\n", - mux->data.gpios[i]); - goto err_request_gpio; - } - - ret = gpio_direction_output(gpio_base + mux->data.gpios[i], - initial_state & (1 << i)); - if (ret) { - dev_err(&pdev->dev, - "Failed to set direction of GPIO %d to output\n", - mux->data.gpios[i]); - i++; /* gpio_request above succeeded, so must free */ - goto err_request_gpio; + struct gpio_desc *gpiod; + enum gpiod_flags flag; + + if (initial_state & BIT(i)) + flag = GPIOD_OUT_HIGH; + else + flag = GPIOD_OUT_LOW; + gpiod = devm_gpiod_get_index(&pdev->dev, NULL, i, flag); + if (IS_ERR(gpiod)) { + ret = PTR_ERR(gpiod); + goto alloc_failed; } - gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]); - mux->gpios[i] = gpio_desc; + mux->gpios[i] = gpiod; if (!muxc->mux_locked) continue; - gpio_dev = &gpio_desc->gdev->dev; + gpio_dev = &gpiod->gdev->dev; muxc->mux_locked = i2c_root_adapter(gpio_dev) == root; } @@ -253,10 +206,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) add_adapter_failed: i2c_mux_del_adapters(muxc); - i = mux->data.n_gpios; -err_request_gpio: - for (; i > 0; i--) - gpio_free(gpio_base + mux->data.gpios[i - 1]); alloc_failed: i2c_put_adapter(parent); @@ -266,14 +215,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) static int i2c_mux_gpio_remove(struct platform_device *pdev) { struct i2c_mux_core *muxc = platform_get_drvdata(pdev); - struct gpiomux *mux = i2c_mux_priv(muxc); - int i; i2c_mux_del_adapters(muxc); - - for (i = 0; i < mux->data.n_gpios; i++) - gpio_free(mux->gpio_base + mux->data.gpios[i]); - i2c_put_adapter(muxc->parent); return 0; diff --git a/include/linux/platform_data/i2c-mux-gpio.h b/include/linux/platform_data/i2c-mux-gpio.h index 4406108201fe..28f288eed652 100644 --- a/include/linux/platform_data/i2c-mux-gpio.h +++ b/include/linux/platform_data/i2c-mux-gpio.h @@ -22,10 +22,6 @@ * position * @n_values: Number of multiplexer positions (busses to instantiate) * @classes: Optional I2C auto-detection classes - * @gpio_chip: Optional GPIO chip name; if set, GPIO pin numbers are given - * relative to the base GPIO number of that chip - * @gpios: Array of GPIO numbers used to control MUX - * @n_gpios: Number of GPIOs used to control MUX * @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used */ struct i2c_mux_gpio_platform_data { @@ -34,9 +30,6 @@ struct i2c_mux_gpio_platform_data { const unsigned *values; int n_values; const unsigned *classes; - char *gpio_chip; - const unsigned *gpios; - int n_gpios; unsigned idle; };