wifi/bt: initial add wifi and bt driver
authorRongjun Chen <rongjun.chen@amlogic.com>
Wed, 29 Mar 2017 07:30:35 +0000 (15:30 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Wed, 5 Apr 2017 10:06:23 +0000 (18:06 +0800)
PD#138714: initial add wifi and bt

Change-Id: I96b3731297860c77a5a125573b98be7e54950cb1
Signed-off-by: Rongjun Chen <rongjun.chen@amlogic.com>
21 files changed:
MAINTAINERS
arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts
arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts
arch/arm64/boot/dts/amlogic/gxl_p400_2g.dts
arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts
arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts
arch/arm64/configs/meson64_defconfig
drivers/amlogic/Kconfig
drivers/amlogic/Makefile
drivers/amlogic/bluetooth/Kconfig [new file with mode: 0644]
drivers/amlogic/bluetooth/Makefile [new file with mode: 0644]
drivers/amlogic/bluetooth/bluesleep.c [new file with mode: 0644]
drivers/amlogic/bluetooth/bluesleep.h [new file with mode: 0644]
drivers/amlogic/bluetooth/bt_device.c [new file with mode: 0644]
drivers/amlogic/wifi/Kconfig [new file with mode: 0644]
drivers/amlogic/wifi/Makefile [new file with mode: 0644]
drivers/amlogic/wifi/dhd_static_buf.c [new file with mode: 0644]
drivers/amlogic/wifi/wifi_dt.c [new file with mode: 0644]
include/linux/amlogic/bt_device.h [new file with mode: 0644]
include/linux/amlogic/wifi_dt.h [new file with mode: 0644]
include/linux/amlogic/wifi_power.h [new file with mode: 0644]

index 8d0a7dc..a85256a 100644 (file)
@@ -13762,3 +13762,10 @@ F: drivers/amlogic/spicc/spicc.c
 F: drivers/amlogic/spicc/spicc.h
 F: drivers/amlogic/spicc/Kconfig
 F: drivers/amlogic/spicc/Makefile
+
+AMLOGIC BT/WIFI
+M: Rongjun Chen <rongjun.chen@amlogic.com>
+F: drivers/amlogic/bluetooth/
+F: drivers/amlogic/wifi/
+
+
index bc3ef3f..1b6ce51 100644 (file)
                };
        };
 
+       wifi{
+               compatible = "amlogic, aml_wifi";
+               dev_name = "aml_wifi";
+               status = "okay";
+               interrupt_pin = <&gpio       GPIOX_7       GPIO_ACTIVE_HIGH>;
+               interrupts = <  0 68 4>;
+               irq_trigger_type = "GPIO_IRQ_LOW";
+               power_on_pin = <&gpio       GPIOX_6       GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "wifi_32k_pins";
+               pinctrl-0 = <&wifi_32k_pins>;
+//             pwm_config = <&wifi_pwm_conf>;
+       };
+
+//     wifi_pwm_conf:wifi_pwm_conf{
+//             pwm_channel1 = <PWM_E>;
+//             pwm_channel2 = <PWM_E2>;
+//             pwm_channel1_conf = <30541 15270 6>;
+//             pwm_channel2_conf = <30518 15259 9>;
+//     };
+
        sd_emmc_c: emmc@d0074000 {
                status = "okay";
                compatible = "amlogic, meson-aml-mmc";
index 7f208b0..d1b231d 100644 (file)
                };
        };
 
+       wifi{
+               compatible = "amlogic, aml_wifi";
+               dev_name = "aml_wifi";
+               status = "okay";
+               interrupt_pin = <&gpio       GPIOX_7       GPIO_ACTIVE_HIGH>;
+               interrupts = <  0 68 4>;
+               irq_trigger_type = "GPIO_IRQ_LOW";
+               power_on_pin = <&gpio       GPIOX_6       GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "wifi_32k_pins";
+               pinctrl-0 = <&wifi_32k_pins>;
+//             pwm_config = <&wifi_pwm_conf>;
+       };
+
+//     wifi_pwm_conf:wifi_pwm_conf{
+//             pwm_channel1 = <PWM_E>;
+//             pwm_channel2 = <PWM_E2>;
+//             pwm_channel1_conf = <30541 15270 6>;
+//             pwm_channel2_conf = <30518 15259 9>;
+//     };
+
        sd_emmc_c: emmc@d0074000 {
                status = "okay";
                compatible = "amlogic, meson-aml-mmc";
index b549ca4..650b9f5 100644 (file)
                };
        };
 
+       wifi{
+               compatible = "amlogic, aml_wifi";
+               dev_name = "aml_wifi";
+               status = "okay";
+               interrupt_pin = <&gpio       GPIOX_7       GPIO_ACTIVE_HIGH>;
+               interrupts = <  0 68 4>;
+               irq_trigger_type = "GPIO_IRQ_LOW";
+               power_on_pin = <&gpio       GPIOX_6       GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "wifi_32k_pins";
+               pinctrl-0 = <&wifi_32k_pins>;
+       };
+
        sd_emmc_c: emmc@d0074000 {
                status = "okay";
                compatible = "amlogic, meson-aml-mmc";
index 9faf933..b411709 100644 (file)
                };
        };
 
+       wifi{
+               compatible = "amlogic, aml_wifi";
+               dev_name = "aml_wifi";
+               status = "okay";
+               interrupt_pin = <&gpio       GPIOX_7       GPIO_ACTIVE_HIGH>;
+               interrupts = <  0 68 4>;
+               irq_trigger_type = "GPIO_IRQ_LOW";
+               power_on_pin = <&gpio       GPIOX_6       GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "wifi_32k_pins";
+               pinctrl-0 = <&wifi_32k_pins>;
+       };
+
        sd_emmc_c: emmc@d0074000 {
                status = "disabled";
                compatible = "amlogic, meson-aml-mmc";
index b25cecf..9106b1d 100644 (file)
                };
        };
 
