usbio-led.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include <linux/kernel.h>
  2. #include <linux/platform_device.h>
  3. #include <linux/leds.h>
  4. #include <linux/module.h>
  5. #include <linux/init.h>
  6. #include <linux/usb.h>
  7. #include <linux/slab.h>
  8. #define USBIO_VENDOR_ID 0x04d8
  9. #define USBIO_PRODUCT_ID 0x003f
  10. enum {
  11. ANSELD = 0x5e,
  12. TRISD = 0x95,
  13. CCPTMRS = 0x59,
  14. PR2 = 0xbb,
  15. CCP1CON = 0xbd,
  16. CCPR1L = 0xbe,
  17. T2CON = 0xba,
  18. PSTR1CON = 0xb9
  19. };
  20. struct usbio_led {
  21. struct usb_device *udev;
  22. struct led_classdev ldev;
  23. struct mutex lock;
  24. };
  25. int usbio_set_register(struct usb_device *usb_dev, u8 reg, u8 value)
  26. {
  27. u8 data[14];
  28. int actual_len = 14;
  29. memset(data, 0, 14);
  30. data[10] = reg;
  31. data[11] = value;
  32. data[0] = 0x99;
  33. return usb_interrupt_msg(usb_dev,
  34. usb_sndintpipe(usb_dev, 1),
  35. data, sizeof(data), &actual_len, USB_CTRL_SET_TIMEOUT);
  36. }
  37. int usbio_set_register_bit(struct usb_device *usb_dev, u8 reg, u8 reg_bit, u8 value)
  38. {
  39. u8 data[14];
  40. int actual_len = 14;
  41. memset(data, 0, 14);
  42. data[10] = reg;
  43. data[11] = reg_bit;
  44. data[12] = value;
  45. data[0] = 0x9b;
  46. return usb_interrupt_msg(usb_dev,
  47. usb_sndintpipe(usb_dev, 1),
  48. data, sizeof(data), &actual_len, USB_CTRL_SET_TIMEOUT);
  49. }
  50. static int usbio_pwm_init(struct usb_device *usb_dev)
  51. {
  52. int i, error = 0;
  53. static const u8 register_bit_to_set[3][3] = {
  54. { ANSELD, 5, 0 },
  55. { TRISD, 5, 1 },
  56. { PSTR1CON, 1, 1 }
  57. };
  58. static const u8 register_to_set[5][2] = {
  59. { CCPTMRS, 0x00 }, /* select timer resource */
  60. { PR2, 199 }, /* load width PWM period value */
  61. { CCP1CON, 0b00001100 }, /* enable pwm mode bit(3-0), bit(5-4) LSB PWM duty cycle */
  62. { CCPR1L, 0x00 },
  63. { T2CON, 0b00000110 }
  64. };
  65. for(i = 0; i < 3; i++) {
  66. error = usbio_set_register_bit(usb_dev,
  67. register_bit_to_set[i][0],
  68. register_bit_to_set[i][1],
  69. register_bit_to_set[i][2]);
  70. if(error < 0)
  71. return error;
  72. }
  73. for(i = 0; i < 5; i++) {
  74. error = usbio_set_register(usb_dev,
  75. register_to_set[i][0],
  76. register_to_set[i][1]);
  77. if(error < 0)
  78. return error;
  79. }
  80. return 0;
  81. }
  82. static void usbio_led_set(struct led_classdev *ldev, enum led_brightness brightness) {
  83. struct usbio_led *led = container_of(ldev, struct usbio_led, ldev);
  84. mutex_lock(&led->lock);
  85. usbio_set_register(led->udev, CCPR1L, brightness);
  86. mutex_unlock(&led->lock);
  87. }
  88. static int usbio_led_probe(struct usb_interface *interface, const struct usb_device_id *id)
  89. {
  90. struct usb_device *udev = interface_to_usbdev(interface);
  91. struct usbio_led *led = NULL;
  92. int retval = -ENOMEM;
  93. led = kzalloc(sizeof(struct usbio_led), GFP_KERNEL);
  94. if(led == NULL) {
  95. dev_err(&interface->dev, "Out of memory");
  96. goto error;
  97. }
  98. led->udev = usb_get_dev(udev);
  99. usb_set_intfdata(interface, led);
  100. dev_info(&interface->dev, "USBIO LED attached\n");
  101. mutex_init(&led->lock);
  102. mutex_lock(&led->lock);
  103. usbio_pwm_init(led->udev);
  104. mutex_unlock(&led->lock);
  105. led->ldev.name = "usbio_led";
  106. led->ldev.max_brightness = 255;
  107. led->ldev.brightness = LED_OFF;
  108. led->ldev.brightness_set = usbio_led_set;
  109. retval = led_classdev_register(&led->udev->dev, &led->ldev);
  110. if(retval < 0) {
  111. printk("whoops");
  112. goto error;
  113. }
  114. return 0;
  115. error:
  116. printk("errors");
  117. kfree(led);
  118. return retval;
  119. }
  120. static void usbio_led_disconnect(struct usb_interface *interface)
  121. {
  122. struct usbio_led *led;
  123. led = usb_get_intfdata(interface);
  124. usb_set_intfdata(interface, NULL);
  125. usb_put_dev(led->udev);
  126. led_classdev_unregister(&led->ldev);
  127. kfree(led);
  128. dev_info(&interface->dev, "USBIO disconnected");
  129. }
  130. static struct usb_device_id usbio_id_table[] = {
  131. { USB_DEVICE(USBIO_VENDOR_ID, USBIO_PRODUCT_ID) },
  132. {}
  133. };
  134. MODULE_DEVICE_TABLE(usb, usbio_id_table);
  135. static struct usb_driver usbio_led_driver = {
  136. .name = "usbio_led",
  137. .probe = usbio_led_probe,
  138. .disconnect = usbio_led_disconnect,
  139. .id_table = usbio_id_table
  140. };
  141. module_usb_driver(usbio_led_driver);
  142. MODULE_LICENSE("GPL");
  143. MODULE_AUTHOR("encrypt <encrypt@labr.xyz>");
  144. MODULE_DESCRIPTION("USBIO led");