Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * HMS Profinet Client Driver
0004  *
0005  * Copyright (C) 2018 Arcx Inc
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/init.h>
0011 #include <linux/slab.h>
0012 
0013 /* move to <linux/fieldbus_dev.h> when taking this out of staging */
0014 #include "../fieldbus_dev.h"
0015 
0016 /* move to <linux/anybuss-client.h> when taking this out of staging */
0017 #include "anybuss-client.h"
0018 
0019 #define PROFI_DPRAM_SIZE    512
0020 
0021 /*
0022  * ---------------------------------------------------------------
0023  * Anybus Profinet mailbox messages - definitions
0024  * ---------------------------------------------------------------
0025  * note that we're depending on the layout of these structures being
0026  * exactly as advertised.
0027  */
0028 
0029 struct msg_mac_addr {
0030     u8 addr[6];
0031 };
0032 
0033 struct profi_priv {
0034     struct fieldbus_dev fbdev;
0035     struct anybuss_client *client;
0036     struct mutex enable_lock; /* serializes card enable */
0037     bool power_on;
0038 };
0039 
0040 static ssize_t
0041 profi_read_area(struct fieldbus_dev *fbdev, char __user *buf, size_t size,
0042         loff_t *offset)
0043 {
0044     struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
0045 
0046     return anybuss_read_output(priv->client, buf, size, offset);
0047 }
0048 
0049 static ssize_t
0050 profi_write_area(struct fieldbus_dev *fbdev, const char __user *buf,
0051          size_t size, loff_t *offset)
0052 {
0053     struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
0054 
0055     return anybuss_write_input(priv->client, buf, size, offset);
0056 }
0057 
0058 static int profi_id_get(struct fieldbus_dev *fbdev, char *buf,
0059             size_t max_size)
0060 {
0061     struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
0062     struct msg_mac_addr response;
0063     int ret;
0064 
0065     ret = anybuss_recv_msg(priv->client, 0x0010, &response,
0066                    sizeof(response));
0067     if (ret < 0)
0068         return ret;
0069     return snprintf(buf, max_size, "%pM\n", response.addr);
0070 }
0071 
0072 static bool profi_enable_get(struct fieldbus_dev *fbdev)
0073 {
0074     struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
0075     bool power_on;
0076 
0077     mutex_lock(&priv->enable_lock);
0078     power_on = priv->power_on;
0079     mutex_unlock(&priv->enable_lock);
0080 
0081     return power_on;
0082 }
0083 
0084 static int __profi_enable(struct profi_priv *priv)
0085 {
0086     int ret;
0087     struct anybuss_client *client = priv->client;
0088     /* Initialization Sequence, Generic Anybus Mode */
0089     const struct anybuss_memcfg mem_cfg = {
0090         .input_io = 220,
0091         .input_dpram = PROFI_DPRAM_SIZE,
0092         .input_total = PROFI_DPRAM_SIZE,
0093         .output_io = 220,
0094         .output_dpram = PROFI_DPRAM_SIZE,
0095         .output_total = PROFI_DPRAM_SIZE,
0096         .offl_mode = FIELDBUS_DEV_OFFL_MODE_CLEAR,
0097     };
0098 
0099     /*
0100      * switch anybus off then on, this ensures we can do a complete
0101      * configuration cycle in case anybus was already on.
0102      */
0103     anybuss_set_power(client, false);
0104     ret = anybuss_set_power(client, true);
0105     if (ret)
0106         goto err;
0107     ret = anybuss_start_init(client, &mem_cfg);
0108     if (ret)
0109         goto err;
0110     ret = anybuss_finish_init(client);
0111     if (ret)
0112         goto err;
0113     priv->power_on = true;
0114     return 0;
0115 
0116 err:
0117     anybuss_set_power(client, false);
0118     priv->power_on = false;
0119     return ret;
0120 }
0121 
0122 static int __profi_disable(struct profi_priv *priv)
0123 {
0124     struct anybuss_client *client = priv->client;
0125 
0126     anybuss_set_power(client, false);
0127     priv->power_on = false;
0128     return 0;
0129 }
0130 
0131 static int profi_simple_enable(struct fieldbus_dev *fbdev, bool enable)
0132 {
0133     int ret;
0134     struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
0135 
0136     mutex_lock(&priv->enable_lock);
0137     if (enable)
0138         ret = __profi_enable(priv);
0139     else
0140         ret = __profi_disable(priv);
0141     mutex_unlock(&priv->enable_lock);
0142 
0143     return ret;
0144 }
0145 
0146 static void profi_on_area_updated(struct anybuss_client *client)
0147 {
0148     struct profi_priv *priv = anybuss_get_drvdata(client);
0149 
0150     fieldbus_dev_area_updated(&priv->fbdev);
0151 }
0152 
0153 static void profi_on_online_changed(struct anybuss_client *client, bool online)
0154 {
0155     struct profi_priv *priv = anybuss_get_drvdata(client);
0156 
0157     fieldbus_dev_online_changed(&priv->fbdev, online);
0158 }
0159 
0160 static int profinet_probe(struct anybuss_client *client)
0161 {
0162     struct profi_priv *priv;
0163     struct device *dev = &client->dev;
0164     int err;
0165 
0166     client->on_area_updated = profi_on_area_updated;
0167     client->on_online_changed = profi_on_online_changed;
0168     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0169     if (!priv)
0170         return -ENOMEM;
0171     mutex_init(&priv->enable_lock);
0172     priv->client = client;
0173     priv->fbdev.read_area_sz = PROFI_DPRAM_SIZE;
0174     priv->fbdev.write_area_sz = PROFI_DPRAM_SIZE;
0175     priv->fbdev.card_name = "HMS Profinet IRT (Anybus-S)";
0176     priv->fbdev.fieldbus_type = FIELDBUS_DEV_TYPE_PROFINET;
0177     priv->fbdev.read_area = profi_read_area;
0178     priv->fbdev.write_area = profi_write_area;
0179     priv->fbdev.fieldbus_id_get = profi_id_get;
0180     priv->fbdev.enable_get = profi_enable_get;
0181     priv->fbdev.simple_enable_set = profi_simple_enable;
0182     priv->fbdev.parent = dev;
0183     err = fieldbus_dev_register(&priv->fbdev);
0184     if (err < 0)
0185         return err;
0186     dev_info(dev, "card detected, registered as %s",
0187          dev_name(priv->fbdev.dev));
0188     anybuss_set_drvdata(client, priv);
0189 
0190     return 0;
0191 }
0192 
0193 static void profinet_remove(struct anybuss_client *client)
0194 {
0195     struct profi_priv *priv = anybuss_get_drvdata(client);
0196 
0197     fieldbus_dev_unregister(&priv->fbdev);
0198 }
0199 
0200 static struct anybuss_client_driver profinet_driver = {
0201     .probe = profinet_probe,
0202     .remove = profinet_remove,
0203     .driver     = {
0204         .name   = "hms-profinet",
0205         .owner  = THIS_MODULE,
0206     },
0207     .anybus_id = 0x0089,
0208 };
0209 
0210 static int __init profinet_init(void)
0211 {
0212     return anybuss_client_driver_register(&profinet_driver);
0213 }
0214 module_init(profinet_init);
0215 
0216 static void __exit profinet_exit(void)
0217 {
0218     return anybuss_client_driver_unregister(&profinet_driver);
0219 }
0220 module_exit(profinet_exit);
0221 
0222 MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
0223 MODULE_DESCRIPTION("HMS Profinet IRT Driver (Anybus-S)");
0224 MODULE_LICENSE("GPL v2");