All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sebastian Reichel <sre@kernel.org>
To: Sebastian Reichel <sre@kernel.org>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	Marcel Holtmann <marcel@holtmann.org>,
	Tony Lindgren <tony@atomide.com>
Cc: Rob Herring <robh@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Pavel Machek <pavel@ucw.cz>,
	linux-bluetooth@vger.kernel.org, linux-media@vger.kernel.org,
	linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org,
	Sebastian Reichel <sebastian.reichel@collabora.com>
Subject: [PATCH 12/14] media: wl128x-radio: move from TI_ST to hci_ll driver
Date: Fri, 21 Dec 2018 02:17:50 +0100	[thread overview]
Message-ID: <20181221011752.25627-13-sre@kernel.org> (raw)
In-Reply-To: <20181221011752.25627-1-sre@kernel.org>

From: Sebastian Reichel <sebastian.reichel@collabora.com>

This updates the wl128x-radio driver to be used with hci_ll
instead of the deprecated TI_ST driver.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/bluetooth/hci_ll.c                | 115 ++++++++++++++++++++--
 drivers/media/radio/wl128x/Kconfig        |   2 +-
 drivers/media/radio/wl128x/fmdrv.h        |   1 +
 drivers/media/radio/wl128x/fmdrv_common.c | 101 ++-----------------
 include/linux/ti_wilink_st.h              |   2 +
 5 files changed, 117 insertions(+), 104 deletions(-)

diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index 3e767f245ed5..6bcba57e9c9c 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -49,6 +49,7 @@
 #include <linux/skbuff.h>
 #include <linux/ti_wilink_st.h>
 #include <linux/clk.h>
+#include <linux/platform_device.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -62,6 +63,7 @@
 #define HCI_VS_UPDATE_UART_HCI_BAUDRATE		0xff36
 
 /* HCILL commands */
+#define HCILL_FM_RADIO		0x08
 #define HCILL_GO_TO_SLEEP_IND	0x30
 #define HCILL_GO_TO_SLEEP_ACK	0x31
 #define HCILL_WAKE_UP_IND	0x32
@@ -81,6 +83,10 @@ struct ll_device {
 	struct gpio_desc *enable_gpio;
 	struct clk *ext_clk;
 	bdaddr_t bdaddr;
+
+	struct platform_device *fmdev;
+	void (*fm_handler) (void *, struct sk_buff *);
+	void *fm_drvdata;
 };
 
 struct ll_struct {
@@ -161,6 +167,35 @@ static int ll_flush(struct hci_uart *hu)
 	return 0;
 }
 
+static int ll_register_fm(struct ll_device *lldev)
+{
+	struct device *dev = &lldev->serdev->dev;
+	int err;
+
+	if (!of_device_is_compatible(dev->of_node, "ti,wl1281-st") &&
+	    !of_device_is_compatible(dev->of_node, "ti,wl1283-st") &&
+	    !of_device_is_compatible(dev->of_node, "ti,wl1285-st"))
+		return -ENODEV;
+
+	lldev->fmdev = platform_device_register_data(dev, "wl128x-fm",
+		PLATFORM_DEVID_AUTO, NULL, 0);
+	err = PTR_ERR_OR_ZERO(lldev->fmdev);
+	if (err) {
+		dev_warn(dev, "cannot register FM radio subdevice: %d\n", err);
+		lldev->fmdev = NULL;
+	}
+
+	return err;
+}
+
+static void ll_unregister_fm(struct ll_device *lldev)
+{
+	if (!lldev->fmdev)
+		return;
+	platform_device_unregister(lldev->fmdev);
+	lldev->fmdev = NULL;
+}
+
 /* Close protocol */
 static int ll_close(struct hci_uart *hu)
 {
@@ -178,6 +213,8 @@ static int ll_close(struct hci_uart *hu)
 		gpiod_set_value_cansleep(lldev->enable_gpio, 0);
 
 		clk_disable_unprepare(lldev->ext_clk);
+
+		ll_unregister_fm(lldev);
 	}
 
 	hu->priv = NULL;
@@ -313,18 +350,11 @@ static void ll_device_woke_up(struct hci_uart *hu)
 	hci_uart_tx_wakeup(hu);
 }
 
