Files
BPI-CM9-Linux/aml-comp/hardware/bluetooth/amlogic/w1/bt_hal_platform.c
T

688 lines
23 KiB
C

/*
* Copyright (c) 202X Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in the
* file 'LICENSE' which is part of this source code package.
*
* Description:
*/
#include "bt_hal_platform.h"
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/version.h>
extern unsigned char (*host_wake_w1_req)(void);
static int reg_config_complete = 0;
static struct cdev BTAML_cdev;
static int BTAML_major;
static int BTAML_devs = 1;
static struct class *pBTClass;
static struct device *pBTDev;
#define BT_NODE "stpbt"
#define BT_DRIVER_NAME "sdio_bt"
#define BT_AML_SDIOBT_VERSION "v2.0.2_20220112_sdiobt"
static char *chip_name = "aml_w1";
//extern unsigned int amlbt_poweron;
extern void aml_wifi_sdio_power_lock(void);
extern void aml_wifi_sdio_power_unlock(void);
static int bt_aml_insmod(void);
static void bt_aml_rmmod(void);
#ifdef CONFIG_AMLOGIC_GX_SUSPEND
extern unsigned int get_resume_method(void);
#endif
static int config_bt_pmu_reg(bool is_power_on)
{
unsigned int value_pmu_A12 = 0, value_pmu_A13 = 0, value_pmu_A14 = 0, value_pmu_A15 = 0,
value_pmu_A16 = 0, value_pmu_A17 = 0, value_pmu_A18 = 0, value_pmu_A20 = 0,
value_pmu_A22 = 0, bt_pmu_status = 0, host_req_status = 0, value_aon_a15 = 0;
int ret = 0;
unsigned char pmu_fsm = 0;
unsigned int reg_addr_mapping_form_pmu_fsm = 0;
unsigned int reg_data = 0;
unsigned int bt_pmu_status_check = 0;
unsigned int wait_count = 0;
/* set wifi keep alive, BIT(5)*/
if (g_w1_hif_ops.hi_bottom_read8 == NULL)
{
PRINT("config_bt_pmu_reg(): can't get g_w1_hif_ops interface!!!!!!!!!!\n");
return (-1);
}
host_req_status = g_w1_hif_ops.hi_bottom_read8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ);
PRINT("host_req_status = 0x%x\n", host_req_status);
host_req_status |= BIT(5);
g_w1_hif_ops.hi_bottom_write8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ, host_req_status);
/* wake wifi fw firstly */
if (host_wake_w1_req != NULL)
{
PRINT("BT lock\n");
aml_wifi_sdio_power_lock();
while (host_wake_w1_req() == 0)
{
msleep(10);
PRINT("BT insmod, wake wifi failed\n");
}
aml_wifi_sdio_power_unlock();
PRINT("BT unlock\n");
}
else
{
/* wifi doesn't insmod */
}
if (is_power_on)
{
value_pmu_A12 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A12);
value_pmu_A13 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A13);
value_pmu_A14 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A14);
value_pmu_A15 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A15);
value_pmu_A16 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16);
value_pmu_A17 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A17);
value_pmu_A18 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A18);
value_pmu_A20 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A20);
value_pmu_A22 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A22);
PRINT("BT power on: before write A12=0x%x, A13=0x%x, A14=0x%x, A15=0x%x, A16=0x%x, A17=0x%x, A18=0x%x, A20=0x%x, A22=0x%x\n",
value_pmu_A12, value_pmu_A13, value_pmu_A14, value_pmu_A15, value_pmu_A16, value_pmu_A17, value_pmu_A18, value_pmu_A20,
value_pmu_A22);
/* set bt work flag && xosc/bbpll/ao_iso/pmu mask*/
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A14, 0x1f);
PRINT("BT power on:RG_BT_PMU_A14 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A14));
/* release pmu fsm : bit0 */
host_req_status = g_w1_hif_ops.hi_bottom_read8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ);
host_req_status &= ~BIT(0);
g_w1_hif_ops.hi_bottom_write8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ, host_req_status);
msleep(10);
/* reset bt, then release bt */
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A17, 0x700);
msleep(1);
PRINT("BT power on:RG_BT_PMU_A17 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A17));
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A20, 0x0);
msleep(1);
PRINT("BT power on:RG_BT_PMU_A20 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A20));
//g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A12, value_pmu_A12|0xc0);
//msleep(1);
//PRINT("BT power on:RG_BT_PMU_A12 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A12));
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A18, 0x1700);
PRINT("BT power on: %s, line=%d\n", __func__, __LINE__);
msleep(1);
PRINT("BT power on:RG_BT_PMU_A18 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A18));
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A22, 0x704);
msleep(10);
PRINT("BT power on:RG_BT_PMU_A22 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A22));
/* rg_bb_reset_man */
value_pmu_A12 = value_pmu_A12 & 0xffffff3f;
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A12, value_pmu_A12 | 0x80);
msleep(1);
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A12, value_pmu_A12 | 0xc0);
msleep(1);
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A12, value_pmu_A12 | 0x80);
msleep(1);
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A12, value_pmu_A12 | 0x00);
msleep(1);
PRINT("BT power on:RG_BT_PMU_A12 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A12));
/* set bt pmu fsm to PMU_PWR_OFF */
host_req_status = g_w1_hif_ops.hi_bottom_read8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ);
host_req_status |= (PMU_PWR_OFF << 1) | BIT(0);
g_w1_hif_ops.hi_bottom_write8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ, host_req_status);
/* release bt pmu fsm */
host_req_status = g_w1_hif_ops.hi_bottom_read8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ);
host_req_status &= ~(0x1f);
g_w1_hif_ops.hi_bottom_write8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ, host_req_status);
msleep(20);
bt_pmu_status = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A15);
PRINT("%s bt_pmu_status:0x%x\n", __func__, bt_pmu_status);
/* wait bt pmu fsm to PMU_ACT_MODE*/
while ((bt_pmu_status & 0xF) != PMU_ACT_MODE)
{
msleep(5);
PRINT("%s bt_pmu_status:0x%x\n", __func__, bt_pmu_status);
bt_pmu_status = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A15);
}
value_pmu_A12 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A12);
value_pmu_A13 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A13);
value_pmu_A14 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A14);
value_pmu_A15 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A15);
value_pmu_A16 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16);
value_pmu_A17 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A17);
value_pmu_A18 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A18);
value_pmu_A20 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A20);
value_pmu_A22 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A22);
PRINT("BT power on: after write A12=0x%x, A13=0x%x, A14=0x%x, A15=0x%x, A16=0x%x, A17=0x%x, A18=0x%x, A20=0x%x, A22=0x%x\n",
value_pmu_A12, value_pmu_A13, value_pmu_A14, value_pmu_A15, value_pmu_A16, value_pmu_A17, value_pmu_A18, value_pmu_A20,
value_pmu_A22);
}
else // turn off bt
{
value_pmu_A16 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16);
value_pmu_A16 |= (0x1 << 30); //bit30 = 1, make sure can't enter power down when turn off BT
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A16, value_pmu_A16);
PRINT("Enable RG_BT_PMU_A16 BIT30, FW can't enter power down!\n");
value_pmu_A12 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A12);
value_pmu_A13 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A13);
value_pmu_A14 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A14);
value_pmu_A15 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A15);
value_pmu_A17 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A17);
value_pmu_A18 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A18);
value_pmu_A20 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A20);
value_pmu_A22 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A22);
value_aon_a15 = g_w1_hif_ops.bt_hi_read_word(RG_AON_A15);
PRINT("BT power off: before write A12=0x%x, A13=0x%x, A14=0x%x, A15=0x%x, A16=0x%x, A17=0x%x, A18=0x%x, A20=0x%x, A22=0x%x, aon_a15=0x%x\n",
value_pmu_A12, value_pmu_A13, value_pmu_A14, value_pmu_A15, value_pmu_A16, value_pmu_A17, value_pmu_A18, value_pmu_A20,
value_pmu_A22, value_aon_a15);
//if (value_pmu_A15 == 8)
{
value_pmu_A16 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16);
value_pmu_A16 &= 0xFffffffE; //bit0 =0
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A16, value_pmu_A16);
msleep(10);
value_pmu_A16 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16);
PRINT("RG_BT_PMU_A16_0 = 0x%x\n", value_pmu_A16);
value_pmu_A16 &= 0xFffffffD; //bit1 =0
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A16, value_pmu_A16);
msleep(10);
if (value_pmu_A15 == 8)
{
PRINT("Is sleep mode, wakeup first!\n");
value_pmu_A16 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16);
PRINT("RG_BT_PMU_A16_1 = 0x%x\n", value_pmu_A16);
value_pmu_A16 |= 0x2; //bit1 = 1
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A16, value_pmu_A16);
msleep(10);
}
value_pmu_A16 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16);
PRINT("RG_BT_PMU_A16_2 = 0x%x\n", value_pmu_A16);
}
value_pmu_A16 &= 0x7fffffff;
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A16, value_pmu_A16);
msleep(1);
PRINT("BT power off:RG_BT_PMU_A16 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16));
PRINT("Check whether is active mode\n");
bt_pmu_status = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A15);
bt_pmu_status_check = bt_pmu_status;
//if (!strcmp(chip_name, "aml_w1u_s"))
bt_pmu_status_check = bt_pmu_status & 0x0f;
while (bt_pmu_status_check != PMU_ACT_MODE)
{
msleep(10);
bt_pmu_status = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A15);
PRINT("wait wakeup, RG_BT_PMU_A15 = 0x%x\n", bt_pmu_status);
wait_count++;
if (wait_count > 50) //
{
#if 0
/* set bt pmu fsm to PMU_SLEEP_MODE */
PRINT("Force BT power off\n");
host_req_status = g_w1_hif_ops.hi_bottom_read8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ);
host_req_status |= (PMU_SLEEP_MODE << 1) | BIT(0);
g_w1_hif_ops.hi_bottom_write8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ, host_req_status);
PRINT("Force BT power on\n");
/* release pmu fsm : bit0 */
host_req_status = g_w1_hif_ops.hi_bottom_read8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ);
host_req_status &= ~BIT(0);
g_w1_hif_ops.hi_bottom_write8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ, host_req_status);
msleep(10);
#else
// add workaroud for pmu lock, when pmu lock trig the bnd let pmu fsm switch to next state.
pmu_fsm = (g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A15) & 0xf);
//if (pmu_fsm == PMU_SLEEP_MODE)
//{
// value_pmu_A16 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16);
// value_pmu_A16 |= 0x2;
// g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A16, value_pmu_A16);
//}
//else
{
PRINT("trig pmu bnd to unlock pmu fsm, pmu_state=0x%x\n", pmu_fsm);
//if ((pmu_fsm == PMU_PWR_OFF) || (pmu_fsm == PMU_PWR_XOSC))
// ; // pmu fsm should not be 0 or 1 when chip on.
if (pmu_fsm == PMU_ACT_MODE) // act mode wait cpu start
reg_addr_mapping_form_pmu_fsm = RG_BT_PMU_A11;
else
reg_addr_mapping_form_pmu_fsm = CHIP_BT_PMU_REG_BASE + ((pmu_fsm - 1) * 4);
reg_data = g_w1_hif_ops.bt_hi_read_word(reg_addr_mapping_form_pmu_fsm);
g_w1_hif_ops.bt_hi_write_word(reg_addr_mapping_form_pmu_fsm, ((reg_data & 0x7fffffff) + 1));
}
msleep(50); // wait pmu wake
//g_funcs.aml_pwr_pwrsave_wake(g_power_down_domain);
#endif
break;
}
}
/* rg_bb_reset_man */
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A12, value_pmu_A12 | 0xc0);
msleep(1);
/* reset bt */
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A22, 0x707);
msleep(1);
PRINT("BT power off:RG_BT_PMU_A22 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A22));
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A18, 0x1787);
msleep(1);
PRINT("BT power off:RG_BT_PMU_A18 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A18));
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A20, 0x0); //0x1f703007
msleep(1);
PRINT("BT power off:RG_BT_PMU_A20 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A20));
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A17, 0x707);
msleep(1);
PRINT("BT power off:RG_BT_PMU_A17 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A17));
/* clear bt work flag for coex */
//value_pmu_A16 &= 0x7fffffff;
//g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A16, value_pmu_A16);
//PRINT("BT power off:RG_BT_PMU_A16 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16));
value_pmu_A12 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A12);
value_pmu_A13 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A13);
value_pmu_A14 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A14);
value_pmu_A15 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A15);
value_pmu_A16 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A16);
value_pmu_A17 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A17);
value_pmu_A18 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A18);
value_pmu_A20 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A20);
value_pmu_A22 = g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A22);
PRINT("BT power off: after write A12=0x%x, A13=0x%x, A14=0x%x, A15=0x%x, A16=0x%x, A17=0x%x, A18=0x%x, A20=0x%x, A22=0x%x\n",
value_pmu_A12, value_pmu_A13, value_pmu_A14, value_pmu_A15, value_pmu_A16, value_pmu_A17, value_pmu_A18, value_pmu_A20,
value_pmu_A22);
/* clear bt work flag && mask */
g_w1_hif_ops.bt_hi_write_word(RG_BT_PMU_A14, 0x0);
PRINT("BT power off: %s, line=%d\n", __func__, __LINE__);
//PRINT("BT power off:RG_BT_PMU_A14 = 0x%x\n", g_w1_hif_ops.bt_hi_read_word(RG_BT_PMU_A14));
/* set bt pmu fsm to PMU_SLEEP_MODE */
host_req_status = g_w1_hif_ops.hi_bottom_read8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ);
host_req_status |= (PMU_SLEEP_MODE << 1) | BIT(0);
g_w1_hif_ops.hi_bottom_write8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ, host_req_status);
PRINT("BT power off: %s, line=%d\n", __func__, __LINE__);
}
/* clear wifi keep alive, BIT(5)*/
host_req_status = g_w1_hif_ops.hi_bottom_read8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ);
host_req_status &= ~BIT(5);
g_w1_hif_ops.hi_bottom_write8(SDIO_FUNC1, RG_BT_SDIO_PMU_HOST_REQ, host_req_status);
reg_config_complete = 1;
return ret;
}
extern unsigned char wifi_in_insmod;
int bt_aml_sdio_init(void)
{
int ret = 0;
int cnt = 0;
//amlwifi_set_sdio_host_clk(50000000);
if (!w1_sdio_driver_insmoded)
{
PRINT("===start register sdio common driver through bt sdio driver===\n");
aml_w1_sdio_init();
msleep(10);
while (!w1_sdio_after_porbe)
{
PRINT("waiting sdio common driver probe complete\n");
msleep(10);
if ((cnt++) > 500)
{
return (-1);
}
}
}
//if (!strcmp(chip_name, "aml_w1"))
{
while (wifi_in_insmod)
{
PRINT("WIFI in insmod\n");
msleep(10);
}
}
ret = config_bt_pmu_reg(BT_PWR_ON);
return ret;
}
static int btaml_fops_open(struct inode *inode, struct file *file)
{
if (!reg_config_complete)
{
PRINT("%s reg_config_complete is %d return\n",
__func__, reg_config_complete);
return -EFAULT;
}
PRINT("%s reg_config_complete is 1\n", __func__);
printk("\n");
printk("\n");
printk("\n");
return 0;
}
static int amlbt_sdio_probe(struct platform_device *dev)
{
int ret = bt_aml_insmod();
unsigned int reg_value = g_w1_hif_ops.bt_hi_read_word(RG_AON_A15);
printk("%s RG_AON_A15:%#x\n", __func__, reg_value);
reg_value &= ~(1<<31);
reg_value &= ~(1<<30);
g_w1_hif_ops.bt_hi_write_word(RG_AON_A15, reg_value);
printk("RG_AON_A15:%#x", g_w1_hif_ops.bt_hi_read_word(RG_AON_A15));
return ret;
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(6, 11, 0)
static void amlbt_sdio_remove(struct platform_device *dev)
#else
static int amlbt_sdio_remove(struct platform_device *dev)
#endif
{
printk("%s \n", __func__);
bt_aml_rmmod();
#if LINUX_VERSION_CODE > KERNEL_VERSION(6, 11, 0)
return;
#else
return 0;
#endif
}
static int amlbt_sdio_suspend(struct platform_device *dev, pm_message_t state)
{
unsigned int reg_value = g_w1_hif_ops.bt_hi_read_word(RG_AON_A15);
printk("%s RG_AON_A15:%#x\n", __func__, reg_value);
reg_value |= (1<<31);
g_w1_hif_ops.bt_hi_write_word(RG_AON_A15, reg_value);
printk("RG_AON_A15:%#x", g_w1_hif_ops.bt_hi_read_word(RG_AON_A15));
return 0;
}
static int amlbt_sdio_resume(struct platform_device *dev)
{
#ifdef CONFIG_AMLOGIC_GX_SUSPEND
if ((get_resume_method() != 3) && (get_resume_method() != 7))
{
unsigned int reg_value = g_w1_hif_ops.bt_hi_read_word(RG_AON_A15);
printk("%s RG_AON_A15:%#x\n", __func__, reg_value);
reg_value &= ~(1<<31);
g_w1_hif_ops.bt_hi_write_word(RG_AON_A15, reg_value);
printk("RG_AON_A15:%#x", g_w1_hif_ops.bt_hi_read_word(RG_AON_A15));
}
#endif
return 0;
}
static void amlbt_sdio_shutdown(struct platform_device *dev)
{
printk("%s \n", __func__);
}
const struct file_operations BTAML_fops =
{
.open = btaml_fops_open,
.release = NULL,
.read = NULL,
.write = NULL,
.poll = NULL,
.unlocked_ioctl = NULL,
.fasync = NULL
};
static struct platform_driver amlbt_sdio_driver =
{
.probe = amlbt_sdio_probe,
.remove = amlbt_sdio_remove,
.suspend = amlbt_sdio_suspend,
.resume = amlbt_sdio_resume,
.shutdown = amlbt_sdio_shutdown,
.driver = {
.name = "sdio_bt",
.owner = THIS_MODULE,
},
};
static void amlbt_dev_release(struct device* dev)
{
return;
}
static struct platform_device amlbt_sdio_device = {
.name = "sdio_bt",
.id = -1,
.dev = {
.release = &amlbt_dev_release,
}
};
static int BTAML_init(void)
{
int ret = 0;
int cdevErr = 0;
dev_t devID = MKDEV(BTAML_major, 0);
PRINT("BTAML_init\n");
ret = alloc_chrdev_region(&devID, 0, 1, "BT_sdiodev");
if (ret)
{
pr_err("fail to allocate chrdev\n");
return ret;
}
BTAML_major = MAJOR(devID);
PRINT("major number:%d\n", BTAML_major);
cdev_init(&BTAML_cdev, &BTAML_fops);
BTAML_cdev.owner = THIS_MODULE;
cdevErr = cdev_add(&BTAML_cdev, devID, BTAML_devs);
if (cdevErr)
goto error;
PRINT("%s driver(major %d) installed.\n",
"BT_sdiodev", BTAML_major);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 16, 20)
pBTClass = class_create(THIS_MODULE, "BT_sdiodev");
#else
pBTClass = class_create("BT_sdiodev");
#endif
if (IS_ERR(pBTClass))
{
pr_err("class create fail, error code(%ld)\n",
PTR_ERR(pBTClass));
goto err1;
}
pBTDev = device_create(pBTClass, NULL, devID, NULL, BT_NODE);
if (IS_ERR(pBTDev))
{
pr_err("device create fail, error code(%ld)\n",
PTR_ERR(pBTDev));
goto err2;
}
PRINT("%s: BT_major %d\n", __func__, BTAML_major);
PRINT("%s: devID %d\n", __func__, devID);
return 0;
err2:
if (pBTClass)
{
class_destroy(pBTClass);
pBTClass = NULL;
}
err1:
error:
if (cdevErr == 0)
cdev_del(&BTAML_cdev);
if (ret == 0)
unregister_chrdev_region(devID, BTAML_devs);
return -1;
}
static void BTAML_exit(void)
{
dev_t dev = MKDEV(BTAML_major, 0);
PRINT("%s 1\n", __func__);
if (pBTDev)
{
device_destroy(pBTClass, dev);
pBTDev = NULL;
}
PRINT("%s 2\n", __func__);
if (pBTClass)
{
class_destroy(pBTClass);
pBTClass = NULL;
}
PRINT("%s 3\n", __func__);
cdev_del(&BTAML_cdev);
PRINT("%s 4\n", __func__);
unregister_chrdev_region(dev, 1);
PRINT("%s driver removed.\n", BT_DRIVER_NAME);
}
static int bt_aml_insmod(void)
{
int ret = 0;
//if (amlbt_poweron == AML_SDIO_EN)
{
PRINT("BTAML SDIOBT version:%s\n", BT_AML_SDIOBT_VERSION);
PRINT("++++++sdio bt driver insmod start.++++++\n");
reg_config_complete = 0;
set_wifi_bt_sdio_driver_bit(REGISTER_BT_SDIO, BT_BIT);
ret = bt_aml_sdio_init();
if (ret)
{
pr_err("%s: bt sdio driver init failed!\n", __func__);
return ret;
}
ret = BTAML_init();
if (ret)
{
pr_err("%s: BTAML_init failed!\n", __func__);
return ret;
}
}
PRINT("------sdio bt driver insmod end.------\n");
return ret;
}
static void bt_aml_rmmod(void)
{
//if (amlbt_poweron == AML_SDIO_EN)
{
printk("\n");
printk("\n");
printk("\n");
PRINT("++++++sdio bt driver rmmod start.++++++\n");
while (wifi_in_insmod)
{
PRINT("WIFI in insmod\n");
msleep(10);
}
config_bt_pmu_reg(BT_PWR_OFF);
set_wifi_bt_sdio_driver_bit(UNREGISTER_BT_SDIO, BT_BIT);
BTAML_exit();
PRINT("------sdio bt driver rmmod end.------\n");
printk("\n");
printk("\n");
printk("\n");
}
}
static int __init amlbt_sdio_init(void)
{
int ret = 0;
ret = platform_device_register(&amlbt_sdio_device);
if (ret)
{
dev_err(&amlbt_sdio_device.dev, "platform_device_register failed!\n");
return ret;
}
ret = platform_driver_register(&amlbt_sdio_driver);
if (ret)
{
dev_err(&amlbt_sdio_device.dev, "platform_driver_register failed!\n");
return ret;
}
dev_info(&amlbt_sdio_device.dev, "Init %s OK!\n", "sdio_bt");
return ret;
}
static void __exit amlbt_sdio_exit(void)
{
platform_driver_unregister(&amlbt_sdio_driver);
platform_device_unregister(&amlbt_sdio_device);
}
module_param(chip_name, charp, S_IRUGO);
module_init(amlbt_sdio_init);
module_exit(amlbt_sdio_exit);
MODULE_LICENSE("GPL");