+       wifi{
+               compatible = "amlogic, aml_wifi";
+               dev_name = "aml_wifi";
+               status = "okay";
+               interrupt_pin = <&gpio       GPIOX_7       GPIO_ACTIVE_HIGH>;
+               interrupts = <  0 68 4>;
+               irq_trigger_type = "GPIO_IRQ_LOW";
+               power_on_pin = <&gpio       GPIOX_6       GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "wifi_32k_pins";
+               pinctrl-0 = <&wifi_32k_pins>;
+       };
+
        sd_emmc_c: emmc@d0074000 {
                status = "okay";
                compatible = "amlogic, meson-aml-mmc";
index 788981c..72ac3ff 100644 (file)
@@ -244,6 +244,8 @@ CONFIG_AMLOGIC_JTAG=y
 CONFIG_AMLOGIC_JTAG_MESON=y
 CONFIG_AMLOGIC_WDT=y
 CONFIG_AMLOGIC_WDT_MESON=y
+CONFIG_AMLOGIC_WIFI=y
+CONFIG_AMLOGIC_BT_DEVICE=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
index 305a4d3..b8f5a50 100644 (file)
@@ -79,5 +79,9 @@ source "drivers/amlogic/jtag/Kconfig"
 
 source "drivers/amlogic/watchdog/Kconfig"
 
+source "drivers/amlogic/wifi/Kconfig"
+
+source "drivers/amlogic/bluetooth/Kconfig"
+
 endmenu
 endif
index 6a8af96..e5c3d77 100644 (file)
@@ -75,3 +75,7 @@ obj-$(CONFIG_AMLOGIC_JTAG)            += jtag/
 
 obj-$(CONFIG_AMLOGIC_WDT)              += watchdog/
 
+obj-$(CONFIG_AMLOGIC_BT_DEVICE)                += bluetooth/
+
+obj-$(CONFIG_AMLOGIC_WIFI)      += wifi/
+
diff --git a/drivers/amlogic/bluetooth/Kconfig b/drivers/amlogic/bluetooth/Kconfig
new file mode 100644 (file)
index 0000000..f8794c1
--- /dev/null
@@ -0,0 +1,8 @@
+comment "Amlogic Bt Rfkill Driver"
+
+menuconfig AMLOGIC_BT_DEVICE
+    bool "BT Device support"
+    depends on BT && RFKILL
+    default n
+    ---help---
+      Say Y here if you want to use the BT device.
diff --git a/drivers/amlogic/bluetooth/Makefile b/drivers/amlogic/bluetooth/Makefile
new file mode 100644 (file)
index 0000000..3478e7a
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_AMLOGIC_BT_DEVICE) += bt_device.o
diff --git a/drivers/amlogic/bluetooth/bluesleep.c b/drivers/amlogic/bluetooth/bluesleep.c
new file mode 100644 (file)
index 0000000..9814640
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ * Date         Author           Comment
+ * -----------  --------------   --------------------------------
+ * 2006-Apr-28 Motorola         The kernel module for running the Bluetooth(R)
+ *                               Sleep-Mode Protocol from the Host side
+ *  2006-Sep-08  Motorola        Added workqueue for handling sleep work.
+ *  2007-Jan-24  Motorola        Added mbm_handle_ioi() call to ISR.
+ *  2009-Aug-10  Motorola        Changed "add_timer" to "mod_timer" to solve
+ *                               race when flurry of queued work comes in.
+ */
+
+#define pr_fmt(fmt)    "Bluetooth: %s: " fmt, __func__
+
+#include <linux/module.h>      /* kernel module definitions */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/irq.h>
+#include <linux/ioport.h>
+#include <linux/param.h>
+#include <linux/bitops.h>
+#include <linux/termios.h>
+#include <linux/wakelock_android.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/serial_core.h>
+
+#include <linux/of_irq.h>
+/* #include <linux/platform_data/msm_serial_hs.h> */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h> /* event notifications */
+#include "../../bluetooth/hci_uart.h"
+#include "bluesleep.h"
+
+#define BT_SLEEP_DBG
+#ifndef BT_SLEEP_DBG
+#define BT_DBG(fmt, arg...)
+#endif
+/*
+ * Defines
+ */
+
+#define VERSION                "1.2"
+#define PROC_DIR       "bluetooth/sleep"
+#define BT_SLEEP "bluesleep"
+
+#define POLARITY_LOW 0
+#define POLARITY_HIGH 1
+
+#define BT_PORT_ID     0
+
+/* enable/disable wake-on-bluetooth */
+#define BT_ENABLE_IRQ_WAKE 0
+
+#define BT_BLUEDROID_SUPPORT 1
+
+enum {
+       DEBUG_USER_STATE = 1U << 0,
+       DEBUG_SUSPEND = 1U << 1,
+       DEBUG_BTWAKE = 1U << 2,
+       DEBUG_VERBOSE = 1U << 3,
+};
+
+static int debug_mask = DEBUG_USER_STATE;
+//module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+module_param_named(debug_mask, debug_mask, int, 0664);
+
+struct bluesleep_info {
+       unsigned int host_wake;
+       unsigned int ext_wake;
+       unsigned int host_wake_irq;
+       struct uart_port *uport;
+       struct wake_lock wake_lock;
+       int irq_polarity;
+       int has_ext_wake;
+};
+
+/* work function */
+static void bluesleep_sleep_work(struct work_struct *work);
+
+/* work queue */
+DECLARE_DELAYED_WORK(sleep_workqueue, bluesleep_sleep_work);
+
+/* Macros for handling sleep work */
+#define bluesleep_rx_busy()     schedule_delayed_work(&sleep_workqueue, 0)
+#define bluesleep_tx_busy()     schedule_delayed_work(&sleep_workqueue, 0)
+#define bluesleep_rx_idle()     schedule_delayed_work(&sleep_workqueue, 0)
+#define bluesleep_tx_idle()     schedule_delayed_work(&sleep_workqueue, 0)
+
+/* 5 second timeout */
+#define TX_TIMER_INTERVAL  5
+
+/* state variable names and bit positions */
+#define BT_PROTO       0x01
+#define BT_TXDATA      0x02
+#define BT_ASLEEP      0x04
+#define BT_EXT_WAKE    0x08
+#define BT_SUSPEND     0x10
+
+#define PROC_BTWAKE    0
+#define PROC_HOSTWAKE  1
+#define PROC_PROTO     2
+#define PROC_ASLEEP    3
+#if BT_BLUEDROID_SUPPORT
+#define PROC_LPM       4
+#define PROC_BTWRITE   5
+#endif
+
+#if BT_BLUEDROID_SUPPORT
+static bool has_lpm_enabled;
+#else
+/* global pointer to a single hci device. */
+static struct hci_dev *bluesleep_hdev;
+#endif
+
+static struct platform_device *bluesleep_uart_dev;
+static struct bluesleep_info *bsi;
+static int bt_port_id = 1;
+
+/* module usage */
+static atomic_t open_count = ATOMIC_INIT(1);
+
+/*
+ * Local function prototypes
+ */
+#if !BT_BLUEDROID_SUPPORT
+static int bluesleep_hci_event(struct notifier_block *this,
+                       unsigned long event, void *data);
+#endif
+static int bluesleep_start(void);
+static void bluesleep_stop(void);
+
+/*
+ * Global variables
+ */
+
+/** Global state flags */
+static unsigned long flags;
+
+/** Tasklet to respond to change in hostwake line */
+static struct tasklet_struct hostwake_task;
+
+/** Transmission timer */
+static void bluesleep_tx_timer_expire(unsigned long data);
+static DEFINE_TIMER(tx_timer, bluesleep_tx_timer_expire, 0, 0);
+
+/** Lock for state transitions */
+static spinlock_t rw_lock;
+
+#if !BT_BLUEDROID_SUPPORT
+/** Notifier block for HCI events */
+struct notifier_block hci_event_nblock = {
+       .notifier_call = bluesleep_hci_event,
+};
+#endif
+
+struct proc_dir_entry *bluetooth_dir, *sleep_dir;
+
+/*
+ * Local functions
+ */
+
+static void hsuart_power(int on)
+{
+}
+
+/**
+ * @return 1 if the Host can go to sleep, 0 otherwise.
+ */
+int bluesleep_can_sleep(void)
+{
+       /* check if WAKE_BT_GPIO and BT_WAKE_GPIO are both deasserted */
+       return (gpio_get_value(bsi->host_wake) != bsi->irq_polarity) &&
+               (test_bit(BT_EXT_WAKE, &flags)) &&
+               (bsi->uport != NULL);
+}
+
+void bluesleep_sleep_wakeup(void)
+{
+       if (test_bit(BT_ASLEEP, &flags)) {
+               if (debug_mask & DEBUG_SUSPEND)
+                       pr_info("waking up...\n");
+               wake_lock(&bsi->wake_lock);
+               /* Start the timer */
+               mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
+               if (debug_mask & DEBUG_BTWAKE)
+                       pr_info("BT WAKE: set to wake\n");
+               if (bsi->has_ext_wake == 1)
+                       gpio_set_value(bsi->ext_wake, 1);
+               clear_bit(BT_EXT_WAKE, &flags);
+               clear_bit(BT_ASLEEP, &flags);
+               /*Activating UART */
+               hsuart_power(1);
+       }
+}
+
+/**
+ * @brief@  main sleep work handling function which update the flags
+ * and activate and deactivate UART ,check FIFO.
+ */
+static void bluesleep_sleep_work(struct work_struct *work)
+{
+       if (bluesleep_can_sleep()) {
+               /* already asleep, this is an error case */
+               if (test_bit(BT_ASLEEP, &flags)) {
+                       if (debug_mask & DEBUG_SUSPEND)
+                               pr_info("already asleep\n");
+                       return;
+               }
+
+               if (bsi->uport->ops->tx_empty(bsi->uport)) {
+                       if (debug_mask & DEBUG_SUSPEND)
+                               pr_info("going to sleep...\n");
+                       set_bit(BT_ASLEEP, &flags);
+                       /*Deactivating UART */
+                       hsuart_power(0);
+                       /* UART clk is not turned off immediately. Release
+                        * wakelock after 500 ms.
+                        */
+                       wake_lock_timeout(&bsi->wake_lock, HZ / 2);
+               } else {
+
+                 mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
+                       return;
+               }
+       } else if (test_bit(BT_EXT_WAKE, &flags)
+                       && !test_bit(BT_ASLEEP, &flags)) {
+               mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
+               if (debug_mask & DEBUG_BTWAKE)
+                       pr_info("BT WAKE: set to wake\n");
+               if (bsi->has_ext_wake == 1)
+                       gpio_set_value(bsi->ext_wake, 1);
+               clear_bit(BT_EXT_WAKE, &flags);
+       } else {
+               bluesleep_sleep_wakeup();
+       }
+}
+
+/**
+ * A tasklet function that runs in tasklet context and reads the value
+ * of the HOST_WAKE GPIO pin and further defer the work.
+ * @param data Not used.
+ */
+static void bluesleep_hostwake_task(unsigned long data)
+{
+       if (debug_mask & DEBUG_SUSPEND)
+               pr_info("hostwake line change\n");
+
+       spin_lock(&rw_lock);
+       if (gpio_get_value(bsi->host_wake) == bsi->irq_polarity)
+               bluesleep_rx_busy();
+       else
+               bluesleep_rx_idle();
+
+       spin_unlock(&rw_lock);
+}
+
+/**
+ * Handles proper timer action when outgoing data is delivered to the
+ * HCI line discipline. Sets BT_TXDATA.
+ */
+static void bluesleep_outgoing_data(void)
+{
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&rw_lock, irq_flags);
+
+       /* log data passing by */
+       set_bit(BT_TXDATA, &flags);
+
+       spin_unlock_irqrestore(&rw_lock, irq_flags);
+
+       /* if the tx side is sleeping... */
+       if (test_bit(BT_EXT_WAKE, &flags)) {
+               if (debug_mask & DEBUG_SUSPEND)
+                       pr_info("tx was sleeping\n");
+               bluesleep_sleep_wakeup();
+       }
+}
+
+
+#if !BT_BLUEDROID_SUPPORT
+/**
+ * Handles HCI device events.
+ * @param this Not used.
+ * @param event The event that occurred.
+ * @param data The HCI device associated with the event.
+ * @return <code>NOTIFY_DONE</code>.
+ */
+static int bluesleep_hci_event(struct notifier_block *this,
+                               unsigned long event, void *data)
+{
+       struct hci_dev *hdev = (struct hci_dev *) data;
+       struct hci_uart *hu;
+       struct uart_state *state;
+
+       if (!hdev)
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case HCI_DEV_REG:
+               if (!bluesleep_hdev) {
+                       bluesleep_hdev = hdev;
+                       hu  = (struct hci_uart *) hdev->driver_data;
+                       state = (struct uart_state *) hu->tty->driver_data;
+                       bsi->uport = state->uart_port;
+                       /* if bluetooth started, start bluesleep*/
+                       bluesleep_start();
+               }
+               break;
+       case HCI_DEV_UNREG:
+               bluesleep_stop();
+               bluesleep_hdev = NULL;
+               bsi->uport = NULL;
+               /* if bluetooth stopped, stop bluesleep also */
+               break;
+       case HCI_DEV_WRITE:
+               bluesleep_outgoing_data();
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+#endif
+
+/**
+ * Handles transmission timer expiration.
+ * @param data Not used.
+ */
+static void bluesleep_tx_timer_expire(unsigned long data)
+{
+       unsigned long irq_flags;
+
+       if (debug_mask & DEBUG_VERBOSE)
+               pr_info("Tx timer expired\n");
+
+       spin_lock_irqsave(&rw_lock, irq_flags);
+
+       /* were we silent during the last timeout? */
+       if (!test_bit(BT_TXDATA, &flags)) {
+               if (debug_mask & DEBUG_SUSPEND)
+                       pr_info("Tx has been idle\n");
+               if (debug_mask & DEBUG_BTWAKE)
+                       pr_info("BT WAKE: set to sleep\n");
+               if (bsi->has_ext_wake == 1)
+                       gpio_set_value(bsi->ext_wake, 0);
+               set_bit(BT_EXT_WAKE, &flags);
+               bluesleep_tx_idle();
+       } else {
+               if (debug_mask & DEBUG_SUSPEND)
+                       pr_info("Tx data during last period\n");
+               mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL*HZ));
+       }
+
+       /* clear the incoming data flag */
+       clear_bit(BT_TXDATA, &flags);
+
+       spin_unlock_irqrestore(&rw_lock, irq_flags);
+}
+
+/**
+ * Schedules a tasklet to run when receiving an interrupt on the
+ * <code>HOST_WAKE</code> GPIO pin.
+ * @param irq Not used.
+ * @param dev_id Not used.
+ */
+static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
+{
+       /* schedule a tasklet to handle the change in the host wake line */
+       tasklet_schedule(&hostwake_task);
+       return IRQ_HANDLED;
+}
+
+/**
+ * Starts the Sleep-Mode Protocol on the Host.
+ * @return On success, 0. On error, -1, and <code>errno</code> is set
+ * appropriately.
+ */
+static int bluesleep_start(void)
+{
+       int retval;
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&rw_lock, irq_flags);
+
+       if (test_bit(BT_PROTO, &flags)) {
+               spin_unlock_irqrestore(&rw_lock, irq_flags);
+               return 0;
+       }
+
+       spin_unlock_irqrestore(&rw_lock, irq_flags);
+
+       if (!atomic_dec_and_test(&open_count)) {
+               atomic_inc(&open_count);
+               return -EBUSY;
+       }
+
+       /* start the timer */
+
+       mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL*HZ));
+
+       /* assert BT_WAKE */
+       if (debug_mask & DEBUG_BTWAKE)
+               pr_info("BT WAKE: set to wake\n");
+       if (bsi->has_ext_wake == 1)
+               gpio_set_value(bsi->ext_wake, 1);
+       clear_bit(BT_EXT_WAKE, &flags);
+       retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
+               IRQF_DISABLED,
+               "bluetooth hostwake", NULL);
+       if (retval  < 0) {
+               BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
+               goto fail;
+       }
+#if BT_ENABLE_IRQ_WAKE
+       retval = enable_irq_wake(bsi->host_wake_irq);
+       if (retval < 0) {
+               BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt");
+               goto fail;
+       }
+#endif
+       set_bit(BT_PROTO, &flags);
+       wake_lock(&bsi->wake_lock);
+       return 0;
+
+fail:
+       del_timer(&tx_timer);
+       atomic_inc(&open_count);
+
+       return retval;
+}
+
+/**
+ * Stops the Sleep-Mode Protocol on the Host.
+ */
+static void bluesleep_stop(void)
+{
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&rw_lock, irq_flags);
+
+       if (!test_bit(BT_PROTO, &flags)) {
+               spin_unlock_irqrestore(&rw_lock, irq_flags);
+               return;
+       }
+
+       /* assert BT_WAKE */
+       if (debug_mask & DEBUG_BTWAKE)
+               pr_info("BT WAKE: set to wake\n");
+       if (bsi->has_ext_wake == 1)
+               gpio_set_value(bsi->ext_wake, 1);
+       clear_bit(BT_EXT_WAKE, &flags);
+       del_timer(&tx_timer);
+       clear_bit(BT_PROTO, &flags);
+
+       if (test_bit(BT_ASLEEP, &flags)) {
+               clear_bit(BT_ASLEEP, &flags);
+               spin_unlock_irqrestore(&rw_lock, irq_flags);
+               hsuart_power(1);
+       } else {
+               spin_unlock_irqrestore(&rw_lock, irq_flags);
+       }
+
+       atomic_inc(&open_count);
+
+#if BT_ENABLE_IRQ_WAKE
+       if (disable_irq_wake(bsi->host_wake_irq))
+               BT_ERR("Couldn't disable hostwake IRQ wakeup mode");
+#endif
+       free_irq(bsi->host_wake_irq, NULL);
+       wake_lock_timeout(&bsi->wake_lock, HZ / 2);
+}
+
+void bluesleep_setup_uart_port(struct platform_device *uart_dev)
+{
+       bluesleep_uart_dev = uart_dev;
+}
+
+static int bluesleep_populate_dt_pinfo(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int tmp;
+       const void *prop;
+
+       tmp = of_get_named_gpio(np, "bt_host_wake", 0);
+       if (tmp < 0) {
+               BT_ERR("couldn't find host_wake gpio");
+               return -ENODEV;
+       }
+       bsi->host_wake = tmp;
+
+       tmp = of_get_named_gpio(np, "bt_ext_wake", 0);
+       if (tmp < 0)
+               bsi->has_ext_wake = 0;
+       else
+               bsi->has_ext_wake = 1;
+
+       if (bsi->has_ext_wake)
+               bsi->ext_wake = tmp;
+
+       prop = of_get_property(np, "bt_port_id", NULL);
+       if (prop) {
+               bt_port_id = of_read_ulong(prop, 1);
+               BT_INFO("bt port id is %d\n", bt_port_id);
+       }
+
+       BT_INFO("bt_host_wake %d, bt_ext_wake %d",
+                       bsi->host_wake,
+                       bsi->ext_wake);
+       return 0;
+}
+
+static int bluesleep_populate_pinfo(struct platform_device *pdev)
+{
+       struct resource *res;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+                               "gpio_host_wake");
+       if (!res) {
+               BT_ERR("couldn't find host_wake gpio");
+               return -ENODEV;
+       }
+       bsi->host_wake = res->start;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+                               "gpio_ext_wake");
+       if (!res)
+               bsi->has_ext_wake = 0;
+       else
+               bsi->has_ext_wake = 1;
+
+       if (bsi->has_ext_wake)
+               bsi->ext_wake = res->start;
+
+       return 0;
+}
+
+static int bluesleep_probe(struct platform_device *pdev)
+{
+       /* struct resource *res; */
+       int ret;
+
+       bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL);
+       if (!bsi)
+               return -ENOMEM;
+
+       if (pdev->dev.of_node) {
+               ret = bluesleep_populate_dt_pinfo(pdev);
+               if (ret < 0) {
+                       BT_ERR("couldn't populate info from dt");
+                       return ret;
+               }
+       } else {
+               ret = bluesleep_populate_pinfo(pdev);
+               if (ret < 0) {
+                       BT_ERR("couldn't populate info");
+                       return ret;
+               }
+       }
+
+       /* configure host_wake as input */
+       ret = gpio_request_one(bsi->host_wake, GPIOF_IN, "bt_host_wake");
+       if (ret < 0) {
+               BT_ERR("failed to configure input direction for GPIO %d err %d",
+                               bsi->host_wake, ret);
+               goto free_bsi;
+       }
+
+       if (debug_mask & DEBUG_BTWAKE)
+               pr_info("BT WAKE: set to wake\n");
+       if (bsi->has_ext_wake) {
+               /* configure ext_wake as output mode*/
+               ret = gpio_request_one(bsi->ext_wake,
+                               GPIOF_OUT_INIT_LOW, "bt_ext_wake");
+               if (ret < 0) {
+                       BT_ERR("failed to config output");
+                       BT_ERR("        for GPIO %d err %d",
+                                       bsi->ext_wake, ret);
+                       goto free_bt_host_wake;
+               }
+       }
+       clear_bit(BT_EXT_WAKE, &flags);
+
+       bsi->host_wake_irq =
+               irq_of_parse_and_map(pdev->dev.of_node, 0);
+       if (bsi->host_wake_irq < 0) {
+               BT_ERR("couldn't find host_wake irq");
+               ret = -ENODEV;
+               goto free_bt_ext_wake;
+       }
+
+       gpio_for_irq(bsi->host_wake,
+                               AML_GPIO_IRQ(bsi->host_wake_irq, FILTER_NUM7,
+                               GPIO_IRQ_FALLING));
+
+       bsi->irq_polarity = POLARITY_LOW;/*low edge (falling edge)*/
+
+       wake_lock_init(&bsi->wake_lock,
+               WAKE_LOCK_SUSPEND, "bluesleep");
+       clear_bit(BT_SUSPEND, &flags);
+
+       BT_INFO("host_wake_irq %d, polarity %d",
+                       bsi->host_wake_irq,
+                       bsi->irq_polarity);
+
+       return 0;
+
+free_bt_ext_wake:
+       gpio_free(bsi->ext_wake);
+free_bt_host_wake:
+       gpio_free(bsi->host_wake);
+free_bsi:
+       kfree(bsi);
+       return ret;
+}
+
+static int bluesleep_remove(struct platform_device *pdev)
+{
+       gpio_free(bsi->host_wake);
+       gpio_free(bsi->ext_wake);
+       wake_lock_destroy(&bsi->wake_lock);
+       kfree(bsi);
+       return 0;
+}
+
+
+static int bluesleep_resume(struct platform_device *pdev)
+{
+       if (test_bit(BT_SUSPEND, &flags)) {
+               if (debug_mask & DEBUG_SUSPEND)
+                       pr_info("bluesleep resuming...\n");
+               if ((bsi->uport != NULL) &&
+                       (gpio_get_value(bsi->host_wake) == bsi->irq_polarity)) {
+                       if (debug_mask & DEBUG_SUSPEND)
+                               pr_info("bluesleep resume from BT event...\n");
+               }
+               clear_bit(BT_SUSPEND, &flags);
+       }
+       return 0;
+}
+
+static int bluesleep_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       if (debug_mask & DEBUG_SUSPEND)
+               pr_info("bluesleep suspending...\n");
+       set_bit(BT_SUSPEND, &flags);
+       return 0;
+}
+
+static const struct of_device_id bluesleep_match_table[] = {
+       { .compatible = "amlogic, bluesleep" },
+       {}
+};
+
+static struct platform_driver bluesleep_driver = {
+       .probe = bluesleep_probe,
+       .remove = bluesleep_remove,
+       .suspend = bluesleep_suspend,
+       .resume = bluesleep_resume,
+       .driver = {
+               .name = "bluesleep",
+               .owner = THIS_MODULE,
+               .of_match_table = bluesleep_match_table,
+       },
+};
+
+static int bluesleep_proc_show(struct seq_file *m, void *v)
+{
+       switch ((long)m->private) {
+       case PROC_BTWAKE:
+               seq_printf(m, "btwake: %u\n", test_bit(BT_EXT_WAKE, &flags));
+               break;
+       case PROC_HOSTWAKE:
+               seq_printf(m, "hostwake: %u\n", gpio_get_value(bsi->host_wake));
+               break;
+       case PROC_PROTO:
+               seq_printf(m, "proto: %u\n",
+                               test_bit(BT_PROTO, &flags) ? 1 : 0);
+               break;
+       case PROC_ASLEEP:
+               seq_printf(m, "asleep: %u\n",
+                               test_bit(BT_ASLEEP, &flags) ? 1 : 0);
+               break;
+       case PROC_LPM:
+               seq_printf(m, "lpm: %u\n",
+                                has_lpm_enabled ? 1 : 0);
+               break;
+       case PROC_BTWRITE:
+               seq_printf(m, "lpm: %u\n",
+                               test_bit(BT_TXDATA, &flags) ? 1 : 0);
+               break;
+
+       default:
+               return 0;
+       }
+       return 0;
+}
+
+static ssize_t bluesleep_proc_write(struct file *file, const char *buf,
+       size_t count, loff_t *pos)
+{
+       void *data = PDE_DATA(file_inode(file));
+       char lbuf[32];
+
+       if (count >= sizeof(lbuf))
+               count = sizeof(lbuf)-1;
+
+       if (copy_from_user(lbuf, buf, count))
+               return -EFAULT;
+       lbuf[count] = 0;
+
+       switch ((long)data) {
+       case PROC_BTWAKE:
+               if (lbuf[0] == '0') {
+                       if (debug_mask & DEBUG_BTWAKE)
+                               pr_info("BT WAKE: set to wake\n");
+                       if (bsi->has_ext_wake == 1)
+                               gpio_set_value(bsi->ext_wake, 1);
+                       clear_bit(BT_EXT_WAKE, &flags);
+               } else if (buf[0] == '1') {
+                       if (debug_mask & DEBUG_BTWAKE)
+                               pr_info("BT WAKE: set to sleep\n");
+                       if (bsi->has_ext_wake == 1)
+                               gpio_set_value(bsi->ext_wake, 0);
+                       set_bit(BT_EXT_WAKE, &flags);
+               }
+               break;
+       case PROC_PROTO:
+               if (lbuf[0] == '0')
+                       bluesleep_stop();
+               else
+                       bluesleep_start();
+               break;
+       case PROC_LPM:
+               if (lbuf[0] == '0') {
+                       bluesleep_stop();
+                       has_lpm_enabled = false;
+                       bsi->uport = NULL;
+               } else {
+                       if (!has_lpm_enabled) {
+                               has_lpm_enabled = true;
+                               bsi->uport = get_uart_port(bt_port_id);
+                               if (bsi->uport)
+                                       bluesleep_start();
+                               else
+                                       pr_info("bt port is null\n");
+                       }
+               }
+               break;
+       case PROC_BTWRITE:
+               if (lbuf[0] != '0' && bsi->uport)
+                       bluesleep_outgoing_data();
+               break;
+       default:
+               return 0;
+       }
+
+       return count;
+}
+
+static int bluesleep_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, bluesleep_proc_show, PDE_DATA(inode));
+}
+
+static const struct file_operations bluesleep_proc_readwrite_fops = {
+       .owner  = THIS_MODULE,
+       .open   = bluesleep_proc_open,
+       .read   = seq_read,
+       .write  = bluesleep_proc_write,
+};
+static const struct file_operations bluesleep_proc_read_fops = {
+       .owner  = THIS_MODULE,
+       .open   = bluesleep_proc_open,
+       .read   = seq_read,
+};
+
+/**
+ * Initializes the module.
+ * @return On success, 0. On error, -1, and <code>errno</code> is set
+ * appropriately.
+ */
+static int __init bluesleep_init(void)
+{
+       int retval;
+       struct proc_dir_entry *ent;
+
+       BT_INFO("BlueSleep Mode Driver Ver %s", VERSION);
+
+       retval = platform_driver_register(&bluesleep_driver);
+       if (retval)
+               return retval;
+
+       if (bsi == NULL)
+               return 0;
+
+#if !BT_BLUEDROID_SUPPORT
+       bluesleep_hdev = NULL;
+#endif
+
+       bluetooth_dir = proc_mkdir("bluetooth", NULL);
+       if (bluetooth_dir == NULL) {
+               BT_ERR("Unable to create /proc/bluetooth directory");
+               return -ENOMEM;
+       }
+
+       sleep_dir = proc_mkdir("sleep", bluetooth_dir);
+       if (sleep_dir == NULL) {
+               BT_ERR("Unable to create /proc/%s directory", PROC_DIR);
+               return -ENOMEM;
+       }
+
+       ent = proc_create_data("btwake", 0664,
+                       sleep_dir, &bluesleep_proc_readwrite_fops,
+                       (void *)PROC_BTWAKE);
+       if (ent == NULL) {
+               BT_ERR("Unable to create /proc/%s/btwake entry", PROC_DIR);
+               retval = -ENOMEM;
+               goto fail;
+       }
+
+       ent = proc_create_data("hostwake", 0444, sleep_dir,
+                               &bluesleep_proc_read_fops,
+                               (void *)PROC_HOSTWAKE);
+       if (ent == NULL) {
+               BT_ERR("Unable to create /proc/%s/hostwake entry", PROC_DIR);
+               retval = -ENOMEM;
+               goto fail;
+       }
+
+       ent = proc_create_data("proto", 0664,
+                       sleep_dir, &bluesleep_proc_readwrite_fops,
+                       (void *)PROC_PROTO);
+       if (ent == NULL) {
+               BT_ERR("Unable to create /proc/%s/proto entry", PROC_DIR);
+               retval = -ENOMEM;
+               goto fail;
+       }
+
+       ent = proc_create_data("asleep", 0444,
+                       sleep_dir, &bluesleep_proc_read_fops,
+                       (void *)PROC_ASLEEP);
+       if (ent == NULL) {
+               BT_ERR("Unable to create /proc/%s/asleep entry", PROC_DIR);
+               retval = -ENOMEM;
+               goto fail;
+       }
+
+#if BT_BLUEDROID_SUPPORT
+       ent = proc_create_data("lpm", 0664,
+                       sleep_dir, &bluesleep_proc_readwrite_fops,
+                       (void *)PROC_LPM);
+       if (ent == NULL) {
+               BT_ERR("Unable to create /proc/%s/lpm entry", PROC_DIR);
+               retval = -ENOMEM;
+               goto fail;
+       }
+
+       ent = proc_create_data("btwrite", 0664,
+                       sleep_dir, &bluesleep_proc_readwrite_fops,
+                       (void *)PROC_BTWRITE);
+       if (ent == NULL) {
+               BT_ERR("Unable to create /proc/%s/btwrite entry", PROC_DIR);
+               retval = -ENOMEM;
+               goto fail;
+       }
+
+#endif
+
+       flags = 0;
+
+       spin_lock_init(&rw_lock);
+
+       init_timer(&tx_timer);
+       tx_timer.function = bluesleep_tx_timer_expire;
+       tx_timer.data = 0;
+
+       tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0);
+
+       if (debug_mask & DEBUG_BTWAKE)
+               pr_info("BT WAKE: set to wake\n");
+       if (bsi->has_ext_wake == 1)
+               gpio_set_value(bsi->ext_wake, 1);
+       clear_bit(BT_EXT_WAKE, &flags);
+#if !BT_BLUEDROID_SUPPORT
+       hci_register_notifier(&hci_event_nblock);
+#endif
+
+       return 0;
+
+fail:
+#if BT_BLUEDROID_SUPPORT
+       remove_proc_entry("btwrite", sleep_dir);
+       remove_proc_entry("lpm", sleep_dir);
+#endif
+       remove_proc_entry("asleep", sleep_dir);
+       remove_proc_entry("proto", sleep_dir);
+       remove_proc_entry("hostwake", sleep_dir);
+       remove_proc_entry("btwake", sleep_dir);
+       remove_proc_entry("sleep", bluetooth_dir);
+       remove_proc_entry("bluetooth", 0);
+       return retval;
+}
+
+/**
+ * Cleans up the module.
+ */
+static void __exit bluesleep_exit(void)
+{
+       if (bsi == NULL)
+               return;
+
+       if (bsi->has_ext_wake == 1)
+               gpio_set_value(bsi->ext_wake, 1);
+       clear_bit(BT_EXT_WAKE, &flags);
+       if (test_bit(BT_PROTO, &flags)) {
+               if (disable_irq_wake(bsi->host_wake_irq))
+                       BT_ERR("Couldn't disable hostwake IRQ wakeup mode");
+               free_irq(bsi->host_wake_irq, NULL);
+               del_timer(&tx_timer);
+               if (test_bit(BT_ASLEEP, &flags))
+                       hsuart_power(1);
+       }
+
+#if !BT_BLUEDROID_SUPPORT
+       hci_unregister_notifier(&hci_event_nblock);
+#endif
+       platform_driver_unregister(&bluesleep_driver);
+
+#if BT_BLUEDROID_SUPPORT
+       remove_proc_entry("btwrite", sleep_dir);
+       remove_proc_entry("lpm", sleep_dir);
+#endif
+       remove_proc_entry("asleep", sleep_dir);
+       remove_proc_entry("proto", sleep_dir);
+       remove_proc_entry("hostwake", sleep_dir);
+       remove_proc_entry("btwake", sleep_dir);
+       remove_proc_entry("sleep", bluetooth_dir);
+       remove_proc_entry("bluetooth", 0);
+}
+
+module_init(bluesleep_init);
+module_exit(bluesleep_exit);
+
+MODULE_DESCRIPTION("Bluetooth Sleep Mode Driver ver %s " VERSION);
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
diff --git a/drivers/amlogic/bluetooth/bluesleep.h b/drivers/amlogic/bluetooth/bluesleep.h
new file mode 100644 (file)
index 0000000..bf2d818
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * drivers/amlogic/bluetooth/bluesleep.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _BLUESLEEP_H
+#define _BLUESLEEP_H
+#include <linux/serial_core.h>
+extern struct uart_port *get_uart_port(int id);
+#endif
diff --git a/drivers/amlogic/bluetooth/bt_device.c b/drivers/amlogic/bluetooth/bt_device.c
new file mode 100644 (file)
index 0000000..42d2e8f
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * drivers/amlogic/bluetooth/bt_device.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/rfkill.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/iomap.h>
+#include <linux/io.h>
+#include <linux/amlogic/bt_device.h>
+#ifdef CONFIG_AM_WIFI_SD_MMC
+#include <linux/amlogic/wifi_dt.h>
+#endif
+#include "../../gpio/gpiolib.h"
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+static struct early_suspend bt_early_suspend;
+#endif
+
+#define BT_RFKILL "bt_rfkill"
+
+struct bt_dev_runtime_data {
+       struct rfkill *bt_rfk;
+       struct bt_dev_data *pdata;
+};
+
+static void bt_device_init(struct bt_dev_data *pdata)
+{
+       if (pdata->gpio_reset > 0)
+               gpio_request(pdata->gpio_reset, BT_RFKILL);
+
+       if (pdata->gpio_en > 0)
+               gpio_request(pdata->gpio_en, BT_RFKILL);
+
+}
+
+static void bt_device_deinit(struct bt_dev_data *pdata)
+{
+       if (pdata->gpio_reset > 0)
+               gpio_free(pdata->gpio_reset);
+
+       if (pdata->gpio_en > 0)
+               gpio_free(pdata->gpio_en);
+
+}
+
+static void bt_device_on(struct bt_dev_data *pdata)
+{
+       if (pdata->gpio_reset > 0) {
+
+               if ((pdata->power_on_pin_OD) && (pdata->power_low_level)) {
+                       gpio_direction_input(pdata->gpio_reset);
+               } else {
+                       gpio_direction_output(pdata->gpio_reset,
+                               pdata->power_low_level);
+               }
+       }
+       if (pdata->gpio_en > 0) {
+
+               if ((pdata->power_on_pin_OD)
+                       && (pdata->power_low_level)) {
+                       gpio_direction_input(pdata->gpio_en);
+               } else {
+                       gpio_direction_output(pdata->gpio_en,
+                               pdata->power_low_level);
+               }
+       }
+       msleep(200);
+       if (pdata->gpio_reset > 0) {
+
+               if ((pdata->power_on_pin_OD)
+                       && (!pdata->power_low_level)) {
+                       gpio_direction_input(pdata->gpio_reset);
+               } else {
+                       gpio_direction_output(pdata->gpio_reset,
+                               !pdata->power_low_level);
+               }
+       }
+       if (pdata->gpio_en > 0) {
+
+               if ((pdata->power_on_pin_OD)
+                       && (!pdata->power_low_level)) {
+                       gpio_direction_input(pdata->gpio_en);
+               } else {
+                       gpio_direction_output(pdata->gpio_en,
+                               !pdata->power_low_level);
+               }
+       }
+       msleep(200);
+}
+
+static void bt_device_off(struct bt_dev_data *pdata)
+{
+       if (pdata->gpio_reset > 0) {
+
+               if ((pdata->power_on_pin_OD)
+                       && (pdata->power_low_level)) {
+                       gpio_direction_input(pdata->gpio_reset);
+               } else {
+                       gpio_direction_output(pdata->gpio_reset,
+                               pdata->power_low_level);
+               }
+       }
+       if (pdata->gpio_en > 0) {
+
+               if ((pdata->power_on_pin_OD)
+                       && (pdata->power_low_level)) {
+                       gpio_direction_input(pdata->gpio_en);
+               } else {
+                       gpio_direction_output(pdata->gpio_en,
+                               pdata->power_low_level);
+               }
+       }
+       msleep(20);
+}
+
+static int bt_set_block(void *data, bool blocked)
+{
+       struct bt_dev_data *pdata = data;
+
+       pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on");
+
+       if (!blocked) {
+               pr_info("BCM_BT: going ON\n");
+               bt_device_on(pdata);
+       } else {
+               pr_info("BCM_BT: going OFF\n");
+       bt_device_off(pdata);
+       }
+       return 0;
+}
+
+static const struct rfkill_ops bt_rfkill_ops = {
+       .set_block = bt_set_block,
+};
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void bt_earlysuspend(struct early_suspend *h)
+{
+
+}
+
+static void bt_lateresume(struct early_suspend *h)
+{
+}
+#endif
+
+static int bt_suspend(struct platform_device *pdev,
+       pm_message_t state)
+{
+
+       return 0;
+}
+
+static int bt_resume(struct platform_device *pdev)
+{
+
+       return 0;
+}
+
+static int bt_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       const void *prop;
+       struct rfkill *bt_rfk;
+       struct bt_dev_data *pdata = NULL;
+       struct bt_dev_runtime_data *prdata;
+
+#ifdef CONFIG_OF
+       if (pdev->dev.of_node) {
+               const char *str;
+               struct gpio_desc *desc;
+
+               pr_info("enter bt_probe of_node\n");
+               pdata = kzalloc(sizeof(struct bt_dev_data), GFP_KERNEL);
+               ret = of_property_read_string(pdev->dev.of_node,
+                       "gpio_reset", &str);
+               if (ret) {
+                       pr_warn("not get gpio_reset\n");
+                       pdata->gpio_reset = 0;
+               } else {
+                       desc = of_get_named_gpiod_flags(pdev->dev.of_node,
+                               "gpio_reset", 0, NULL);
+                       pdata->gpio_reset = desc_to_gpio(desc);
+               }
+
+       ret = of_property_read_string(pdev->dev.of_node,
+               "gpio_en", &str);
+               if (ret) {
+                       pr_warn("not get gpio_en\n");
+                       pdata->gpio_en = 0;
+               } else {
+                       desc = of_get_named_gpiod_flags(pdev->dev.of_node,
+                               "gpio_en", 0, NULL);
+                       pdata->gpio_en = desc_to_gpio(desc);
+               }
+
+               prop = of_get_property(pdev->dev.of_node,
+               "power_low_level", NULL);
+               if (prop) {
+                       pr_info("power on valid level is low");
+                       pdata->power_low_level = 1;
+               } else {
+                       pr_info("power on valid level is high");
+                       pdata->power_low_level = 0;
+                       pdata->power_on_pin_OD = 0;
+               }
+               ret = of_property_read_u32(pdev->dev.of_node,
+               "power_on_pin_OD", &pdata->power_on_pin_OD);
+               if (ret)
+                       pdata->power_on_pin_OD = 0;
+               pr_info("bt: power_on_pin_OD = %d;\n", pdata->power_on_pin_OD);
+       }
+#else
+       pdata = (struct bt_dev_data *)(pdev->dev.platform_data);
+#endif
+
+       bt_device_init(pdata);
+       /* default to bluetooth off */
+       /* rfkill_switch_all(RFKILL_TYPE_BLUETOOTH, 1); */
+       /* bt_device_off(pdata); */
+
+       bt_rfk = rfkill_alloc("bt-dev", &pdev->dev,
+               RFKILL_TYPE_BLUETOOTH,
+               &bt_rfkill_ops, pdata);
+
+       if (!bt_rfk) {
+               pr_info("rfk alloc fail\n");
+               ret = -ENOMEM;
+               goto err_rfk_alloc;
+       }
+
+       rfkill_init_sw_state(bt_rfk, false);
+       ret = rfkill_register(bt_rfk);
+       if (ret) {
+               pr_err("rfkill_register fail\n");
+               goto err_rfkill;
+       }
+       prdata = kmalloc(sizeof(struct bt_dev_runtime_data),
+       GFP_KERNEL);
+
+       if (!prdata)
+               goto err_rfkill;
+
+       prdata->bt_rfk = bt_rfk;
+       prdata->pdata = pdata;
+       platform_set_drvdata(pdev, prdata);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       bt_early_suspend.level =
+               EARLY_SUSPEND_LEVEL_DISABLE_FB;
+       bt_early_suspend.suspend = bt_earlysuspend;
+       bt_early_suspend.resume = bt_lateresume;
+       bt_early_suspend.param = pdev;
+       register_early_suspend(&bt_early_suspend);
+#endif
+
+       return 0;
+
+err_rfkill:
+       rfkill_destroy(bt_rfk);
+err_rfk_alloc:
+       bt_device_deinit(pdata);
+       return ret;
+
+}
+
+static int bt_remove(struct platform_device *pdev)
+{
+       struct bt_dev_runtime_data *prdata =
+               platform_get_drvdata(pdev);
+       struct rfkill *rfk = NULL;
+       struct bt_dev_data *pdata = NULL;
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (prdata) {
+               rfk = prdata->bt_rfk;
+               pdata = prdata->pdata;
+       }
+
+       if (pdata) {
+               bt_device_deinit(pdata);
+               kfree(pdata);
+       }
+
+       if (rfk) {
+               rfkill_unregister(rfk);
+               rfkill_destroy(rfk);
+       }
+       rfk = NULL;
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id bt_dev_dt_match[] = {
+       {       .compatible = "amlogic, bt-dev",
+       },
+       {},
+};
+#else
+#define bt_dev_dt_match NULL
+#endif
+
+static struct platform_driver bt_driver = {
+       .driver         = {
+               .name   = "bt-dev",
+               .of_match_table = bt_dev_dt_match,
+       },
+       .probe          = bt_probe,
+       .remove         = bt_remove,
+       .suspend        = bt_suspend,
+       .resume  = bt_resume,
+};
+
+static int __init bt_init(void)
+{
+       pr_info("amlogic rfkill init\n");
+
+       return platform_driver_register(&bt_driver);
+}
+static void __exit bt_exit(void)
+{
+       platform_driver_unregister(&bt_driver);
+}
+
+module_init(bt_init);
+module_exit(bt_exit);
+MODULE_DESCRIPTION("bt rfkill");
+MODULE_AUTHOR("");
+MODULE_LICENSE("GPL");
diff --git a/drivers/amlogic/wifi/Kconfig b/drivers/amlogic/wifi/Kconfig
new file mode 100644 (file)
index 0000000..1f3c445
--- /dev/null
@@ -0,0 +1,7 @@
+comment "Amlogic Wifi Driver"
+
+menuconfig AMLOGIC_WIFI
+       bool "WiFi support"
+       default n
+       help
+               select y to support wifi
diff --git a/drivers/amlogic/wifi/Makefile b/drivers/amlogic/wifi/Makefile
new file mode 100644 (file)
index 0000000..d91ae85
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_AMLOGIC_WIFI) +=  wifi_dt.o
diff --git a/drivers/amlogic/wifi/dhd_static_buf.c b/drivers/amlogic/wifi/dhd_static_buf.c
new file mode 100644 (file)
index 0000000..530b567
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * drivers/amlogic/wifi/dhd_static_buf.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt)    "Wifi: %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/skbuff.h>
+#include <linux/wlan_plat.h>
+#include <linux/amlogic/dhd_buf.h>
+
+#define CONFIG_BROADCOM_WIFI_RESERVED_MEM
+
+#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
+
+#define WLAN_STATIC_PKT_BUF                    4
+#define WLAN_STATIC_SCAN_BUF0          5
+#define WLAN_STATIC_SCAN_BUF1          6
+#define WLAN_STATIC_DHD_INFO           7
+#define WLAN_STATIC_DHD_WLFC_INFO              8
+#define PREALLOC_WLAN_SEC_NUM          6
+#define PREALLOC_WLAN_BUF_NUM          160
+#define PREALLOC_WLAN_SECTION_HEADER   24
+
+#define WLAN_SECTION_SIZE_0    (PREALLOC_WLAN_BUF_NUM * 128)
+#define WLAN_SECTION_SIZE_1    (PREALLOC_WLAN_BUF_NUM * 128)
+#define WLAN_SECTION_SIZE_2    (PREALLOC_WLAN_BUF_NUM * 512)
+#define WLAN_SECTION_SIZE_3    (PREALLOC_WLAN_BUF_NUM * 1024)
+#define WLAN_SECTION_SIZE_7    (PREALLOC_WLAN_BUF_NUM * 128)
+#define WLAN_SECTION_SIZE_8    (PREALLOC_WLAN_BUF_NUM * 512)
+
+#define DHD_SKB_HDRSIZE                        336
+#define DHD_SKB_1PAGE_BUFSIZE  ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE)
+#define DHD_SKB_2PAGE_BUFSIZE  ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE)
+#define DHD_SKB_4PAGE_BUFSIZE  ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE)
+
+#define WLAN_SKB_BUF_NUM       17
+
+static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
+
+struct wlan_mem_prealloc {
+       void *mem_ptr;
+       unsigned long size;
+};
+
+static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = {
+       {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)},
+       {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)},
+       {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)},
+       {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)},
+       {NULL, (WLAN_SECTION_SIZE_7 + PREALLOC_WLAN_SECTION_HEADER)},
+       {NULL, (WLAN_SECTION_SIZE_8 + PREALLOC_WLAN_SECTION_HEADER)}
+};
+
+void *wlan_static_scan_buf0;
+void *wlan_static_scan_buf1;
+void *bcmdhd_mem_prealloc(int section, unsigned long size)
+{
+       if (section == WLAN_STATIC_PKT_BUF) {
+               pr_info("1 %s: section=%d, wlan_static_skb=%p\n",
+                       __func__, section, wlan_static_skb);
+               return wlan_static_skb;
+       }
+       if (section == WLAN_STATIC_SCAN_BUF0) {
+               pr_info("2 %s: section=%d, wlan_static_scan_buf0=%p\n",
+                       __func__, section, wlan_static_scan_buf0);
+               return wlan_static_scan_buf0;
+       }
+       if (section == WLAN_STATIC_SCAN_BUF1) {
+               pr_info("3 %s: section=%d, wlan_static_scan_buf1=%p\n",
+                       __func__, section, wlan_static_scan_buf1);
+               return wlan_static_scan_buf1;
+       }
+       if (section == WLAN_STATIC_DHD_INFO) {
+               pr_info("4 %s: section=%d, wlan_mem_array[4]=%p\n",
+                       __func__, section, wlan_mem_array[4].mem_ptr);
+               return wlan_mem_array[4].mem_ptr;
+       }
+       if (section == WLAN_STATIC_DHD_WLFC_INFO) {
+               pr_info("5 %s: section=%d, wlan_mem_array[5]=%p\n",
+                       __func__, section, wlan_mem_array[5].mem_ptr);
+               return wlan_mem_array[5].mem_ptr;
+       }
+       if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM)) {
+               pr_info("5 %s: out of section %d\n", __func__, section);
+               return NULL;
+       }
+
+       if (wlan_mem_array[section].size < size) {
+               pr_info("6 %s: wlan_mem_array[section].size=%lu, size=%lu\n",
+                       __func__, wlan_mem_array[section].size, size);
+               return NULL;
+       }
+       pr_info("7 %s: wlan_mem_array[section].mem_ptr=%p, size=%lu\n",
+               __func__, &wlan_mem_array[section], size);
+
+       return wlan_mem_array[section].mem_ptr;
+}
+EXPORT_SYMBOL(bcmdhd_mem_prealloc);
+
+int bcmdhd_init_wlan_mem(void)
+{
+       int i;
+       int j;
+
+       for (i = 0; i < 8; i++) {
+               wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE);
+               if (!wlan_static_skb[i])
+                       goto err_skb_alloc;
+               pr_debug("1 %s: wlan_static_skb[%d]=%p, size=%lu\n",
+                       __func__, i, wlan_static_skb[i], DHD_SKB_1PAGE_BUFSIZE);
+       }
+
+       for (; i < 16; i++) {
+               wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE);
+               if (!wlan_static_skb[i])
+                       goto err_skb_alloc;
+               pr_debug("2 %s: wlan_static_skb[%d]=%p, size=%lu\n",
+                       __func__, i, wlan_static_skb[i], DHD_SKB_2PAGE_BUFSIZE);
+       }
+
+       wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE);
+       if (!wlan_static_skb[i])
+               goto err_skb_alloc;
+       pr_debug("3 %s: wlan_static_skb[%d]=%p, size=%lu\n",
+               __func__, i, wlan_static_skb[i], DHD_SKB_4PAGE_BUFSIZE);
+
+       for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) {
+               wlan_mem_array[i].mem_ptr =
+                               kmalloc(wlan_mem_array[i].size, GFP_KERNEL);
+
+               if (!wlan_mem_array[i].mem_ptr)
+                       goto err_mem_alloc;
+               pr_debug("4 %s: wlan_mem_array[%d]=%p, size=%lu\n",
+                       __func__, i, wlan_static_skb[i],
+                       wlan_mem_array[i].size);
+       }
+
+       wlan_static_scan_buf0 = kmalloc(65536, GFP_KERNEL);
+       if (!wlan_static_scan_buf0)
+               goto err_mem_alloc;
+       pr_debug("5 %s: wlan_static_scan_buf0=%p, size=%d\n",
+               __func__, wlan_static_scan_buf0, 65536);
+
+       wlan_static_scan_buf1 = kmalloc(65536, GFP_KERNEL);
+       if (!wlan_static_scan_buf1)
+               goto err_mem_alloc;
+       pr_debug("6 %s: wlan_static_scan_buf1=%p, size=%d\n",
+               __func__, wlan_static_scan_buf1, 65536);
+
+       pr_info("%s: WIFI MEM Allocated\n", __func__);
+       return 0;
+
+err_mem_alloc:
+       pr_err("Failed to mem_alloc for WLAN\n");
+       for (j = 0; j < i; j++)
+               kfree(wlan_mem_array[j].mem_ptr);
+
+       i = WLAN_SKB_BUF_NUM;
+
+err_skb_alloc:
+       pr_err("Failed to skb_alloc for WLAN\n");
+       for (j = 0; j < i; j++)
+               dev_kfree_skb(wlan_static_skb[j]);
+
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(bcmdhd_init_wlan_mem);
+#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
+#if 0
+static int __init bcmdhd_wlan_init(void)
+{
+       pr_info("%s()\n", __func__);
+
+#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
+       bcmdhd_init_wlan_mem();
+#endif
+
+       return 0;
+}
+
+device_initcall(bcmdhd_wlan_init);
+#endif
+MODULE_DESCRIPTION("Amlogic S912/wifi driver");
+MODULE_AUTHOR("Kevin Hilman <khilman@baylibre.com>");
+MODULE_LICENSE("GPL")
diff --git a/drivers/amlogic/wifi/wifi_dt.c b/drivers/amlogic/wifi/wifi_dt.c
new file mode 100644 (file)
index 0000000..8acd1fc
--- /dev/null
@@ -0,0 +1,854 @@
+/*
+ * drivers/amlogic/wifi/wifi_dt.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/amlogic/wifi_dt.h>
+#ifdef CONFIG_BCMDHD_USE_STATIC_BUF
+#include <linux/amlogic/dhd_buf.h>
+#endif
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/delay.h>
+#include <linux/cdev.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/media/old_cpu_version.h>
+#include <linux/amlogic/iomap.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/pwm.h>
+#include <linux/amlogic/pwm_meson.h>
+#include "../../gpio/gpiolib.h"
+#define OWNER_NAME "sdio_wifi"
+
+int wifi_power_gpio;
+int wifi_power_gpio2;
+
+/*
+ *there are two pwm channel outputs using one gpio
+ *for gxtvbb and the follows soc
+ */
+struct pwm_config_gxtvbb {
+       unsigned int pwm_channel1;
+       unsigned int pwm_channel2;
+       unsigned int pwm_config1[3];
+       unsigned int pwm_config2[3];
+};
+
+struct pwm_config_gxbb {
+       unsigned int pwm_channel;
+       unsigned int pwm_config[2];
+};
+
+struct wifi_plat_info {
+       int interrupt_pin;
+       int irq_num;
+       int irq_trigger_type;
+
+       int power_on_pin;
+       int power_on_pin_level;
+       int power_on_pin_OD;
+       int power_on_pin2;
+
+       int clock_32k_pin;
+       struct gpio_desc *interrupt_desc;
+       struct gpio_desc *powe_desc;
+
+       int plat_info_valid;
+       struct pinctrl *p;
+       struct device           *dev;
+       struct pwm_config_gxtvbb gxtv_conf;
+       struct pwm_config_gxbb gxb_conf;
+};
+
+#define WIFI_POWER_MODULE_NAME "wifi_power"
+#define WIFI_POWER_DRIVER_NAME "wifi_power"
+#define WIFI_POWER_DEVICE_NAME "wifi_power"
+#define WIFI_POWER_CLASS_NAME          "wifi_power"
+
+#define USB_POWER_UP    _IO('m', 1)
+#define USB_POWER_DOWN  _IO('m', 2)
+#define SDIO_POWER_UP    _IO('m', 3)
+#define SDIO_POWER_DOWN  _IO('m', 4)
+#define SDIO_GET_DEV_TYPE  _IO('m', 5)
+static struct wifi_plat_info wifi_info;
+static dev_t wifi_power_devno;
+static struct cdev *wifi_power_cdev;
+static struct device *devp;
+struct wifi_power_platform_data *pdata;
+
+static int usb_power;
+#define BT_BIT 0
+#define WIFI_BIT       1
+static DEFINE_MUTEX(wifi_bt_mutex);
+
+#define WIFI_INFO(fmt, args...)        \
+       dev_info(wifi_info.dev, "[%s] " fmt, __func__, ##args)
+
+#ifdef CONFIG_OF
+static const struct of_device_id wifi_match[] = {
+       {
+               .compatible = "amlogic, aml_wifi",
+               .data           = (void *)&wifi_info
+       },
+       {},
+};
+
+static struct wifi_plat_info *wifi_get_driver_data
+       (struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+
+       match = of_match_node(wifi_match, pdev->dev.of_node);
+       return (struct wifi_plat_info *)match->data;
+}
+#else
+#define wifi_match NULL
+#endif
+
+
+
+#define SHOW_PIN_OWN(pin_str, pin_num) \
+       WIFI_INFO("%s(%d)\n", pin_str, pin_num)
+
+static int set_power(int value)
+{
+       if (!wifi_info.power_on_pin_OD) {
+               if (wifi_info.power_on_pin_level)
+                       return gpio_direction_output(wifi_info.power_on_pin,
+                                       !value);
+               else
+                       return gpio_direction_output(wifi_info.power_on_pin,
+                                       value);
+       } else {
+               if (wifi_info.power_on_pin_level) {
+                       if (value)
+                               gpio_direction_input(wifi_info.power_on_pin);
+                       else
+                               gpio_direction_output(wifi_info.power_on_pin,
+                                       0);
+               } else {
+                       if (value)
+                               gpio_direction_output(wifi_info.power_on_pin,
+                                       0);
+                       else
+                               gpio_direction_input(wifi_info.power_on_pin);
+               }
+       }
+       return 0;
+}
+
+static int set_power2(int value)
+{
+       if (wifi_info.power_on_pin_level)
+               return gpio_direction_output(wifi_info.power_on_pin2,
+                               !value);
+       else
+               return gpio_direction_output(wifi_info.power_on_pin2,
+                               value);
+}
+
+static int set_wifi_power(int is_power)
+{
+       int ret = 0;
+
+       if (is_power) {
+               if (wifi_info.power_on_pin) {
+                       ret = set_power(1);
+                       if (ret)
+                               WIFI_INFO("power up failed(%d)\n", ret);
+               }
+               if (wifi_info.power_on_pin2) {
+                       ret = set_power2(1);
+                       if (ret)
+                               WIFI_INFO("power2 up failed(%d)\n", ret);
+               }
+       } else {
+               if (wifi_info.power_on_pin) {
+                       ret = set_power(0);
+                       if (ret)
+                               WIFI_INFO("power down failed(%d)\n", ret);
+               }
+               if (wifi_info.power_on_pin2) {
+                       ret = set_power2(0);
+                       if (ret)
+                               WIFI_INFO("power2 down failed(%d)\n", ret);
+               }
+       }
+       return ret;
+}
+
+static void usb_power_control(int is_power, int shift)
+{
+       mutex_lock(&wifi_bt_mutex);
+       if (is_power) {
+               if (!usb_power)
+                       set_wifi_power(is_power);
+               usb_power |= (1 << shift);
+               WIFI_INFO("Set %s power on !\n", (shift ? "WiFi":"BT"));
+       } else {
+               usb_power &= ~(1 << shift);
+               if (!usb_power)
+                       set_wifi_power(is_power);
+               WIFI_INFO("Set %s power down !\n", (shift ? "WiFi":"BT"));
+       }
+       mutex_unlock(&wifi_bt_mutex);
+}
+
+void set_usb_bt_power(int is_power)
+{
+       usb_power_control(is_power, BT_BIT);
+}
+EXPORT_SYMBOL(set_usb_bt_power);
+
+void set_usb_wifi_power(int is_power)
+{
+       usb_power_control(is_power, WIFI_BIT);
+}
+
+static int  wifi_power_open(struct inode *inode, struct file *file)
+{
+       struct cdev *cdevp = inode->i_cdev;
+
+       file->private_data = cdevp;
+       return 0;
+}
+
+static int  wifi_power_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+static long wifi_power_ioctl(struct file *filp,
+       unsigned int cmd, unsigned long arg)
+{
+       char dev_type[10] = {'\0'};
+
+       switch (cmd) {
+       case USB_POWER_UP:
+               set_usb_wifi_power(0);
+               mdelay(200);
+               set_usb_wifi_power(1);
+               break;
+       case USB_POWER_DOWN:
+               set_usb_wifi_power(0);
+               WIFI_INFO(KERN_INFO "Set usb_sdio wifi power down!\n");
+               break;
+       case SDIO_POWER_UP:
+               extern_wifi_set_enable(0);
+               mdelay(200);
+               extern_wifi_set_enable(1);
+               mdelay(200);
+               sdio_reinit();
+               WIFI_INFO("Set sdio wifi power up!\n");
+               break;
+       case SDIO_POWER_DOWN:
+               extern_wifi_set_enable(0);
+               break;
+       case SDIO_GET_DEV_TYPE:
+               memcpy(dev_type, get_wifi_inf(), strlen(get_wifi_inf()));
+               WIFI_INFO("wifi interface dev type: %s, length = %d\n",
+                               dev_type, (int)strlen(dev_type));
+               if (copy_to_user((char __user *)arg,
+                               dev_type, strlen(dev_type)))
+                       return -ENOTTY;
+               break;
+       default:
+               WIFI_INFO("usb wifi_power_ioctl: default !!!\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct file_operations wifi_power_fops = {
+       .unlocked_ioctl = wifi_power_ioctl,
+       .compat_ioctl = wifi_power_ioctl,
+       .open   = wifi_power_open,
+       .release        = wifi_power_release,
+};
+
+static struct class wifi_power_class = {
+       .name = WIFI_POWER_CLASS_NAME,
+       .owner = THIS_MODULE,
+};
+
+static int wifi_setup_dt(void)
+{
+       int ret;
+
+       WIFI_INFO("wifi_setup_dt\n");
+       if (!wifi_info.plat_info_valid) {
+               WIFI_INFO("wifi_setup_dt : invalid device tree setting\n");
+               return -1;
+       }
+
+       /* setup irq */
+       if (wifi_info.interrupt_pin) {
+               ret = gpio_request(wifi_info.interrupt_pin,
+                       OWNER_NAME);
+               if (ret)
+                       WIFI_INFO("interrupt_pin request failed(%d)\n", ret);
+
+               ret = gpio_direction_input(wifi_info.interrupt_pin);
+               if (ret)
+                       WIFI_INFO("set interrupt_pin input failed(%d)\n", ret);
+
+               wifi_info.irq_num = gpio_to_irq(wifi_info.interrupt_pin);
+               if (wifi_info.irq_num)
+                       WIFI_INFO("irq num is:(%d)\n", wifi_info.irq_num);
+
+               SHOW_PIN_OWN("interrupt_pin", wifi_info.interrupt_pin);
+       }
+
+       /* setup power */
+       if (wifi_info.power_on_pin) {
+               ret = gpio_request(wifi_info.power_on_pin, OWNER_NAME);
+               if (ret)
+                       WIFI_INFO("power_on_pin request failed(%d)\n", ret);
+               if (wifi_info.power_on_pin_level)
+                       ret = set_power(1);
+               else
+                       ret = set_power(0);
+               if (ret)
+                       WIFI_INFO("power_on_pin output failed(%d)\n", ret);
+               SHOW_PIN_OWN("power_on_pin", wifi_info.power_on_pin);
+       }
+
+       if (wifi_info.power_on_pin2) {
+               ret = gpio_request(wifi_info.power_on_pin2,
+                       OWNER_NAME);
+               if (ret)
+                       WIFI_INFO("power_on_pin2 request failed(%d)\n", ret);
+               if (wifi_info.power_on_pin_level)
+                       ret = set_power2(1);
+               else
+                       ret = set_power2(0);
+               if (ret)
+                       WIFI_INFO("power_on_pin2 output failed(%d)\n", ret);
+               SHOW_PIN_OWN("power_on_pin2", wifi_info.power_on_pin2);
+       }
+
+       return 0;
+}
+
+static void wifi_teardown_dt(void)
+{
+
+       WIFI_INFO("wifi_teardown_dt\n");
+       if (!wifi_info.plat_info_valid) {
+               WIFI_INFO("wifi_teardown_dt : invalid device tree setting\n");
+               return;
+       }
+
+       if (wifi_info.power_on_pin)
+               gpio_free(wifi_info.power_on_pin);
+
+       if (wifi_info.power_on_pin2)
+               gpio_free(wifi_info.power_on_pin2);
+
+       if (wifi_info.interrupt_pin)
+               gpio_free(wifi_info.interrupt_pin);
+
+}
+
+
+/*
+ * fot gxb soc
+ */
+int pwm_single_channel_conf_dt(struct wifi_plat_info *plat)
+{
+       phandle pwm_phandle;
+       int val;
+       int ret;
+       int count = 2;
+       struct device_node *np_wifi_pwm_conf = plat->dev->of_node;
+
+       ret = of_property_read_u32(np_wifi_pwm_conf, "pwm_config", &val);
+       if (ret) {
+               pr_err("not match wifi_pwm_config node\n");
+               return -1;
+
+       } else {
+               pwm_phandle = val;
+               np_wifi_pwm_conf = of_find_node_by_phandle(pwm_phandle);
+               if (!np_wifi_pwm_conf) {
+                       pr_err("can't find wifi_pwm_config node\n");
+                       return -1;
+               }
+       }
+
+       ret = of_property_read_u32(np_wifi_pwm_conf, "pwm_channel",
+                 &(plat->gxb_conf.pwm_channel));
+       if (ret) {
+               pr_err("not config pwm channel num\n");
+               return -1;
+       }
+
+       ret = of_property_read_u32_array(np_wifi_pwm_conf, "pwm_channel_conf",
+               (plat->gxb_conf.pwm_config), count);
+       if (ret) {
+               pr_err("not config pwm channel parameters\n");
+               return -1;
+       }
+
+       WIFI_INFO("pwm phandle val=%x,pwm-channel=%d\n",
+       val, plat->gxb_conf.pwm_channel);
+       WIFI_INFO("pwm_config[0] = %d,pwm_config[1] = %d\n",
+       plat->gxb_conf.pwm_config[0], plat->gxb_conf.pwm_config[1]);
+       WIFI_INFO("wifi pwm dt ok\n");
+
+       return 0;
+}
+
+/*
+ *configuration for single pwm
+ */
+int pwm_single_channel_conf(struct wifi_plat_info *plat)
+{
+       struct pwm_device *pwm_ch = NULL;
+       struct aml_pwm_chip *aml_chip = NULL;
+       struct pwm_config_gxbb pg = plat->gxb_conf;
+       unsigned int pwm_num = pg.pwm_channel;
+       unsigned int pwm_period = pg.pwm_config[0];
+       unsigned int pwm_duty = pg.pwm_config[1];
+
+       pwm_ch = pwm_request(pwm_num, NULL);
+       if (IS_ERR(pwm_ch)) {
+               WIFI_INFO("request pwm %d failed\n",
+               plat->gxb_conf.pwm_channel);
+       }
+       aml_chip = to_aml_pwm_chip(pwm_ch->chip);
+       pwm_set_period(pwm_ch, pwm_period);
+       pwm_config(pwm_ch, pwm_duty, pwm_period);
+       pwm_enable(pwm_ch);
+       WIFI_INFO("wifi pwm conf ok\n");
+
+       return 0;
+}
+
+int pwm_double_channel_conf_dt(struct wifi_plat_info *plat)
+{
+       phandle pwm_phandle;
+       int val;
+       int ret;
+       int count = 3;
+       int i;
+       struct device_node *np_wifi_pwm_conf = plat->dev->of_node;
+
+       ret = of_property_read_u32(np_wifi_pwm_conf, "pwm_config", &val);
+       if (ret) {
+               pr_err("not match wifi_pwm_config node\n");
+               return -1;
+       }
+       pwm_phandle = val;
+       np_wifi_pwm_conf = of_find_node_by_phandle(pwm_phandle);
+       if (!np_wifi_pwm_conf) {
+               pr_err("can't find wifi_pwm_config node\n");
+               return -1;
+       }
+
+
+       ret = of_property_read_u32(np_wifi_pwm_conf, "pwm_channel1",
+                 &(plat->gxtv_conf.pwm_channel1));
+       if (ret) {
+               pr_err("not config pwm channel 1 num\n");
+               return -1;
+       }
+       ret = of_property_read_u32(np_wifi_pwm_conf, "pwm_channel2",
+               &(plat->gxtv_conf.pwm_channel2));
+       if (ret) {
+               pr_err("not config pwm channel 2 num\n");
+               return -1;
+       }
+       ret = of_property_read_u32_array(np_wifi_pwm_conf, "pwm_channel1_conf",
+               (plat->gxtv_conf.pwm_config1), count);
+       if (ret) {
+               pr_err("not config pwm channel 1 parameters\n");
+               return -1;
+       }
+       ret = of_property_read_u32_array(np_wifi_pwm_conf, "pwm_channel2_conf",
+               (plat->gxtv_conf.pwm_config2), count);
+       if (ret) {
+               pr_err("not config pwm channel 2 parameters\n");
+               return -1;
+       }
+
+       WIFI_INFO("pwm phandle val=%x;pwm-channel1=%d;pwm-channel2=%d\n",
+                       val, plat->gxtv_conf.pwm_channel1,
+                       plat->gxtv_conf.pwm_channel2);
+       for (i = 0; i < count; i++) {
+               WIFI_INFO("pwm_config1[%d] = %d\n",
+               i, plat->gxtv_conf.pwm_config1[i]);
+               WIFI_INFO("pwm_config2[%d] = %d\n",
+               i, plat->gxtv_conf.pwm_config2[i]);
+       }
+       WIFI_INFO("wifi pwm dt ok\n");
+
+       return 0;
+}
+/*
+ *configuration for double pwm
+ */
+int pwm_double_channel_conf(struct wifi_plat_info *plat)
+{
+       struct pwm_device *pwm_ch1 = NULL;
+       struct pwm_device *pwm_ch2 = NULL;
+       struct aml_pwm_chip *aml_chip1 = NULL;
+       struct aml_pwm_chip *aml_chip2 = NULL;
+       struct pwm_config_gxtvbb pg = plat->gxtv_conf;
+       unsigned int pwm_ch1_num = pg.pwm_channel1;
+       unsigned int pwm_ch2_num = pg.pwm_channel2;
+       unsigned int pwm_ch1_period = pg.pwm_config1[0];
+       unsigned int pwm_ch1_duty = pg.pwm_config1[1];
+       unsigned int pwm_ch1_times = pg.pwm_config1[2];
+       unsigned int pwm_ch2_period = pg.pwm_config2[0];
+       unsigned int pwm_ch2_duty = pg.pwm_config2[1];
+       unsigned int pwm_ch2_times = pg.pwm_config2[2];
+
+
+       pwm_ch1 = pwm_request(pwm_ch1_num, NULL);
+       if (IS_ERR(pwm_ch1)) {
+               WIFI_INFO("request pwm %d failed\n",
+               plat->gxtv_conf.pwm_channel1);
+       }
+       pwm_ch2 = pwm_request(pwm_ch2_num, NULL);
+       if (IS_ERR(pwm_ch2)) {
+               WIFI_INFO("request pwm %d failed\n",
+               plat->gxtv_conf.pwm_channel2);
+       }
+
+       aml_chip1 = to_aml_pwm_chip(pwm_ch1->chip);
+       aml_chip2 = to_aml_pwm_chip(pwm_ch2->chip);
+
+       pwm_set_period(pwm_ch1, pwm_ch1_period);
+       pwm_set_period(pwm_ch2, pwm_ch2_period);
+
+       pwm_config(pwm_ch1, pwm_ch1_duty, pwm_ch1_period);
+       pwm_config(pwm_ch2, pwm_ch2_duty, pwm_ch2_period);
+
+       pwm_set_times(aml_chip1, pwm_ch1_num, pwm_ch1_times);
+       pwm_set_times(aml_chip2, pwm_ch2_num, pwm_ch2_times);
+
+       pwm_enable(pwm_ch1);
+       pwm_enable(pwm_ch2);
+       WIFI_INFO("wifi pwm conf ok\n");
+
+       return 0;
+}
+
+static int wifi_dev_probe(struct platform_device *pdev)
+{
+       int ret;
+
+#ifdef CONFIG_OF
+       struct wifi_plat_info *plat;
+       const char *value;
+       struct gpio_desc *desc;
+#else
+       struct wifi_plat_info *plat =
+        (struct wifi_plat_info *)(pdev->dev.platform_data);
+#endif
+
+#ifdef CONFIG_OF
+       if (pdev->dev.of_node) {
+               plat = wifi_get_driver_data(pdev);
+               plat->plat_info_valid = 0;
+               plat->dev = &pdev->dev;
+
+               ret = of_property_read_string(pdev->dev.of_node,
+                       "interrupt_pin", &value);
+               if (ret) {
+                       WIFI_INFO("no interrupt pin");
+                       plat->interrupt_pin = 0;
+               } else {
+                       desc = of_get_named_gpiod_flags(pdev->dev.of_node,
+                               "interrupt_pin", 0, NULL);
+                       plat->interrupt_desc = desc;
+                       plat->interrupt_pin = desc_to_gpio(desc);
+
+                       ret = of_property_read_string(pdev->dev.of_node,
+                       "irq_trigger_type", &value);
+                       if (ret) {
+                               WIFI_INFO("no irq_trigger_type");
+                               plat->irq_trigger_type = 0;
+                               return -1;
+                       }
+
+                       if (strcmp(value, "GPIO_IRQ_HIGH") == 0)
+                               plat->irq_trigger_type = GPIO_IRQ_HIGH;
+                       else if (strcmp(value, "GPIO_IRQ_LOW") == 0)
+                               plat->irq_trigger_type = GPIO_IRQ_LOW;
+                       else if (strcmp(value, "GPIO_IRQ_RISING") == 0)
+                               plat->irq_trigger_type = GPIO_IRQ_RISING;
+                       else if (strcmp(value, "GPIO_IRQ_FALLING") == 0)
+                               plat->irq_trigger_type = GPIO_IRQ_FALLING;
+                       else {
+                               WIFI_INFO("unknown irq trigger type-%s\n",
+                                value);
+                               return -1;
+                       }
+               }
+
+               ret = of_property_read_string(pdev->dev.of_node,
+                       "power_on_pin", &value);
+               if (ret) {
+                       WIFI_INFO("no power_on_pin");
+                       plat->power_on_pin = 0;
+                       plat->power_on_pin_OD = 0;
+               } else {
+                       wifi_power_gpio = 1;
+                       desc = of_get_named_gpiod_flags(pdev->dev.of_node,
+                       "power_on_pin", 0, NULL);
+                       plat->powe_desc = desc;
+                       plat->power_on_pin = desc_to_gpio(desc);
+               }
+
+               ret = of_property_read_u32(pdev->dev.of_node,
+               "power_on_pin_level", &plat->power_on_pin_level);
+
+               ret = of_property_read_u32(pdev->dev.of_node,
+               "power_on_pin_OD", &plat->power_on_pin_OD);
+               if (ret)
+                       plat->power_on_pin_OD = 0;
+               pr_info("wifi: power_on_pin_OD = %d;\n", plat->power_on_pin_OD);
+               ret = of_property_read_string(pdev->dev.of_node,
+                       "power_on_pin2", &value);
+               if (ret) {
+                       WIFI_INFO("no power_on_pin2");
+                       plat->power_on_pin2 = 0;
+               } else {
+                       wifi_power_gpio2 = 1;
+                       desc = of_get_named_gpiod_flags(pdev->dev.of_node,
+                               "power_on_pin2", 0, NULL);
+                       plat->power_on_pin2 = desc_to_gpio(desc);
+               }
+
+               if (of_get_property(pdev->dev.of_node,
+                       "pinctrl-names", NULL)) {
+                       unsigned int pwm_misc;
+                       unsigned int pwm_time_count;
+
+                       if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) {
+                               WIFI_INFO("set pwm as 32k output");
+                               aml_write_cbus(0x21b0, 0x16d016e);
+                               aml_write_cbus(0x21b5, 0x16d016d);
+
+                               pwm_time_count = aml_read_cbus(0x21b4);
+                               pwm_time_count &= ~(0xffff << 16);
+                               pwm_time_count |= ((3 << 16) | (2 << 24));
+                               aml_write_cbus(0x21b4, pwm_time_count);
+
+                               pwm_misc = aml_read_cbus(0x21b2);
+                               pwm_misc &= ~((0x7f << 8) | (3 << 4) |
+                                       (1 << 2) | (1 << 0));
+                               pwm_misc |= ((3 << 24) | (1 << 15) |
+                                       (0 << 8) | (0 << 4));
+                               aml_write_cbus(0x21b2, (pwm_misc | (1 << 0)));
+
+                       } else if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) {
+
+                               WIFI_INFO("set pwm as 32k output");
+                               aml_write_cbus(0x21b0, 0x7f107f2);
+                               pwm_misc = aml_read_cbus(0x21b2);
+                               pwm_misc &= ~((0x7f << 8) | (3 << 4) |
+                                       (1 << 2) | (1 << 0));
+                               pwm_misc |= ((1 << 15) | (4 << 8) | (3 << 4));
+                               aml_write_cbus(0x21b2, pwm_misc);
+                               aml_write_cbus(0x21b2, (pwm_misc | (1 << 0)));
+
+                       } else if (get_cpu_type() == MESON_CPU_MAJOR_ID_M8B) {
+
+                               WIFI_INFO("set pwm as 32k output");
+                               aml_write_cbus(0x21b0, 0x7980799);
+                               pwm_misc = aml_read_cbus(0x21b2);
+                               pwm_misc &= ~((0x7f << 8) | (3 << 4) |
+                                       (1 << 2) | (1 << 0));
+                               pwm_misc |= ((1 << 15) | (4 << 8) | (2 << 4));
+                               aml_write_cbus(0x21b2, pwm_misc);
+                               aml_write_cbus(0x21b2, (pwm_misc | (1 << 0)));
+                       }
+
+                       plat->p = devm_pinctrl_get_select(&pdev->dev,
+                               "wifi_32k_pins");
+               }
+#ifdef CONFIG_BCMDHD_USE_STATIC_BUF
+               if (of_get_property(pdev->dev.of_node,
+                       "dhd_static_buf", NULL)) {
+                       WIFI_INFO("dhd_static_buf setup\n");
+                       bcmdhd_init_wlan_mem();
+               }
+#endif
+
+               plat->plat_info_valid = 1;
+
+               WIFI_INFO("interrupt_pin=%d\n", plat->interrupt_pin);
+               WIFI_INFO("irq_num=%d, irq_trigger_type=%d\n",
+                       plat->irq_num, plat->irq_trigger_type);
+               WIFI_INFO("power_on_pin=%d\n", plat->power_on_pin);
+               WIFI_INFO("clock_32k_pin=%d\n", plat->clock_32k_pin);
+       }
+#endif
+       ret = alloc_chrdev_region(&wifi_power_devno,
+                       0, 1, WIFI_POWER_DRIVER_NAME);
+       if (ret < 0) {
+               ret = -ENODEV;
+               goto out;
+       }
+       ret = class_register(&wifi_power_class);
+       if (ret < 0)
+               goto error1;
+       wifi_power_cdev = cdev_alloc();
+       if (!wifi_power_cdev)
+               goto error2;
+       cdev_init(wifi_power_cdev, &wifi_power_fops);
+       wifi_power_cdev->owner = THIS_MODULE;
+       ret = cdev_add(wifi_power_cdev, wifi_power_devno, 1);
+       if (ret)
+               goto error3;
+       devp = device_create(&wifi_power_class, NULL,
+                       wifi_power_devno, NULL, WIFI_POWER_DEVICE_NAME);
+       if (IS_ERR(devp)) {
+               ret = PTR_ERR(devp);
+               goto error3;
+       }
+       devp->platform_data = pdata;
+
+       wifi_setup_dt();
+
+       return 0;
+error3:
+       cdev_del(wifi_power_cdev);
+error2:
+       class_unregister(&wifi_power_class);
+error1:
+       unregister_chrdev_region(wifi_power_devno, 1);
+out:
+       return ret;
+}
+
+static int wifi_dev_remove(struct platform_device *pdev)
+{
+       WIFI_INFO("wifi_dev_remove\n");
+       wifi_teardown_dt();
+       return 0;
+}
+
+static struct platform_driver wifi_plat_driver = {
+       .probe = wifi_dev_probe,
+       .remove = wifi_dev_remove,
+       .driver = {
+       .name = "aml_wifi",
+       .owner = THIS_MODULE,
+       .of_match_table = wifi_match
+       },
+};
+
+static int __init wifi_dt_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&wifi_plat_driver);
+       return ret;
+}
+/* module_init(wifi_dt_init); */
+fs_initcall_sync(wifi_dt_init);
+
+static void __exit wifi_dt_exit(void)
+{
+       platform_driver_unregister(&wifi_plat_driver);
+}
+module_exit(wifi_dt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("AMLOGIC");
+MODULE_DESCRIPTION("wifi device tree driver");
+
+/**************** wifi mac *****************/
+u8 WIFI_MAC[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static unsigned char chartonum(char c)
+{
+       if (c >= '0' && c <= '9')
+               return c - '0';
+       if (c >= 'A' && c <= 'F')
+               return (c - 'A') + 10;
+       if (c >= 'a' && c <= 'f')
+               return (c - 'a') + 10;
+       return 0;
+}
+
+static int __init mac_addr_set(char *line)
+{
+       unsigned char mac[6];
+       int i = 0;
+
+       WIFI_INFO("try to wifi mac from emmc key!\n");
+       for (i = 0; i < 6 && line[0] != '\0' && line[1] != '\0'; i++) {
+               mac[i] = chartonum(line[0]) << 4 | chartonum(line[1]);
+               line += 3;
+       }
+       memcpy(WIFI_MAC, mac, 6);
+       WIFI_INFO("uboot setup mac-addr: %x:%x:%x:%x:%x:%x\n",
+       WIFI_MAC[0], WIFI_MAC[1], WIFI_MAC[2], WIFI_MAC[3], WIFI_MAC[4],
+       WIFI_MAC[5]);
+
+       return 1;
+}
+
+__setup("mac_wifi=", mac_addr_set);
+
+u8 *wifi_get_mac(void)
+{
+       return WIFI_MAC;
+}
+EXPORT_SYMBOL(wifi_get_mac);
+
+void extern_wifi_set_enable(int is_on)
+{
+
+       if (is_on) {
+               set_wifi_power(1);
+               WIFI_INFO("WIFI  Enable! %d\n", wifi_info.power_on_pin);
+       } else {
+               set_wifi_power(0);
+               WIFI_INFO("WIFI  Disable! %d\n", wifi_info.power_on_pin);
+
+       }
+}
+EXPORT_SYMBOL(extern_wifi_set_enable);
+
+int wifi_irq_num(void)
+{
+       return wifi_info.irq_num;
+}
+EXPORT_SYMBOL(wifi_irq_num);
+
+int wifi_irq_trigger_level(void)
+{
+       return wifi_info.irq_trigger_type;
+}
+EXPORT_SYMBOL(wifi_irq_trigger_level);
+MODULE_DESCRIPTION("Amlogic S912/wifi driver");
+MODULE_AUTHOR("Kevin Hilman <khilman@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/amlogic/bt_device.h b/include/linux/amlogic/bt_device.h
new file mode 100644 (file)
index 0000000..51bbbc4
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * include/linux/amlogic/bt_device.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __PLAT_MESON_BT_DEVICE_H
+#define __PLAT_MESON_BT_DEVICE_H
+
+struct bt_dev_data {
+       int gpio_reset;
+       int gpio_en;
+       int power_low_level;
+       int power_on_pin_OD;
+};
+
+#endif
diff --git a/include/linux/amlogic/wifi_dt.h b/include/linux/amlogic/wifi_dt.h
new file mode 100644 (file)
index 0000000..43ee4ed
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * include/linux/amlogic/wifi_dt.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _wifi_dt_h_
+#define _wifi_dt_h_
+
+extern void sdio_reinit(void);
+extern char *get_wifi_inf(void);
+void extern_wifi_set_enable(int is_on);
+int wifi_irq_num(void);
+
+#endif /* _wifi_dt_h_ */
diff --git a/include/linux/amlogic/wifi_power.h b/include/linux/amlogic/wifi_power.h
new file mode 100644 (file)
index 0000000..50c6708
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * include/linux/amlogic/wifi_power.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __PLAT_MESON_WIFI_POWER_H
+#define __PLAT_MESON_WIFI_POWER_H
+
+struct wifi_power_platform_data {
+       int power_gpio;
+       int power_gpio2;
+       int (*set_power)(int val);
+       int (*set_reset)(int val);
+       int (*set_carddetect)(int val);
+       void * (*mem_prealloc)(int section, unsigned long size);
+       int (*get_mac_addr)(unsigned char *buf);
+       void * (*get_country_code)(char *ccode);
+       void (*usb_set_power)(int val);
+};
+
+int wifi_power_control(int power_up);
+extern void sdio_reinit(void);
+
+#endif /*__PLAT_MESON_WIFI_POWER_H*/