Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Nano River Technologies viperboard driver
0004  *
0005  *  This is the core driver for the viperboard. There are cell drivers
0006  *  available for I2C, ADC and both GPIOs. SPI is not yet supported.
0007  *  The drivers do not support all features the board exposes. See user
0008  *  manual of the viperboard.
0009  *
0010  *  (C) 2012 by Lemonage GmbH
0011  *  Author: Lars Poeschel <poeschel@lemonage.de>
0012  *  All rights reserved.
0013  */
0014 
0015 #include <linux/kernel.h>
0016 #include <linux/errno.h>
0017 #include <linux/module.h>
0018 #include <linux/slab.h>
0019 #include <linux/types.h>
0020 #include <linux/mutex.h>
0021 
0022 #include <linux/mfd/core.h>
0023 #include <linux/mfd/viperboard.h>
0024 
0025 #include <linux/usb.h>
0026 
0027 
0028 static const struct usb_device_id vprbrd_table[] = {
0029     { USB_DEVICE(0x2058, 0x1005) },   /* Nano River Technologies */
0030     { }                               /* Terminating entry */
0031 };
0032 
0033 MODULE_DEVICE_TABLE(usb, vprbrd_table);
0034 
0035 static const struct mfd_cell vprbrd_devs[] = {
0036     {
0037         .name = "viperboard-gpio",
0038     },
0039     {
0040         .name = "viperboard-i2c",
0041     },
0042     {
0043         .name = "viperboard-adc",
0044     },
0045 };
0046 
0047 static int vprbrd_probe(struct usb_interface *interface,
0048                   const struct usb_device_id *id)
0049 {
0050     struct vprbrd *vb;
0051 
0052     u16 version = 0;
0053     int pipe, ret;
0054 
0055     /* allocate memory for our device state and initialize it */
0056     vb = kzalloc(sizeof(*vb), GFP_KERNEL);
0057     if (!vb)
0058         return -ENOMEM;
0059 
0060     mutex_init(&vb->lock);
0061 
0062     vb->usb_dev = usb_get_dev(interface_to_usbdev(interface));
0063 
0064     /* save our data pointer in this interface device */
0065     usb_set_intfdata(interface, vb);
0066     dev_set_drvdata(&vb->pdev.dev, vb);
0067 
0068     /* get version information, major first, minor then */
0069     pipe = usb_rcvctrlpipe(vb->usb_dev, 0);
0070     ret = usb_control_msg(vb->usb_dev, pipe, VPRBRD_USB_REQUEST_MAJOR,
0071         VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, vb->buf, 1,
0072         VPRBRD_USB_TIMEOUT_MS);
0073     if (ret == 1)
0074         version = vb->buf[0];
0075 
0076     ret = usb_control_msg(vb->usb_dev, pipe, VPRBRD_USB_REQUEST_MINOR,
0077         VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, vb->buf, 1,
0078         VPRBRD_USB_TIMEOUT_MS);
0079     if (ret == 1) {
0080         version <<= 8;
0081         version = version | vb->buf[0];
0082     }
0083 
0084     dev_info(&interface->dev,
0085          "version %x.%02x found at bus %03d address %03d\n",
0086          version >> 8, version & 0xff,
0087          vb->usb_dev->bus->busnum, vb->usb_dev->devnum);
0088 
0089     ret = mfd_add_hotplug_devices(&interface->dev, vprbrd_devs,
0090                       ARRAY_SIZE(vprbrd_devs));
0091     if (ret != 0) {
0092         dev_err(&interface->dev, "Failed to add mfd devices to core.");
0093         goto error;
0094     }
0095 
0096     return 0;
0097 
0098 error:
0099     if (vb) {
0100         usb_put_dev(vb->usb_dev);
0101         kfree(vb);
0102     }
0103 
0104     return ret;
0105 }
0106 
0107 static void vprbrd_disconnect(struct usb_interface *interface)
0108 {
0109     struct vprbrd *vb = usb_get_intfdata(interface);
0110 
0111     mfd_remove_devices(&interface->dev);
0112     usb_set_intfdata(interface, NULL);
0113     usb_put_dev(vb->usb_dev);
0114     kfree(vb);
0115 
0116     dev_dbg(&interface->dev, "disconnected\n");
0117 }
0118 
0119 static struct usb_driver vprbrd_driver = {
0120     .name       = "viperboard",
0121     .probe      = vprbrd_probe,
0122     .disconnect = vprbrd_disconnect,
0123     .id_table   = vprbrd_table,
0124 };
0125 
0126 module_usb_driver(vprbrd_driver);
0127 
0128 MODULE_DESCRIPTION("Nano River Technologies viperboard mfd core driver");
0129 MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
0130 MODULE_LICENSE("GPL");