-/* Enqueue frame for transmittion (padding, crc, etc) */
-/* may be called from two simultaneous tasklets */
-static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+static int ll_enqueue_prefixed(struct hci_uart *hu, struct sk_buff *skb)
 {
 	unsigned long flags = 0;
 	struct ll_struct *ll = hu->priv;
 
-	BT_DBG("hu %p skb %p", hu, skb);
-
-	/* Prepend skb with frame type */
-	memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
-
 	/* lock hcill state */
 	spin_lock_irqsave(&ll->hcill_lock, flags);
 
@@ -361,6 +391,18 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 	return 0;
 }
 
+/* Enqueue frame for transmittion (padding, crc, etc) */
+/* may be called from two simultaneous tasklets */
+static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+	BT_DBG("hu %p skb %p", hu, skb);
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+
+	return ll_enqueue_prefixed(hu, skb);
+}
+
 static int ll_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_uart *hu = hci_get_drvdata(hdev);
@@ -390,6 +432,32 @@ static int ll_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
 	return 0;
 }
 
+static int ll_recv_radio(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_uart *hu = hci_get_drvdata(hdev);
+	struct serdev_device *serdev = hu->serdev;
+	struct ll_device *lldev = serdev_device_get_drvdata(serdev);
+
+	if (!lldev->fm_handler) {
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+
+	lldev->fm_handler(lldev->fm_drvdata, skb);
+
+	return 0;
+}
+
+#define LL_RECV_FM_RADIO \
+	.type = HCILL_FM_RADIO, \
+	.hlen = 1, \
+	.loff = 0, \
+	.lsize = 1, \
+	.maxlen = 0xff
+
 #define LL_RECV_SLEEP_IND \
 	.type = HCILL_GO_TO_SLEEP_IND, \
 	.hlen = 0, \
@@ -422,6 +490,7 @@ static const struct h4_recv_pkt ll_recv_pkts[] = {
 	{ H4_RECV_ACL,       .recv = hci_recv_frame },
 	{ H4_RECV_SCO,       .recv = hci_recv_frame },
 	{ H4_RECV_EVENT,     .recv = hci_recv_frame },
+	{ LL_RECV_FM_RADIO,  .recv = ll_recv_radio },
 	{ LL_RECV_SLEEP_IND, .recv = ll_recv_frame  },
 	{ LL_RECV_SLEEP_ACK, .recv = ll_recv_frame  },
 	{ LL_RECV_WAKE_IND,  .recv = ll_recv_frame  },
@@ -669,11 +738,41 @@ static int ll_setup(struct hci_uart *hu)
 		}
 	}
 
+	/* We intentionally ignore failures and proceed without FM device */
+	ll_register_fm(lldev);
+
 	return 0;
 }
 
 static const struct hci_uart_proto llp;
 
