190 lines
3.4 KiB
C
190 lines
3.4 KiB
C
/*
|
|
* xr806/hwio.c
|
|
*
|
|
* Copyright (c) 2022
|
|
* Allwinner Technology Co., Ltd. <www.allwinner.com>
|
|
* laumy <liumingyuan@allwinner.com>
|
|
*
|
|
* hardware interface implementation for Xr806 drivers
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
*/
|
|
#include "os_intf.h"
|
|
#include "xradio.h"
|
|
#include "hwio.h"
|
|
#include "spi.h"
|
|
#include "txrx.h"
|
|
#include "debug.h"
|
|
|
|
#define SPI_BUF_SIZE 1536
|
|
|
|
#define IO_WAIT_TIME_S 10
|
|
|
|
static struct xradio_bus_ops *ops;
|
|
|
|
void xradio_hwio_rx_irq(void *arg)
|
|
{
|
|
if (!arg)
|
|
return;
|
|
|
|
xradio_wake_up_rx_work(arg);
|
|
}
|
|
|
|
int xradio_hwio_init(void *priv)
|
|
{
|
|
ops = xradio_get_bus_ops();
|
|
if (!ops)
|
|
return -EFAULT;
|
|
|
|
if (ops->init(priv))
|
|
return -1;
|
|
|
|
if (ops->gpio_init()) {
|
|
ops->deinit(priv);
|
|
return -1;
|
|
}
|
|
|
|
if (ops->reg_rx_ind(xradio_hwio_rx_irq)) {
|
|
ops->gpio_deinit();
|
|
ops->deinit(priv);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int xradio_hwio_deinit(void *priv)
|
|
{
|
|
ops->gpio_deinit();
|
|
|
|
ops->deinit(priv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xradio_write_response(void)
|
|
{
|
|
u8 res[8];
|
|
unsigned long delay;
|
|
|
|
// wait dev enter write state(gpio == 0)
|
|
delay = jiffies + IO_WAIT_TIME_S * HZ;
|
|
while (ops->read_rw_gpio()) {
|
|
if (time_after(jiffies, delay))
|
|
return -1;
|
|
xradio_k_usleep(1);
|
|
}
|
|
|
|
if (!ops->read(res, 8))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int xradio_hwio_write(struct sk_buff *skb)
|
|
{
|
|
unsigned long delay;
|
|
|
|
if (!ops || !ops->write)
|
|
return -EFAULT;
|
|
|
|
if (!skb) {
|
|
hwio_printk(XRADIO_DBG_ERROR, "skb invaild\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
// wait dev enter read state(gpio == 1)
|
|
delay = jiffies + IO_WAIT_TIME_S * HZ;
|
|
while (!ops->read_rw_gpio()) {
|
|
if (time_after(jiffies, delay)) {
|
|
hwio_printk(XRADIO_DBG_ERROR, "write data wait dev read state faild\n");
|
|
return -1;
|
|
}
|
|
xradio_k_usleep(300);
|
|
}
|
|
|
|
if (ops->write(skb->data, skb->len)) {
|
|
hwio_printk(XRADIO_DBG_ERROR, "write data error\n");
|
|
return -1;
|
|
}
|
|
|
|
if (xradio_write_response() != 0) {
|
|
hwio_printk(XRADIO_DBG_ERROR, "write rsp error\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int xradio_read_request(void)
|
|
{
|
|
u8 req[8] = {0, 0, 2, 0, 0, 0, 0, 0};
|
|
unsigned long delay;
|
|
// wait dev enter read state(gpio == 1)
|
|
delay = jiffies + IO_WAIT_TIME_S * HZ;
|
|
while (!ops->read_rw_gpio()) {
|
|
if (time_after(jiffies, delay))
|
|
return -1;
|
|
xradio_k_usleep(1);
|
|
}
|
|
|
|
return ops->write(req, 8);
|
|
}
|
|
|
|
struct sk_buff *xradio_hwio_read(u16 len)
|
|
{
|
|
struct sk_buff *rx_skb = NULL;
|
|
u8 *buf = NULL;
|
|
unsigned long delay;
|
|
|
|
if (!ops || !ops->read)
|
|
return NULL;
|
|
|
|
if (xradio_read_request()) {
|
|
hwio_printk(XRADIO_DBG_ERROR, "read request failed\n");
|
|
return NULL;
|
|
}
|
|
|
|
// wait dev enter write state(gpio == 0)
|
|
delay = jiffies + IO_WAIT_TIME_S * HZ;
|
|
while (ops->read_rw_gpio()) {
|
|
if (time_after(jiffies, delay))
|
|
return NULL;
|
|
xradio_k_usleep(1);
|
|
}
|
|
|
|
if (len == 0 || len > SPI_BUF_SIZE)
|
|
len = SPI_BUF_SIZE;
|
|
|
|
rx_skb = xradio_alloc_skb(len, __func__);
|
|
|
|
buf = skb_put(rx_skb, len);
|
|
|
|
memset(buf, 0, len);
|
|
|
|
if (ops->read(buf, len) < 0)
|
|
goto end;
|
|
|
|
if (buf[0] == 0 && buf[1] == 0) {
|
|
// hwio_printk(XRADIO_DBG_ERROR, "read data is exception.\n");
|
|
goto end;
|
|
}
|
|
|
|
return rx_skb;
|
|
|
|
end:
|
|
xradio_free_skb(rx_skb, __func__);
|
|
return NULL;
|
|
}
|
|
|
|
int xradio_hwio_rx_pending(void)
|
|
{
|
|
if (!ops || !ops->read_rx_gpio)
|
|
return 0;
|
|
|
|
return ops->read_rx_gpio();
|
|
}
|