Hi Abhishek, > Without updating the patchram, the BCM4354 does not support a higher > operating speed. The normal bcm_setup follows the correct order > (init_speed, patchram and then oper_speed) but the serdev driver will > set the operating speed before calling the hu->setup function. Thus, > for the BCM4354, disallow setting the operating speed before patchram. > If set_baudrate is called before setup, it will return -EBUSY. > > Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@xxxxxxxxxxxx> > --- > > Changes in v4: None > Changes in v3: None > Changes in v2: None > > drivers/bluetooth/hci_bcm.c | 37 ++++++++++++++++++++++++++++++++++++- > 1 file changed, 36 insertions(+), 1 deletion(-) > > diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c > index 0f851c0dde7f..6134bff58748 100644 > --- a/drivers/bluetooth/hci_bcm.c > +++ b/drivers/bluetooth/hci_bcm.c > @@ -47,6 +47,14 @@ > > #define BCM_NUM_SUPPLIES 2 > > +/** > + * struct bcm_device_data - device specific data > + * @no_early_set_baudrate: Disallow set baudrate before driver setup() > + */ > +struct bcm_device_data { > + bool no_early_set_baudrate; > +}; > + > /** > * struct bcm_device - device driver resources > * @serdev_hu: HCI UART controller struct > @@ -79,6 +87,7 @@ > * @hu: pointer to HCI UART controller struct, > * used to disable flow control during runtime suspend and system sleep > * @is_suspended: whether flow control is currently disabled > + * @disallow_set_baudrate: don't allow set_baudrate > */ > struct bcm_device { > /* Must be the first member, hci_serdev.c expects this. */ > @@ -112,6 +121,7 @@ struct bcm_device { > struct hci_uart *hu; > bool is_suspended; > #endif > + bool disallow_set_baudrate; > }; call it no_early_set_baudrate here as well. > > /* generic bcm uart resources */ > @@ -141,9 +151,13 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed) > static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed) > { > struct hci_dev *hdev = hu->hdev; > + struct bcm_data *bcm = hu->priv; > struct sk_buff *skb; > struct bcm_update_uart_baud_rate param; > > + if (bcm && bcm->dev && bcm->dev->disallow_set_baudrate) > + return -EBUSY; > + > if (speed > 3000000) { > struct bcm_write_uart_clock_setting clock; > > @@ -551,6 +565,12 @@ static int bcm_setup(struct hci_uart *hu) > goto finalize; > } > > + /* If we disallow early set baudrate, we can re-enable it now that > + * patchram is done > + */ > + if (bcm->dev && bcm->dev->disallow_set_baudrate) > + bcm->dev->disallow_set_baudrate = false; > + Lets not hack a different behavior of bcm_set_baudrate that magically changes based on a bool. Actually wouldn’t be setting hu->oper_speed to 0 have the same affect and bcm_set_baudrate will not be called after setting the init speed. We should be ensuring that in the case where we do not want the baudrate change before calling ->setup() is somehow covered in hci_ldisc directly and not hacked into the ->set_baudrate callback. > /* Init speed if any */ > if (hu->init_speed) > speed = hu->init_speed; > @@ -1371,6 +1391,15 @@ static struct platform_driver bcm_driver = { > }, > }; > > +static void bcm_configure_device_data(struct bcm_device *bdev) > +{ > + const struct bcm_device_data *data = device_get_match_data(bdev->dev); > + > + if (data) { > + bdev->disallow_set_baudrate = data->no_early_set_baudrate; > + } > +} > + > static int bcm_serdev_probe(struct serdev_device *serdev) > { > struct bcm_device *bcmdev; > @@ -1408,6 +1437,8 @@ static int bcm_serdev_probe(struct serdev_device *serdev) > if (err) > dev_err(&serdev->dev, "Failed to power down\n"); > > + bcm_configure_device_data(bcmdev); > + I would not split this out into a separate function. Lets do this in probe() right here. > return hci_uart_register_device(&bcmdev->serdev_hu, &bcm_proto); > } > > @@ -1419,12 +1450,16 @@ static void bcm_serdev_remove(struct serdev_device *serdev) > } > > #ifdef CONFIG_OF > +struct bcm_device_data bcm4354_device_data = { > + .no_early_set_baudrate = true, > +}; > + > static const struct of_device_id bcm_bluetooth_of_match[] = { > { .compatible = "brcm,bcm20702a1" }, > { .compatible = "brcm,bcm4345c5" }, > { .compatible = "brcm,bcm4330-bt" }, > { .compatible = "brcm,bcm43438-bt" }, > - { .compatible = "brcm,bcm43540-bt" }, > + { .compatible = "brcm,bcm43540-bt", .data = &bcm4354_device_data }, > { }, > }; > MODULE_DEVICE_TABLE(of, bcm_bluetooth_of_match); Regards Marcel