mirror of
https://gitee.com/open-loongarch/linux-5.10.git
synced 2026-10-25 12:47:11 +08:00
update to b8ae5357def2c
1.Support RTL8821CU_BT USB-BlueTooth 2.pwm: support analy polarity from dts pwm desc node and setup polarity as normal default 3.2K300 OTG:Optimize otg compatibility 4.FT5426: Fix reset GPIO Dump 5.perf: Fix perf compile error 6.dts:ls2k300:Correct label of spi 7.2K300: drivers/net/can/spi: mcp251x: Fix mcp251x irq bug 8.2K300-G2K03Z02: dts: spi-flash: Lower spi flash frequency 9.2k300: i2c: refactor to improve stablility
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/clock/loongson2k1000-clock.h>
|
||||
#include <dt-bindings/usb/dwc2-loongson-fix.h>
|
||||
|
||||
/ {
|
||||
model = "loongson-2k1000";
|
||||
@@ -505,12 +506,14 @@
|
||||
};
|
||||
|
||||
otg: otg@40000000 {
|
||||
compatible = "loongson,dwc2-otg";
|
||||
compatible = "loongson,loongson2-dwc2";
|
||||
reg = <0 0x40000000 0 0x40000>;
|
||||
interrupt-parent = <&icu>;
|
||||
interrupts = <49>;
|
||||
dma-mask = <0x0 0xffffffff>;
|
||||
status = "disabled";
|
||||
/* 2k1000 暂时不用修正 */
|
||||
loongson,dwc2-fix = <DWC2_LOONGSON_FIX_NONE>;
|
||||
};
|
||||
|
||||
ohci@40070000 {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/dts-v1/;
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/clock/loongson2k300-clock.h>
|
||||
#include <dt-bindings/usb/dwc2-loongson-fix.h>
|
||||
|
||||
/ {
|
||||
model = "loongson,generic";
|
||||
@@ -163,10 +164,23 @@
|
||||
pinctrl-single,bits = <0x14 0x00000a00 0x000000f00>;
|
||||
};
|
||||
|
||||
spi0_as_gpio_pins: pinmux_G56_G79_as_gpio {
|
||||
pinctrl-single,bits = <0xc 0x00000000 0x00ff0000>;
|
||||
};
|
||||
|
||||
spi0_full_cs_pins: pinmux_G56_G70_as_spi1 {
|
||||
pinctrl-single,bits = <0xc 0x00ff0000 0x00ff0000
|
||||
0x10 0x00005500 0x0000ff00>;
|
||||
};
|
||||
|
||||
spi1_pins: pinmux_G60_G63_as_spi1 {
|
||||
pinctrl-single,bits = <0xc 0xff000000 0xff000000>;
|
||||
};
|
||||
|
||||
spi1_as_gpio_pins: pinmux_G60_G63_as_gpio {
|
||||
pinctrl-single,bits = <0xc 0x00000000 0xff000000>;
|
||||
};
|
||||
|
||||
spi2_pins: pinmux_G64_G67_as_spi2 {
|
||||
pinctrl-single,bits = <0x10 0x000000ff 0x000000ff>;
|
||||
};
|
||||
@@ -232,10 +246,18 @@
|
||||
pinctrl-single,bits = <0x14 0x0000000c 0x0000000c>;
|
||||
};
|
||||
|
||||
tim1_ch1n_as_gpio:pinmux_G84_as_gpio{
|
||||
pinctrl-single,bits = <0x14 0x00000000 0x000000300>;
|
||||
};
|
||||
|
||||
tim1_ch1n:pinmux_G84_as_tim1_ch1n {
|
||||
pinctrl-single,bits = <0x14 0x00000300 0x000000300>;
|
||||
};
|
||||
|
||||
tim1_ch2n_as_gpio:pinmux_G85_as_gpio{
|
||||
pinctrl-single,bits = <0x14 0x00000000 0x000000c00>;
|
||||
};
|
||||
|
||||
tim1_ch2n:pinmux_G85_as_tim1_ch2n {
|
||||
pinctrl-single,bits = <0x14 0x00000c00 0x000000c00>;
|
||||
};
|
||||
@@ -610,7 +632,7 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spi2: spi@0x1601c000 {
|
||||
spi2: spi@0x1610c000 {
|
||||
compatible = "loongson,ls-spi-io";
|
||||
reg = <0 0x1610c000 0 0x2000>;
|
||||
#address-cells = <1>;
|
||||
@@ -621,7 +643,7 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spi3: spi@0x1601e000 {
|
||||
spi3: spi@0x1610e000 {
|
||||
compatible = "loongson,ls-spi-io";
|
||||
reg = <0 0x1610e000 0 0x2000>;
|
||||
#address-cells = <1>;
|
||||
@@ -738,12 +760,16 @@
|
||||
dma-mask = <0x0 0xffffffff>;
|
||||
};
|
||||
|
||||
otg@0x16040000 {
|
||||
otg: otg@0x16040000 {
|
||||
compatible = "loongson,loongson2-dwc2";
|
||||
reg = <0 0x16040000 0 0x40000>;
|
||||
interrupt-parent = <&icu>;
|
||||
interrupts = <48>;
|
||||
dma-mask = <0x0 0xffffffff>;
|
||||
/* Use for most devices */
|
||||
//loongson,dwc2-fix = <DWC2_LOONGSON_FIX_DMA>;
|
||||
/* Use for 4G model*/
|
||||
loongson,dwc2-fix = <DWC2_LOONGSON_FIX_DELAY>;
|
||||
//dr_mode = "peripheral";
|
||||
/* Optional for that dr_mode = "host" or dr_mode = "peripheral" */
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/clock/loongson2k500-clock.h>
|
||||
#include <dt-bindings/usb/dwc2-loongson-fix.h>
|
||||
/dts-v1/;
|
||||
/ {
|
||||
model = "loongson,generic";
|
||||
@@ -1014,12 +1015,14 @@
|
||||
};
|
||||
|
||||
otg: otg@1f080000 {
|
||||
compatible = "loongson,dwc2-otg";
|
||||
compatible = "loongson,loongson2-dwc2";
|
||||
reg = <0 0x1f080000 0 0x40000>;
|
||||
interrupt-parent = <&extioiic>;
|
||||
interrupts = <73>;
|
||||
dma-mask = <0x0 0xffffffff>;
|
||||
status = "disabled";
|
||||
/* 2k500 暂时不用修正 */
|
||||
loongson,dwc2-fix = <DWC2_LOONGSON_FIX_NONE>;
|
||||
};
|
||||
|
||||
pwm0: pwm@1ff5c000 {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
spi-flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <25000000>;
|
||||
spi-max-frequency = <1000000>;
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -425,4 +425,10 @@ config BT_HCIRSI
|
||||
Say Y here to compile support for HCI over Redpine into the
|
||||
kernel or say M to compile as a module.
|
||||
|
||||
config BT_RTKUSB
|
||||
tristate "RTK USB driver"
|
||||
depends on USB
|
||||
help
|
||||
Bluetooth RTK USB driver.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -46,3 +46,6 @@ hci_uart-$(CONFIG_BT_HCIUART_QCA) += hci_qca.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_AG6XX) += hci_ag6xx.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_MRVL) += hci_mrvl.o
|
||||
hci_uart-objs := $(hci_uart-y)
|
||||
|
||||
rtk_btusb-y = rtk_coex.o rtk_bt.o
|
||||
obj-$(CONFIG_BT_RTKUSB) := rtk_btusb.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB driver
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/hci.h>
|
||||
|
||||
/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */
|
||||
#define HCI_VERSION_CODE LINUX_VERSION_CODE
|
||||
|
||||
#define BTCOEX
|
||||
|
||||
#if 1
|
||||
#define RTKBT_DBG(fmt, arg...) printk(KERN_INFO "rtk_btusb: " fmt "\n" , ## arg)
|
||||
#define RTKBT_INFO(fmt, arg...) printk(KERN_INFO "rtk_btusb: " fmt "\n" , ## arg)
|
||||
#define RTKBT_WARN(fmt, arg...) printk(KERN_WARNING "rtk_btusb: " fmt "\n", ## arg)
|
||||
#else
|
||||
#define RTKBT_DBG(fmt, arg...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define RTKBT_ERR(fmt, arg...) printk(KERN_ERR "rtk_btusb: " fmt "\n" , ## arg)
|
||||
#else
|
||||
#define RTKBT_ERR(fmt, arg...)
|
||||
#endif
|
||||
|
||||
/***********************************
|
||||
** Realtek - For rtk_btusb driver **
|
||||
***********************************/
|
||||
#define BTUSB_RPM 0* USB_RPM // 1 SS enable; 0 SS disable
|
||||
#define BTUSB_WAKEUP_HOST 0 /* 1 enable; 0 disable */
|
||||
|
||||
/* If, when os suspend, module is still powered,
|
||||
* no needs binding, and must comply with special patch code
|
||||
*/
|
||||
#define CONFIG_NEEDS_BINDING 1
|
||||
|
||||
#define URB_CANCELING_DELAY_MS 10 // Added by Realtek
|
||||
#define PRINT_CMD_EVENT 0
|
||||
#define PRINT_ACL_DATA 0
|
||||
|
||||
#if HCI_VERSION_CODE > KERNEL_VERSION(2, 6, 33)
|
||||
#define HDEV_BUS hdev->bus
|
||||
#else
|
||||
#define HDEV_BUS hdev->type
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 33)
|
||||
#define USB_RPM 1
|
||||
#else
|
||||
#define USB_RPM 0
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
|
||||
#define NUM_REASSEMBLY 3
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
|
||||
#define GET_DRV_DATA(x) hci_get_drvdata(x)
|
||||
#else
|
||||
#define GET_DRV_DATA(x) x->driver_data
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
#define SCO_NUM hdev->conn_hash.sco_num
|
||||
#else
|
||||
#define SCO_NUM hci_conn_num(hdev, SCO_LINK)
|
||||
#endif
|
||||
|
||||
int patch_add(struct usb_interface *intf);
|
||||
void patch_remove(struct usb_interface *intf);
|
||||
int download_patch(struct usb_interface *intf);
|
||||
int set_btoff(struct usb_interface *intf);
|
||||
void print_event(struct sk_buff *skb);
|
||||
void print_command(struct sk_buff *skb);
|
||||
void print_acl(struct sk_buff *skb, int dataOut);
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
|
||||
int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
#else
|
||||
int btusb_send_frame(struct sk_buff *skb);
|
||||
#endif
|
||||
|
||||
#define BTUSB_MAX_ISOC_FRAMES 10
|
||||
#define BTUSB_INTR_RUNNING 0
|
||||
#define BTUSB_BULK_RUNNING 1
|
||||
#define BTUSB_ISOC_RUNNING 2
|
||||
#define BTUSB_SUSPENDING 3
|
||||
#define BTUSB_DID_ISO_RESUME 4
|
||||
|
||||
struct btusb_data {
|
||||
struct hci_dev *hdev;
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct usb_interface *isoc;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
struct work_struct work;
|
||||
struct work_struct waker;
|
||||
|
||||
struct usb_anchor tx_anchor;
|
||||
struct usb_anchor intr_anchor;
|
||||
struct usb_anchor bulk_anchor;
|
||||
struct usb_anchor isoc_anchor;
|
||||
struct usb_anchor deferred;
|
||||
int tx_in_flight;
|
||||
spinlock_t txlock;
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
spinlock_t rxlock;
|
||||
struct sk_buff *evt_skb;
|
||||
struct sk_buff *acl_skb;
|
||||
struct sk_buff *sco_skb;
|
||||
#endif
|
||||
|
||||
struct usb_endpoint_descriptor *intr_ep;
|
||||
struct usb_endpoint_descriptor *bulk_tx_ep;
|
||||
struct usb_endpoint_descriptor *bulk_rx_ep;
|
||||
struct usb_endpoint_descriptor *isoc_tx_ep;
|
||||
struct usb_endpoint_descriptor *isoc_rx_ep;
|
||||
|
||||
__u8 cmdreq_type;
|
||||
|
||||
unsigned int sco_num;
|
||||
int isoc_altsetting;
|
||||
int suspend_count;
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
int (*recv_bulk) (struct btusb_data * data, void *buffer, int count);
|
||||
#endif
|
||||
};
|
||||
|
||||
#define HCI_CMD_READ_BD_ADDR 0x1009
|
||||
#define HCI_VENDOR_CHANGE_BDRATE 0xfc17
|
||||
#define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d
|
||||
#define HCI_VENDOR_READ_LMP_VERISION 0x1001
|
||||
|
||||
#define ROM_LMP_NONE 0x0000
|
||||
#define ROM_LMP_8723a 0x1200
|
||||
#define ROM_LMP_8723b 0x8723
|
||||
#define ROM_LMP_8821a 0X8821
|
||||
#define ROM_LMP_8761a 0X8761
|
||||
#define ROM_LMP_8822b 0X8822
|
||||
|
||||
struct rtk_eversion_evt {
|
||||
uint8_t status;
|
||||
uint8_t version;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtk_epatch_entry {
|
||||
uint16_t chipID;
|
||||
uint16_t patch_length;
|
||||
uint32_t start_offset;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtk_epatch {
|
||||
uint8_t signature[8];
|
||||
uint32_t fw_version;
|
||||
uint16_t number_of_total_patch;
|
||||
struct rtk_epatch_entry entry[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtk_extension_entry {
|
||||
uint8_t opcode;
|
||||
uint8_t length;
|
||||
uint8_t *data;
|
||||
} __attribute__ ((packed));
|
||||
/* Realtek - For rtk_btusb driver end */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,335 @@
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
/***********************************
|
||||
** Realtek - For coexistence **
|
||||
***********************************/
|
||||
#define BTRTL_HCIUSB 0
|
||||
#define BTRTL_HCIUART 1
|
||||
|
||||
#define BTRTL_HCI_IF BTRTL_HCIUSB
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define CONNECT_PORT 30001
|
||||
#define CONNECT_PORT_WIFI 30000
|
||||
|
||||
#define invite_req "INVITE_REQ"
|
||||
#define invite_rsp "INVITE_RSP"
|
||||
#define attend_req "ATTEND_REQ"
|
||||
#define attend_ack "ATTEND_ACK"
|
||||
#define wifi_leave "WIFI_LEAVE"
|
||||
#define leave_ack "LEAVE_ACK"
|
||||
#define bt_leave "BT_LEAVE"
|
||||
|
||||
#define HCI_OP_PERIODIC_INQ 0x0403
|
||||
#define HCI_EV_LE_META 0x3e
|
||||
#define HCI_EV_LE_CONN_COMPLETE 0x01
|
||||
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
|
||||
|
||||
//vendor cmd to fw
|
||||
#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND 0xfc18
|
||||
#define HCI_VENDOR_SET_PROFILE_REPORT_COMMAND 0xfc19
|
||||
#define HCI_VENDOR_MAILBOX_CMD 0xfc8f
|
||||
#define HCI_VENDOR_SET_BITPOOL 0xfc51
|
||||
|
||||
//subcmd to fw
|
||||
#define HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD 0x11
|
||||
#define HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD 0x17
|
||||
#define HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD 0x1B
|
||||
#define HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO 0x23
|
||||
#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_STATUS_INFO 0x27
|
||||
#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE 0x28
|
||||
#define HCI_VENDOR_SUB_CMD_BT_SET_TXRETRY_REPORT_PARAM 0x29
|
||||
#define HCI_VENDOR_SUB_CMD_BT_SET_PTATABLE 0x2A
|
||||
#define HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE 0x31
|
||||
#define HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT 0x32
|
||||
#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L 0x40
|
||||
#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M 0x41
|
||||
#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H 0x42
|
||||
#define HCI_VENDOR_SUB_CMD_RD_REG_REQ 0x43
|
||||
#define HCI_VENDOR_SUB_CMD_WR_REG_REQ 0x44
|
||||
|
||||
#define HCI_EV_VENDOR_SPECIFIC 0xff
|
||||
|
||||
//sub event from fw start
|
||||
#define HCI_VENDOR_PTA_REPORT_EVENT 0x24
|
||||
#define HCI_VENDOR_PTA_AUTO_REPORT_EVENT 0x25
|
||||
|
||||
//vendor cmd to wifi driver
|
||||
#define HCI_GRP_VENDOR_SPECIFIC (0x3f << 10)
|
||||
#define HCI_OP_HCI_EXTENSION_VERSION_NOTIFY (0x0100 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_BT_OPERATION_NOTIFY (0x0102 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_INFO_NOTIFY (0x0106 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_COEX_NOTIFY (0x0107 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_PATCH_VER_NOTIFY (0x0108 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_AFH_MAP_NOTIFY (0x0109 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY (0x010a | HCI_GRP_VENDOR_SPECIFIC)
|
||||
|
||||
//bt info reason to wifi
|
||||
#define HOST_RESPONSE 0 //Host response when receive the BT Info Control Event
|
||||
#define POLLING_RESPONSE 1 //The BT Info response for polling by BT firmware.
|
||||
#define AUTO_REPORT 2 //BT auto report by BT firmware.
|
||||
#define STACK_REPORT_WHILE_DEVICE_D2 3 //Stack report when BT firmware is under power save state(ex:D2)
|
||||
|
||||
// vendor event from wifi
|
||||
#define RTK_HS_EXTENSION_EVENT_WIFI_SCAN 0x01
|
||||
#define RTK_HS_EXTENSION_EVENT_RADIO_STATUS_NOTIFY 0x02
|
||||
#define RTK_HS_EXTENSION_EVENT_HCI_BT_INFO_CONTROL 0x03
|
||||
#define RTK_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL 0x04
|
||||
|
||||
//op code from wifi
|
||||
#define BT_PATCH_VERSION_QUERY 0x00
|
||||
#define IGNORE_WLAN_ACTIVE_CONTROL 0x01
|
||||
#define LNA_CONSTRAIN_CONTROL 0x02
|
||||
#define BT_POWER_DECREASE_CONTROL 0x03
|
||||
#define BT_PSD_MODE_CONTROL 0x04
|
||||
#define WIFI_BW_CHNL_NOTIFY 0x05
|
||||
#define QUERY_BT_AFH_MAP 0x06
|
||||
#define BT_REGISTER_ACCESS 0x07
|
||||
|
||||
//bt operation to notify
|
||||
#define BT_OPCODE_NONE 0
|
||||
#define BT_OPCODE_INQUIRY_START 1
|
||||
#define BT_OPCODE_INQUIRY_END 2
|
||||
#define BT_OPCODE_PAGE_START 3
|
||||
#define BT_OPCODE_PAGE_SUCCESS_END 4
|
||||
#define BT_OPCODE_PAGE_UNSUCCESS_END 5
|
||||
#define BT_OPCODE_PAIR_START 6
|
||||
#define BT_OPCODE_PAIR_END 7
|
||||
#define BT_OPCODE_ENABLE_BT 8
|
||||
#define BT_OPCODE_DISABLE_BT 9
|
||||
|
||||
#define HCI_EXTENSION_VERSION 0x0004
|
||||
#define HCI_CMD_PREAMBLE_SIZE 3
|
||||
#define PAN_PACKET_COUNT 5
|
||||
|
||||
#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;}
|
||||
#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);}
|
||||
|
||||
#define PSM_SDP 0x0001
|
||||
#define PSM_RFCOMM 0x0003
|
||||
#define PSM_PAN 0x000F
|
||||
#define PSM_HID 0x0011
|
||||
#define PSM_HID_INT 0x0013
|
||||
#define PSM_AVCTP 0x0017
|
||||
#define PSM_AVDTP 0x0019
|
||||
#define PSM_FTP 0x1001
|
||||
#define PSM_BIP 0x1003
|
||||
#define PSM_OPP 0x1015
|
||||
//--add more if needed--//
|
||||
|
||||
enum {
|
||||
profile_sco = 0,
|
||||
profile_hid = 1,
|
||||
profile_a2dp = 2,
|
||||
profile_pan = 3,
|
||||
profile_hid_interval = 4,
|
||||
profile_hogp = 5,
|
||||
profile_voice = 6,
|
||||
profile_max = 7
|
||||
};
|
||||
|
||||
//profile info data
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
uint16_t handle;
|
||||
uint16_t psm;
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
uint8_t profile_index;
|
||||
} rtk_prof_info, *prtk_prof_info;
|
||||
|
||||
//profile info for each connection
|
||||
typedef struct rtl_hci_conn {
|
||||
struct list_head list;
|
||||
uint16_t handle;
|
||||
uint8_t type; // 0:l2cap, 1:sco/esco, 2:le
|
||||
uint8_t profile_bitmap;
|
||||
int8_t profile_refcount[8];
|
||||
} rtk_conn_prof, *prtk_conn_prof;
|
||||
|
||||
struct rtl_btinfo {
|
||||
u8 cmd;
|
||||
u8 len;
|
||||
u8 data[6];
|
||||
};
|
||||
#define RTL_BTINFO_LEN (sizeof(struct rtl_btinfo))
|
||||
/* typedef struct {
|
||||
* uint8_t cmd_index;
|
||||
* uint8_t cmd_length;
|
||||
* uint8_t link_status;
|
||||
* uint8_t retry_cnt;
|
||||
* uint8_t rssi;
|
||||
* uint8_t mailbox_info;
|
||||
* uint16_t acl_throughput;
|
||||
* } hci_linkstatus_report; */
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint32_t offset;
|
||||
uint32_t value;
|
||||
} hci_mailbox_register;
|
||||
|
||||
struct rtl_btinfo_ctl {
|
||||
uint8_t polling_enable;
|
||||
uint8_t polling_time;
|
||||
uint8_t autoreport_enable;
|
||||
};
|
||||
|
||||
#define MAX_LEN_OF_HCI_EV 32
|
||||
#define NUM_RTL_HCI_EV 32
|
||||
struct rtl_hci_ev {
|
||||
__u8 data[MAX_LEN_OF_HCI_EV];
|
||||
__u16 len;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define L2_MAX_SUBSEC_LEN 128
|
||||
#define L2_MAX_PKTS 16
|
||||
struct rtl_l2_buff {
|
||||
__u8 data[L2_MAX_SUBSEC_LEN];
|
||||
__u16 len;
|
||||
__u16 out;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct rtl_coex_struct {
|
||||
struct list_head conn_hash; //hash for connections
|
||||
struct list_head profile_list; //hash for profile info
|
||||
struct hci_dev *hdev;
|
||||
struct socket *udpsock;
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_in wifi_addr;
|
||||
struct timer_list polling_timer;
|
||||
struct timer_list a2dp_count_timer;
|
||||
struct timer_list pan_count_timer;
|
||||
struct timer_list hogp_count_timer;
|
||||
struct workqueue_struct *sock_wq;
|
||||
struct workqueue_struct *fw_wq;
|
||||
struct delayed_work sock_work;
|
||||
struct delayed_work fw_work;
|
||||
struct delayed_work l2_work;
|
||||
struct sock *sk;
|
||||
struct urb *urb;
|
||||
spinlock_t spin_lock_sock;
|
||||
spinlock_t spin_lock_profile;
|
||||
uint32_t a2dp_packet_count;
|
||||
uint32_t pan_packet_count;
|
||||
uint32_t hogp_packet_count;
|
||||
uint32_t voice_packet_count;
|
||||
uint8_t profile_bitmap;
|
||||
uint8_t profile_status;
|
||||
int8_t profile_refcount[8];
|
||||
uint8_t ispairing;
|
||||
uint8_t isinquirying;
|
||||
uint8_t ispaging;
|
||||
uint8_t wifi_state;
|
||||
uint8_t autoreport;
|
||||
uint8_t polling_enable;
|
||||
uint8_t polling_interval;
|
||||
uint8_t piconet_id;
|
||||
uint8_t mode;
|
||||
uint8_t afh_map[10];
|
||||
uint16_t hci_reversion;
|
||||
uint16_t lmp_subversion;
|
||||
uint8_t wifi_on;
|
||||
uint8_t sock_open;
|
||||
unsigned long cmd_last_tx;
|
||||
|
||||
/* hci ev buff */
|
||||
struct list_head ev_used_list;
|
||||
struct list_head ev_free_list;
|
||||
|
||||
spinlock_t rxlock;
|
||||
__u8 pkt_type;
|
||||
__u16 expect;
|
||||
__u8 *tbuff;
|
||||
__u16 elen;
|
||||
__u8 back_buff[HCI_MAX_EVENT_SIZE];
|
||||
|
||||
/* l2cap rx buff */
|
||||
struct list_head l2_used_list;
|
||||
struct list_head l2_free_list;
|
||||
|
||||
/* buff addr and size */
|
||||
spinlock_t buff_lock;
|
||||
unsigned long pages_addr;
|
||||
unsigned long buff_size;
|
||||
|
||||
#define RTL_COEX_RUNNING (1 << 0)
|
||||
unsigned long flags;
|
||||
|
||||
};
|
||||
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
struct sbc_frame_hdr {
|
||||
uint8_t syncword:8; /* Sync word */
|
||||
uint8_t subbands:1; /* Subbands */
|
||||
uint8_t allocation_method:1; /* Allocation method */
|
||||
uint8_t channel_mode:2; /* Channel mode */
|
||||
uint8_t blocks:2; /* Blocks */
|
||||
uint8_t sampling_frequency:2; /* Sampling frequency */
|
||||
uint8_t bitpool:8; /* Bitpool */
|
||||
uint8_t crc_check:8; /* CRC check */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* NOTE: The code is copied from pa.
|
||||
* only the bit field in 8-bit is affected by endian, not the 16-bit or 32-bit.
|
||||
* why?
|
||||
*/
|
||||
struct rtp_header {
|
||||
unsigned cc:4;
|
||||
unsigned x:1;
|
||||
unsigned p:1;
|
||||
unsigned v:2;
|
||||
|
||||
unsigned pt:7;
|
||||
unsigned m:1;
|
||||
|
||||
uint16_t sequence_number;
|
||||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
uint32_t csrc[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#else
|
||||
/* big endian */
|
||||
struct sbc_frame_hdr {
|
||||
uint8_t syncword:8; /* Sync word */
|
||||
uint8_t sampling_frequency:2; /* Sampling frequency */
|
||||
uint8_t blocks:2; /* Blocks */
|
||||
uint8_t channel_mode:2; /* Channel mode */
|
||||
uint8_t allocation_method:1; /* Allocation method */
|
||||
uint8_t subbands:1; /* Subbands */
|
||||
uint8_t bitpool:8; /* Bitpool */
|
||||
uint8_t crc_check:8; /* CRC check */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtp_header {
|
||||
unsigned v:2;
|
||||
unsigned p:1;
|
||||
unsigned x:1;
|
||||
unsigned cc:4;
|
||||
|
||||
unsigned m:1;
|
||||
unsigned pt:7;
|
||||
|
||||
uint16_t sequence_number;
|
||||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
uint32_t csrc[0];
|
||||
} __attribute__ ((packed));
|
||||
#endif /* __LITTLE_ENDIAN */
|
||||
|
||||
void rtk_btcoex_parse_event(uint8_t *buffer, int count);
|
||||
void rtk_btcoex_parse_cmd(uint8_t *buffer, int count);
|
||||
void rtk_btcoex_parse_l2cap_data_tx(uint8_t *buffer, int count);
|
||||
void rtk_btcoex_parse_l2cap_data_rx(uint8_t *buffer, int count);
|
||||
|
||||
void rtk_btcoex_open(struct hci_dev *hdev);
|
||||
void rtk_btcoex_close(void);
|
||||
void rtk_btcoex_probe(struct hci_dev *hdev);
|
||||
void rtk_btcoex_init(void);
|
||||
void rtk_btcoex_exit(void);
|
||||
+363
-252
@@ -22,6 +22,16 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
// #define I2C_LSFS_DEBUG
|
||||
|
||||
#ifdef I2C_LSFS_DEBUG
|
||||
#define i2c_lsfs_err dev_err
|
||||
#define i2c_lsfs_info dev_info
|
||||
#else
|
||||
#define i2c_lsfs_err(dev, fmt, ...)
|
||||
#define i2c_lsfs_info(dev, fmt, ...)
|
||||
#endif
|
||||
|
||||
/* Loongson I2C offset registers */
|
||||
#define I2C_CR1 0x00
|
||||
#define I2C_CR2 0x04
|
||||
@@ -33,6 +43,8 @@
|
||||
#define I2C_FLTR 0x24
|
||||
|
||||
/* Loongson I2C control 1*/
|
||||
#define I2C_CR1_SWRST BIT(15)
|
||||
#define I2C_CR1_RECOVER BIT(14)
|
||||
#define I2C_CR1_POS BIT(11)
|
||||
#define I2C_CR1_ACK BIT(10)
|
||||
#define I2C_CR1_STOP BIT(9)
|
||||
@@ -103,6 +115,7 @@ struct priv_msg {
|
||||
* @complete: completion of I2C message
|
||||
* @speed: Standard or Fast are supported
|
||||
* @msg: I2C transfer information
|
||||
* @freq: I2C controller input clock freq
|
||||
*/
|
||||
struct ls_i2c_dev {
|
||||
struct i2c_adapter adap;
|
||||
@@ -111,6 +124,7 @@ struct ls_i2c_dev {
|
||||
struct completion complete;
|
||||
int speed;
|
||||
struct priv_msg msg;
|
||||
int freq;
|
||||
};
|
||||
|
||||
static inline void i2c_set_bits(void __iomem *reg, u32 mask)
|
||||
@@ -130,7 +144,7 @@ static void ls_i2c_disable_irq(struct ls_i2c_dev *i2c_dev)
|
||||
i2c_clr_bits(reg, I2C_CR2_IRQ_MASK);
|
||||
}
|
||||
|
||||
#define INPUT_REF_CLK 120000000
|
||||
#define INPUT_DEFAULT_CLK 200000000
|
||||
|
||||
static int ls_i2c_hw_config(struct ls_i2c_dev *i2c_dev)
|
||||
{
|
||||
@@ -141,10 +155,10 @@ static int ls_i2c_hw_config(struct ls_i2c_dev *i2c_dev)
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR2, 0x3f);
|
||||
i2c_set_bits(i2c_dev->base + I2C_TRISE, 0x3f);
|
||||
|
||||
if (i2c_dev->speed == LS_I2C_SPEED_STANDARD) {
|
||||
val = DIV_ROUND_UP(INPUT_REF_CLK, 100000 * 2);
|
||||
} else {
|
||||
val = DIV_ROUND_UP(INPUT_REF_CLK, 400000 * 3);
|
||||
if (i2c_dev->speed == LS_I2C_SPEED_STANDARD)
|
||||
val = DIV_ROUND_UP(i2c_dev->freq, 100000 * 2);
|
||||
else {
|
||||
val = DIV_ROUND_UP(i2c_dev->freq, 400000 * 3);
|
||||
|
||||
/* Select Fast mode */
|
||||
ccr |= I2C_CCR_FS;
|
||||
@@ -166,7 +180,7 @@ static int ls_i2c_wait_free_bus(struct ls_i2c_dev *i2c_dev)
|
||||
ret = readl_poll_timeout(i2c_dev->base + I2C_SR2,
|
||||
status,
|
||||
!(status & I2C_SR2_BUSY),
|
||||
10, 1000);
|
||||
10, 2000);
|
||||
if (ret) {
|
||||
dev_dbg(i2c_dev->dev, "bus not free\n");
|
||||
ret = -EBUSY;
|
||||
@@ -175,236 +189,305 @@ static int ls_i2c_wait_free_bus(struct ls_i2c_dev *i2c_dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ls_i2c_write_byte(struct ls_i2c_dev *i2c_dev, u8 byte)
|
||||
static int i2c_wait_EV_signal(struct ls_i2c_dev *i2c_dev, int reg, int mask, int target)
|
||||
{
|
||||
writel(byte, i2c_dev->base + I2C_DR);
|
||||
}
|
||||
|
||||
static void ls_i2c_read_msg(struct ls_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct priv_msg *msg = &i2c_dev->msg;
|
||||
|
||||
*msg->buf++ = readl(i2c_dev->base + I2C_DR);
|
||||
msg->count--;
|
||||
}
|
||||
|
||||
static void ls_i2c_terminate_xfer(struct ls_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct priv_msg *msg = &i2c_dev->msg;
|
||||
|
||||
ls_i2c_disable_irq(i2c_dev);
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR1, (1 << (8 + msg->stop)));
|
||||
complete(&i2c_dev->complete);
|
||||
}
|
||||
|
||||
static void ls_i2c_handle_write(struct ls_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct priv_msg *msg = &i2c_dev->msg;
|
||||
void __iomem *reg = i2c_dev->base + I2C_CR2;
|
||||
|
||||
if (msg->count) {
|
||||
ls_i2c_write_byte(i2c_dev, *msg->buf++);
|
||||
msg->count--;
|
||||
if (!msg->count)
|
||||
i2c_clr_bits(reg, I2C_CR2_ITBUFEN);
|
||||
} else {
|
||||
ls_i2c_terminate_xfer(i2c_dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void ls_i2c_handle_read(struct ls_i2c_dev *i2c_dev, int flag)
|
||||
{
|
||||
struct priv_msg *msg = &i2c_dev->msg;
|
||||
void __iomem *reg = i2c_dev->base + I2C_CR2;
|
||||
int i;
|
||||
|
||||
switch (msg->count) {
|
||||
case 1:
|
||||
/* only transmit 1 bytes condition */
|
||||
ls_i2c_disable_irq(i2c_dev);
|
||||
ls_i2c_read_msg(i2c_dev);
|
||||
complete(&i2c_dev->complete);
|
||||
break;
|
||||
case 2:
|
||||
if (flag != 1) {
|
||||
/* ensure only transmit 2 bytes condition */
|
||||
i2c_clr_bits(reg, I2C_CR2_ITBUFEN);
|
||||
break;
|
||||
}
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR1, (1 << (8 + msg->stop)));
|
||||
|
||||
ls_i2c_disable_irq(i2c_dev);
|
||||
|
||||
for (i = 2; i > 0; i--)
|
||||
ls_i2c_read_msg(i2c_dev);
|
||||
|
||||
i2c_clr_bits(i2c_dev->base + I2C_CR1, I2C_CR1_POS);
|
||||
complete(&i2c_dev->complete);
|
||||
break;
|
||||
case 3:
|
||||
if (readl(i2c_dev->base + I2C_CR2) & I2C_CR2_ITBUFEN) {
|
||||
i2c_clr_bits(reg, I2C_CR2_ITBUFEN);
|
||||
break;
|
||||
}
|
||||
|
||||
reg = i2c_dev->base + I2C_CR1;
|
||||
i2c_clr_bits(reg, I2C_CR1_ACK);
|
||||
default:
|
||||
ls_i2c_read_msg(i2c_dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ls_i2c_handle_rx_addr()
|
||||
* master receiver
|
||||
* @i2c_dev: Controller's private data
|
||||
*/
|
||||
static void ls_i2c_handle_rx_addr(struct ls_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct priv_msg *msg = &i2c_dev->msg;
|
||||
|
||||
switch (msg->count) {
|
||||
case 0:
|
||||
ls_i2c_terminate_xfer(i2c_dev);
|
||||
break;
|
||||
case 1:
|
||||
i2c_clr_bits(i2c_dev->base + I2C_CR1,
|
||||
(I2C_CR1_ACK | I2C_CR1_POS));
|
||||
/* start or stop */
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR1, (1 << (8 + msg->stop)));
|
||||
break;
|
||||
case 2:
|
||||
i2c_clr_bits(i2c_dev->base + I2C_CR1, I2C_CR1_ACK);
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR1, I2C_CR1_POS);
|
||||
break;
|
||||
|
||||
default:
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR1, I2C_CR1_ACK);
|
||||
i2c_clr_bits(i2c_dev->base + I2C_CR1, I2C_CR1_POS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t ls_i2c_isr_error(u32 status, void *data)
|
||||
{
|
||||
struct ls_i2c_dev *i2c_dev = data;
|
||||
struct priv_msg *msg = &i2c_dev->msg;
|
||||
|
||||
/* Arbitration lost */
|
||||
if (status & I2C_SR1_ARLO) {
|
||||
i2c_clr_bits(i2c_dev->base + I2C_SR1, I2C_SR1_ARLO);
|
||||
msg->result = -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Acknowledge failure:
|
||||
* In master transmitter mode a Stop must be generated by software
|
||||
*/
|
||||
if (status & I2C_SR1_AF) {
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR1, I2C_CR1_STOP);
|
||||
i2c_clr_bits(i2c_dev->base + I2C_SR1, I2C_SR1_AF);
|
||||
msg->result = -EIO;
|
||||
}
|
||||
|
||||
/* Bus error */
|
||||
if (status & I2C_SR1_BERR) {
|
||||
i2c_clr_bits(i2c_dev->base + I2C_SR1, I2C_SR1_BERR);
|
||||
msg->result = -EIO;
|
||||
}
|
||||
|
||||
ls_i2c_disable_irq(i2c_dev);
|
||||
complete(&i2c_dev->complete);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* ls_i2c_isr_event() - Interrupt routine for I2C bus event
|
||||
* @irq: interrupt number
|
||||
* @data: Controller's private data
|
||||
*/
|
||||
static irqreturn_t ls_i2c_isr_event(int irq, void *data)
|
||||
{
|
||||
struct ls_i2c_dev *i2c_dev = data;
|
||||
struct priv_msg *msg = &i2c_dev->msg;
|
||||
u32 status, ien, event, cr2;
|
||||
u32 possible_status = I2C_SR1_ITEVTEN_MASK;
|
||||
int i;
|
||||
|
||||
status = readl(i2c_dev->base + I2C_SR1);
|
||||
if (status & (I2C_SR1_ARLO | I2C_SR1_AF | I2C_SR1_BERR))
|
||||
return ls_i2c_isr_error(status, data);
|
||||
|
||||
cr2 = readl(i2c_dev->base + I2C_CR2);
|
||||
ien = cr2 & I2C_CR2_IRQ_MASK;
|
||||
|
||||
/* Update possible_status if buffer interrupt is enabled */
|
||||
if (ien & I2C_CR2_ITBUFEN)
|
||||
possible_status |= I2C_SR1_ITBUFEN_MASK;
|
||||
event = status & possible_status;
|
||||
|
||||
if (!event) {
|
||||
dev_dbg(i2c_dev->dev,
|
||||
"spurious evt irq (status=0x%08x, ien=0x%08x)\n",
|
||||
status, ien);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Start condition generated */
|
||||
if (event & I2C_SR1_SB)
|
||||
ls_i2c_write_byte(i2c_dev, msg->addr);
|
||||
|
||||
/* I2C Address sent */
|
||||
if (event & I2C_SR1_ADDR) {
|
||||
if (msg->addr & I2C_M_RD)
|
||||
ls_i2c_handle_rx_addr(i2c_dev);
|
||||
/* Clear ADDR flag */
|
||||
readl(i2c_dev->base + I2C_SR2);
|
||||
/* Enable buffer interrupts for RX/TX not empty events */
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR2, I2C_CR2_ITBUFEN);
|
||||
}
|
||||
|
||||
if (msg->addr & I2C_M_RD) {
|
||||
/* RX */
|
||||
if (event & 0x40)
|
||||
ls_i2c_handle_read(i2c_dev, 0);
|
||||
if (event & 0x4)
|
||||
ls_i2c_handle_read(i2c_dev, 1);
|
||||
} else {
|
||||
/* TX */
|
||||
if (event & 0x84)
|
||||
for (i = 0; i < 1 + !!((event & 0x84) == 0x84); i++)
|
||||
ls_i2c_handle_write(i2c_dev);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ls_i2c_xfer_msg(struct ls_i2c_dev *i2c_dev,
|
||||
struct i2c_msg *msg, bool is_stop)
|
||||
{
|
||||
struct priv_msg *priv_msg = &i2c_dev->msg;
|
||||
unsigned long timeout;
|
||||
u32 status;
|
||||
int ret;
|
||||
|
||||
priv_msg->addr = i2c_8bit_addr_from_msg(msg);
|
||||
priv_msg->buf = msg->buf;
|
||||
priv_msg->count = msg->len;
|
||||
priv_msg->stop = is_stop;
|
||||
priv_msg->result = 0;
|
||||
ret = readl_poll_timeout(i2c_dev->base + reg,
|
||||
status,
|
||||
(!!(status & mask) == target),
|
||||
20, 1000);
|
||||
if (ret) {
|
||||
dev_dbg(i2c_dev->dev, "wait timeout\n");
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
reinit_completion(&i2c_dev->complete);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable events and errors interrupts */
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR2,
|
||||
I2C_CR2_ITEVTEN | I2C_CR2_ITERREN);
|
||||
// i2c_wait_EV_signal 返回非 0 时所在对应函数返回 I2C_XFER_TIMEOUT_ERROR
|
||||
#define i2c_wait_EV_signal_t(dev, reg_offset, mask, target) if (i2c_wait_EV_signal(dev, reg_offset, mask, target)) { return -EBUSY;}
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
i2c_dev->adap.timeout);
|
||||
ret = priv_msg->result;
|
||||
/*
|
||||
* @brief: i2c bus 状态机复位
|
||||
* @param: i2c_dev: struct ls_i2c_dev
|
||||
*/
|
||||
static void i2c_bus_error_reset_end_of_xfer(struct ls_i2c_dev *i2c_dev)
|
||||
{
|
||||
unsigned char* base;
|
||||
unsigned int temp;
|
||||
unsigned int temp_SR1;
|
||||
unsigned int temp_CR1_mask;
|
||||
|
||||
if (!timeout)
|
||||
ret = -ETIMEDOUT;
|
||||
base = i2c_dev->base;
|
||||
|
||||
temp_SR1 = readl((base + I2C_SR1));
|
||||
if (temp_SR1 & I2C_SR1_BERR)
|
||||
temp_CR1_mask = I2C_CR1_RECOVER;
|
||||
|
||||
// 状态机复位
|
||||
temp = readl((base + I2C_CR1));
|
||||
temp |= (I2C_CR1_SWRST | temp_CR1_mask);
|
||||
writel(temp, (base + I2C_CR1));
|
||||
|
||||
// 错误复位
|
||||
temp = readl((base + I2C_SR1));
|
||||
temp |= (0xf << 8);
|
||||
temp ^= (0xf << 8);
|
||||
writel(temp, (base + I2C_SR1));
|
||||
temp = readl((base + I2C_SR1));
|
||||
|
||||
temp = readl((base + I2C_CR1));
|
||||
temp |= (I2C_CR1_SWRST | temp_CR1_mask);
|
||||
temp ^= (I2C_CR1_SWRST | temp_CR1_mask);
|
||||
writel(temp, (base + I2C_CR1));
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: i2c主模式,接收状态结束时的设置
|
||||
* @param: base: i2c控制器基地址
|
||||
* @param: stop: 是否发送关闭i2c总线信号
|
||||
*/
|
||||
static inline void i2c_setup_CR1_end_read(unsigned char *base, uint8_t stop)
|
||||
{
|
||||
unsigned int temp;
|
||||
|
||||
temp = readl((base + I2C_CR1));
|
||||
temp |= (I2C_CR1_ACK | I2C_CR1_POS);
|
||||
temp ^= (I2C_CR1_ACK | I2C_CR1_POS);
|
||||
temp |= (stop << 9);
|
||||
|
||||
writel(temp, (base + I2C_CR1));
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: i2c主模式接收状态,读取i2c DR 寄存器,放到msg的data里面
|
||||
* @param: base: i2c控制器基地址
|
||||
* @param: msg: i2c读取描述(i2c_msg)实例指针
|
||||
* @param: i: 当前读取数据所在data数组的下标
|
||||
*/
|
||||
static inline void i2c_update_read_msg_data(unsigned char *base, struct i2c_msg *msg, int i)
|
||||
{
|
||||
msg->buf[i] = ((readl(base + I2C_DR)) & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: i2c主模式接收状态,当只读取1个字节时的操作函数(从地址发送后的操作)
|
||||
* @param: i2c_dev: ls_i2c_dev
|
||||
* @param: msg: i2c读取描述(i2c_msg)实例指针
|
||||
* @return: 0代表操作成功,否则操作失败
|
||||
*/
|
||||
static int i2c_xfer_r_1(struct ls_i2c_dev *i2c_dev, struct i2c_msg *msg, int is_stop)
|
||||
{
|
||||
unsigned char* base;
|
||||
base = i2c_dev->base;
|
||||
|
||||
i2c_setup_CR1_end_read(base, is_stop);
|
||||
i2c_wait_EV_signal_t(i2c_dev, I2C_SR1, I2C_SR1_RXNE, 1);
|
||||
i2c_update_read_msg_data(base, msg, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: i2c主模式接收状态,当只读取2个字节时的操作函数(从地址发送后的操作)
|
||||
* @param: i2c_dev: ls_i2c_dev
|
||||
* @param: msg: i2c读取描述(i2c_msg)实例指针
|
||||
* @return: 0代表操作成功,否则操作失败
|
||||
*/
|
||||
static int i2c_xfer_r_2(struct ls_i2c_dev *i2c_dev, struct i2c_msg *msg, int is_stop)
|
||||
{
|
||||
unsigned char* base;
|
||||
base = i2c_dev->base;
|
||||
|
||||
i2c_wait_EV_signal_t(i2c_dev, I2C_SR1, I2C_SR1_RXNE, 1);
|
||||
i2c_update_read_msg_data(base, msg, 0);
|
||||
i2c_setup_CR1_end_read(base, is_stop);
|
||||
i2c_wait_EV_signal_t(i2c_dev, I2C_SR1, I2C_SR1_RXNE, 1);
|
||||
i2c_update_read_msg_data(base, msg, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: i2c主模式接收状态,当读取大于等于3个字节时的操作函数(从地址发送后的操作)
|
||||
* @param: i2c_dev: ls_i2c_dev
|
||||
* @param: msg: i2c读取描述(i2c_msg)实例指针
|
||||
* @return: 0代表操作成功,否则操作失败
|
||||
*/
|
||||
static int i2c_xfer_r_3m(struct ls_i2c_dev *i2c_dev, struct i2c_msg *msg, int is_stop)
|
||||
{
|
||||
unsigned char* base;
|
||||
int i;
|
||||
int remain_read;
|
||||
|
||||
base = i2c_dev->base;
|
||||
|
||||
i = 0;
|
||||
remain_read = msg->len;
|
||||
while (1) {
|
||||
if (remain_read <= 3)
|
||||
break;
|
||||
|
||||
// 倒数3个字节之前,看 I2C_SR1_RXNE 信号即可,有就读取DR
|
||||
i2c_wait_EV_signal_t(i2c_dev, I2C_SR1, I2C_SR1_RXNE, 1);
|
||||
i2c_update_read_msg_data(base, msg, i++);
|
||||
--remain_read;
|
||||
}
|
||||
// 见2k300手册 主接收模式(非及时、3 字节)示意图
|
||||
i2c_wait_EV_signal_t(i2c_dev, I2C_SR1, I2C_SR1_BTF, 1); // 倒数3个字节,I2C_SR1_BTF信号为1时,代表已经接收了两个字节
|
||||
i2c_update_read_msg_data(base, msg, i++); // 读取DR,此时倒数第二个字节开始从移位寄存器到DR
|
||||
i2c_setup_CR1_end_read(base, is_stop); // 下一个字节(也就是最后一个字节)之后需要发送 NACK 和 stop 命令了
|
||||
i2c_wait_EV_signal_t(i2c_dev, I2C_SR1, I2C_SR1_BTF, 1); // 这时已经最后一个字节到来
|
||||
i2c_update_read_msg_data(base, msg, i++); // 这次读取之后,等待移位寄存器填充DR
|
||||
i2c_wait_EV_signal_t(i2c_dev, I2C_SR1, I2C_SR1_RXNE, 1); // 没有字节传输动作,但是移位寄存器已经把最后一个字节填充到DR
|
||||
i2c_update_read_msg_data(base, msg, i++); // 读取DR
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: i2c主模式读取数据处理函数
|
||||
* @param: i2c_dev: ls_i2c_dev
|
||||
* @param: msg: i2c读取描述(i2c_msg)实例指针
|
||||
* @return: 0代表操作成功,否则操作失败
|
||||
*/
|
||||
static int i2c_xfer_r(struct ls_i2c_dev *i2c_dev, struct i2c_msg *msg, int is_stop)
|
||||
{
|
||||
unsigned char* base;
|
||||
unsigned int temp;
|
||||
unsigned char xfer_data;
|
||||
int ret;
|
||||
|
||||
base = i2c_dev->base;
|
||||
|
||||
// START信号发送开始命令,ACK则会在接收到数据后发送ACK命令
|
||||
temp = readl((base + I2C_CR1));
|
||||
temp |= I2C_CR1_START;
|
||||
temp |= I2C_CR1_ACK;
|
||||
writel(temp, (base + I2C_CR1));
|
||||
|
||||
ret = i2c_wait_EV_signal(i2c_dev, I2C_SR1, I2C_SR1_SB, 1);
|
||||
if (ret) {
|
||||
i2c_lsfs_err(i2c_dev->dev, "i2c read SR1_SB error(%d) addr 0x%.2x\n", ret, msg->addr);
|
||||
goto i2c_xfer_r_end;
|
||||
}
|
||||
|
||||
// 把7bit地址左移一位,然后最后1bit设置为1,代表此从地址用于读取
|
||||
xfer_data = msg->addr;
|
||||
xfer_data <<= 1;
|
||||
xfer_data |= 1; // bit 0 == 1 read
|
||||
writeb(xfer_data, (base + I2C_DR));
|
||||
|
||||
ret = i2c_wait_EV_signal(i2c_dev, I2C_SR1, I2C_SR1_ADDR, 1);
|
||||
if (ret) {
|
||||
i2c_lsfs_err(i2c_dev->dev, "i2c read SR1_ADDR error(%d) addr 0x%.2x\n", ret, msg->addr);
|
||||
goto i2c_xfer_r_end;
|
||||
}
|
||||
|
||||
temp = readl((base + I2C_SR2));
|
||||
|
||||
// 针对不同的需要读取的字节数,调用不同的处理函数
|
||||
if (msg->len == 1) // read 1 byte
|
||||
ret = i2c_xfer_r_1(i2c_dev, msg, is_stop);
|
||||
else if (msg->len == 2) // read 2 byte
|
||||
ret = i2c_xfer_r_2(i2c_dev, msg, is_stop);
|
||||
else if (msg->len > 3) // read 3 or more than 3 byte
|
||||
ret = i2c_xfer_r_3m(i2c_dev, msg, is_stop);
|
||||
|
||||
if (ret) {
|
||||
i2c_lsfs_err(i2c_dev->dev, "i2c read xfer data error(%d) addr 0x%.2x\n", ret, msg->addr);
|
||||
goto i2c_xfer_r_end;
|
||||
}
|
||||
|
||||
i2c_xfer_r_end:
|
||||
|
||||
if (ret)
|
||||
i2c_bus_error_reset_end_of_xfer(i2c_dev);
|
||||
else {
|
||||
// 如果需要关闭总线,等待busy信号为0,代表总线总体已经空闲
|
||||
if (is_stop)
|
||||
i2c_wait_EV_signal_t(i2c_dev, I2C_SR2, I2C_SR2_BUSY, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: i2c主模式写入数据处理函数
|
||||
* @param: i2c_dev: ls_i2c_dev
|
||||
* @param: msg: i2c写入描述(i2c_msg)实例指针
|
||||
* @return: 0代表操作成功,否则操作失败
|
||||
*/
|
||||
static int i2c_xfer_w(struct ls_i2c_dev *i2c_dev, struct i2c_msg *msg, int is_stop)
|
||||
{
|
||||
unsigned char* base;
|
||||
unsigned int temp;
|
||||
int i;
|
||||
unsigned char xfer_data;
|
||||
int ret;
|
||||
|
||||
base = i2c_dev->base;
|
||||
|
||||
// START信号发送开始命令,ACK则会在接收到数据后发送ACK命令
|
||||
temp = readl((base + I2C_CR1));
|
||||
temp |= I2C_CR1_START;
|
||||
writel(temp, (base + I2C_CR1));
|
||||
|
||||
ret = i2c_wait_EV_signal(i2c_dev, I2C_SR1, I2C_SR1_SB, 1);
|
||||
if (ret) {
|
||||
i2c_lsfs_err(i2c_dev->dev, "i2c write SR1_SB error(%d) addr 0x%.2x\n", ret, msg->addr);
|
||||
goto i2c_xfer_w_end;
|
||||
}
|
||||
|
||||
// 把7bit地址左移一位,然后最后1bit设置为1,代表此从地址用于读取
|
||||
xfer_data = msg->addr;
|
||||
xfer_data <<= 1; // bit 0 == 0 write
|
||||
writeb(xfer_data, (base + I2C_DR));
|
||||
|
||||
ret = i2c_wait_EV_signal(i2c_dev, I2C_SR1, I2C_SR1_ADDR, 1);
|
||||
if (ret) {
|
||||
i2c_lsfs_err(i2c_dev->dev, "i2c write SR1_ADDR error(%d) addr 0x%.2x\n", ret, msg->addr);
|
||||
goto i2c_xfer_w_end;
|
||||
}
|
||||
|
||||
temp = readl((base + I2C_SR2));
|
||||
|
||||
// 等待发送数据寄存器为空
|
||||
ret = i2c_wait_EV_signal(i2c_dev, I2C_SR1, I2C_SR1_TXE, 1);
|
||||
if (ret) {
|
||||
i2c_lsfs_err(i2c_dev->dev, "i2c write SR1_TXE error(%d) addr 0x%.2x\n", ret, msg->addr);
|
||||
goto i2c_xfer_w_end;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (1) {
|
||||
if (i == msg->len)
|
||||
break;
|
||||
|
||||
xfer_data = msg->buf[i];
|
||||
++i;
|
||||
writeb(xfer_data, (base + I2C_DR));
|
||||
|
||||
// 等待传送结束
|
||||
ret = i2c_wait_EV_signal(i2c_dev, I2C_SR1, I2C_SR1_BTF, 1);
|
||||
if (ret) {
|
||||
i2c_lsfs_err(i2c_dev->dev, "i2c write SR1_BTF error(%d) addr 0x%.2x\n", ret, msg->addr);
|
||||
goto i2c_xfer_w_end;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_xfer_w_end:
|
||||
if (ret)
|
||||
i2c_bus_error_reset_end_of_xfer(i2c_dev);
|
||||
else {
|
||||
if (is_stop) {
|
||||
// 关闭总线
|
||||
temp = readl((base + I2C_CR1));
|
||||
temp |= (I2C_CR1_STOP);
|
||||
writel(temp, (base + I2C_CR1));
|
||||
// 等待busy信号为0,代表总线总体已经空闲
|
||||
i2c_wait_EV_signal_t(i2c_dev, I2C_SR2, I2C_SR2_BUSY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -415,21 +498,32 @@ static int ls_i2c_xfer_msg(struct ls_i2c_dev *i2c_dev,
|
||||
* @msgs: Pointer to data to be written.
|
||||
* @num: Number of messages to be executed
|
||||
*/
|
||||
static int ls_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
|
||||
int num)
|
||||
static int ls_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct ls_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
|
||||
int ret = 0;
|
||||
struct i2c_msg* cur_msg;
|
||||
int i;
|
||||
int stop;
|
||||
|
||||
ret = ls_i2c_wait_free_bus(i2c_dev);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
i2c_lsfs_err(i2c_dev->dev, "i2c buf free error(%d)\n", ret);
|
||||
return ret;
|
||||
/* START generation */
|
||||
i2c_set_bits(i2c_dev->base + I2C_CR1, I2C_CR1_START);
|
||||
}
|
||||
|
||||
for (i = 0; i < num && !ret; i++)
|
||||
ret = ls_i2c_xfer_msg(i2c_dev, &msgs[i], i == num - 1);
|
||||
for (i = 0; i < num; i++) {
|
||||
cur_msg = msgs + i;
|
||||
stop = (i == (num - 1));
|
||||
if (cur_msg->flags & I2C_M_RD)
|
||||
ret += i2c_xfer_r(i2c_dev, cur_msg, stop);
|
||||
else
|
||||
ret += i2c_xfer_w(i2c_dev, cur_msg, stop);
|
||||
|
||||
if (ret) {
|
||||
i2c_lsfs_err(i2c_dev->dev, "i2c %s error(%d)\n", (cur_msg->flags & I2C_M_RD) ? "read" : "write", ret); // maybe is null
|
||||
}
|
||||
}
|
||||
|
||||
return (ret < 0) ? ret : num;
|
||||
}
|
||||
@@ -444,14 +538,39 @@ static const struct i2c_algorithm ls_i2c_algo = {
|
||||
.functionality = ls_i2c_func,
|
||||
};
|
||||
|
||||
static void ls_i2c_bus_clock_probe(struct ls_i2c_dev *i2c_dev)
|
||||
{
|
||||
int ret;
|
||||
struct clk* clk;
|
||||
int of_clk_freq;
|
||||
|
||||
i2c_dev->freq = INPUT_DEFAULT_CLK;
|
||||
ret = 1;
|
||||
clk = devm_clk_get_optional(i2c_dev->dev, NULL);
|
||||
if (clk) {
|
||||
ret = clk_rate_exclusive_get(clk);
|
||||
if (!ret)
|
||||
i2c_dev->freq = clk_get_rate(clk);
|
||||
} else {
|
||||
if (!of_property_read_u32(i2c_dev->dev->of_node, "clock-frequency", &of_clk_freq)) {
|
||||
ret = 0;
|
||||
i2c_dev->freq = of_clk_freq;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
pr_info("%s warning: use default clk freq %d\n", __func__, INPUT_DEFAULT_CLK);
|
||||
}
|
||||
|
||||
static int ls_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ls_i2c_dev *i2c_dev;
|
||||
struct resource *res;
|
||||
u32 irq_event, clk_rate;
|
||||
u32 clk_rate;
|
||||
struct i2c_adapter *adap;
|
||||
int ret;
|
||||
int name_buffer_len;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
@@ -459,12 +578,6 @@ static int ls_i2c_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
irq_event = platform_get_irq(pdev, 0);
|
||||
if (irq_event <= 0) {
|
||||
dev_err(&pdev->dev, "IRQ event missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
|
||||
if (!i2c_dev)
|
||||
return -ENOMEM;
|
||||
@@ -484,20 +597,18 @@ static int ls_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
i2c_dev->dev = &pdev->dev;
|
||||
|
||||
ret = request_irq(irq_event, ls_i2c_isr_event, IRQF_SHARED,
|
||||
pdev->name, i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq event %i\n",
|
||||
irq_event);
|
||||
goto free_i2c_ioremap;
|
||||
}
|
||||
|
||||
ls_i2c_bus_clock_probe(i2c_dev);
|
||||
ls_i2c_hw_config(i2c_dev);
|
||||
ls_i2c_disable_irq(i2c_dev); // 不需要中断 轮询等待
|
||||
|
||||
adap = &i2c_dev->adap;
|
||||
i2c_set_adapdata(adap, i2c_dev);
|
||||
adap->nr = pdev->id;
|
||||
strlcpy(adap->name, pdev->name, sizeof(adap->name));
|
||||
name_buffer_len = strlen(pdev->name);
|
||||
name_buffer_len = (name_buffer_len >= sizeof(adap->name)) ? sizeof(adap->name) - 1 : name_buffer_len;
|
||||
memset(adap->name, 0, name_buffer_len + 1);
|
||||
strncpy(adap->name, pdev->name, name_buffer_len);
|
||||
adap->name[name_buffer_len] = 0;
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->retries = 5;
|
||||
adap->algo = &ls_i2c_algo;
|
||||
|
||||
@@ -147,11 +147,13 @@ void fts_tp_state_recovery(struct i2c_client *client)
|
||||
*****************************************************************************/
|
||||
int fts_reset_proc(int hdelayms)
|
||||
{
|
||||
if (gpio_is_valid(fts_wq_data->pdata->reset_gpio))
|
||||
{
|
||||
gpio_direction_output(fts_wq_data->pdata->reset_gpio, 0);
|
||||
msleep(20);
|
||||
gpio_direction_output(fts_wq_data->pdata->reset_gpio, 1);
|
||||
msleep(hdelayms);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1203,6 +1203,8 @@ static int mcp251x_open(struct net_device *net)
|
||||
|
||||
if (!dev_fwnode(&spi->dev))
|
||||
flags = IRQF_TRIGGER_FALLING;
|
||||
flags = IRQF_ONESHOT | IRQF_TRIGGER_FALLING;
|
||||
//flags = IRQF_ONESHOT | IRQF_TRIGGER_LOW;
|
||||
|
||||
ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
|
||||
flags | IRQF_ONESHOT, dev_name(&spi->dev),
|
||||
|
||||
+15
-4
@@ -65,10 +65,10 @@ static int ls_pwm_set_polarity(struct pwm_chip *chip,
|
||||
val = readl(ls_pwm->mmio_base + CTRL);
|
||||
switch (polarity) {
|
||||
case PWM_POLARITY_NORMAL:
|
||||
val &= ~CTRL_INVERT;
|
||||
val |= CTRL_INVERT; // 周期以高电平开始 为正极性
|
||||
break;
|
||||
case PWM_POLARITY_INVERSED:
|
||||
val |= CTRL_INVERT;
|
||||
val &= ~CTRL_INVERT; // 周期以低电平开始 为负极性
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -193,8 +193,9 @@ void ls_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
state->duty_cycle = val1;
|
||||
|
||||
ctrl_reg = readl(ls_pwm->mmio_base + CTRL);
|
||||
state->polarity = (ctrl_reg & CTRL_INVERT) ? PWM_POLARITY_INVERSED
|
||||
: PWM_POLARITY_NORMAL;
|
||||
// polarity 0为正极性,高电平开始,所以对应位为1,相反,则为0
|
||||
state->polarity = (ctrl_reg & CTRL_INVERT) ? PWM_POLARITY_NORMAL
|
||||
: PWM_POLARITY_INVERSED;
|
||||
state->enabled = (ctrl_reg & CTRL_EN) ? true : false;
|
||||
|
||||
ls_pwm->low_buffer_reg = readl(ls_pwm->mmio_base + LOW_BUFFER);
|
||||
@@ -260,6 +261,14 @@ static int ls_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &ls_pwm_ops;
|
||||
// 这是设置扫描类似下面的dts声明要用的一个公用函数
|
||||
// pwms = <&pwm5 0 100000 PWM_POLARITY_INVERTED>;
|
||||
pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
// 这里规定最大是3个参数,但是 #pwm-cells = <3>; 这里规定最多可以接受多少参数
|
||||
// 如果 #pwm-cells = <2>; 那么就算提供三个参数,那么也只会看前2个
|
||||
// 如果 #pwm-cells = <3>; 那么提供2个参数,就会报错
|
||||
// 所以 #pwm-cells 的值要设置好,2个还是3个,后续使用者都应该提供正确所需数量为好
|
||||
pwm->chip.of_pwm_n_cells = 3;
|
||||
pwm->chip.base = -1;
|
||||
pwm->chip.npwm = 1;
|
||||
|
||||
@@ -290,6 +299,8 @@ static int ls_pwm_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, pwm);
|
||||
dev_dbg(&pdev->dev, "pwm probe successful\n");
|
||||
|
||||
// 默认设置为正极性,即开始为高电平
|
||||
ls_pwm_set_polarity(&pwm->chip, pwm->chip.pwms, PWM_POLARITY_NORMAL);
|
||||
if (!(of_property_read_u32(np, "polarity", &polarity)))
|
||||
ls_pwm_set_polarity(&pwm->chip, pwm->chip.pwms, polarity);
|
||||
|
||||
|
||||
@@ -2919,7 +2919,7 @@ try_rst_again:
|
||||
if (status && status != -ENOTCONN && status != -ENODEV) {
|
||||
if (rst_try < 5) {
|
||||
rst_try++;
|
||||
udelay(10);
|
||||
mdelay(10);
|
||||
goto try_rst_again;
|
||||
}
|
||||
dev_dbg(hub->intfdev,
|
||||
|
||||
@@ -516,6 +516,12 @@ struct dwc2_core_params {
|
||||
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
|
||||
|
||||
bool change_speed_quirk;
|
||||
|
||||
#define DWC2_LOONGSON_FIX_NONE 0
|
||||
#define DWC2_LOONGSON_FIX_DMA 1
|
||||
#define DWC2_LOONGSON_FIX_DELAY 2
|
||||
#define DWC2_LOONGSON_FIX_DELAY_FULL 3
|
||||
u32 loongson_fix;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+12
-1
@@ -640,6 +640,13 @@ static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg,
|
||||
dwc2_writel(hsotg, hcintmsk, HCINTMSK(chan->hc_num));
|
||||
if (dbg_hc(chan))
|
||||
dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
|
||||
|
||||
// EP0 & CONTROL & BULK must delay for a while
|
||||
if(hsotg->params.loongson_fix == DWC2_LOONGSON_FIX_DELAY &&
|
||||
chan->ep_num == 0 &&
|
||||
(chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
|
||||
chan->ep_type == USB_ENDPOINT_XFER_BULK) )
|
||||
mdelay(2);
|
||||
}
|
||||
|
||||
static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg,
|
||||
@@ -697,7 +704,6 @@ static void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
|
||||
hcintmsk = 0xffffffff;
|
||||
hcintmsk &= ~HCINTMSK_RESERVED14_31;
|
||||
dwc2_writel(hsotg, hcintmsk, HCINT(hc_num));
|
||||
|
||||
/* Enable channel interrupts required for this transfer */
|
||||
dwc2_hc_enable_ints(hsotg, chan);
|
||||
|
||||
@@ -734,6 +740,11 @@ static void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
|
||||
chan->max_packet);
|
||||
}
|
||||
|
||||
// EP0 must delay for a while
|
||||
if(hsotg->params.loongson_fix == DWC2_LOONGSON_FIX_DELAY &&
|
||||
chan->ep_num == 0)
|
||||
mdelay(2);
|
||||
|
||||
/* Program the HCSPLT register for SPLITs */
|
||||
if (chan->do_split) {
|
||||
if (dbg_hc(chan))
|
||||
|
||||
@@ -165,6 +165,12 @@ static void dwc2_set_loongson_params(struct dwc2_hsotg *hsotg)
|
||||
#else
|
||||
p->power_down = DWC2_POWER_DOWN_PARAM_HIBERNATION;
|
||||
#endif
|
||||
device_property_read_u32(hsotg->dev, "loongson,dwc2-fix",
|
||||
&p->loongson_fix);
|
||||
dev_info(hsotg->dev, "Loongson Fix Param: %d\n", p->loongson_fix);
|
||||
|
||||
if (p->loongson_fix == DWC2_LOONGSON_FIX_DMA)
|
||||
p->dma_desc_enable = true;
|
||||
}
|
||||
|
||||
const struct of_device_id dwc2_of_match_table[] = {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef __DT_DWC2_LOONGSON_FIX_H
|
||||
#define __DT_DWC2_LOONGSON_FIX_H
|
||||
|
||||
#define DWC2_LOONGSON_FIX_NONE 0
|
||||
#define DWC2_LOONGSON_FIX_DMA 1
|
||||
#define DWC2_LOONGSON_FIX_DELAY 2
|
||||
#define DWC2_LOONGSON_FIX_DELAY_FULL 3
|
||||
|
||||
#endif
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#define PERF_REGS_MASK ((1ULL << PERF_REG_LOONGARCH_MAX) - 1)
|
||||
|
||||
static inline const char *__perf_reg_name(int id)
|
||||
static inline const char *perf_reg_name(int id)
|
||||
{
|
||||
switch (id) {
|
||||
case PERF_REG_LOONGARCH_PC:
|
||||
|
||||
Reference in New Issue
Block a user