0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
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) },
0030 { }
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
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
0065 usb_set_intfdata(interface, vb);
0066 dev_set_drvdata(&vb->pdev.dev, vb);
0067
0068
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");