brintos

brintos / linux-shallow public Read only

0
0
Text · 17.2 KiB · dc9541e Raw
756 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR MIT)2/*3 * Copyright (C) 2024 Amlogic, Inc. All rights reserved4 */5 6#include <linux/kernel.h>7#include <linux/delay.h>8#include <linux/device.h>9#include <linux/property.h>10#include <linux/of.h>11#include <linux/serdev.h>12#include <linux/clk.h>13#include <linux/firmware.h>14#include <linux/gpio/consumer.h>15#include <linux/regulator/consumer.h>16#include <net/bluetooth/bluetooth.h>17#include <net/bluetooth/hci_core.h>18#include <net/bluetooth/hci.h>19 20#include "hci_uart.h"21 22#define AML_EVT_HEAD_SIZE		423#define AML_BDADDR_DEFAULT (&(bdaddr_t) {{ 0x00, 0xff, 0x00, 0x22, 0x2d, 0xae }})24 25#define AML_FIRMWARE_OPERATION_SIZE		(248)26#define AML_FIRMWARE_MAX_SIZE			(512 * 1024)27 28/* TCI command */29#define AML_TCI_CMD_READ			0xFEF030#define AML_TCI_CMD_WRITE			0xFEF131#define AML_TCI_CMD_UPDATE_BAUDRATE		0xFEF232#define AML_TCI_CMD_HARDWARE_RESET		0xFEF233#define AML_TCI_CMD_DOWNLOAD_BT_FW		0xFEF334 35/* Vendor command */36#define AML_BT_HCI_VENDOR_CMD			0xFC1A37 38/* TCI operation parameter in controller chip */39#define AML_OP_UART_MODE			0x00A3012840#define AML_OP_EVT_ENABLE			0x00A7001441#define AML_OP_MEM_HARD_TRANS_EN		0x00A7000C42#define AML_OP_RF_CFG				0x00F0304043#define AML_OP_RAM_POWER_CTR			0x00F0305044#define AML_OP_HARDWARE_RST			0x00F0305845#define AML_OP_ICCM_RAM_BASE			0x0000000046#define AML_OP_DCCM_RAM_BASE			0x00D0000047 48/* UART configuration */49#define AML_UART_XMIT_EN			BIT(12)50#define AML_UART_RECV_EN			BIT(13)51#define AML_UART_TIMEOUT_INT_EN			BIT(14)52#define AML_UART_CLK_SOURCE			4000000053 54/* Controller event */55#define AML_EVT_EN				BIT(24)56 57/* RAM power control */58#define AML_RAM_POWER_ON			(0)59#define AML_RAM_POWER_OFF			(1)60 61/* RF configuration */62#define AML_RF_ANT_SINGLE			BIT(28)63#define AML_RF_ANT_DOUBLE			BIT(29)64 65/* Memory transaction */66#define AML_MM_CTR_HARD_TRAS_EN			BIT(27)67 68/* Controller reset */69#define AML_CTR_CPU_RESET			BIT(8)70#define AML_CTR_MAC_RESET			BIT(9)71#define AML_CTR_PHY_RESET			BIT(10)72 73enum {74	FW_ICCM,75	FW_DCCM76};77 78struct aml_fw_len {79	u32 iccm_len;80	u32 dccm_len;81};82 83struct aml_tci_rsp {84	u8 num_cmd_packet;85	u16 opcode;86	u8 status;87} __packed;88 89struct aml_device_data {90	int iccm_offset;91	int dccm_offset;92	bool is_coex;93};94 95struct aml_serdev {96	struct hci_uart serdev_hu;97	struct device *dev;98	struct gpio_desc *bt_en_gpio;99	struct regulator *bt_supply;100	struct clk *lpo_clk;101	const struct aml_device_data *aml_dev_data;102	const char *firmware_name;103};104 105struct aml_data {106	struct sk_buff *rx_skb;107	struct sk_buff_head txq;108};109 110static const struct h4_recv_pkt aml_recv_pkts[] = {111	{ H4_RECV_ACL, .recv = hci_recv_frame },112	{ H4_RECV_SCO, .recv = hci_recv_frame },113	{ H4_RECV_EVENT, .recv = hci_recv_frame },114	{ H4_RECV_ISO, .recv = hci_recv_frame },115};116 117/* The TCI command is a private command, which is for setting baud rate,118 * downloading firmware, initiating RAM.119 *120 * op_code |      op_len           | op_addr | parameter   |121 * --------|-----------------------|---------|-------------|122 *   2B    | 1B len(addr+param)    |    4B   |  len(param) |123 */124static int aml_send_tci_cmd(struct hci_dev *hdev, u16 op_code, u32 op_addr,125			    u32 *param, u32 param_len)126{127	struct aml_tci_rsp *rsp = NULL;128	struct sk_buff *skb = NULL;129	size_t buf_len = 0;130	u8 *buf = NULL;131	int err = 0;132 133	buf_len = sizeof(op_addr) + param_len;134	buf = kmalloc(buf_len, GFP_KERNEL);135	if (!buf)136		return -ENOMEM;137 138	memcpy(buf, &op_addr, sizeof(op_addr));139	if (param && param_len > 0)140		memcpy(buf + sizeof(op_addr), param, param_len);141 142	skb = __hci_cmd_sync_ev(hdev, op_code, buf_len, buf,143				HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);144	if (IS_ERR(skb)) {145		err = PTR_ERR(skb);146		bt_dev_err(hdev, "Failed to send TCI cmd (error: %d)", err);147		goto exit;148	}149 150	rsp = skb_pull_data(skb, sizeof(struct aml_tci_rsp));151	if (!rsp)152		goto skb_free;153 154	if (rsp->opcode != op_code || rsp->status != 0x00) {155		bt_dev_err(hdev, "send TCI cmd (0x%04X), response (0x%04X):(%d)",156		       op_code, rsp->opcode, rsp->status);157		err = -EINVAL;158		goto skb_free;159	}160 161skb_free:162	kfree_skb(skb);163 164exit:165	kfree(buf);166	return err;167}168 169static int aml_update_chip_baudrate(struct hci_dev *hdev, u32 baud)170{171	u32 value;172 173	value = ((AML_UART_CLK_SOURCE / baud) - 1) & 0x0FFF;174	value |= AML_UART_XMIT_EN | AML_UART_RECV_EN | AML_UART_TIMEOUT_INT_EN;175 176	return aml_send_tci_cmd(hdev, AML_TCI_CMD_UPDATE_BAUDRATE,177				  AML_OP_UART_MODE, &value, sizeof(value));178}179 180static int aml_start_chip(struct hci_dev *hdev)181{182	u32 value = 0;183	int ret;184 185	value = AML_MM_CTR_HARD_TRAS_EN;186	ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,187			       AML_OP_MEM_HARD_TRANS_EN,188			       &value, sizeof(value));189	if (ret)190		return ret;191 192	/* controller hardware reset */193	value = AML_CTR_CPU_RESET | AML_CTR_MAC_RESET | AML_CTR_PHY_RESET;194	ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_HARDWARE_RESET,195			       AML_OP_HARDWARE_RST,196			       &value, sizeof(value));197	return ret;198}199 200static int aml_send_firmware_segment(struct hci_dev *hdev,201				     u8 fw_type,202				     u8 *seg,203				     u32 seg_size,204				     u32 offset)205{206	u32 op_addr = 0;207 208	if (fw_type == FW_ICCM)209		op_addr = AML_OP_ICCM_RAM_BASE  + offset;210	else if (fw_type == FW_DCCM)211		op_addr = AML_OP_DCCM_RAM_BASE + offset;212 213	return aml_send_tci_cmd(hdev, AML_TCI_CMD_DOWNLOAD_BT_FW,214			     op_addr, (u32 *)seg, seg_size);215}216 217static int aml_send_firmware(struct hci_dev *hdev, u8 fw_type,218			     u8 *fw, u32 fw_size, u32 offset)219{220	u32 seg_size = 0;221	u32 seg_off = 0;222 223	if (fw_size > AML_FIRMWARE_MAX_SIZE) {224		bt_dev_err(hdev,225			"Firmware size %d kB is larger than the maximum of 512 kB. Aborting.",226			fw_size);227		return -EINVAL;228	}229	while (fw_size > 0) {230		seg_size = (fw_size > AML_FIRMWARE_OPERATION_SIZE) ?231			   AML_FIRMWARE_OPERATION_SIZE : fw_size;232		if (aml_send_firmware_segment(hdev, fw_type, (fw + seg_off),233					      seg_size, offset)) {234			bt_dev_err(hdev, "Failed send firmware, type: %d, offset: 0x%x",235			       fw_type, offset);236			return -EINVAL;237		}238		seg_off += seg_size;239		fw_size -= seg_size;240		offset += seg_size;241	}242	return 0;243}244 245static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)246{247	struct hci_uart *hu = hci_get_drvdata(hdev);248	struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);249	const struct firmware *firmware = NULL;250	struct aml_fw_len *fw_len = NULL;251	u8 *iccm_start = NULL, *dccm_start = NULL;252	u32 iccm_len, dccm_len;253	u32 value = 0;254	int ret = 0;255 256	/* Enable firmware download event */257	value = AML_EVT_EN;258	ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,259			       AML_OP_EVT_ENABLE,260			       &value, sizeof(value));261	if (ret)262		goto exit;263 264	/* RAM power on */265	value = AML_RAM_POWER_ON;266	ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,267			       AML_OP_RAM_POWER_CTR,268			       &value, sizeof(value));269	if (ret)270		goto exit;271 272	/* Check RAM power status */273	ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_READ,274			       AML_OP_RAM_POWER_CTR, NULL, 0);275	if (ret)276		goto exit;277 278	ret = request_firmware(&firmware, fw_name, &hdev->dev);279	if (ret < 0) {280		bt_dev_err(hdev, "Failed to load <%s>:(%d)", fw_name, ret);281		goto exit;282	}283 284	fw_len = (struct aml_fw_len *)firmware->data;285 286	/* Download ICCM */287	iccm_start = (u8 *)(firmware->data) + sizeof(struct aml_fw_len)288			+ amldev->aml_dev_data->iccm_offset;289	iccm_len = fw_len->iccm_len - amldev->aml_dev_data->iccm_offset;290	ret = aml_send_firmware(hdev, FW_ICCM, iccm_start, iccm_len,291				amldev->aml_dev_data->iccm_offset);292	if (ret) {293		bt_dev_err(hdev, "Failed to send FW_ICCM (%d)", ret);294		goto exit;295	}296 297	/* Download DCCM */298	dccm_start = (u8 *)(firmware->data) + sizeof(struct aml_fw_len) + fw_len->iccm_len;299	dccm_len = fw_len->dccm_len;300	ret = aml_send_firmware(hdev, FW_DCCM, dccm_start, dccm_len,301				amldev->aml_dev_data->dccm_offset);302	if (ret) {303		bt_dev_err(hdev, "Failed to send FW_DCCM (%d)", ret);304		goto exit;305	}306 307	/* Disable firmware download event */308	value = 0;309	ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,310			       AML_OP_EVT_ENABLE,311			       &value, sizeof(value));312	if (ret)313		goto exit;314 315exit:316	if (firmware)317		release_firmware(firmware);318	return ret;319}320 321static int aml_send_reset(struct hci_dev *hdev)322{323	struct sk_buff *skb;324	int err;325 326	skb = __hci_cmd_sync_ev(hdev, HCI_OP_RESET, 0, NULL,327				HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);328	if (IS_ERR(skb)) {329		err = PTR_ERR(skb);330		bt_dev_err(hdev, "Failed to send hci reset cmd (%d)", err);331		return err;332	}333 334	kfree_skb(skb);335	return 0;336}337 338static int aml_dump_fw_version(struct hci_dev *hdev)339{340	struct aml_tci_rsp *rsp = NULL;341	struct sk_buff *skb;342	u8 value[6] = {0};343	u8 *fw_ver = NULL;344	int err = 0;345 346	skb = __hci_cmd_sync_ev(hdev, AML_BT_HCI_VENDOR_CMD, sizeof(value), value,347				HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);348	if (IS_ERR(skb)) {349		err = PTR_ERR(skb);350		bt_dev_err(hdev, "Failed to get fw version (error: %d)", err);351		return err;352	}353 354	rsp = skb_pull_data(skb, sizeof(struct aml_tci_rsp));355	if (!rsp)356		goto exit;357 358	if (rsp->opcode != AML_BT_HCI_VENDOR_CMD || rsp->status != 0x00) {359		bt_dev_err(hdev, "dump version, error response (0x%04X):(%d)",360		       rsp->opcode, rsp->status);361		err = -EINVAL;362		goto exit;363	}364 365	fw_ver = (u8 *)rsp + AML_EVT_HEAD_SIZE;366	bt_dev_info(hdev, "fw_version: date = %02x.%02x, number = 0x%02x%02x",367		*(fw_ver + 1), *fw_ver, *(fw_ver + 3), *(fw_ver + 2));368 369exit:370	kfree_skb(skb);371	return err;372}373 374static int aml_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)375{376	struct aml_tci_rsp *rsp = NULL;377	struct sk_buff *skb;378	int err = 0;379 380	bt_dev_info(hdev, "set bdaddr (%pM)", bdaddr);381	skb = __hci_cmd_sync_ev(hdev, AML_BT_HCI_VENDOR_CMD,382				sizeof(bdaddr_t), bdaddr,383				HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);384	if (IS_ERR(skb)) {385		err = PTR_ERR(skb);386		bt_dev_err(hdev, "Failed to set bdaddr (error: %d)", err);387		return err;388	}389 390	rsp = skb_pull_data(skb, sizeof(struct aml_tci_rsp));391	if (!rsp)392		goto exit;393 394	if (rsp->opcode != AML_BT_HCI_VENDOR_CMD || rsp->status != 0x00) {395		bt_dev_err(hdev, "error response (0x%x):(%d)", rsp->opcode, rsp->status);396		err = -EINVAL;397		goto exit;398	}399 400exit:401	kfree_skb(skb);402	return err;403}404 405static int aml_check_bdaddr(struct hci_dev *hdev)406{407	struct hci_rp_read_bd_addr *paddr;408	struct sk_buff *skb;409	int err;410 411	if (bacmp(&hdev->public_addr, BDADDR_ANY))412		return 0;413 414	skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,415			     HCI_INIT_TIMEOUT);416	if (IS_ERR(skb)) {417		err = PTR_ERR(skb);418		bt_dev_err(hdev, "Failed to read bdaddr (error: %d)", err);419		return err;420	}421 422	paddr = skb_pull_data(skb, sizeof(struct hci_rp_read_bd_addr));423	if (!paddr)424		goto exit;425 426	if (!bacmp(&paddr->bdaddr, AML_BDADDR_DEFAULT)) {427		bt_dev_info(hdev, "amlbt using default bdaddr (%pM)", &paddr->bdaddr);428		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);429	}430 431exit:432	kfree_skb(skb);433	return 0;434}435 436static int aml_config_rf(struct hci_dev *hdev, bool is_coex)437{438	u32 value = AML_RF_ANT_DOUBLE;439 440	/* Use a single antenna when co-existing with wifi */441	if (is_coex)442		value = AML_RF_ANT_SINGLE;443 444	return aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,445				AML_OP_RF_CFG,446				&value, sizeof(value));447}448 449static int aml_parse_dt(struct aml_serdev *amldev)450{451	struct device *pdev = amldev->dev;452 453	amldev->bt_en_gpio = devm_gpiod_get(pdev, "enable",454					GPIOD_OUT_LOW);455	if (IS_ERR(amldev->bt_en_gpio)) {456		dev_err(pdev, "Failed to acquire enable gpios");457		return PTR_ERR(amldev->bt_en_gpio);458	}459 460	if (device_property_read_string(pdev, "firmware-name",461					&amldev->firmware_name)) {462		dev_err(pdev, "Failed to acquire firmware path");463		return -ENODEV;464	}465 466	amldev->bt_supply = devm_regulator_get(pdev, "vddio");467	if (IS_ERR(amldev->bt_supply)) {468		dev_err(pdev, "Failed to acquire regulator");469		return PTR_ERR(amldev->bt_supply);470	}471 472	amldev->lpo_clk = devm_clk_get(pdev, NULL);473	if (IS_ERR(amldev->lpo_clk)) {474		dev_err(pdev, "Failed to acquire clock source");475		return PTR_ERR(amldev->lpo_clk);476	}477 478	return 0;479}480 481static int aml_power_on(struct aml_serdev *amldev)482{483	int err;484 485	err = regulator_enable(amldev->bt_supply);486	if (err) {487		dev_err(amldev->dev, "Failed to enable regulator: (%d)", err);488		return err;489	}490 491	err = clk_prepare_enable(amldev->lpo_clk);492	if (err) {493		dev_err(amldev->dev, "Failed to enable lpo clock: (%d)", err);494		return err;495	}496 497	gpiod_set_value_cansleep(amldev->bt_en_gpio, 1);498 499	/* Wait 20ms for bluetooth controller power on */500	msleep(20);501	return 0;502}503 504static int aml_power_off(struct aml_serdev *amldev)505{506	gpiod_set_value_cansleep(amldev->bt_en_gpio, 0);507 508	clk_disable_unprepare(amldev->lpo_clk);509 510	regulator_disable(amldev->bt_supply);511 512	return 0;513}514 515static int aml_set_baudrate(struct hci_uart *hu, unsigned int speed)516{517	/* update controller baudrate */518	if (aml_update_chip_baudrate(hu->hdev, speed) != 0) {519		bt_dev_err(hu->hdev, "Failed to update baud rate");520		return -EINVAL;521	}522 523	/* update local baudrate */524	serdev_device_set_baudrate(hu->serdev, speed);525 526	return 0;527}528 529/* Initialize protocol */530static int aml_open(struct hci_uart *hu)531{532	struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);533	struct aml_data *aml_data;534	int err;535 536	err = aml_parse_dt(amldev);537	if (err)538		return err;539 540	if (!hci_uart_has_flow_control(hu)) {541		bt_dev_err(hu->hdev, "no flow control");542		return -EOPNOTSUPP;543	}544 545	aml_data = kzalloc(sizeof(*aml_data), GFP_KERNEL);546	if (!aml_data)547		return -ENOMEM;548 549	skb_queue_head_init(&aml_data->txq);550 551	hu->priv = aml_data;552 553	return 0;554}555 556static int aml_close(struct hci_uart *hu)557{558	struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);559	struct aml_data *aml_data = hu->priv;560 561	skb_queue_purge(&aml_data->txq);562	kfree_skb(aml_data->rx_skb);563	kfree(aml_data);564 565	hu->priv = NULL;566 567	return aml_power_off(amldev);568}569 570static int aml_flush(struct hci_uart *hu)571{572	struct aml_data *aml_data = hu->priv;573 574	skb_queue_purge(&aml_data->txq);575 576	return 0;577}578 579static int aml_setup(struct hci_uart *hu)580{581	struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);582	struct hci_dev *hdev = amldev->serdev_hu.hdev;583	int err;584 585	/* Setup bdaddr */586	hdev->set_bdaddr = aml_set_bdaddr;587 588	err = aml_power_on(amldev);589	if (err)590		return err;591 592	err = aml_set_baudrate(hu, amldev->serdev_hu.proto->oper_speed);593	if (err)594		return err;595 596	err = aml_download_firmware(hdev, amldev->firmware_name);597	if (err)598		return err;599 600	err = aml_config_rf(hdev, amldev->aml_dev_data->is_coex);601	if (err)602		return err;603 604	err = aml_start_chip(hdev);605	if (err)606		return err;607 608	/* Wait 60ms for controller startup */609	msleep(60);610 611	err = aml_dump_fw_version(hdev);612	if (err)613		return err;614 615	err = aml_send_reset(hdev);616	if (err)617		return err;618 619	err = aml_check_bdaddr(hdev);620	if (err)621		return err;622 623	return 0;624}625 626static int aml_enqueue(struct hci_uart *hu, struct sk_buff *skb)627{628	struct aml_data *aml_data = hu->priv;629 630	skb_queue_tail(&aml_data->txq, skb);631 632	return 0;633}634 635static struct sk_buff *aml_dequeue(struct hci_uart *hu)636{637	struct aml_data *aml_data = hu->priv;638	struct sk_buff *skb;639 640	skb = skb_dequeue(&aml_data->txq);641 642	/* Prepend skb with frame type */643	if (skb)644		memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);645 646	return skb;647}648 649static int aml_recv(struct hci_uart *hu, const void *data, int count)650{651	struct aml_data *aml_data = hu->priv;652	int err;653 654	aml_data->rx_skb = h4_recv_buf(hu->hdev, aml_data->rx_skb, data, count,655				       aml_recv_pkts,656				       ARRAY_SIZE(aml_recv_pkts));657	if (IS_ERR(aml_data->rx_skb)) {658		err = PTR_ERR(aml_data->rx_skb);659		bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);660		aml_data->rx_skb = NULL;661		return err;662	}663 664	return count;665}666 667static const struct hci_uart_proto aml_hci_proto = {668	.id		= HCI_UART_AML,669	.name		= "AML",670	.init_speed	= 115200,671	.oper_speed	= 4000000,672	.open		= aml_open,673	.close		= aml_close,674	.setup		= aml_setup,675	.flush		= aml_flush,676	.recv		= aml_recv,677	.enqueue	= aml_enqueue,678	.dequeue	= aml_dequeue,679};680 681static void aml_device_driver_shutdown(struct device *dev)682{683	struct aml_serdev *amldev = dev_get_drvdata(dev);684 685	aml_power_off(amldev);686}687 688static int aml_serdev_probe(struct serdev_device *serdev)689{690	struct aml_serdev *amldev;691	int err;692 693	amldev = devm_kzalloc(&serdev->dev, sizeof(*amldev), GFP_KERNEL);694	if (!amldev)695		return -ENOMEM;696 697	amldev->serdev_hu.serdev = serdev;698	amldev->dev = &serdev->dev;699	serdev_device_set_drvdata(serdev, amldev);700 701	err = hci_uart_register_device(&amldev->serdev_hu, &aml_hci_proto);702	if (err)703		return dev_err_probe(amldev->dev, err,704			      "Failed to register hci uart device");705 706	amldev->aml_dev_data = device_get_match_data(&serdev->dev);707 708	return 0;709}710 711static void aml_serdev_remove(struct serdev_device *serdev)712{713	struct aml_serdev *amldev = serdev_device_get_drvdata(serdev);714 715	hci_uart_unregister_device(&amldev->serdev_hu);716}717 718static const struct aml_device_data data_w155s2 = {719	.iccm_offset = 256 * 1024,720};721 722static const struct aml_device_data data_w265s2 = {723	.iccm_offset = 384 * 1024,724};725 726static const struct of_device_id aml_bluetooth_of_match[] = {727	{ .compatible = "amlogic,w155s2-bt", .data = &data_w155s2 },728	{ .compatible = "amlogic,w265s2-bt", .data = &data_w265s2 },729	{ /* sentinel */ },730};731MODULE_DEVICE_TABLE(of, aml_bluetooth_of_match);732 733static struct serdev_device_driver aml_serdev_driver = {734	.probe = aml_serdev_probe,735	.remove = aml_serdev_remove,736	.driver = {737		.name = "hci_uart_aml",738		.of_match_table = aml_bluetooth_of_match,739		.shutdown = aml_device_driver_shutdown,740	},741};742 743int __init aml_init(void)744{745	serdev_device_driver_register(&aml_serdev_driver);746 747	return hci_uart_register_proto(&aml_hci_proto);748}749 750int __exit aml_deinit(void)751{752	serdev_device_driver_unregister(&aml_serdev_driver);753 754	return hci_uart_unregister_proto(&aml_hci_proto);755}756