i2c-robotfuzz-osif.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * Driver for RobotFuzz OSIF
  3. *
  4. * Copyright (c) 2013 Andrew Lunn <andrew@lunn.ch>
  5. * Copyright (c) 2007 Barry Carter <Barry.Carter@robotfuzz.com>
  6. *
  7. * Based on the i2c-tiny-usb by
  8. *
  9. * Copyright (C) 2006 Til Harbaum (Till@Harbaum.org)
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License as
  13. * published by the Free Software Foundation, version 2.
  14. */
  15. #include <linux/kernel.h>
  16. #include <linux/module.h>
  17. #include <linux/errno.h>
  18. #include <linux/i2c.h>
  19. #include <linux/slab.h>
  20. #include <linux/usb.h>
  21. #define OSIFI2C_READ 20
  22. #define OSIFI2C_WRITE 21
  23. #define OSIFI2C_STOP 22
  24. #define OSIFI2C_STATUS 23
  25. #define OSIFI2C_SET_BIT_RATE 24
  26. #define STATUS_ADDRESS_ACK 0
  27. #define STATUS_ADDRESS_NAK 2
  28. struct osif_priv {
  29. struct usb_device *usb_dev;
  30. struct usb_interface *interface;
  31. struct i2c_adapter adapter;
  32. unsigned char status;
  33. };
  34. static int osif_usb_read(struct i2c_adapter *adapter, int cmd,
  35. int value, int index, void *data, int len)
  36. {
  37. struct osif_priv *priv = adapter->algo_data;
  38. return usb_control_msg(priv->usb_dev, usb_rcvctrlpipe(priv->usb_dev, 0),
  39. cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
  40. USB_DIR_IN, value, index, data, len, 2000);
  41. }
  42. static int osif_usb_write(struct i2c_adapter *adapter, int cmd,
  43. int value, int index, void *data, int len)
  44. {
  45. struct osif_priv *priv = adapter->algo_data;
  46. return usb_control_msg(priv->usb_dev, usb_sndctrlpipe(priv->usb_dev, 0),
  47. cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
  48. value, index, data, len, 2000);
  49. }
  50. static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
  51. int num)
  52. {
  53. struct osif_priv *priv = adapter->algo_data;
  54. struct i2c_msg *pmsg;
  55. int ret;
  56. int i;
  57. for (i = 0; i < num; i++) {
  58. pmsg = &msgs[i];
  59. if (pmsg->flags & I2C_M_RD) {
  60. ret = osif_usb_read(adapter, OSIFI2C_READ,
  61. pmsg->flags, pmsg->addr,
  62. pmsg->buf, pmsg->len);
  63. if (ret != pmsg->len) {
  64. dev_err(&adapter->dev, "failure reading data\n");
  65. return -EREMOTEIO;
  66. }
  67. } else {
  68. ret = osif_usb_write(adapter, OSIFI2C_WRITE,
  69. pmsg->flags, pmsg->addr,
  70. pmsg->buf, pmsg->len);
  71. if (ret != pmsg->len) {
  72. dev_err(&adapter->dev, "failure writing data\n");
  73. return -EREMOTEIO;
  74. }
  75. }
  76. ret = osif_usb_read(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
  77. if (ret) {
  78. dev_err(&adapter->dev, "failure sending STOP\n");
  79. return -EREMOTEIO;
  80. }
  81. /* read status */
  82. ret = osif_usb_read(adapter, OSIFI2C_STATUS, 0, 0,
  83. &priv->status, 1);
  84. if (ret != 1) {
  85. dev_err(&adapter->dev, "failure reading status\n");
  86. return -EREMOTEIO;
  87. }
  88. if (priv->status != STATUS_ADDRESS_ACK) {
  89. dev_dbg(&adapter->dev, "status = %d\n", priv->status);
  90. return -EREMOTEIO;
  91. }
  92. }
  93. return i;
  94. }
  95. static u32 osif_func(struct i2c_adapter *adapter)
  96. {
  97. return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
  98. }
  99. static const struct i2c_algorithm osif_algorithm = {
  100. .master_xfer = osif_xfer,
  101. .functionality = osif_func,
  102. };
  103. #define USB_OSIF_VENDOR_ID 0x1964
  104. #define USB_OSIF_PRODUCT_ID 0x0001
  105. static const struct usb_device_id osif_table[] = {
  106. { USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) },
  107. { }
  108. };
  109. MODULE_DEVICE_TABLE(usb, osif_table);
  110. static int osif_probe(struct usb_interface *interface,
  111. const struct usb_device_id *id)
  112. {
  113. int ret;
  114. struct osif_priv *priv;
  115. u16 version;
  116. priv = devm_kzalloc(&interface->dev, sizeof(*priv), GFP_KERNEL);
  117. if (!priv)
  118. return -ENOMEM;
  119. priv->usb_dev = usb_get_dev(interface_to_usbdev(interface));
  120. priv->interface = interface;
  121. usb_set_intfdata(interface, priv);
  122. priv->adapter.owner = THIS_MODULE;
  123. priv->adapter.class = I2C_CLASS_HWMON;
  124. priv->adapter.algo = &osif_algorithm;
  125. priv->adapter.algo_data = priv;
  126. snprintf(priv->adapter.name, sizeof(priv->adapter.name),
  127. "OSIF at bus %03d device %03d",
  128. priv->usb_dev->bus->busnum, priv->usb_dev->devnum);
  129. /*
  130. * Set bus frequency. The frequency is:
  131. * 120,000,000 / ( 16 + 2 * div * 4^prescale).
  132. * Using dev = 52, prescale = 0 give 100KHz */
  133. ret = osif_usb_read(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
  134. NULL, 0);
  135. if (ret) {
  136. dev_err(&interface->dev, "failure sending bit rate");
  137. usb_put_dev(priv->usb_dev);
  138. return ret;
  139. }
  140. i2c_add_adapter(&(priv->adapter));
  141. version = le16_to_cpu(priv->usb_dev->descriptor.bcdDevice);
  142. dev_info(&interface->dev,
  143. "version %x.%02x found at bus %03d address %03d",
  144. version >> 8, version & 0xff,
  145. priv->usb_dev->bus->busnum, priv->usb_dev->devnum);
  146. return 0;
  147. }
  148. static void osif_disconnect(struct usb_interface *interface)
  149. {
  150. struct osif_priv *priv = usb_get_intfdata(interface);
  151. i2c_del_adapter(&(priv->adapter));
  152. usb_set_intfdata(interface, NULL);
  153. usb_put_dev(priv->usb_dev);
  154. }
  155. static struct usb_driver osif_driver = {
  156. .name = "RobotFuzz Open Source InterFace, OSIF",
  157. .probe = osif_probe,
  158. .disconnect = osif_disconnect,
  159. .id_table = osif_table,
  160. };
  161. module_usb_driver(osif_driver);
  162. MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
  163. MODULE_AUTHOR("Barry Carter <barry.carter@robotfuzz.com>");
  164. MODULE_DESCRIPTION("RobotFuzz OSIF driver");
  165. MODULE_LICENSE("GPL v2");