BCM chips may require configuration of PCM to operate correctly and
there is a vendor specific HCI command to do this. Add support in the
hci_bcm driver to parse this from devicetree and configure the chip.
Signed-off-by: Abhishek Pandit-Subedi <[email protected]>
---
Looks like hcitool cmd 0x3f 0x001d will read back the PCM parameters so
I experimented with different values for sco_routing, interface_rate and
other values.
The hardware doesn't care about frame_type, sync_mode or clock_mode (I
put them all as 0, all as 1, etc). Only the sco_routing seems to have
a discernable effect on the hardware.
To avoid complicating this, I opted not to read PCM settings and then
write back to it. Let the user decide what to write themselves. I've
opted to add a comment explaining that 0x001d is the read opcode if they
want to verify it themselves.
Changes in v5:
- Rename parameters to bt-* and read as integer instead of bytestring
- Update documentation with defaults and put values in header
- Changed patch order
Changes in v4:
- Fix incorrect function name in hci_bcm
Changes in v3:
- Change disallow baudrate setting to return -EBUSY if called before
ready. bcm_proto is no longer modified and is back to being const.
- Changed btbcm_set_pcm_params to btbcm_set_pcm_int_params
- Changed brcm,sco-routing to brcm,bt-sco-routing
Changes in v2:
- Use match data to disallow baudrate setting
- Parse pcm parameters by name instead of as a byte string
- Fix prefix for dt-bindings commit
drivers/bluetooth/hci_bcm.c | 47 +++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index ee40003008d8..ad694b0436c9 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -25,6 +25,7 @@
#include <linux/pm_runtime.h>
#include <linux/serdev.h>
+#include <dt-bindings/bluetooth/brcm.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -88,6 +89,8 @@ struct bcm_device_data {
* used to disable flow control during runtime suspend and system sleep
* @is_suspended: whether flow control is currently disabled
* @no_early_set_baudrate: don't set_baudrate before setup()
+ * @has_pcm_params: whether PCM parameters need to be configured
+ * @pcm_params: PCM and routing parameters
*/
struct bcm_device {
/* Must be the first member, hci_serdev.c expects this. */
@@ -122,6 +125,9 @@ struct bcm_device {
bool is_suspended;
#endif
bool no_early_set_baudrate;
+
+ bool has_pcm_params;
+ struct bcm_set_pcm_int_params pcm_params;
};
/* generic bcm uart resources */
@@ -594,6 +600,16 @@ static int bcm_setup(struct hci_uart *hu)
host_set_baudrate(hu, speed);
}
+ /* PCM parameters if any*/
+ if (bcm->dev && bcm->dev->has_pcm_params) {
+ err = btbcm_set_pcm_int_params(hu->hdev, &bcm->dev->pcm_params);
+
+ if (err) {
+ bt_dev_info(hu->hdev, "BCM: Set pcm params failed (%d)",
+ err);
+ }
+ }
+
finalize:
release_firmware(fw);
@@ -1128,9 +1144,40 @@ static int bcm_acpi_probe(struct bcm_device *dev)
}
#endif /* CONFIG_ACPI */
+static int property_read_u8(struct device *dev, const char *prop, u8 *value)
+{
+ int err;
+ u32 tmp;
+
+ err = device_property_read_u32(dev, prop, &tmp);
+
+ if (!err)
+ *value = (u8)tmp;
+
+ return err;
+}
+
static int bcm_of_probe(struct bcm_device *bdev)
{
+ int err;
+
device_property_read_u32(bdev->dev, "max-speed", &bdev->oper_speed);
+
+ err = property_read_u8(bdev->dev, "brcm,bt-sco-routing",
+ &bdev->pcm_params.routing);
+
+ if (!err)
+ bdev->has_pcm_params = true;
+
+ property_read_u8(bdev->dev, "brcm,bt-pcm-interface-rate",
+ &bdev->pcm_params.rate);
+ property_read_u8(bdev->dev, "brcm,bt-pcm-frame-type",
+ &bdev->pcm_params.frame_sync);
+ property_read_u8(bdev->dev, "brcm,bt-pcm-sync-mode",
+ &bdev->pcm_params.sync_mode);
+ property_read_u8(bdev->dev, "brcm,bt-pcm-clock-mode",
+ &bdev->pcm_params.clock_mode);
+
return 0;
}
--
2.24.0.432.g9d3f5f5b63-goog