From patchwork Thu Nov 22 03:52:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Ranostay X-Patchwork-Id: 10693461 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A7A2C16B1 for ; Thu, 22 Nov 2018 03:52:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 93C112CB58 for ; Thu, 22 Nov 2018 03:52:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9206E2CBE7; Thu, 22 Nov 2018 03:52:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 29B3D2CB58 for ; Thu, 22 Nov 2018 03:52:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731213AbeKVOaE (ORCPT ); Thu, 22 Nov 2018 09:30:04 -0500 Received: from mail-pl1-f196.google.com ([209.85.214.196]:34679 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730904AbeKVOaE (ORCPT ); Thu, 22 Nov 2018 09:30:04 -0500 Received: by mail-pl1-f196.google.com with SMTP id f12-v6so8423542plo.1 for ; Wed, 21 Nov 2018 19:52:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=konsulko.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ekzR+yHCCoQc9XKif9a/Xi5cUJgPOvS46llIcWaMrYU=; b=BqkCpdGIrkba6n4YkPcHqPdq5X7Z0LnwGVk6CPjFhpq1bArlh2zj4h7eBZ/qEjON11 nkWIpLNhkgrSxg0Z0M51wxFYbK3p6ByLCG8KpZAYS0CuuSvuNa1lSgy5owxIbX8s//7G rdZzqjC0DWKhY7zL1xrefi8/mOHgHx7gJot28= 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:in-reply-to :references; bh=ekzR+yHCCoQc9XKif9a/Xi5cUJgPOvS46llIcWaMrYU=; b=XzmEcx+7Tz1SPBX7LOgrNxgQxJFD54N7xwICZwWsQ7siF8AGnVNuT0jTZpR7zMUrYZ KkPHfAIRl7ILohXMwpkaePBxtEvPLP/TLSW0VcxmmOUEtEQr3vpeWT5FonvvxF1pTZds NPN0NYP5jI0yiMlaaP/+b/hY+lrLsWzWF6yOFRAWaRnWsenXSu/6Sk76u50sOAysCntq ztOksIA4Y8wwDKj+QfyahdTUwdtV9apdLCreJoAKuTW9suiffLVYKBkmqiXAh5PbTzhy /INs4M/9afKx6obs/wVrqcR7nWa7amaRdwrMzSmsfd2ImqNDm/Bt6vJel8WLXySGFjMU W9+A== X-Gm-Message-State: AA+aEWYK3NJXf6dOhvxO5sgopw4YtBP0WrGInMKL0Upd9qwa0D+DcRTF AdGFU+vQF2PqyAEJL+uKBgBNdqJTs8WPiQ== X-Google-Smtp-Source: AFSGD/XPlekH+87PxYL9orzIYY0BWWAym5OlBWSekYY/YS3ybt4mfzMW+Z3s6wSPa1550GHe/85ggg== X-Received: by 2002:a63:fd0a:: with SMTP id d10mr8684648pgh.164.1542858755483; Wed, 21 Nov 2018 19:52:35 -0800 (PST) Received: from virtualbox.hsd1.wa.comcast.net (c-67-171-239-254.hsd1.wa.comcast.net. [67.171.239.254]) by smtp.gmail.com with ESMTPSA id p5-v6sm58275500pfb.109.2018.11.21.19.52.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 Nov 2018 19:52:34 -0800 (PST) From: Matt Ranostay To: linux-media@vger.kernel.org Cc: Matt Ranostay Subject: [PATCH v2 1/2] media: video-i2c: check if chip struct has set_power function Date: Wed, 21 Nov 2018 19:52:28 -0800 Message-Id: <20181122035229.3630-2-matt.ranostay@konsulko.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181122035229.3630-1-matt.ranostay@konsulko.com> References: <20181122035229.3630-1-matt.ranostay@konsulko.com> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Not all future supported video chips will always have power management support, and so it is important to check before calling set_power() is defined. Signed-off-by: Matt Ranostay --- drivers/media/i2c/video-i2c.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 981166010c9b..a64e1a725a20 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -736,9 +736,11 @@ static int video_i2c_probe(struct i2c_client *client, video_set_drvdata(&data->vdev, data); i2c_set_clientdata(client, data); - ret = data->chip->set_power(data, true); - if (ret) - goto error_unregister_device; + if (data->chip->set_power) { + ret = data->chip->set_power(data, true); + if (ret) + goto error_unregister_device; + } pm_runtime_get_noresume(&client->dev); pm_runtime_set_active(&client->dev); @@ -767,7 +769,8 @@ static int video_i2c_probe(struct i2c_client *client, pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); pm_runtime_put_noidle(&client->dev); - data->chip->set_power(data, false); + if (data->chip->set_power) + data->chip->set_power(data, false); error_unregister_device: v4l2_device_unregister(v4l2_dev); @@ -791,7 +794,9 @@ static int video_i2c_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); pm_runtime_put_noidle(&client->dev); - data->chip->set_power(data, false); + + if (data->chip->set_power) + data->chip->set_power(data, false); video_unregister_device(&data->vdev); @@ -804,6 +809,9 @@ static int video_i2c_pm_runtime_suspend(struct device *dev) { struct video_i2c_data *data = i2c_get_clientdata(to_i2c_client(dev)); + if (!data->chip->set_power) + return 0; + return data->chip->set_power(data, false); } @@ -811,6 +819,9 @@ static int video_i2c_pm_runtime_resume(struct device *dev) { struct video_i2c_data *data = i2c_get_clientdata(to_i2c_client(dev)); + if (!data->chip->set_power) + return 0; + return data->chip->set_power(data, true); } From patchwork Thu Nov 22 03:52:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Ranostay X-Patchwork-Id: 10693463 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 29BA41926 for ; Thu, 22 Nov 2018 03:52:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 184882CBD1 for ; Thu, 22 Nov 2018 03:52:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0C0E22CBD2; Thu, 22 Nov 2018 03:52:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4ACA92CBEC for ; Thu, 22 Nov 2018 03:52:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731494AbeKVOaF (ORCPT ); Thu, 22 Nov 2018 09:30:05 -0500 Received: from mail-pl1-f196.google.com ([209.85.214.196]:40731 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731268AbeKVOaF (ORCPT ); Thu, 22 Nov 2018 09:30:05 -0500 Received: by mail-pl1-f196.google.com with SMTP id b22-v6so8414391pls.7 for ; Wed, 21 Nov 2018 19:52:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=konsulko.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=qipMAmHkL0SE+o5nQQrbD9J3e1og4Ny+iN7qBjaDvzk=; b=rwMfcj9O/kuSkP2G/PINXAhiq4QGruhJqneQZ8WvT8Mj0+5l/DOUpwMegfmk5MVWHu p/r6FgyTx3hR0qkXA/LfveH2+6Pj9ywlgVTlVGqq/xQVglQDViSmv0NptGFmdLPH6yy6 Gno3m0gBHt5nQVyxSaIVyXYsSBsEvYPv6GZfo= 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:in-reply-to :references; bh=qipMAmHkL0SE+o5nQQrbD9J3e1og4Ny+iN7qBjaDvzk=; b=kuyX85HqRbCt6b0S3RQtPiqLrPZTrgOoNV41i+Y8jE36gpP+kaRhblXZfMV4+BTz5B 5f0auYiPCNJssWNL0ew1Bvr9Ctwq6/l54ksuNhQv+VxnHNER3pbKoeUliedPC8KFkKo5 KpivnPF2SBNe9lf/Df0S+W0ukOgwZcdLxwIo2E7/4lWTWLrJRyFedvbNx8UphpvkWjJp Q6IvhrGaqwS8wmUoJxRaOvo0BMMyi+y2nEkj8rlEzezpr9eJUg9bdm0TdeyhvHj3KEQm UFYtBu4jKzoDd8xMAoqd0S+2gQEQcdBba1zkjkL88vwmhLr1BBLjbu3ipivm0asEJShz zOwQ== X-Gm-Message-State: AA+aEWahMMotnbFEWApuiTqcWyH3kjltuWZOnUGxChlCSw6Ohufq71p2 JsOqzqxpaj4Y7ljw6B8miLRmfVfl/sMWpg== X-Google-Smtp-Source: AFSGD/WSbBG5O5YhoxRgGCqOsCvvZr1mjyfocUWippZUcImoQnbEuxK13c1PzERN0JgajRHO5O3xRw== X-Received: by 2002:a63:f65:: with SMTP id 37mr8428126pgp.238.1542858756364; Wed, 21 Nov 2018 19:52:36 -0800 (PST) Received: from virtualbox.hsd1.wa.comcast.net (c-67-171-239-254.hsd1.wa.comcast.net. [67.171.239.254]) by smtp.gmail.com with ESMTPSA id p5-v6sm58275500pfb.109.2018.11.21.19.52.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 Nov 2018 19:52:35 -0800 (PST) From: Matt Ranostay To: linux-media@vger.kernel.org Cc: Matt Ranostay , devicetree@vger.kernel.org Subject: [PATCH v2 2/2] media: video-i2c: add Melexis MLX90640 thermal camera support Date: Wed, 21 Nov 2018 19:52:29 -0800 Message-Id: <20181122035229.3630-3-matt.ranostay@konsulko.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181122035229.3630-1-matt.ranostay@konsulko.com> References: <20181122035229.3630-1-matt.ranostay@konsulko.com> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add initial support for MLX90640 thermal cameras which output an 32x24 greyscale pixel image along with 2 rows of coefficent data. Because of this the data outputed is really 32x26 and needs the two rows removed after using the coefficent information to generate processed images in userspace. Cc: devicetree@vger.kernel.org Signed-off-by: Matt Ranostay --- .../bindings/media/i2c/melexis,mlx90640.txt | 20 ++++ drivers/media/i2c/Kconfig | 1 + drivers/media/i2c/video-i2c.c | 110 +++++++++++++++++- 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/media/i2c/melexis,mlx90640.txt diff --git a/Documentation/devicetree/bindings/media/i2c/melexis,mlx90640.txt b/Documentation/devicetree/bindings/media/i2c/melexis,mlx90640.txt new file mode 100644 index 000000000000..060d2b7a5893 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/melexis,mlx90640.txt @@ -0,0 +1,20 @@ +* Melexis MLX90640 FIR Sensor + +Melexis MLX90640 FIR sensor support which allows recording of thermal data +with 32x24 resolution excluding 2 lines of coefficient data that is used by +userspace to render processed frames. + +Required Properties: + - compatible : Must be "melexis,mlx90640" + - reg : i2c address of the device + +Example: + + i2c0@1c22000 { + ... + mlx90640@33 { + compatible = "melexis,mlx90640"; + reg = <0x33>; + }; + ... + }; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 66bbbec487ec..24342f283f2a 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1097,6 +1097,7 @@ config VIDEO_I2C Enable the I2C transport video support which supports the following: * Panasonic AMG88xx Grid-Eye Sensors + * Melexis MLX90640 Thermal Cameras To compile this driver as a module, choose M here: the module will be called video-i2c diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index a64e1a725a20..d58f40334e8b 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -6,6 +6,7 @@ * * Supported: * - Panasonic AMG88xx Grid-Eye Sensors + * - Melexis MLX90640 Thermal Cameras */ #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -66,12 +68,26 @@ static const struct v4l2_frmsize_discrete amg88xx_size = { .height = 8, }; +static const struct v4l2_fmtdesc mlx90640_format = { + .pixelformat = V4L2_PIX_FMT_Y16_BE, +}; + +static const struct v4l2_frmsize_discrete mlx90640_size = { + .width = 32, + .height = 26, /* 24 lines of pixel data + 2 lines of processing data */ +}; + static const struct regmap_config amg88xx_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0xff }; +static const struct regmap_config mlx90640_regmap_config = { + .reg_bits = 16, + .val_bits = 16, +}; + struct video_i2c_chip { /* video dimensions */ const struct v4l2_fmtdesc *format; @@ -88,6 +104,7 @@ struct video_i2c_chip { unsigned int bpp; const struct regmap_config *regmap_config; + struct nvmem_config *nvmem_config; /* setup function */ int (*setup)(struct video_i2c_data *data); @@ -102,6 +119,22 @@ struct video_i2c_chip { int (*hwmon_init)(struct video_i2c_data *data); }; +static int mlx90640_nvram_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct video_i2c_data *data = priv; + + return regmap_bulk_read(data->regmap, 0x2400 + offset, val, bytes); +} + +static struct nvmem_config mlx90640_nvram_config = { + .name = "mlx90640_nvram", + .word_size = 2, + .stride = 1, + .size = 1664, + .reg_read = mlx90640_nvram_read, +}; + /* Power control register */ #define AMG88XX_REG_PCTL 0x00 #define AMG88XX_PCTL_NORMAL 0x00 @@ -122,12 +155,23 @@ struct video_i2c_chip { /* Temperature register */ #define AMG88XX_REG_T01L 0x80 +/* Control register */ +#define MLX90640_REG_CTL1 0x800d +#define MLX90640_REG_CTL1_MASK 0x0380 +#define MLX90640_REG_CTL1_MASK_SHIFT 7 + static int amg88xx_xfer(struct video_i2c_data *data, char *buf) { return regmap_bulk_read(data->regmap, AMG88XX_REG_T01L, buf, data->chip->buffer_size); } +static int mlx90640_xfer(struct video_i2c_data *data, char *buf) +{ + return regmap_bulk_read(data->regmap, 0x400, buf, + data->chip->buffer_size); +} + static int amg88xx_setup(struct video_i2c_data *data) { unsigned int mask = AMG88XX_FPSC_1FPS; @@ -141,6 +185,27 @@ static int amg88xx_setup(struct video_i2c_data *data) return regmap_update_bits(data->regmap, AMG88XX_REG_FPSC, mask, val); } +static int mlx90640_setup(struct video_i2c_data *data) +{ + unsigned int n, idx; + + for (n = 0; n < data->chip->num_frame_intervals - 1; n++) { + if (data->frame_interval.numerator + != data->chip->frame_intervals[n].numerator) + continue; + + if (data->frame_interval.denominator + == data->chip->frame_intervals[n].denominator) + break; + } + + idx = data->chip->num_frame_intervals - n - 1; + + return regmap_update_bits(data->regmap, MLX90640_REG_CTL1, + MLX90640_REG_CTL1_MASK, + idx << MLX90640_REG_CTL1_MASK_SHIFT); +} + static int amg88xx_set_power_on(struct video_i2c_data *data) { int ret; @@ -274,13 +339,27 @@ static int amg88xx_hwmon_init(struct video_i2c_data *data) #define amg88xx_hwmon_init NULL #endif -#define AMG88XX 0 +enum { + AMG88XX, + MLX90640, +}; static const struct v4l2_fract amg88xx_frame_intervals[] = { { 1, 10 }, { 1, 1 }, }; +static const struct v4l2_fract mlx90640_frame_intervals[] = { + { 1, 64 }, + { 1, 32 }, + { 1, 16 }, + { 1, 8 }, + { 1, 4 }, + { 1, 2 }, + { 1, 1 }, + { 2, 1 }, +}; + static const struct video_i2c_chip video_i2c_chip[] = { [AMG88XX] = { .size = &amg88xx_size, @@ -295,6 +374,18 @@ static const struct video_i2c_chip video_i2c_chip[] = { .set_power = amg88xx_set_power, .hwmon_init = amg88xx_hwmon_init, }, + [MLX90640] = { + .size = &mlx90640_size, + .format = &mlx90640_format, + .frame_intervals = mlx90640_frame_intervals, + .num_frame_intervals = ARRAY_SIZE(mlx90640_frame_intervals), + .buffer_size = 1664, + .bpp = 16, + .regmap_config = &mlx90640_regmap_config, + .nvmem_config = &mlx90640_nvram_config, + .setup = mlx90640_setup, + .xfer = mlx90640_xfer, + }, }; static const struct v4l2_file_operations video_i2c_fops = { @@ -756,6 +847,21 @@ static int video_i2c_probe(struct i2c_client *client, } } + if (data->chip->nvmem_config) { + struct nvmem_config *config = data->chip->nvmem_config; + struct nvmem_device *device; + + config->priv = data; + config->dev = &client->dev; + + device = devm_nvmem_register(&client->dev, config); + + if (IS_ERR(device)) { + dev_warn(&client->dev, + "failed to register nvmem device\n"); + } + } + ret = video_register_device(&data->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) goto error_pm_disable; @@ -834,12 +940,14 @@ static const struct dev_pm_ops video_i2c_pm_ops = { static const struct i2c_device_id video_i2c_id_table[] = { { "amg88xx", AMG88XX }, + { "mlx90640", MLX90640 }, {} }; MODULE_DEVICE_TABLE(i2c, video_i2c_id_table); static const struct of_device_id video_i2c_of_match[] = { { .compatible = "panasonic,amg88xx", .data = &video_i2c_chip[AMG88XX] }, + { .compatible = "melexis,mlx90640", .data = &video_i2c_chip[MLX90640] }, {} }; MODULE_DEVICE_TABLE(of, video_i2c_of_match);