Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp8775800imu; Tue, 4 Dec 2018 14:03:44 -0800 (PST) X-Google-Smtp-Source: AFSGD/W6wkG2V1VrhgThTUwWx31lHSGcm+yZF+JDejqznGv1GajPQRLXdnZ90d6Wz9u2Y44B09QP X-Received: by 2002:a17:902:1101:: with SMTP id d1mr16264523pla.136.1543961023978; Tue, 04 Dec 2018 14:03:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1543961023; cv=none; d=google.com; s=arc-20160816; b=NBFaUGuZlxIhBE+CobUebHLVpie2NcG3VpLD2sabYGu1fBhDW8XlFnevzfPTHYrh8r roP2CmZVLVHXBghvNn4uphYQtj+EpT5CagzKk7+O3wF3trMREQOfdvkABYaqooVTJc9c LJVvLPHF7rDk1TBzX3zg7RbDEgJZMnkP3GlHQHKQql4TB8SFYJ8xK2G8vTvHHeXOQhwY +Z7djYTWnrBeiUgMLTL5eoJi4xZns/qHzvd/JpZST8zh5jmq8NeAMxOlxdLAR8PfwHCI db/ZAcvS6YJit2gFccnUzAjEIaRJu/m4NBZatwtxBdeauNjZKo3kvEfp6lACJvw0k8QD b29Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature; bh=XkpJZ0fqHegd6aAxNdHnttBFt+tY0XQp8B5oQ8AYuuM=; b=EDqGGKtk2TEXmo1vua7ESz9ty8lxG0aUbXOwy3Qiiar4G/tV0/4pZlUfJYpq8J2T0R QEvCDQxMUgmF2thfa8Ky0tzMxy5VKOJqY13lQemrF+JSlxpJtwjU4C+yraGcdsOnQSV6 ATwcBt7jEYJ74HfmXM2L/2KqA9MueSGrJTydZiUPtfnxNRs/Xmp75LM9Zlc0IXJ3aDYi 0R2FHcQ0sBxiimKxA3rUuAU8jqgviDTe8Uz9YQOeMjA9/GbztWPHbulfYMPEIorZWRRm 90O+jC6qx2GttH5gDRQpks5xbM2bFM/w7bvu8tPsvsQK7Xl4k8qRpE5BWnx/Ri9Li4fY MnGQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=mGC+UPCp; 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; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s123si18870690pfb.274.2018.12.04.14.03.28; Tue, 04 Dec 2018 14:03:43 -0800 (PST) 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; dkim=pass header.i=@gmail.com header.s=20161025 header.b=mGC+UPCp; 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; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726617AbeLDWCq (ORCPT + 99 others); Tue, 4 Dec 2018 17:02:46 -0500 Received: from mail-io1-f68.google.com ([209.85.166.68]:41257 "EHLO mail-io1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726519AbeLDWCi (ORCPT ); Tue, 4 Dec 2018 17:02:38 -0500 Received: by mail-io1-f68.google.com with SMTP id s22so14974969ioc.8; Tue, 04 Dec 2018 14:02:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=XkpJZ0fqHegd6aAxNdHnttBFt+tY0XQp8B5oQ8AYuuM=; b=mGC+UPCpMFDcm1BqGnJ08MZFepHIFRy5x08Isj1QItUBRUfSehBN4t8ZItMqPL0KTX EknXM9u7GKoQWZH3lFgrT/HMORnhvdClbX802nkRjnhZ1u6sDgCKENuZGfZfg1fGRxV4 h3ZBAuBpcCg/sgIEPV3d03JRmVymOt7JHSvMr5xdRTrl4ZcG2InQVYE5/kR/DJdf3jD8 qQXtnRcwhyhRAoLhRRNpnkY/RZiSljWu5ewOZlTSq7xX1cT2PKP+FoRvxB1g+KLDhb2k GoeSLeJIm05TYcepIIhc8ZQQJk7Bym2E8bK6ISV3W+Gs/G3FCF5s1HHqnwFzEAxVA1WW LzXA== 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=XkpJZ0fqHegd6aAxNdHnttBFt+tY0XQp8B5oQ8AYuuM=; b=MNhTRo8NGbnZhVGincdGylgxhyF9PSWgG9bjJS3n3D/zv/wTmNFWANoBQW7IiBfRvO YYveJmNzcOt6VZVf/iM3ns6/EAXxAZhf2AXSyxku/zeq070DgzdqJF5KdpnpYEaBURpE UwaKilTBj9m20WDqUB0KVMRgCJIa3bsDI6uNOVqhABjydfmppnJB1K/sxRF/t8mKncd1 YE+yPn9ET46OX6SkMSzWa12rNaY3zOXArRsRrud8bS35IOLudPRqaCdN2DZezhpB5SUv Qgr4kza8fabjtgn7WnsAF6sAB+jWixPf8Ufc1ChP1bcQxcgWlHzkwkHRlt46x+UCcwsA wL8A== X-Gm-Message-State: AA+aEWbnfVcttvrLVKvQ8lwpRfd0Lcoz4IeaE80dNg/b5PgObABUfFhT ks0vjZI8G5dh3NXLELrRTSQ= X-Received: by 2002:a6b:490f:: with SMTP id u15mr18448817iob.297.1543960956860; Tue, 04 Dec 2018 14:02:36 -0800 (PST) Received: from svens-asus.arcx.com ([184.94.50.30]) by smtp.gmail.com with ESMTPSA id m2sm4962544iol.75.2018.12.04.14.02.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 04 Dec 2018 14:02:36 -0800 (PST) From: Sven Van Asbroeck X-Google-Original-From: Sven Van Asbroeck To: svendev@arcx.com, robh+dt@kernel.org, linus.walleij@linaro.org Cc: lee.jones@linaro.org, mark.rutland@arm.com, afaerber@suse.de, treding@nvidia.com, david@lechnology.com, noralf@tronnes.org, johan@kernel.org, monstr@monstr.eu, michal.vokac@ysoft.com, arnd@arndb.de, gregkh@linuxfoundation.org, john.garry@huawei.com, geert+renesas@glider.be, robin.murphy@arm.com, paul.gortmaker@windriver.com, sebastien.bourdelin@savoirfairelinux.com, icenowy@aosc.io, stuyoder@gmail.com, maxime.ripard@bootlin.com, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH v5 6/6] fieldbus_dev: support HMS Profinet IRT industrial controller Date: Tue, 4 Dec 2018 17:02:24 -0500 Message-Id: <20181204220224.27324-7-TheSven73@googlemail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181204220224.27324-1-TheSven73@googlemail.com> References: <20181204220224.27324-1-TheSven73@googlemail.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The Anybus-S PROFINET IRT communication module provides instant integration to any Ethernet based LAN via SMTP, FTP, HTTP as well as PROFINET and Modbus-TCP. Additional protocols can be implemented on top of TCP/IP or UDP using the transparent socket interface. Official documentation: https://www.anybus.com/docs/librariesprovider7/default-document-library /manuals-design-guides/hms-hmsi-168-52.pdf This implementation is an Anybus-S client driver, designed to be instantiated by the Anybus-S bus driver when it discovers the Profinet card. If loaded successfully, the driver registers itself as a fieldbus_dev, and userspace can access it through the fieldbus_dev interface. Signed-off-by: Sven Van Asbroeck --- drivers/fieldbus/anybuss/Kconfig | 16 ++ drivers/fieldbus/anybuss/Makefile | 1 + drivers/fieldbus/anybuss/hms-profinet.c | 223 ++++++++++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 drivers/fieldbus/anybuss/hms-profinet.c diff --git a/drivers/fieldbus/anybuss/Kconfig b/drivers/fieldbus/anybuss/Kconfig index 7e563a78be13..1d0e7516b18e 100644 --- a/drivers/fieldbus/anybuss/Kconfig +++ b/drivers/fieldbus/anybuss/Kconfig @@ -20,4 +20,20 @@ config ARCX_ANYBUS_CONTROLLER There is also a CAN power readout, unrelated to the Anybus, modelled as a regulator. +config HMS_PROFINET + tristate "HMS Profinet IRT Controller (Anybus-S)" + depends on FIELDBUS_DEV && HMS_ANYBUSS_BUS + help + If you say yes here you get support for the HMS Industrial + Networks Profinet IRT Controller. + + It will be registered with the kernel as a fieldbus_dev, + so userspace can interact with it via the fieldbus_dev userspace + interface(s). + + This driver can also be built as a module. If so, the module + will be called hms-profinet. + + If unsure, say N. + endif diff --git a/drivers/fieldbus/anybuss/Makefile b/drivers/fieldbus/anybuss/Makefile index 815155f02700..322963a452dc 100644 --- a/drivers/fieldbus/anybuss/Makefile +++ b/drivers/fieldbus/anybuss/Makefile @@ -7,3 +7,4 @@ obj-y += anybuss_core.o anybuss_core-y += host.o obj-$(CONFIG_ARCX_ANYBUS_CONTROLLER) += arcx-anybus.o +obj-$(CONFIG_HMS_PROFINET) += hms-profinet.o diff --git a/drivers/fieldbus/anybuss/hms-profinet.c b/drivers/fieldbus/anybuss/hms-profinet.c new file mode 100644 index 000000000000..eb51aa1e7885 --- /dev/null +++ b/drivers/fieldbus/anybuss/hms-profinet.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * HMS Profinet Client Driver + * + * Copyright (C) 2018 Arcx Inc + */ + +#include +#include +#include +#include +#include +#include + +#define PROFI_DPRAM_SIZE 512 + +/* + * --------------------------------------------------------------- + * Anybus Profinet mailbox messages - definitions + * --------------------------------------------------------------- + * note that we're depending on the layout of these structures being + * exactly as advertised. + */ + +struct msgMacAddr { + u8 addr[6]; +}; + +struct profi_priv { + struct fieldbus_dev fbdev; + struct anybuss_client *client; + struct mutex enable_lock; + bool power_on; +}; + +static ssize_t +profi_read_area(struct fieldbus_dev *fbdev, char __user *buf, size_t size, + loff_t *offset) +{ + struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); + + return anybuss_read_output(priv->client, buf, size, offset); +} + +static ssize_t +profi_write_area(struct fieldbus_dev *fbdev, const char __user *buf, + size_t size, loff_t *offset) +{ + struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); + + return anybuss_write_input(priv->client, buf, size, offset); +} + +static int profi_id_get(struct fieldbus_dev *fbdev, char *buf, + size_t max_size) +{ + struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); + struct msgMacAddr response; + int ret; + + ret = anybuss_recv_msg(priv->client, 0x0010, &response, + sizeof(response)); + if (ret < 0) + return ret; + return snprintf(buf, max_size, "%02X:%02X:%02X:%02X:%02X:%02X\n", + response.addr[0], response.addr[1], + response.addr[2], response.addr[3], + response.addr[4], response.addr[5]); +} + +static bool profi_enable_get(struct fieldbus_dev *fbdev) +{ + struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); + bool power_on; + + mutex_lock(&priv->enable_lock); + power_on = priv->power_on; + mutex_unlock(&priv->enable_lock); + + return power_on; +} + +static int __profi_enable(struct profi_priv *priv) +{ + int ret; + struct anybuss_client *client = priv->client; + /* Initialization Sequence, Generic Anybus Mode */ + const struct anybuss_memcfg mem_cfg = { + .input_io = 220, + .input_dpram = PROFI_DPRAM_SIZE, + .input_total = PROFI_DPRAM_SIZE, + .output_io = 220, + .output_dpram = PROFI_DPRAM_SIZE, + .output_total = PROFI_DPRAM_SIZE, + .offl_mode = AB_OFFL_MODE_CLEAR, + }; + + /* + * switch anybus off then on, this ensures we can do a complete + * configuration cycle in case anybus was already on. + */ + anybuss_set_power(client, false); + ret = anybuss_set_power(client, true); + if (ret) + goto err; + ret = anybuss_start_init(client, &mem_cfg); + if (ret) + goto err; + ret = anybuss_finish_init(client); + if (ret) + goto err; + priv->power_on = true; + return 0; + +err: + anybuss_set_power(client, false); + priv->power_on = false; + return ret; +} + +static int __profi_disable(struct profi_priv *priv) +{ + struct anybuss_client *client = priv->client; + + anybuss_set_power(client, false); + priv->power_on = false; + return 0; +} + +static int profi_simple_enable(struct fieldbus_dev *fbdev, bool enable) +{ + int ret; + struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); + + mutex_lock(&priv->enable_lock); + if (enable) + ret = __profi_enable(priv); + else + ret = __profi_disable(priv); + mutex_unlock(&priv->enable_lock); + + return ret; +} + +static void profi_on_area_updated(struct anybuss_client *client) +{ + struct profi_priv *priv = anybuss_get_drvdata(client); + + fieldbus_dev_area_updated(&priv->fbdev); +} + +static void profi_on_online_changed(struct anybuss_client *client, bool online) +{ + struct profi_priv *priv = anybuss_get_drvdata(client); + + fieldbus_dev_online_changed(&priv->fbdev, online); +} + +static int profinet_probe(struct anybuss_client *client) +{ + struct profi_priv *priv; + struct device *dev = &client->dev; + int err; + + client->on_area_updated = profi_on_area_updated; + client->on_online_changed = profi_on_online_changed; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + mutex_init(&priv->enable_lock); + priv->client = client; + priv->fbdev.read_area_sz = priv->fbdev.write_area_sz = PROFI_DPRAM_SIZE; + priv->fbdev.card_name = "HMS Profinet IRT (Anybus-S)"; + priv->fbdev.fieldbus_type = FIELDBUS_DEV_TYPE_PROFINET; + priv->fbdev.read_area = profi_read_area; + priv->fbdev.write_area = profi_write_area; + priv->fbdev.fieldbus_id_get = profi_id_get; + priv->fbdev.enable_get = profi_enable_get; + priv->fbdev.simple_enable_set = profi_simple_enable; + priv->fbdev.parent = dev; + err = fieldbus_dev_register(&priv->fbdev); + if (err < 0) + return err; + dev_info(dev, "card detected, registered as %s", + dev_name(priv->fbdev.dev)); + anybuss_set_drvdata(client, priv); + + return 0; +} + +static int profinet_remove(struct anybuss_client *client) +{ + struct profi_priv *priv = anybuss_get_drvdata(client); + + fieldbus_dev_unregister(&priv->fbdev); + return 0; +} + +static struct anybuss_client_driver profinet_driver = { + .probe = profinet_probe, + .remove = profinet_remove, + .driver = { + .name = "hms-profinet", + .owner = THIS_MODULE, + }, + .fieldbus_type = 0x0089, +}; + +static int __init profinet_init(void) +{ + return anybuss_client_driver_register(&profinet_driver); +} +module_init(profinet_init); + +static void __exit profinet_exit(void) +{ + return anybuss_client_driver_unregister(&profinet_driver); +} +module_exit(profinet_exit); + +MODULE_AUTHOR("Sven Van Asbroeck "); +MODULE_DESCRIPTION("HMS Profinet IRT Driver (Anybus-S)"); +MODULE_LICENSE("GPL v2"); -- 2.17.1