tosa-bt.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Bluetooth built-in chip control
  4. *
  5. * Copyright (c) 2008 Dmitry Baryshkov
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/gpio.h>
  11. #include <linux/delay.h>
  12. #include <linux/rfkill.h>
  13. #include "tosa_bt.h"
  14. static void tosa_bt_on(struct tosa_bt_data *data)
  15. {
  16. gpio_set_value(data->gpio_reset, 0);
  17. gpio_set_value(data->gpio_pwr, 1);
  18. gpio_set_value(data->gpio_reset, 1);
  19. mdelay(20);
  20. gpio_set_value(data->gpio_reset, 0);
  21. }
  22. static void tosa_bt_off(struct tosa_bt_data *data)
  23. {
  24. gpio_set_value(data->gpio_reset, 1);
  25. mdelay(10);
  26. gpio_set_value(data->gpio_pwr, 0);
  27. gpio_set_value(data->gpio_reset, 0);
  28. }
  29. static int tosa_bt_set_block(void *data, bool blocked)
  30. {
  31. pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on");
  32. if (!blocked) {
  33. pr_info("TOSA_BT: going ON\n");
  34. tosa_bt_on(data);
  35. } else {
  36. pr_info("TOSA_BT: going OFF\n");
  37. tosa_bt_off(data);
  38. }
  39. return 0;
  40. }
  41. static const struct rfkill_ops tosa_bt_rfkill_ops = {
  42. .set_block = tosa_bt_set_block,
  43. };
  44. static int tosa_bt_probe(struct platform_device *dev)
  45. {
  46. int rc;
  47. struct rfkill *rfk;
  48. struct tosa_bt_data *data = dev->dev.platform_data;
  49. rc = gpio_request(data->gpio_reset, "Bluetooth reset");
  50. if (rc)
  51. goto err_reset;
  52. rc = gpio_direction_output(data->gpio_reset, 0);
  53. if (rc)
  54. goto err_reset_dir;
  55. rc = gpio_request(data->gpio_pwr, "Bluetooth power");
  56. if (rc)
  57. goto err_pwr;
  58. rc = gpio_direction_output(data->gpio_pwr, 0);
  59. if (rc)
  60. goto err_pwr_dir;
  61. rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH,
  62. &tosa_bt_rfkill_ops, data);
  63. if (!rfk) {
  64. rc = -ENOMEM;
  65. goto err_rfk_alloc;
  66. }
  67. rc = rfkill_register(rfk);
  68. if (rc)
  69. goto err_rfkill;
  70. platform_set_drvdata(dev, rfk);
  71. return 0;
  72. err_rfkill:
  73. rfkill_destroy(rfk);
  74. err_rfk_alloc:
  75. tosa_bt_off(data);
  76. err_pwr_dir:
  77. gpio_free(data->gpio_pwr);
  78. err_pwr:
  79. err_reset_dir:
  80. gpio_free(data->gpio_reset);
  81. err_reset:
  82. return rc;
  83. }
  84. static int tosa_bt_remove(struct platform_device *dev)
  85. {
  86. struct tosa_bt_data *data = dev->dev.platform_data;
  87. struct rfkill *rfk = platform_get_drvdata(dev);
  88. platform_set_drvdata(dev, NULL);
  89. if (rfk) {
  90. rfkill_unregister(rfk);
  91. rfkill_destroy(rfk);
  92. }
  93. rfk = NULL;
  94. tosa_bt_off(data);
  95. gpio_free(data->gpio_pwr);
  96. gpio_free(data->gpio_reset);
  97. return 0;
  98. }
  99. static struct platform_driver tosa_bt_driver = {
  100. .probe = tosa_bt_probe,
  101. .remove = tosa_bt_remove,
  102. .driver = {
  103. .name = "tosa-bt",
  104. },
  105. };
  106. module_platform_driver(tosa_bt_driver);
  107. MODULE_LICENSE("GPL");
  108. MODULE_AUTHOR("Dmitry Baryshkov");
  109. MODULE_DESCRIPTION("Bluetooth built-in chip control");