From patchwork Wed Jan 4 11:36:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Hepp X-Patchwork-Id: 13088502 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 613B6C46467 for ; Wed, 4 Jan 2023 11:42:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239005AbjADLmJ (ORCPT ); Wed, 4 Jan 2023 06:42:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55524 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239171AbjADLmI (ORCPT ); Wed, 4 Jan 2023 06:42:08 -0500 X-Greylist: delayed 304 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Wed, 04 Jan 2023 03:42:06 PST Received: from mail-108-mta71.mxroute.com (mail-108-mta71.mxroute.com [136.175.108.71]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4719E11477 for ; Wed, 4 Jan 2023 03:42:06 -0800 (PST) Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta71.mxroute.com (ZoneMTA) with ESMTPSA id 1857c91f54e000011e.002 for (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Wed, 04 Jan 2023 11:36:58 +0000 X-Zone-Loop: 7c63159ec0fb3fe48e5d385939369886259ade97826e X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=ahepp.dev; s=x; h=Content-Transfer-Encoding:MIME-Version:Message-Id:Date:Subject:Cc:To: From:Sender:Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post: List-Owner:List-Archive; bh=Avh2booVCUAW082VuflGNAAEehokiRWjcXIyunJx9tw=; b=Z kSp4lI5UchLgxLhKqCfF4tA+iRY3JNvJr/D2LeqDT+M1ti5VcCKkeAePyNG93i7UIF1Va+mNau7BJ zb5xroCQFTrD4mQuPHUddtOxmB9hHF6DROGBiFstrqmYpoY00sefXjaY1i+88xgV3TqstxZtO39R1 DhX7WyUHGd3rP6Bw/C6EKPNYh0X6baAjThAFHQE+xMZR/DA3pEeCTU+UaugoPUjMD6gNcp24IocAi Yyvra3K+Xnk4x0C8mgEb7xm9YNMTd4stfp1Ib4PLug8YAzOofv90v+moioFimXUskyPRWPUNxjgEU /W71H4Nav47GcSVya03XWs2Si8pYndGHQ==; From: Andrew Hepp To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Jonathan Cameron Cc: "Andrew.Hepp" Subject: [PATCH] iio: temperature: Add MCP9600 thermocouple EMF converter driver Date: Wed, 4 Jan 2023 03:36:12 -0800 Message-Id: <20230104113612.4732-1-andrew.hepp@ahepp.dev> MIME-Version: 1.0 X-Authenticated-Id: andrew.hepp@ahepp.dev Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org From: "Andrew.Hepp" Add support for the MCP9600 thermocouple EMF converter. Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/MCP960X-Data-Sheet-20005426.pdf Signed-off-by: Andrew Hepp --- drivers/iio/temperature/Kconfig | 10 ++ drivers/iio/temperature/Makefile | 1 + drivers/iio/temperature/mcp9600.c | 174 ++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 drivers/iio/temperature/mcp9600.c diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig index ed384f33e0c7..ea2ce364b2e9 100644 --- a/drivers/iio/temperature/Kconfig +++ b/drivers/iio/temperature/Kconfig @@ -158,4 +158,14 @@ config MAX31865 This driver can also be build as a module. If so, the module will be called max31865. +config MCP9600 + tristate "MCP9600 thermocouple EMF converter" + depends on I2C + help + If you say yes here you get support for MCP9600 + thermocouple EMF converter connected via I2C. + + This driver can also be built as a module. If so, the module + will be called mcp9600. + endmenu diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile index dfec8c6d3019..9330d4a39598 100644 --- a/drivers/iio/temperature/Makefile +++ b/drivers/iio/temperature/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o obj-$(CONFIG_MAX30208) += max30208.o obj-$(CONFIG_MAX31856) += max31856.o obj-$(CONFIG_MAX31865) += max31865.o +obj-$(CONFIG_MCP9600) += mcp9600.o obj-$(CONFIG_MLX90614) += mlx90614.o obj-$(CONFIG_MLX90632) += mlx90632.o obj-$(CONFIG_TMP006) += tmp006.o diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c new file mode 100644 index 000000000000..2c1c4bb5e1c3 --- /dev/null +++ b/drivers/iio/temperature/mcp9600.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * mcp9600.c - Support for Microchip MCP9600 thermocouple EMF converter + * + * Copyright (c) 2022 Andrew Hepp + * Author: + */ + +#include +#include +#include +#include +#include + +#include +#include + +/* MCP9600 registers */ +#define MCP9600_HOT_JUNCTION 0x0 +#define MCP9600_COLD_JUNCTION 0x2 +#define MCP9600_DEVICE_ID 0x20 + +/* MCP9600 device id value */ +#define MCP9600_DEVICE_ID_MCP9600 0x40 + +static const struct iio_chan_spec mcp9600_channels[] = { + { + .type = IIO_TEMP, + .address = MCP9600_HOT_JUNCTION, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .shift = 0, + .endianness = IIO_BE, + }, + }, + { + .type = IIO_TEMP, + .address = MCP9600_COLD_JUNCTION, + .channel2 = IIO_MOD_TEMP_AMBIENT, + .modified = 1, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 13, + .storagebits = 16, + .shift = 0, + .endianness = IIO_BE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + +struct mcp9600_data { + struct i2c_client *client; +}; + +static int mcp9600_read(struct mcp9600_data *data, + struct iio_chan_spec const *chan, int *val) +{ + __be16 buf; + int ret; + + ret = i2c_smbus_read_i2c_block_data(data->client, chan->address, 2, + (u8 *)&buf); + if (ret < 0) + return ret; + *val = be16_to_cpu(buf); + + return 0; +} + +static int mcp9600_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct mcp9600_data *data = iio_priv(indio_dev); + int ret = -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = mcp9600_read(data, chan, val); + iio_device_release_direct_mode(indio_dev); + if (!ret) + return IIO_VAL_INT; + + break; + case IIO_CHAN_INFO_SCALE: + *val = 62; + *val2 = 500000; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + } + + return ret; +} + +static const struct iio_info mcp9600_info = { + .read_raw = mcp9600_read_raw, +}; + +static int mcp9600_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct mcp9600_data *data; + int ret; + + ret = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID); + if (ret < 0) + return ret; + if (ret != MCP9600_DEVICE_ID_MCP9600) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + + i2c_set_clientdata(client, indio_dev); + indio_dev->info = &mcp9600_info; + indio_dev->name = "mcp9600"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mcp9600_channels; + indio_dev->num_channels = ARRAY_SIZE(mcp9600_channels); + + return iio_device_register(indio_dev); +} + +static int mcp9600_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + printk(KERN_ALERT "mcp9600_remove\n"); + + indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + return 0; +} + +static const struct i2c_device_id mcp9600_id[] = { { "mcp9600" }, {} }; +MODULE_DEVICE_TABLE(i2c, mcp9600_id); + +static const struct of_device_id mcp9600_of_match[] = { + { .compatible = "microchip,mcp9600" }, + {} +}; +MODULE_DEVICE_TABLE(of, mcp9600_of_match); + +static struct i2c_driver mcp9600_driver = { + .driver = { + .name = "mcp9600", + .of_match_table = mcp9600_of_match, + }, + .probe_new = mcp9600_probe, + .remove = mcp9600_remove, + .id_table = mcp9600_id +}; +module_i2c_driver(mcp9600_driver); + +MODULE_AUTHOR("Andrew Hepp "); +MODULE_DESCRIPTION("Microchip MCP9600 thermocouple EMF converter driver"); +MODULE_LICENSE("GPL");