diff options
author | Lars Poeschel <poeschel@lemonage.de> | 2012-11-05 09:48:23 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-11-20 06:21:12 -0500 |
commit | f01312d846016dbd38cc9865e580298fb61f2aa7 (patch) | |
tree | de82be5e80055f91363e218d099002e72b5bc7d6 | |
parent | b9fbb62eb61452d728c39b2e5020739c575aac53 (diff) |
mfd: Add viperboard driver
Add mfd driver for Nano River Technologies viperboard.
Signed-off-by: Lars Poeschel <poeschel@lemonage.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r-- | drivers/mfd/Kconfig | 14 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/viperboard.c | 129 | ||||
-rw-r--r-- | include/linux/mfd/viperboard.h | 105 |
4 files changed, 249 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 34242cada125..b280639a7634 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -1065,6 +1065,20 @@ config MFD_PALMAS | |||
1065 | If you say yes here you get support for the Palmas | 1065 | If you say yes here you get support for the Palmas |
1066 | series of PMIC chips from Texas Instruments. | 1066 | series of PMIC chips from Texas Instruments. |
1067 | 1067 | ||
1068 | config MFD_VIPERBOARD | ||
1069 | tristate "Support for Nano River Technologies Viperboard" | ||
1070 | select MFD_CORE | ||
1071 | depends on USB | ||
1072 | default n | ||
1073 | help | ||
1074 | Say yes here if you want support for Nano River Technologies | ||
1075 | Viperboard. | ||
1076 | There are mfd cell drivers available for i2c master, adc and | ||
1077 | both gpios found on the board. The spi part does not yet | ||
1078 | have a driver. | ||
1079 | You need to select the mfd cell drivers separately. | ||
1080 | The drivers do not support all features the board exposes. | ||
1081 | |||
1068 | endmenu | 1082 | endmenu |
1069 | endif | 1083 | endif |
1070 | 1084 | ||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 632cce09e407..1c3ee7c76906 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -139,6 +139,7 @@ obj-$(CONFIG_MFD_TPS65090) += tps65090.o | |||
139 | obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o | 139 | obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o |
140 | obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o | 140 | obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o |
141 | obj-$(CONFIG_MFD_PALMAS) += palmas.o | 141 | obj-$(CONFIG_MFD_PALMAS) += palmas.o |
142 | obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o | ||
142 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o | 143 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o |
143 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o | 144 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o |
144 | obj-$(CONFIG_MFD_SYSCON) += syscon.o | 145 | obj-$(CONFIG_MFD_SYSCON) += syscon.o |
diff --git a/drivers/mfd/viperboard.c b/drivers/mfd/viperboard.c new file mode 100644 index 000000000000..cd1e2fe95647 --- /dev/null +++ b/drivers/mfd/viperboard.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * Nano River Technologies viperboard driver | ||
3 | * | ||
4 | * This is the core driver for the viperboard. There are cell drivers | ||
5 | * available for I2C, ADC and both GPIOs. SPI is not yet supported. | ||
6 | * The drivers do not support all features the board exposes. See user | ||
7 | * manual of the viperboard. | ||
8 | * | ||
9 | * (C) 2012 by Lemonage GmbH | ||
10 | * Author: Lars Poeschel <poeschel@lemonage.de> | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/types.h> | ||
25 | #include <linux/mutex.h> | ||
26 | |||
27 | #include <linux/mfd/core.h> | ||
28 | #include <linux/mfd/viperboard.h> | ||
29 | |||
30 | #include <linux/usb.h> | ||
31 | |||
32 | |||
33 | static const struct usb_device_id vprbrd_table[] = { | ||
34 | { USB_DEVICE(0x2058, 0x1005) }, /* Nano River Technologies */ | ||
35 | { } /* Terminating entry */ | ||
36 | }; | ||
37 | |||
38 | MODULE_DEVICE_TABLE(usb, vprbrd_table); | ||
39 | |||
40 | static struct mfd_cell vprbrd_devs[] = { | ||
41 | }; | ||
42 | |||
43 | static int vprbrd_probe(struct usb_interface *interface, | ||
44 | const struct usb_device_id *id) | ||
45 | { | ||
46 | struct vprbrd *vb; | ||
47 | |||
48 | u16 version = 0; | ||
49 | int pipe, ret; | ||
50 | unsigned char buf[1]; | ||
51 | |||
52 | /* allocate memory for our device state and initialize it */ | ||
53 | vb = kzalloc(sizeof(*vb), GFP_KERNEL); | ||
54 | if (vb == NULL) { | ||
55 | dev_err(&interface->dev, "Out of memory\n"); | ||
56 | return -ENOMEM; | ||
57 | } | ||
58 | |||
59 | mutex_init(&vb->lock); | ||
60 | |||
61 | vb->usb_dev = usb_get_dev(interface_to_usbdev(interface)); | ||
62 | |||
63 | /* save our data pointer in this interface device */ | ||
64 | usb_set_intfdata(interface, vb); | ||
65 | dev_set_drvdata(&vb->pdev.dev, vb); | ||
66 | |||
67 | /* get version information, major first, minor then */ | ||
68 | pipe = usb_rcvctrlpipe(vb->usb_dev, 0); | ||
69 | ret = usb_control_msg(vb->usb_dev, pipe, VPRBRD_USB_REQUEST_MAJOR, | ||
70 | VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, buf, 1, | ||
71 | VPRBRD_USB_TIMEOUT_MS); | ||
72 | if (ret == 1) | ||
73 | version = buf[0]; | ||
74 | |||
75 | ret = usb_control_msg(vb->usb_dev, pipe, VPRBRD_USB_REQUEST_MINOR, | ||
76 | VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, buf, 1, | ||
77 | VPRBRD_USB_TIMEOUT_MS); | ||
78 | if (ret == 1) { | ||
79 | version <<= 8; | ||
80 | version = version | buf[0]; | ||
81 | } | ||
82 | |||
83 | dev_info(&interface->dev, | ||
84 | "version %x.%02x found at bus %03d address %03d\n", | ||
85 | version >> 8, version & 0xff, | ||
86 | vb->usb_dev->bus->busnum, vb->usb_dev->devnum); | ||
87 | |||
88 | ret = mfd_add_devices(&interface->dev, -1, vprbrd_devs, | ||
89 | ARRAY_SIZE(vprbrd_devs), NULL, 0, NULL); | ||
90 | if (ret != 0) { | ||
91 | dev_err(&interface->dev, "Failed to add mfd devices to core."); | ||
92 | goto error; | ||
93 | } | ||
94 | |||
95 | return 0; | ||
96 | |||
97 | error: | ||
98 | if (vb) { | ||
99 | usb_put_dev(vb->usb_dev); | ||
100 | kfree(vb); | ||
101 | } | ||
102 | |||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | static void vprbrd_disconnect(struct usb_interface *interface) | ||
107 | { | ||
108 | struct vprbrd *vb = usb_get_intfdata(interface); | ||
109 | |||
110 | mfd_remove_devices(&interface->dev); | ||
111 | usb_set_intfdata(interface, NULL); | ||
112 | usb_put_dev(vb->usb_dev); | ||
113 | kfree(vb); | ||
114 | |||
115 | dev_dbg(&interface->dev, "disconnected\n"); | ||
116 | } | ||
117 | |||
118 | static struct usb_driver vprbrd_driver = { | ||
119 | .name = "viperboard", | ||
120 | .probe = vprbrd_probe, | ||
121 | .disconnect = vprbrd_disconnect, | ||
122 | .id_table = vprbrd_table, | ||
123 | }; | ||
124 | |||
125 | module_usb_driver(vprbrd_driver); | ||
126 | |||
127 | MODULE_DESCRIPTION("Nano River Technologies viperboard mfd core driver"); | ||
128 | MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>"); | ||
129 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/linux/mfd/viperboard.h b/include/linux/mfd/viperboard.h new file mode 100644 index 000000000000..0d1342466db5 --- /dev/null +++ b/include/linux/mfd/viperboard.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * include/linux/mfd/viperboard.h | ||
3 | * | ||
4 | * Nano River Technologies viperboard definitions | ||
5 | * | ||
6 | * (C) 2012 by Lemonage GmbH | ||
7 | * Author: Lars Poeschel <poeschel@lemonage.de> | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __MFD_VIPERBOARD_H__ | ||
18 | #define __MFD_VIPERBOARD_H__ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/usb.h> | ||
22 | |||
23 | #define VPRBRD_EP_OUT 0x02 | ||
24 | #define VPRBRD_EP_IN 0x86 | ||
25 | |||
26 | #define VPRBRD_I2C_MSG_LEN 512 /* max length of a msg on USB level */ | ||
27 | |||
28 | #define VPRBRD_I2C_FREQ_6MHZ 1 /* 6 MBit/s */ | ||
29 | #define VPRBRD_I2C_FREQ_3MHZ 2 /* 3 MBit/s */ | ||
30 | #define VPRBRD_I2C_FREQ_1MHZ 3 /* 1 MBit/s */ | ||
31 | #define VPRBRD_I2C_FREQ_FAST 4 /* 400 kbit/s */ | ||
32 | #define VPRBRD_I2C_FREQ_400KHZ VPRBRD_I2C_FREQ_FAST | ||
33 | #define VPRBRD_I2C_FREQ_200KHZ 5 /* 200 kbit/s */ | ||
34 | #define VPRBRD_I2C_FREQ_STD 6 /* 100 kbit/s */ | ||
35 | #define VPRBRD_I2C_FREQ_100KHZ VPRBRD_I2C_FREQ_STD | ||
36 | #define VPRBRD_I2C_FREQ_10KHZ 7 /* 10 kbit/s */ | ||
37 | |||
38 | #define VPRBRD_I2C_CMD_WRITE 0x00 | ||
39 | #define VPRBRD_I2C_CMD_READ 0x01 | ||
40 | #define VPRBRD_I2C_CMD_ADDR 0x02 | ||
41 | |||
42 | #define VPRBRD_USB_TYPE_OUT 0x40 | ||
43 | #define VPRBRD_USB_TYPE_IN 0xc0 | ||
44 | #define VPRBRD_USB_TIMEOUT_MS 100 | ||
45 | #define VPRBRD_USB_REQUEST_MAJOR 0xea | ||
46 | #define VPRBRD_USB_REQUEST_MINOR 0xeb | ||
47 | |||
48 | struct vprbrd_i2c_write_hdr { | ||
49 | u8 cmd; | ||
50 | u16 addr; | ||
51 | u8 len1; | ||
52 | u8 len2; | ||
53 | u8 last; | ||
54 | u8 chan; | ||
55 | u16 spi; | ||
56 | } __packed; | ||
57 | |||
58 | struct vprbrd_i2c_read_hdr { | ||
59 | u8 cmd; | ||
60 | u16 addr; | ||
61 | u8 len0; | ||
62 | u8 len1; | ||
63 | u8 len2; | ||
64 | u8 len3; | ||
65 | u8 len4; | ||
66 | u8 len5; | ||
67 | u16 tf1; /* transfer 1 length */ | ||
68 | u16 tf2; /* transfer 2 length */ | ||
69 | } __packed; | ||
70 | |||
71 | struct vprbrd_i2c_status { | ||
72 | u8 unknown[11]; | ||
73 | u8 status; | ||
74 | } __packed; | ||
75 | |||
76 | struct vprbrd_i2c_write_msg { | ||
77 | struct vprbrd_i2c_write_hdr header; | ||
78 | u8 data[VPRBRD_I2C_MSG_LEN | ||
79 | - sizeof(struct vprbrd_i2c_write_hdr)]; | ||
80 | } __packed; | ||
81 | |||
82 | struct vprbrd_i2c_read_msg { | ||
83 | struct vprbrd_i2c_read_hdr header; | ||
84 | u8 data[VPRBRD_I2C_MSG_LEN | ||
85 | - sizeof(struct vprbrd_i2c_read_hdr)]; | ||
86 | } __packed; | ||
87 | |||
88 | struct vprbrd_i2c_addr_msg { | ||
89 | u8 cmd; | ||
90 | u8 addr; | ||
91 | u8 unknown1; | ||
92 | u16 len; | ||
93 | u8 unknown2; | ||
94 | u8 unknown3; | ||
95 | } __packed; | ||
96 | |||
97 | /* Structure to hold all device specific stuff */ | ||
98 | struct vprbrd { | ||
99 | struct usb_device *usb_dev; /* the usb device for this device */ | ||
100 | struct mutex lock; | ||
101 | u8 buf[sizeof(struct vprbrd_i2c_write_msg)]; | ||
102 | struct platform_device pdev; | ||
103 | }; | ||
104 | |||
105 | #endif /* __MFD_VIPERBOARD_H__ */ | ||