From patchwork Sat Oct 1 00:52:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Ranostay X-Patchwork-Id: 12996183 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1612C4332F for ; Sat, 1 Oct 2022 00:52:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230017AbiJAAwc (ORCPT ); Fri, 30 Sep 2022 20:52:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53218 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231758AbiJAAwb (ORCPT ); Fri, 30 Sep 2022 20:52:31 -0400 Received: from mail-qk1-x72d.google.com (mail-qk1-x72d.google.com [IPv6:2607:f8b0:4864:20::72d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F1DC115D854 for ; Fri, 30 Sep 2022 17:52:29 -0700 (PDT) Received: by mail-qk1-x72d.google.com with SMTP id u28so3830678qku.2 for ; Fri, 30 Sep 2022 17:52:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=konsulko.com; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date; bh=YbYc9Wb8hOpiGkV8KRi+RzCLZEcBuGY8tuloAubI/yo=; b=laaWXpp3rMJ6tr8a9Gk7ORzcIWmhcJfeFhVS/n7Wq3VKzwVJV4SEMNNsNgGhMPgT77 s3Y7AY70DhdnxNurnPG7A9oBsuDhtvMuhnDdGExT4EwrcrHxHWcwRRfn/UhPytf9eGea uCj+Dr5/3qYUsMgLo5gK8x+rGSqgF5NQmK84c= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date; bh=YbYc9Wb8hOpiGkV8KRi+RzCLZEcBuGY8tuloAubI/yo=; b=NWx2YgQFHtXJWNHgrrIvCDPC+LL8ddrZ20riIuwKmOvOnM8AR9WCc60NucXvpHDRnx C844vVuBBAfY1HdkcGP5KpB80u37MGmO6Agdvk+IJIsRDWZIU5E4FSZJVzbD2kLnb5Ua +opOMfchA+mYiUET/HgSz2u9IrrZbHkjdv/ZH1+ZhB5ZsD7R2y6kRavFGUxsbMzT3okY 0W0t9VWp/kb7xBOrEkb3QCDVOzz8jXkkDqPoA2KRXNjFBApy8FqR3+w/4xMrVwBdaEok /qPoyihKMYVBNhsBUOUR/NhdDrzLBPHM0w45AxBhswRqzQ0BnQfY+zKqgx41SjqG8lpD SPrQ== X-Gm-Message-State: ACrzQf0GTt5AlDMZfj2AEYSiLu/8/g4ATaJSUXc5AnZHoHpfKWW0DBjd OXVZOaZlbPxlo/wuf4pXHvQQyMGPc/Ev5kKmenY= X-Google-Smtp-Source: AMsMyM5O5w2hZz9fNfq/AAOhgrUdclGfgEsIXdtv6p5xgtyrAQAwuPagdmmDKF1cnnI7e2olQHYxJQ== X-Received: by 2002:a05:620a:24cf:b0:6ce:7d6a:9c85 with SMTP id m15-20020a05620a24cf00b006ce7d6a9c85mr8125458qkn.271.1664585549150; Fri, 30 Sep 2022 17:52:29 -0700 (PDT) Received: from localhost.localdomain ([185.193.125.71]) by smtp.gmail.com with ESMTPSA id r10-20020a05622a034a00b0035ce8965045sm3224817qtw.42.2022.09.30.17.52.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 30 Sep 2022 17:52:28 -0700 (PDT) From: Matt Ranostay To: jic23@kernel.org, gupt21@gmail.com, benjamin.tissoires@redhat.com, jikos@kernel.org Cc: linux-iio@vger.kernel.org, linux-input@vger.kernel.org, Matt Ranostay Subject: [PATCH v6 1/3] HID: mcp2221: switch i2c registration to devm functions Date: Fri, 30 Sep 2022 17:52:06 -0700 Message-Id: <20221001005208.8010-2-matt.ranostay@konsulko.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221001005208.8010-1-matt.ranostay@konsulko.com> References: <20221001005208.8010-1-matt.ranostay@konsulko.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Switch from i2c_add_adapter() to resource managed devm_i2c_add_adapter() for matching rest of driver initialization, and more concise code. Signed-off-by: Matt Ranostay --- drivers/hid/hid-mcp2221.c | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index de52e9f7bb8c..4d10a24e3e13 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -824,6 +824,20 @@ static int mcp2221_raw_event(struct hid_device *hdev, return 1; } +/* Device resource managed function for HID unregistration */ +static void mcp2221_hid_unregister(void *ptr) +{ + struct hid_device *hdev = ptr; + + hid_hw_close(hdev); + hid_hw_stop(hdev); +} + +/* This is needed to be sure hid_hw_stop() isn't called twice by the subsystem */ +static void mcp2221_remove(struct hid_device *hdev) +{ +} + static int mcp2221_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -849,7 +863,8 @@ static int mcp2221_probe(struct hid_device *hdev, ret = hid_hw_open(hdev); if (ret) { hid_err(hdev, "can't open device\n"); - goto err_hstop; + hid_hw_stop(hdev); + return ret; } mutex_init(&mcp->lock); @@ -857,6 +872,10 @@ static int mcp2221_probe(struct hid_device *hdev, hid_set_drvdata(hdev, mcp); mcp->hdev = hdev; + ret = devm_add_action_or_reset(&hdev->dev, mcp2221_hid_unregister, hdev); + if (ret) + return ret; + /* Set I2C bus clock diviser */ if (i2c_clk_freq > 400) i2c_clk_freq = 400; @@ -873,19 +892,17 @@ static int mcp2221_probe(struct hid_device *hdev, "MCP2221 usb-i2c bridge on hidraw%d", ((struct hidraw *)hdev->hidraw)->minor); - ret = i2c_add_adapter(&mcp->adapter); + ret = devm_i2c_add_adapter(&hdev->dev, &mcp->adapter); if (ret) { hid_err(hdev, "can't add usb-i2c adapter: %d\n", ret); - goto err_i2c; + return ret; } i2c_set_adapdata(&mcp->adapter, mcp); /* Setup GPIO chip */ mcp->gc = devm_kzalloc(&hdev->dev, sizeof(*mcp->gc), GFP_KERNEL); - if (!mcp->gc) { - ret = -ENOMEM; - goto err_gc; - } + if (!mcp->gc) + return -ENOMEM; mcp->gc->label = "mcp2221_gpio"; mcp->gc->direction_input = mcp_gpio_direction_input; @@ -900,26 +917,9 @@ static int mcp2221_probe(struct hid_device *hdev, ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp); if (ret) - goto err_gc; + return ret; return 0; - -err_gc: - i2c_del_adapter(&mcp->adapter); -err_i2c: - hid_hw_close(mcp->hdev); -err_hstop: - hid_hw_stop(mcp->hdev); - return ret; -} - -static void mcp2221_remove(struct hid_device *hdev) -{ - struct mcp2221 *mcp = hid_get_drvdata(hdev); - - i2c_del_adapter(&mcp->adapter); - hid_hw_close(mcp->hdev); - hid_hw_stop(mcp->hdev); } static const struct hid_device_id mcp2221_devices[] = { From patchwork Sat Oct 1 00:52:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Ranostay X-Patchwork-Id: 12996184 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 96942C4332F for ; Sat, 1 Oct 2022 00:52:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232696AbiJAAwf (ORCPT ); Fri, 30 Sep 2022 20:52:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53230 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230311AbiJAAwe (ORCPT ); Fri, 30 Sep 2022 20:52:34 -0400 Received: from mail-qt1-x82e.google.com (mail-qt1-x82e.google.com [IPv6:2607:f8b0:4864:20::82e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E7167156C15 for ; Fri, 30 Sep 2022 17:52:33 -0700 (PDT) Received: by mail-qt1-x82e.google.com with SMTP id gb14so3657989qtb.3 for ; Fri, 30 Sep 2022 17:52:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=konsulko.com; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date; bh=43gzEa2PJ7BwB8QNFJAKxtAPXq825c9gJhzxVtgpXYU=; b=gCL0o32ELkJnWqHRNTnsP6xIKkDAUr6r8ssfKQeZIThUxYB3urPC6CTLHqWDhMRfOG rti47f5kn/2jTKY4SRrtNz1jNVXaEfEp11rCEWWGro/c19syTjKGW4minl3AZ+XCW0+N d/cwCADQiRgXOwuGZkCxKkXk2ZIumLrTCK+rA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date; bh=43gzEa2PJ7BwB8QNFJAKxtAPXq825c9gJhzxVtgpXYU=; b=c0juGHh2Z69YeHp765cb611CwLRIFXNKU60P9zG30JQK9hd8i4faboFGZfeGrCdIlY Lp622DWZmeMaYBMV1G3fTGm9z7qEeJLtpRAUEuMaCSMwf36GENeezzFu6W7SJreq79H5 CQYd+31N+7E8/lgC/st/u0yhvZ/4ORz84BHKgR98V3AnOg82fSpPUlEHLAQdIFYyILlx mzaTcemVXMxzulFTiznzC0V2nNoImtH5QKhY6c4447DqHFD/XgTS/FgoT1uVTyDOCePR OPUAsr9wBVtra4U9WobsE+j3Fs+ZMi2IKJwbrwh16zpu2D6GpnXrbkmyusYlvIt481NU NRUQ== X-Gm-Message-State: ACrzQf2e6LpmrtewsNcSXDjoXHxrw1gd4/iB+K5W2oBrIH6Ad5s0Rzx9 YKN/vGzBHK2nbnZYUND7R0yZij0iZ2QpZmF2Iuw= X-Google-Smtp-Source: AMsMyM5wOUMSFzTFjMEkSPzbPyBHI15ta9wP8AM4Ym2l1rCQqx43ikewMl5EhIbgKpaHRdCDOpunZg== X-Received: by 2002:a05:622a:1390:b0:35d:1f0a:dd99 with SMTP id o16-20020a05622a139000b0035d1f0add99mr9371443qtk.403.1664585553133; Fri, 30 Sep 2022 17:52:33 -0700 (PDT) Received: from localhost.localdomain ([185.193.125.71]) by smtp.gmail.com with ESMTPSA id r10-20020a05622a034a00b0035ce8965045sm3224817qtw.42.2022.09.30.17.52.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 30 Sep 2022 17:52:32 -0700 (PDT) From: Matt Ranostay To: jic23@kernel.org, gupt21@gmail.com, benjamin.tissoires@redhat.com, jikos@kernel.org Cc: linux-iio@vger.kernel.org, linux-input@vger.kernel.org, Matt Ranostay Subject: [PATCH v6 2/3] HID: mcp2221: change 'select GPIOLIB' to imply Date: Fri, 30 Sep 2022 17:52:07 -0700 Message-Id: <20221001005208.8010-3-matt.ranostay@konsulko.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221001005208.8010-1-matt.ranostay@konsulko.com> References: <20221001005208.8010-1-matt.ranostay@konsulko.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org To avoid recursive dependencies on GPIOLIB when 'imply IIO' is requested with other drivers we should switch GPIOLIB to an imply. This isn't the most ideal solution but avoids modifiying the Kconfig for other drivers, and only requires a singular IS_REACHABLE(CONFIG_GPIOLIB) check. Signed-off-by: Matt Ranostay --- drivers/hid/Kconfig | 2 +- drivers/hid/hid-mcp2221.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 185a077d59cd..745fc38794ad 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1252,7 +1252,7 @@ config HID_ALPS config HID_MCP2221 tristate "Microchip MCP2221 HID USB-to-I2C/SMbus host support" depends on USB_HID && I2C - depends on GPIOLIB + imply GPIOLIB help Provides I2C and SMBUS host adapter functionality over USB-HID through MCP2221 device. diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index 4d10a24e3e13..fb54f1c6fd9c 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -915,9 +915,11 @@ static int mcp2221_probe(struct hid_device *hdev, mcp->gc->can_sleep = 1; mcp->gc->parent = &hdev->dev; +#if IS_REACHABLE(CONFIG_GPIOLIB) ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp); if (ret) return ret; +#endif return 0; } From patchwork Sat Oct 1 00:52:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Ranostay X-Patchwork-Id: 12996185 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9741CC4332F for ; Sat, 1 Oct 2022 00:52:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232538AbiJAAwk (ORCPT ); Fri, 30 Sep 2022 20:52:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53254 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230450AbiJAAwj (ORCPT ); Fri, 30 Sep 2022 20:52:39 -0400 Received: from mail-qt1-x831.google.com (mail-qt1-x831.google.com [IPv6:2607:f8b0:4864:20::831]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 71A93157B9E for ; Fri, 30 Sep 2022 17:52:38 -0700 (PDT) Received: by mail-qt1-x831.google.com with SMTP id a20so3649022qtw.10 for ; Fri, 30 Sep 2022 17:52:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=konsulko.com; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date; bh=yNhCyplIk7hFF6L+RQG60LJiofe2O5/nfA2qcsGAJqg=; b=FC8QmrfagLfPRpHm1HJz36o/k9mLeEP46i0GsyVeqIDMtBtRWlndnKqM9nbOAZ9hPW 7VGohjyZs1s7Sn8rrgQqjd59kbQJMC9aQLYpCuLh7J/eepXMSqiTZX1KGxGobwa/UfzJ hTChBohSQyXwKixdjbm8Fr0mezfY4tiVHY7v4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date; bh=yNhCyplIk7hFF6L+RQG60LJiofe2O5/nfA2qcsGAJqg=; b=OtZSZKqmrsE3/W2Nkjl8gNXzS9JfJc8RAGCKZ6X3Q62xdiJwestQ0IIF1H3crcKwL/ 97RUCnvomXkpuMN40iDnPyIJtQVpIXUGNM6gCMiSIjcmzfuwjznkd6oHP3u9zXgrFe3n dpTZZ6wH8KhehS091dinC6rFgpQTiGL0rBLhbzzbBX7byMd0gjiWnzmLMU/kLecePKGH OB2UzjpjITSmLOPT/xup9jH61meyHf29pZ1HUHIvRu1VUMrWJkUWAqg4nm8URDgBi1Br ZEZV0jS0t48UFI2qd+zAyEGnVp3PWT+F76qEajraP6KMcjC2PJnQmN9EoZ9Q3V/1XqCC dFsg== X-Gm-Message-State: ACrzQf1EzksqbWDynurXysajehIS8mdpPJUwbGoAgFzWc5m0caoB9bLW T01ZILl8o4tT0pS9FETdfTiStA== X-Google-Smtp-Source: AMsMyM7B5F6qNX3e3Fm2Sj5gQmNVRNVnam4t/DiEw/9BDbmh91su1xx4m0Zw/lz1E2QidzcHleFVOQ== X-Received: by 2002:ac8:5952:0:b0:35c:2f9b:3be5 with SMTP id 18-20020ac85952000000b0035c2f9b3be5mr9009219qtz.44.1664585557585; Fri, 30 Sep 2022 17:52:37 -0700 (PDT) Received: from localhost.localdomain ([185.193.125.71]) by smtp.gmail.com with ESMTPSA id r10-20020a05622a034a00b0035ce8965045sm3224817qtw.42.2022.09.30.17.52.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 30 Sep 2022 17:52:37 -0700 (PDT) From: Matt Ranostay To: jic23@kernel.org, gupt21@gmail.com, benjamin.tissoires@redhat.com, jikos@kernel.org Cc: linux-iio@vger.kernel.org, linux-input@vger.kernel.org, Matt Ranostay Subject: [PATCH v6 3/3] HID: mcp2221: add ADC/DAC support via iio subsystem Date: Fri, 30 Sep 2022 17:52:08 -0700 Message-Id: <20221001005208.8010-4-matt.ranostay@konsulko.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221001005208.8010-1-matt.ranostay@konsulko.com> References: <20221001005208.8010-1-matt.ranostay@konsulko.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Add support for 3x 10-bit ADC and 1x DAC channels registered via the iio subsystem. To prevent breakage and unexpected dependencies this support only is only built if CONFIG_IIO is enabled, and is only weakly referenced by 'imply IIO' within the respective Kconfig. Additionally the iio device only gets registered if at least one channel is enabled in the power-on configuration read from SRAM. Signed-off-by: Matt Ranostay Reviewed-by: Jonathan Cameron --- drivers/hid/Kconfig | 1 + drivers/hid/hid-mcp2221.c | 258 +++++++++++++++++++++++++++++++++++++- 2 files changed, 258 insertions(+), 1 deletion(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 745fc38794ad..17cce4c50e8d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1253,6 +1253,7 @@ config HID_MCP2221 tristate "Microchip MCP2221 HID USB-to-I2C/SMbus host support" depends on USB_HID && I2C imply GPIOLIB + imply IIO help Provides I2C and SMBUS host adapter functionality over USB-HID through MCP2221 device. diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index fb54f1c6fd9c..2b3c3a483300 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -10,12 +10,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "hid-ids.h" /* Commands codes in a raw output report */ @@ -30,6 +32,9 @@ enum { MCP2221_I2C_CANCEL = 0x10, MCP2221_GPIO_SET = 0x50, MCP2221_GPIO_GET = 0x51, + MCP2221_SET_SRAM_SETTINGS = 0x60, + MCP2221_GET_SRAM_SETTINGS = 0x61, + MCP2221_READ_FLASH_DATA = 0xb0, }; /* Response codes in a raw input report */ @@ -89,6 +94,7 @@ struct mcp2221 { struct i2c_adapter adapter; struct mutex lock; struct completion wait_in_report; + struct delayed_work init_work; u8 *rxbuf; u8 txbuf[64]; int rxbuf_idx; @@ -97,6 +103,18 @@ struct mcp2221 { struct gpio_chip *gc; u8 gp_idx; u8 gpio_dir; + u8 mode[4]; +#if IS_REACHABLE(CONFIG_IIO) + struct iio_chan_spec iio_channels[3]; + u16 adc_values[3]; + u8 adc_scale; + u8 dac_value; + u16 dac_scale; +#endif +}; + +struct mcp2221_iio { + struct mcp2221 *mcp; }; /* @@ -713,7 +731,7 @@ static int mcp_get_i2c_eng_state(struct mcp2221 *mcp, static int mcp2221_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { - u8 *buf; + u8 *buf, tmp; struct mcp2221 *mcp = hid_get_drvdata(hdev); switch (data[0]) { @@ -745,6 +763,9 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; } mcp->status = mcp_get_i2c_eng_state(mcp, data, 8); +#if IS_REACHABLE(CONFIG_IIO) + memcpy(&mcp->adc_values, &data[50], sizeof(mcp->adc_values)); +#endif break; default: mcp->status = -EIO; @@ -816,6 +837,66 @@ static int mcp2221_raw_event(struct hid_device *hdev, complete(&mcp->wait_in_report); break; + case MCP2221_SET_SRAM_SETTINGS: + switch (data[1]) { + case MCP2221_SUCCESS: + mcp->status = 0; + break; + default: + mcp->status = -EAGAIN; + } + complete(&mcp->wait_in_report); + break; + + case MCP2221_GET_SRAM_SETTINGS: + switch (data[1]) { + case MCP2221_SUCCESS: + memcpy(&mcp->mode, &data[22], 4); +#if IS_REACHABLE(CONFIG_IIO) + mcp->dac_value = data[6] & GENMASK(4, 0); +#endif + mcp->status = 0; + break; + default: + mcp->status = -EAGAIN; + } + complete(&mcp->wait_in_report); + break; + + case MCP2221_READ_FLASH_DATA: + switch (data[1]) { + case MCP2221_SUCCESS: + mcp->status = 0; + + /* Only handles CHIP SETTINGS subpage currently */ + if (mcp->txbuf[1] != 0) { + mcp->status = -EIO; + break; + } + +#if IS_REACHABLE(CONFIG_IIO) + /* DAC scale value */ + tmp = FIELD_GET(GENMASK(7, 6), data[6]); + if ((data[6] & BIT(5)) && tmp) + mcp->dac_scale = tmp + 4; + else + mcp->dac_scale = 5; + + /* ADC scale value */ + tmp = FIELD_GET(GENMASK(4, 3), data[7]); + if ((data[7] & BIT(2)) && tmp) + mcp->adc_scale = tmp - 1; + else + mcp->adc_scale = 0; +#endif + + break; + default: + mcp->status = -EAGAIN; + } + complete(&mcp->wait_in_report); + break; + default: mcp->status = -EIO; complete(&mcp->wait_in_report); @@ -838,6 +919,176 @@ static void mcp2221_remove(struct hid_device *hdev) { } +#if IS_REACHABLE(CONFIG_IIO) +static int mcp2221_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct mcp2221_iio *priv = iio_priv(indio_dev); + struct mcp2221 *mcp = priv->mcp; + int ret; + + if (mask == IIO_CHAN_INFO_SCALE) { + if (channel->output) + *val = 1 << mcp->dac_scale; + else + *val = 1 << mcp->adc_scale; + + return IIO_VAL_INT; + } + + mutex_lock(&mcp->lock); + + if (channel->output) { + *val = mcp->dac_value; + ret = IIO_VAL_INT; + } else { + /* Read ADC values */ + ret = mcp_chk_last_cmd_status(mcp); + + if (!ret) { + *val = le16_to_cpu(mcp->adc_values[channel->address]); + if (*val >= BIT(10)) + ret = -EINVAL; + else + ret = IIO_VAL_INT; + } + } + + mutex_unlock(&mcp->lock); + + return ret; +} + +static int mcp2221_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mcp2221_iio *priv = iio_priv(indio_dev); + struct mcp2221 *mcp = priv->mcp; + int ret; + + if (val < 0 || val >= BIT(5)) + return -EINVAL; + + mutex_lock(&mcp->lock); + + memset(mcp->txbuf, 0, 12); + mcp->txbuf[0] = MCP2221_SET_SRAM_SETTINGS; + mcp->txbuf[4] = BIT(7) | val; + + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 12); + if (!ret) + mcp->dac_value = val; + + mutex_unlock(&mcp->lock); + + return ret; +} + +static const struct iio_info mcp2221_info = { + .read_raw = &mcp2221_read_raw, + .write_raw = &mcp2221_write_raw, +}; + +static int mcp_iio_channels(struct mcp2221 *mcp) +{ + int idx, cnt = 0; + bool dac_created = false; + + /* GP0 doesn't have ADC/DAC alternative function */ + for (idx = 1; idx < MCP_NGPIO; idx++) { + struct iio_chan_spec *chan = &mcp->iio_channels[cnt]; + + switch (mcp->mode[idx]) { + case 2: + chan->address = idx - 1; + chan->channel = cnt++; + break; + case 3: + /* GP1 doesn't have DAC alternative function */ + if (idx == 1 || dac_created) + continue; + /* DAC1 and DAC2 outputs are connected to the same DAC */ + dac_created = true; + chan->output = 1; + cnt++; + break; + default: + continue; + }; + + chan->type = IIO_VOLTAGE; + chan->indexed = 1; + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + chan->scan_index = -1; + } + + return cnt; +} + +static void mcp_init_work(struct work_struct *work) +{ + struct iio_dev *indio_dev; + struct mcp2221 *mcp = container_of(work, struct mcp2221, init_work.work); + struct mcp2221_iio *data; + static int retries = 5; + int ret, num_channels; + + hid_hw_power(mcp->hdev, PM_HINT_FULLON); + mutex_lock(&mcp->lock); + + mcp->txbuf[0] = MCP2221_GET_SRAM_SETTINGS; + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); + + if (ret == -EAGAIN) + goto reschedule_task; + + num_channels = mcp_iio_channels(mcp); + if (!num_channels) + goto unlock; + + mcp->txbuf[0] = MCP2221_READ_FLASH_DATA; + mcp->txbuf[1] = 0; + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 2); + + if (ret == -EAGAIN) + goto reschedule_task; + + indio_dev = devm_iio_device_alloc(&mcp->hdev->dev, sizeof(*data)); + if (!indio_dev) + goto unlock; + + data = iio_priv(indio_dev); + data->mcp = mcp; + + indio_dev->name = "mcp2221"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mcp2221_info; + indio_dev->channels = mcp->iio_channels; + indio_dev->num_channels = num_channels; + + devm_iio_device_register(&mcp->hdev->dev, indio_dev); + +unlock: + mutex_unlock(&mcp->lock); + hid_hw_power(mcp->hdev, PM_HINT_NORMAL); + + return; + +reschedule_task: + mutex_unlock(&mcp->lock); + hid_hw_power(mcp->hdev, PM_HINT_NORMAL); + + if (!retries--) + return; + + /* Device is not ready to read SRAM or FLASH data, try again */ + schedule_delayed_work(&mcp->init_work, msecs_to_jiffies(100)); +} +#endif + static int mcp2221_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -921,6 +1172,11 @@ static int mcp2221_probe(struct hid_device *hdev, return ret; #endif +#if IS_REACHABLE(CONFIG_IIO) + INIT_DELAYED_WORK(&mcp->init_work, mcp_init_work); + schedule_delayed_work(&mcp->init_work, msecs_to_jiffies(100)); +#endif + return 0; }