1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2025-09-16 03:59:21 +00:00
Files
physwizz 99537be4e2 first
2024-03-11 06:53:12 +11:00

328 lines
8.0 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include "ccci_debug.h"
#include "ccci_config.h"
#include "ccci_common_config.h"
#include "ccci_modem.h"
#include "ccci_swtp.h"
#include "ccci_fsm.h"
/* must keep ARRAY_SIZE(swtp_of_match) = ARRAY_SIZE(irq_name) */
const struct of_device_id swtp_of_match[] = {
{ .compatible = SWTP_COMPATIBLE_DEVICE_ID, },
{ .compatible = SWTP1_COMPATIBLE_DEVICE_ID,},
{ .compatible = SWTP2_COMPATIBLE_DEVICE_ID,},
{ .compatible = SWTP3_COMPATIBLE_DEVICE_ID,},
{ .compatible = SWTP4_COMPATIBLE_DEVICE_ID,},
{},
};
static const char irq_name[][16] = {
"swtp0-eint",
"swtp1-eint",
"swtp2-eint",
"swtp3-eint",
"swtp4-eint",
"",
};
#define SWTP_MAX_SUPPORT_MD 1
struct swtp_t swtp_data[SWTP_MAX_SUPPORT_MD];
static const char rf_name[] = "RF_cable";
#define MAX_RETRY_CNT 30
static int swtp_send_tx_power(struct swtp_t *swtp)
{
unsigned long flags;
int power_mode, ret = 0;
if (swtp == NULL) {
CCCI_LEGACY_ERR_LOG(-1, SYS, "%s:swtp is null\n", __func__);
return -1;
}
spin_lock_irqsave(&swtp->spinlock, flags);
ret = exec_ccci_kern_func_by_md_id(swtp->md_id, ID_UPDATE_TX_POWER,
(char *)&swtp->tx_power_mode, sizeof(swtp->tx_power_mode));
power_mode = swtp->tx_power_mode;
spin_unlock_irqrestore(&swtp->spinlock, flags);
if (ret != 0)
CCCI_LEGACY_ERR_LOG(swtp->md_id, SYS,
"%s to MD%d,state=%d,ret=%d\n",
__func__, swtp->md_id + 1, power_mode, ret);
return ret;
}
static int swtp_switch_state(int irq, struct swtp_t *swtp)
{
unsigned long flags;
int i;
if (swtp == NULL) {
CCCI_LEGACY_ERR_LOG(-1, SYS, "%s:data is null\n", __func__);
return -1;
}
spin_lock_irqsave(&swtp->spinlock, flags);
for (i = 0; i < MAX_PIN_NUM; i++) {
if (swtp->irq[i] == irq)
break;
}
if (i == MAX_PIN_NUM) {
spin_unlock_irqrestore(&swtp->spinlock, flags);
CCCI_LEGACY_ERR_LOG(-1, SYS,
"%s:can't find match irq\n", __func__);
return -1;
}
if (swtp->eint_type[i] == IRQ_TYPE_LEVEL_LOW) {
irq_set_irq_type(swtp->irq[i], IRQ_TYPE_LEVEL_HIGH);
swtp->eint_type[i] = IRQ_TYPE_LEVEL_HIGH;
} else {
irq_set_irq_type(swtp->irq[i], IRQ_TYPE_LEVEL_LOW);
swtp->eint_type[i] = IRQ_TYPE_LEVEL_LOW;
}
if (swtp->gpio_state[i] == SWTP_EINT_PIN_PLUG_IN)
swtp->gpio_state[i] = SWTP_EINT_PIN_PLUG_OUT;
else
swtp->gpio_state[i] = SWTP_EINT_PIN_PLUG_IN;
swtp->tx_power_mode = SWTP_NO_TX_POWER;
for (i = 0; i < MAX_PIN_NUM; i++) {
if (swtp->gpio_state[i] == SWTP_EINT_PIN_PLUG_IN) {
swtp->tx_power_mode = SWTP_DO_TX_POWER;
break;
}
}
inject_pin_status_event(swtp->curr_mode, rf_name);
spin_unlock_irqrestore(&swtp->spinlock, flags);
return swtp->tx_power_mode;
}
static void swtp_send_tx_power_state(struct swtp_t *swtp)
{
int ret = 0;
if (!swtp) {
CCCI_LEGACY_ERR_LOG(-1, SYS,
"%s:swtp is null\n", __func__);
return;
}
if (swtp->md_id == 0) {
ret = swtp_send_tx_power(swtp);
if (ret < 0) {
CCCI_LEGACY_ERR_LOG(swtp->md_id, SYS,
"%s send tx power failed, ret=%d, schedule delayed work\n",
__func__, ret);
schedule_delayed_work(&swtp->delayed_work, 5 * HZ);
}
} else
CCCI_LEGACY_ERR_LOG(swtp->md_id, SYS,
"%s:md is no support\n", __func__);
}
static irqreturn_t swtp_irq_handler(int irq, void *data)
{
struct swtp_t *swtp = (struct swtp_t *)data;
int ret = 0;
ret = swtp_switch_state(irq, swtp);
if (ret < 0) {
CCCI_LEGACY_ERR_LOG(swtp->md_id, SYS,
"%s swtp_switch_state failed in irq, ret=%d\n",
__func__, ret);
} else
swtp_send_tx_power_state(swtp);
return IRQ_HANDLED;
}
static void swtp_tx_delayed_work(struct work_struct *work)
{
struct swtp_t *swtp = container_of(to_delayed_work(work),
struct swtp_t, delayed_work);
int ret, retry_cnt = 0;
while (retry_cnt < MAX_RETRY_CNT) {
ret = swtp_send_tx_power(swtp);
if (ret != 0) {
msleep(2000);
retry_cnt++;
} else
break;
}
}
int swtp_md_tx_power_req_hdlr(int md_id, int data)
{
struct swtp_t *swtp = NULL;
#ifdef CUST_FT_SEND_TX_POWER
unsigned long flags;
#endif
if (md_id < 0 || md_id >= SWTP_MAX_SUPPORT_MD) {
CCCI_LEGACY_ERR_LOG(md_id, SYS,
"%s:md_id=%d not support\n",
__func__, md_id);
return -1;
}
swtp = &swtp_data[md_id];
#ifdef CUST_FT_SEND_TX_POWER
/*default do tx power for special use*/
spin_lock_irqsave(&swtp->spinlock, flags);
swtp->tx_power_mode = SWTP_DO_TX_POWER;
spin_unlock_irqrestore(&swtp->spinlock, flags);
#endif
swtp_send_tx_power_state(swtp);
return 0;
}
static void swtp_init_delayed_work(struct work_struct *work)
{
struct swtp_t *swtp = container_of(to_delayed_work(work),
struct swtp_t, init_delayed_work);
int md_id;
int i, ret = 0;
#ifdef CONFIG_MTK_EIC
u32 ints[2] = { 0, 0 };
#else
u32 ints[1] = { 0 };
#endif
u32 ints1[2] = { 0, 0 };
struct device_node *node = NULL;
CCCI_NORMAL_LOG(-1, SYS, "%s start\n", __func__);
CCCI_BOOTUP_LOG(-1, SYS, "%s start\n", __func__);
md_id = swtp->md_id;
if (md_id < 0 || md_id >= SWTP_MAX_SUPPORT_MD) {
ret = -2;
CCCI_LEGACY_ERR_LOG(-1, SYS,
"%s: invalid md_id = %d\n", __func__, md_id);
goto SWTP_INIT_END;
}
if (ARRAY_SIZE(swtp_of_match) != ARRAY_SIZE(irq_name) ||
ARRAY_SIZE(swtp_of_match) > MAX_PIN_NUM + 1 ||
ARRAY_SIZE(irq_name) > MAX_PIN_NUM + 1) {
ret = -3;
CCCI_LEGACY_ERR_LOG(-1, SYS,
"%s: invalid array count = %lu(of_match), %lu(irq_name)\n",
__func__, ARRAY_SIZE(swtp_of_match),
ARRAY_SIZE(irq_name));
goto SWTP_INIT_END;
}
for (i = 0; i < MAX_PIN_NUM; i++)
swtp_data[md_id].gpio_state[i] = SWTP_EINT_PIN_PLUG_OUT;
for (i = 0; i < MAX_PIN_NUM; i++) {
node = of_find_matching_node(NULL, &swtp_of_match[i]);
if (node) {
ret = of_property_read_u32_array(node, "debounce",
ints, ARRAY_SIZE(ints));
if (ret) {
CCCI_LEGACY_ERR_LOG(md_id, SYS,
"%s:swtp%d get debounce fail\n",
__func__, i);
break;
}
ret = of_property_read_u32_array(node, "interrupts",
ints1, ARRAY_SIZE(ints1));
if (ret) {
CCCI_LEGACY_ERR_LOG(md_id, SYS,
"%s:swtp%d get interrupts fail\n",
__func__, i);
break;
}
#ifdef CONFIG_MTK_EIC /* for chips before mt6739 */
swtp_data[md_id].gpiopin[i] = ints[0];
swtp_data[md_id].setdebounce[i] = ints[1];
#else /* for mt6739,and chips after mt6739 */
swtp_data[md_id].setdebounce[i] = ints[0];
swtp_data[md_id].gpiopin[i] =
of_get_named_gpio(node, "deb-gpios", 0);
#endif
gpio_set_debounce(swtp_data[md_id].gpiopin[i],
swtp_data[md_id].setdebounce[i]);
swtp_data[md_id].eint_type[i] = ints1[1];
swtp_data[md_id].irq[i] = irq_of_parse_and_map(node, 0);
ret = request_irq(swtp_data[md_id].irq[i],
swtp_irq_handler, IRQF_TRIGGER_NONE,
irq_name[i], &swtp_data[md_id]);
if (ret) {
CCCI_LEGACY_ERR_LOG(md_id, SYS,
"swtp%d-eint IRQ LINE NOT AVAILABLE\n",
i);
break;
}
} else {
CCCI_LEGACY_ERR_LOG(md_id, SYS,
"%s:can't find swtp%d compatible node\n",
__func__, i);
ret = -4;
}
}
register_ccci_sys_call_back(md_id, MD_SW_MD1_TX_POWER_REQ,
swtp_md_tx_power_req_hdlr);
SWTP_INIT_END:
CCCI_BOOTUP_LOG(md_id, SYS, "%s end: ret = %d\n", __func__, ret);
CCCI_NORMAL_LOG(md_id, SYS, "%s end: ret = %d\n", __func__, ret);
return;
}
int swtp_init(int md_id)
{
/* parameter check */
if (md_id < 0 || md_id >= SWTP_MAX_SUPPORT_MD) {
CCCI_LEGACY_ERR_LOG(-1, SYS,
"%s: invalid md_id = %d\n", __func__, md_id);
return -1;
}
/* init woke setting */
swtp_data[md_id].md_id = md_id;
INIT_DELAYED_WORK(&swtp_data[md_id].init_delayed_work,
swtp_init_delayed_work);
/* tx work setting */
INIT_DELAYED_WORK(&swtp_data[md_id].delayed_work,
swtp_tx_delayed_work);
swtp_data[md_id].tx_power_mode = SWTP_NO_TX_POWER;
spin_lock_init(&swtp_data[md_id].spinlock);
/* schedule init work */
schedule_delayed_work(&swtp_data[md_id].init_delayed_work, HZ);
CCCI_BOOTUP_LOG(md_id, SYS, "%s end, init_delayed_work scheduled\n",
__func__);
return 0;
}