[PATCH 2/2] Bluetooth: hci_bcm: Add serdev support

Peter Robinson pbrobinson at gmail.com
Sun Aug 6 23:58:25 PDT 2017


On Mon, Jul 31, 2017 at 11:03 AM, Loic Poulain <loic.poulain at gmail.com> wrote:
> Add basic support for Broadcom serial slave devices.
> Probe the serial device, retrieve its maximum speed and
> register a new hci uart device.
>
> Tested/compatible with bcm43438 (RPi3).
>
> Signed-off-by: Loic Poulain <loic.poulain at gmail.com>
> ---
>  drivers/bluetooth/hci_bcm.c | 82 ++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 78 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
> index 6b42372..f824738 100644
> --- a/drivers/bluetooth/hci_bcm.c
> +++ b/drivers/bluetooth/hci_bcm.c
> @@ -27,6 +27,7 @@
>  #include <linux/firmware.h>
>  #include <linux/module.h>
>  #include <linux/acpi.h>
> +#include <linux/of.h>
>  #include <linux/platform_device.h>
>  #include <linux/clk.h>
>  #include <linux/gpio/consumer.h>
> @@ -34,6 +35,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/dmi.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/serdev.h>
>
>  #include <net/bluetooth/bluetooth.h>
>  #include <net/bluetooth/hci_core.h>
> @@ -46,6 +48,7 @@
>
>  #define BCM_AUTOSUSPEND_DELAY  5000 /* default autosleep delay */
>
> +/* platform device driver resources */
>  struct bcm_device {
>         struct list_head        list;
>
> @@ -68,6 +71,12 @@ struct bcm_device {
>  #endif
>  };
>
> +/* serdev driver resources */
> +struct bcm_bt_device {
> +       struct hci_uart hu;
> +};
> +
> +/* generic bcm uart resources */
>  struct bcm_data {
>         struct sk_buff          *rx_skb;
>         struct sk_buff_head     txq;
> @@ -289,6 +298,11 @@ static int bcm_open(struct hci_uart *hu)
>
>         hu->priv = bcm;
>
> +       if (hu->serdev) {
> +               serdev_device_open(hu->serdev);
> +               goto out;
> +       }
> +
>         if (!hu->tty->dev)
>                 goto out;
>
> @@ -323,6 +337,9 @@ static int bcm_close(struct hci_uart *hu)
>
>         bt_dev_dbg(hu->hdev, "hu %p", hu);
>
> +       if (hu->serdev)
> +               serdev_device_close(hu->serdev);
> +
>         /* Protect bcm->dev against removal of the device or driver */
>         mutex_lock(&bcm_device_lock);
>         if (bcm_device_exists(bdev)) {
> @@ -397,8 +414,12 @@ static int bcm_setup(struct hci_uart *hu)
>         else
>                 speed = 0;
>
> -       if (speed)
> -               hci_uart_set_baudrate(hu, speed);
> +       if (speed) {
> +               if (hu->serdev)
> +                       serdev_device_set_baudrate(hu->serdev, speed);
> +               else
> +                       hci_uart_set_baudrate(hu, speed);
> +       }
>
>         /* Operational speed if any */
>         if (hu->oper_speed)
> @@ -410,8 +431,12 @@ static int bcm_setup(struct hci_uart *hu)
>
>         if (speed) {
>                 err = bcm_set_baudrate(hu, speed);
> -               if (!err)
> -                       hci_uart_set_baudrate(hu, speed);
> +               if (!err) {
> +                       if (hu->serdev)
> +                               serdev_device_set_baudrate(hu->serdev, speed);
> +                       else
> +                               hci_uart_set_baudrate(hu, speed);
> +               }
>         }
>
>  finalize:
> @@ -903,9 +928,57 @@ static int bcm_remove(struct platform_device *pdev)
>         },
>  };
>
> +static int bcm_serdev_probe(struct serdev_device *serdev)
> +{
> +       struct bcm_bt_device *bcmdev;
> +       u32 speed;
> +       int err;
> +
> +       bcmdev = devm_kzalloc(&serdev->dev, sizeof(*bcmdev), GFP_KERNEL);
> +       if (!bcmdev)
> +               return -ENOMEM;
> +
> +       bcmdev->hu.serdev = serdev;
> +       serdev_device_set_drvdata(serdev, bcmdev);
> +
> +       err = of_property_read_u32(serdev->dev.of_node, "max-speed", &speed);
> +       if (!err)
> +               bcmdev->hu.oper_speed = speed;
> +
> +       return hci_uart_register_device(&bcmdev->hu, &bcm_proto);
> +}
> +
> +static void bcm_serdev_remove(struct serdev_device *serdev)
> +{
> +       struct bcm_bt_device *bcmdev = serdev_device_get_drvdata(serdev);
> +
> +       hci_uart_unregister_device(&bcmdev->hu);
> +}

I'm seeing the following warning when building this with Fedora-26/gcc7:

drivers/bluetooth/hci_bcm.c: In function 'bcm_serdev_remove':
drivers/bluetooth/hci_bcm.c:953:2: error: implicit declaration of
function 'hci_uart_unregister_device'; did you mean
'hci_uart_register_device'? [-Werror=implicit-function-declaration]
  hci_uart_unregister_device(&bcmdev->hu);
  ^~~~~~~~~~~~~~~~~~~~~~~~~~
  hci_uart_register_device
cc1: some warnings being treated as errors

> +#ifdef CONFIG_OF
> +static const struct of_device_id bcm_bluetooth_of_match[] = {
> +       { .compatible = "brcm,bcm43438-bt" },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(of, bcm_bluetooth_of_match);
> +#endif
> +
> +static struct serdev_device_driver bcm_serdev_driver = {
> +       .probe = bcm_serdev_probe,
> +       .remove = bcm_serdev_remove,
> +       .driver = {
> +               .name = "hci_uart_bcm",
> +               .of_match_table = of_match_ptr(bcm_bluetooth_of_match),
> +       },
> +};
> +
>  int __init bcm_init(void)
>  {
> +       /* For now, we need to keep both platform device
> +        * driver (ACPI generated) and serdev driver (DT).
> +        */
>         platform_driver_register(&bcm_driver);
> +       serdev_device_driver_register(&bcm_serdev_driver);
>
>         return hci_uart_register_proto(&bcm_proto);
>  }
> @@ -913,6 +986,7 @@ int __init bcm_init(void)
>  int __exit bcm_deinit(void)
>  {
>         platform_driver_unregister(&bcm_driver);
> +       serdev_device_driver_unregister(&bcm_serdev_driver);
>
>         return hci_uart_unregister_proto(&bcm_proto);
>  }
> --
> 1.9.1
>
>
> _______________________________________________
> linux-rpi-kernel mailing list
> linux-rpi-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rpi-kernel



More information about the linux-rpi-kernel mailing list