+void hci_ti_set_fm_handler(struct device *dev, void (*recv_handler) (void *, struct sk_buff *), void *drvdata)
+{
+	struct serdev_device *serdev = to_serdev_device(dev);
+	struct ll_device *lldev = serdev_device_get_drvdata(serdev);
+
+	lldev->fm_drvdata = drvdata;
+	lldev->fm_handler = recv_handler;
+}
+EXPORT_SYMBOL_GPL(hci_ti_set_fm_handler);
+
+int hci_ti_fm_send(struct device *dev, struct sk_buff *skb)
+{
+	struct serdev_device *serdev = to_serdev_device(dev);
+	struct ll_device *lldev = serdev_device_get_drvdata(serdev);
+	struct hci_uart *hu = &lldev->hu;
+	int ret;
+
+	hci_skb_pkt_type(skb) = HCILL_FM_RADIO;
+	ret = ll_enqueue_prefixed(hu, skb);
+
+	if (!ret)
+		hci_uart_tx_wakeup(hu);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(hci_ti_fm_send);
+
 static int hci_ti_probe(struct serdev_device *serdev)
 {
 	struct hci_uart *hu;
diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig
index 64b66bbdae72..847b3ed92639 100644
--- a/drivers/media/radio/wl128x/Kconfig
+++ b/drivers/media/radio/wl128x/Kconfig
@@ -4,7 +4,7 @@
 menu "Texas Instruments WL128x FM driver (ST based)"
 config RADIO_WL128X
 	tristate "Texas Instruments WL128x FM Radio"
-	depends on VIDEO_V4L2 && RFKILL && TTY && TI_ST
+	depends on VIDEO_V4L2 && RFKILL && TTY && BT_HCIUART_LL
 	depends on GPIOLIB || COMPILE_TEST
 	help
 	  Choose Y here if you have this FM radio chip.
diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h
index 4a337f38cfc9..717a8a3f533f 100644
--- a/drivers/media/radio/wl128x/fmdrv.h
+++ b/drivers/media/radio/wl128x/fmdrv.h
@@ -197,6 +197,7 @@ struct fmtx_data {
 
 /* FM driver operation structure */
 struct fmdev {
+	struct device *dev;
 	struct video_device radio_dev;	/* V4L2 video device pointer */
 	struct v4l2_device v4l2_dev;	/* V4L2 top level struct */
 	struct snd_card *card;	/* Card which holds FM mixer controls */
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index c20d518af4f3..88a2197c4815 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -172,9 +172,6 @@ static int_handler_prototype int_handler_table[] = {
 	fm_irq_handle_intmsk_cmd_resp
 };
 
-static long (*g_st_write) (struct sk_buff *skb);
-static struct completion wait_for_fmdrv_reg_comp;
-
 static inline void fm_irq_call(struct fmdev *fmdev)
 {
 	fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev);
@@ -373,7 +370,7 @@ static void send_tasklet(unsigned long arg)
 
 	/* Write FM packet to ST driver */
 	dump_tx_skb_data(skb);
-	len = g_st_write(skb);
+	len = hci_ti_fm_send(fmdev->dev->parent, skb);
 	if (len < 0) {
 		kfree_skb(skb);
 		fmdev->resp_comp = NULL;
@@ -1441,42 +1438,13 @@ int fmc_get_mode(struct fmdev *fmdev, u8 *fmmode)
 }
 
 /* Called by ST layer when FM packet is available */
-static long fm_st_receive(void *arg, struct sk_buff *skb)
+static void fm_st_receive(void *arg, struct sk_buff *skb)
 {
-	struct fmdev *fmdev;
-
-	fmdev = (struct fmdev *)arg;
-
-	if (skb == NULL) {
-		fmerr("Invalid SKB received from ST\n");
-		return -EFAULT;
-	}
-
-	if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) {
-		fmerr("Received SKB (%p) is not FM Channel 8 pkt\n", skb);
-		return -EINVAL;
-	}
+	struct fmdev *fmdev = (struct fmdev *) arg;
 
-	memcpy(skb_push(skb, 1), &skb->cb[0], 1);
 	dump_rx_skb_data(skb);
-
 	skb_queue_tail(&fmdev->rx_q, skb);
 	tasklet_schedule(&fmdev->rx_task);
-
-	return 0;
-}
-
-/*
- * Called by ST layer to indicate protocol registration completion
- * status.
- */
-static void fm_st_reg_comp_cb(void *arg, int data)
-{
-	struct fmdev *fmdev;
-
-	fmdev = (struct fmdev *)arg;
-	fmdev->streg_cbdata = data;
-	complete(&wait_for_fmdrv_reg_comp);
 }
 
 /*
@@ -1485,59 +1453,12 @@ static void fm_st_reg_comp_cb(void *arg, int data)
  */
 void fmc_prepare(struct fmdev *fmdev)
 {
-	static struct st_proto_s fm_st_proto;
-
 	if (test_bit(FM_CORE_READY, &fmdev->flag)) {
 		fmdbg("FM Core is already up\n");
 		return;
 	}
 
-	memset(&fm_st_proto, 0, sizeof(fm_st_proto));
-	fm_st_proto.recv = fm_st_receive;
-	fm_st_proto.match_packet = NULL;
-	fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb;
-	fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */
-	fm_st_proto.priv_data = fmdev;
-	fm_st_proto.chnl_id = 0x08;
-	fm_st_proto.max_frame_size = 0xff;
-	fm_st_proto.hdr_len = 1;
-	fm_st_proto.offset_len_in_hdr = 0;
-	fm_st_proto.len_size = 1;
-	fm_st_proto.reserve = 1;
-
-	ret = st_register(&fm_st_proto);
-	if (ret == -EINPROGRESS) {
-		init_completion(&wait_for_fmdrv_reg_comp);
-		fmdev->streg_cbdata = -EINPROGRESS;
-		fmdbg("%s waiting for ST reg completion signal\n", __func__);
-
-		if (!wait_for_completion_timeout(&wait_for_fmdrv_reg_comp,
-						 FM_ST_REG_TIMEOUT)) {
-			fmerr("Timeout(%d sec), didn't get reg completion signal from ST\n",
-					jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000);
-			return -ETIMEDOUT;
-		}
-		if (fmdev->streg_cbdata != 0) {
-			fmerr("ST reg comp CB called with error status %d\n",
-			      fmdev->streg_cbdata);
-			return -EAGAIN;
-		}
-
-		ret = 0;
-	} else if (ret == -1) {
-		fmerr("st_register failed %d\n", ret);
-		return -EAGAIN;
-	}
-
-	if (fm_st_proto.write != NULL) {
-		g_st_write = fm_st_proto.write;
-	} else {
-		fmerr("Failed to get ST write func pointer\n");
-		ret = st_unregister(&fm_st_proto);
-		if (ret < 0)
-			fmerr("st_unregister failed %d\n", ret);
-		return -EAGAIN;
-	}
+	hci_ti_set_fm_handler(fmdev->dev->parent, fm_st_receive, fmdev);
 
 	spin_lock_init(&fmdev->rds_buff_lock);
 	spin_lock_init(&fmdev->resp_skb_lock);
@@ -1582,9 +1503,6 @@ void fmc_prepare(struct fmdev *fmdev)
  */
 void fmc_release(struct fmdev *fmdev)
 {
-	static struct st_proto_s fm_st_proto;
-	int ret;
-
 	if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
 		fmdbg("FM Core is already down\n");
 		return;
@@ -1601,15 +1519,7 @@ void fmc_release(struct fmdev *fmdev)
 	fmdev->resp_comp = NULL;
 	fmdev->rx.freq = 0;
 
-	memset(&fm_st_proto, 0, sizeof(fm_st_proto));
-	fm_st_proto.chnl_id = 0x08;
-
-	ret = st_unregister(&fm_st_proto);
-
-	if (ret < 0)
-		fmerr("Failed to de-register FM from ST %d\n", ret);
-	else
-		fmdbg("Successfully unregistered from ST\n");
+	hci_ti_set_fm_handler(fmdev->dev->parent, NULL, NULL);
 
 	clear_bit(FM_CORE_READY, &fmdev->flag);
 }
@@ -1624,6 +1534,7 @@ static int wl128x_fm_probe(struct platform_device *pdev)
 	if (!fmdev)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, fmdev);
+	fmdev->dev = &pdev->dev;
 
 	fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLK_SIZE;
 	fmdev->rx.rds.buff = devm_kzalloc(&pdev->dev, fmdev->rx.rds.buf_size, GFP_KERNEL);
diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
index f2293028ab9d..a9de5654b0cd 100644
--- a/include/linux/ti_wilink_st.h
+++ b/include/linux/ti_wilink_st.h
@@ -86,6 +86,8 @@ struct st_proto_s {
 extern long st_register(struct st_proto_s *);
 extern long st_unregister(struct st_proto_s *);
 
+void hci_ti_set_fm_handler(struct device *dev, void (*recv_handler) (void *, struct sk_buff *), void *drvdata);
+int hci_ti_fm_send(struct device *dev, struct sk_buff *skb);
 
 /*
  * header information used by st_core.c
-- 
2.19.2


  parent reply	other threads:[~2018-12-21  1:18 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-21  1:17 [PATCH 00/14] Add support for FM radio in hcill and kill TI_ST Sebastian Reichel
2018-12-21  1:17 ` [PATCH 01/14] ARM: dts: LogicPD Torpedo: Add WiLink UART node Sebastian Reichel
2018-12-21 20:05   ` Adam Ford
2018-12-21  1:17 ` [PATCH 02/14] ARM: dts: IGEP: " Sebastian Reichel
2019-02-18 22:04   ` Enric Balletbo Serra
2018-12-21  1:17 ` [PATCH 03/14] ARM: OMAP2+: pdata-quirks: drop TI_ST/KIM support Sebastian Reichel
2018-12-21  1:17 ` [PATCH 04/14] media: wl128x-radio: remove module version Sebastian Reichel
2018-12-21  1:17 ` [PATCH 05/14] media: wl128x-radio: remove global radio_disconnected Sebastian Reichel
2018-12-22 19:10   ` Pavel Machek
2018-12-21  1:17 ` [PATCH 06/14] media: wl128x-radio: remove global radio_dev Sebastian Reichel
2018-12-22 19:16   ` Pavel Machek
2018-12-21  1:17 ` [PATCH 07/14] media: wl128x-radio: convert to platform device Sebastian Reichel
2018-12-22 19:17   ` Pavel Machek
2018-12-21  1:17 ` [PATCH 08/14] media: wl128x-radio: use device managed memory allocation Sebastian Reichel
2018-12-22 19:20   ` Pavel Machek
2018-12-21  1:17 ` [PATCH 09/14] media: wl128x-radio: load firmware from ti-connectivity/ Sebastian Reichel
2018-12-21  1:17 ` [PATCH 10/14] media: wl128x-radio: simplify fmc_prepare/fmc_release Sebastian Reichel
2018-12-22 19:29   ` Pavel Machek
2019-01-09 18:17     ` Sebastian Reichel
2018-12-21  1:17 ` [PATCH 11/14] media: wl128x-radio: fix skb debug printing Sebastian Reichel
2018-12-22 19:30   ` Pavel Machek
2018-12-21  1:17 ` Sebastian Reichel [this message]
2018-12-23 15:56   ` [PATCH 12/14] media: wl128x-radio: move from TI_ST to hci_ll driver Marcel Holtmann
2019-01-09 18:11     ` Sebastian Reichel
2019-01-09 19:24       ` Marcel Holtmann
2019-01-10  1:23         ` Rob Herring
2018-12-21  1:17 ` [PATCH 13/14] Bluetooth: btwilink: drop superseded driver Sebastian Reichel
2018-12-21  1:17 ` [PATCH 14/14] misc: ti-st: Drop " Sebastian Reichel
2018-12-21 21:10   ` Adam Ford
2018-12-22  3:00     ` Sebastian Reichel
2018-12-22 13:17       ` Adam Ford
2018-12-21 18:02 ` [PATCH 00/14] Add support for FM radio in hcill and kill TI_ST Tony Lindgren
2018-12-21 18:02   ` Tony Lindgren
2018-12-22  2:47   ` Sebastian Reichel
2018-12-23 16:15     ` Tony Lindgren
2018-12-22 20:36   ` Adam Ford
2018-12-23 16:22     ` Tony Lindgren
2018-12-22 20:08 ` Pavel Machek
2018-12-22 22:40   ` Pavel Machek
2019-01-10 17:42   ` Sebastian Reichel
2019-03-14  8:20 ` Hans Verkuil
2019-03-14 12:18   ` Adam Ford
2019-03-19 13:31   ` Sebastian Reichel
2019-05-07 17:26     ` Adam Ford
2019-05-07 18:34       ` Adam Ford
2019-05-08 20:58         ` Marcel Holtmann
2019-05-10 13:28           ` Adam Ford
2019-05-10 15:38             ` Marcel Holtmann
2019-09-30 23:42               ` Adam Ford
2019-10-02 19:03     ` Adam Ford
2019-10-03 13:42       ` Sebastian Reichel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181221011752.25627-13-sre@kernel.org \
    --to=sre@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=marcel@holtmann.org \
    --cc=mchehab@kernel.org \
    --cc=pavel@ucw.cz \
    --cc=robh@kernel.org \
    --cc=sebastian.reichel@collabora.com \
    --cc=tony@atomide.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.