# CONFIG_HAMRADIO is not set
# CONFIG_CAN is not set
# CONFIG_IRDA is not set
-# CONFIG_BT is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=y
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_BCSP is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+CONFIG_BT_WILINK=m
# CONFIG_AF_RXRPC is not set
CONFIG_WIRELESS=y
CONFIG_CFG80211=m
# CONFIG_MAC80211_DEBUG_MENU is not set
# CONFIG_WIMAX is not set
CONFIG_RFKILL=y
-CONFIG_RFKILL_PM=m
+CONFIG_RFKILL_PM=y
# CONFIG_RFKILL_INPUT is not set
# CONFIG_RFKILL_REGULATOR is not set
# CONFIG_NET_9P is not set
# CONFIG_VMWARE_BALLOON is not set
# CONFIG_BMP085 is not set
# CONFIG_PCH_PHUB is not set
+# CONFIG_WL127X_RFKILL is not set
# CONFIG_APANIC is not set
CONFIG_A1026=y
# CONFIG_C2PORT is not set
#
# Texas Instruments shared transport line discipline
#
-# CONFIG_TI_ST is not set
+CONFIG_TI_ST=m
# CONFIG_SENSORS_LIS3_SPI is not set
# CONFIG_SENSORS_LIS3_I2C is not set
CONFIG_HAVE_IDE=y
#include <linux/power/max17042_battery.h>
#include <linux/power/intel_mdf_battery.h>
#include <linux/nfc/pn544.h>
+#include <linux/skbuff.h>
+#include <linux/ti_wilink_st.h>
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
},
};
+#if defined(CONFIG_TI_ST) || defined(CONFIG_TI_ST_MODULE)
+
+/* KIM related */
+static int mrst_kim_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+static int mrst_kim_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct ti_st_plat_data kim_pdata = {
+ .nshutdown_gpio = -1,/* BT, FM, GPS gpios */
+ .flow_cntrl = 1, /* flow control flag */
+ .suspend = mrst_kim_suspend,
+ .resume = mrst_kim_resume,
+};
+
+static struct platform_device linux_kim_device = {
+ .name = "kim", /* named after init manager for ST */
+ .id = -1,
+ .dev.platform_data = &kim_pdata,
+};
+
+/* BT WILINK related */
+static int mrst_bt_enable(struct platform_device *pdev)
+{
+ return 0;
+}
+static int mrst_bt_disable(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct ti_st_plat_data bt_pdata = {
+ .chip_enable = mrst_bt_enable,
+ .chip_disable = mrst_bt_disable,
+};
+
+static struct platform_device linux_bt_device = {
+ .name = "btwilink", /* named after init manager for ST */
+ .id = -1,
+ .dev.platform_data = &bt_pdata,
+};
+static int __init bluetooth_init(void)
+{
+ unsigned int UART_index;
+ long unsigned int UART_baud_rate;
+ int error_reg;
+
+ /* KIM INIT */
+ /* Get the GPIO number from the SFI table
+ if FM gpio is not provided then BT-reset line is
+ also used to enable FM
+ */
+ kim_pdata.nshutdown_gpio = get_gpio_by_name("BT-reset");
+ if (kim_pdata.nshutdown_gpio == -1)
+ return -ENODEV;
+
+ /* Get Share Transport uart settings */
+ /* TODO : add SFI table parsing and one SFI entry for this settings */
+ UART_index = 0;
+ UART_baud_rate = 3500000;
+
+ /* Share Transport uart settings */
+ sprintf((char *)kim_pdata.dev_name, "/dev/ttyMFD%u", UART_index);
+ kim_pdata.baud_rate = UART_baud_rate;
+
+ pr_info("%s: Setting platform_data with UART device name:%s and "
+ "UART baud rate:%lu.\n",
+ __func__, kim_pdata.dev_name, kim_pdata.baud_rate);
+
+ error_reg = platform_device_register(&linux_kim_device);
+ if (error_reg < 0) {
+ pr_err("platform_device_register for kim failed\n");
+ goto exit_on_error;
+ }
+
+ /* BT WILINK INIT */
+ error_reg = platform_device_register(&linux_bt_device);
+ if (error_reg < 0)
+ pr_err("platform_device_register for btwilink failed\n");
+exit_on_error:
+ return error_reg;
+
+}
+device_initcall(bluetooth_init);
+
+#endif
+
/*
* Shrink the non-existent buttons, register the gpio button
* device if there is some
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#define DEBUG
+
#include <linux/platform_device.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
config ANDROID_PMEM
bool "Android pmem allocator"
- default y
+ default n
config ATMEL_PWM
tristate "Atmel AT32/AT91 PWM support"
to register themselves with core and send data, the responses
are returned to relevant protocol drivers based on their
packet types.
-
endmenu
#include <linux/skbuff.h>
#include <linux/ti_wilink_st.h>
+#include <linux/pm_runtime.h>
+
+#ifndef DEBUG
+#ifdef pr_info
+#undef pr_info
+#define pr_info(fmt, arg...)
+#endif
+#endif
/* function pointer pointing to either,
* st_kim_recv during registration to receive fw download responses
for (i = 0; i < ST_MAX_CHANNELS; i++) {
if (likely(st_gdata != NULL &&
st_gdata->is_registered[i] == true &&
- st_gdata->list[i]->reg_complete_cb != NULL)) {
+ st_gdata->list[i]->reg_complete_cb != NULL)) {
st_gdata->list[i]->reg_complete_cb
(st_gdata->list[i]->priv_data, err);
pr_info("protocol %d's cb sent %d\n", i, err);
* and assume chip awake
*/
spin_unlock_irqrestore(&st_gdata->lock, flags);
- if (st_ll_getstate(st_gdata) == ST_LL_AWAKE)
+ if (st_ll_getstate(st_gdata) == ST_LL_AWAKE) {
+ /* pm_runtime_get has already been done
+ * in st_ll_sleep_state. st_wakeup_ack will
+ * call st_ll_sleep_state again and another
+ * pm_runtime_get will be done. We need to
+ * compensate the first one here.
+ */
+ pm_runtime_put(st_gdata->tty_dev);
st_wakeup_ack(st_gdata, LL_WAKE_UP_ACK);
+ }
spin_lock_irqsave(&st_gdata->lock, flags);
ptr++;
/* Unknow packet? */
default:
type = *ptr;
+ if (type < ST_MAX_CHANNELS) {
+ if (!st_gdata->list[type]) {
+ pr_err("dropping frame "
+ "starting with 0x%02x\n", type);
+ goto done;
+ }
+ } else {
+ pr_err("Invalid packet type : 0x%02x\n", type);
+ goto done;
+ }
st_gdata->rx_skb = alloc_skb(
st_gdata->list[type]->max_frame_size,
GFP_ATOMIC);
- skb_reserve(st_gdata->rx_skb,
+ if (st_gdata->rx_skb) {
+ skb_reserve(st_gdata->rx_skb,
st_gdata->list[type]->reserve);
+ } else {
+ pr_err("alloc_skb error\n");
+ goto done;
+ }
/* next 2 required for BT only */
st_gdata->rx_skb->cb[0] = type; /*pkt_type*/
st_gdata->rx_skb->cb[1] = 0; /*incoming*/
ptr++;
count--;
}
+done:
spin_unlock_irqrestore(&st_gdata->lock, flags);
pr_debug("done %s", __func__);
return;
{
seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n",
st_gdata->protos_registered,
- st_gdata->is_registered[0x04] == true ? 'R' : 'U',
- st_gdata->is_registered[0x08] == true ? 'R' : 'U',
- st_gdata->is_registered[0x09] == true ? 'R' : 'U');
+ st_gdata->is_registered[ST_BT] == true ? 'R' : 'U',
+ st_gdata->is_registered[ST_FM] == true ? 'R' : 'U',
+ st_gdata->is_registered[ST_GPS] == true ? 'R' : 'U');
}
/********************************************************************/
pr_debug("%s: %d ", __func__, proto->chnl_id);
st_kim_ref(&st_gdata, 0);
- if (!st_gdata || proto->chnl_id >= ST_MAX_CHANNELS) {
+ if (proto->chnl_id >= ST_MAX_CHANNELS) {
pr_err(" chnl_id %d not supported", proto->chnl_id);
return -EPROTONOSUPPORT;
}
pr_err("data/tty unavailable to perform write");
return -EINVAL;
}
-
pr_debug("%d to be written", skb->len);
len = skb->len;
st_gdata->tty = tty;
tty->disc_data = st_gdata;
+ if (tty->dev->parent)
+ st_gdata->tty_dev = tty->dev->parent;
+ else
+ return -EINVAL;
+
+ /* Asynchronous Get is enough here since we just want to avoid
+ * interface to be released too early
+ */
+ pm_runtime_get(st_gdata->tty_dev);
+
/* don't do an wakeup for now */
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
*/
spin_lock_irqsave(&st_gdata->lock, flags);
for (i = ST_BT; i < ST_MAX_CHANNELS; i++) {
- if (st_gdata->list[i] != NULL)
+ if (st_gdata->is_registered[i] == true)
pr_err("%d not un-registered", i);
st_gdata->list[i] = NULL;
}
st_gdata->rx_skb = NULL;
spin_unlock_irqrestore(&st_gdata->lock, flags);
+ pm_runtime_put(st_gdata->tty_dev);
+
pr_debug("%s: done ", __func__);
}
kfree(st_gdata);
}
}
-
-
#include <linux/seq_file.h>
#include <linux/sched.h>
#include <linux/sysfs.h>
+#include <linux/rfkill.h>
#include <linux/tty.h>
-#include <linux/skbuff.h>
+/* understand BT events for fw response */
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
#include <linux/ti_wilink_st.h>
+#ifndef DEBUG
+#ifdef pr_info
+#undef pr_info
+#define pr_info(fmt, arg...)
+#endif
+#endif
#define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */
static struct platform_device *st_kim_devices[MAX_ST_DEVICES];
} /* end of if rx_state */
switch (*ptr) {
/* Bluetooth event packet? */
- case 0x04:
+ case HCI_EVENT_PKT:
+ pr_debug("Event packet");
kim_gdata->rx_state = ST_W4_HEADER;
- kim_gdata->rx_count = 2;
- type = *ptr;
+ kim_gdata->rx_count = HCI_EVENT_HDR_SIZE;
+ type = HCI_EVENT_PKT;
break;
default:
pr_info("unknown packet");
ptr++;
count--;
kim_gdata->rx_skb =
- alloc_skb(1024+8, GFP_ATOMIC);
+ alloc_skb(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
if (!kim_gdata->rx_skb) {
pr_err("can't allocate mem for new packet");
kim_gdata->rx_state = ST_W4_PACKET_TYPE;
kim_gdata->rx_skb->cb[1] = 0;
}
+ pr_debug("done %s", __func__);
return;
}
int wr_room_space;
int cmd_size;
unsigned long timeout;
+ struct st_data_s *core_data;
+ core_data = kim_gdata->core_data;
+ pr_err("download_firmware start");
err = read_local_version(kim_gdata, bts_scr_name);
if (err != 0) {
pr_err("kim: failed to read local ver");
skip_change_remote_baud(&ptr, &len);
break;
}
+ /*Enable the ST_LL state machine if HCILL SLEEP command
+ * enabled in BT init script*/
+ if (unlikely
+ (((struct hci_command *)action_ptr)->opcode ==
+ HCILL_SLEEP_MODE_OPCODE))
+ st_ll_enable(core_data);
/*
* Make sure we have enough free space in uart
* tx buffer to write current firmware command
}
/* fw download complete */
release_firmware(kim_gdata->fw_entry);
+ pr_err("download_firmware complete");
+
+
+ /* If the firmware wasn't parsed completely, warn user about remaining
+ * commands in firmware, so that the firmware can be relooked at
+ */
+ if (len != 0)
+ pr_err("%s:incomplete, script not parsed completely", __func__);
return 0;
}
struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
struct kim_data_s *kim_gdata = st_gdata->kim_data;
+ pr_debug(" %s ", __func__);
/* copy to local buffer */
if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
/* must be the read_ver_cmd */
{
struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
complete(&kim_gdata->ldisc_installed);
+ pr_info("%s", __func__);
}
/**
do {
/* Configure BT nShutdown to HIGH state */
+ pr_err("Access to gpio %d", kim_gdata->nshutdown);
gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
mdelay(5); /* FIXME: a proper toggle */
gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
pr_info("ldisc_install = 0");
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
NULL, "install");
- err = -ETIMEDOUT;
+
+ /* wait for uart close */
+ err = wait_for_completion_timeout(
+ &kim_gdata->ldisc_installed,
+ msecs_to_jiffies(1000));
+ if (!err) { /* timeout */
+ pr_err("uart close timeout");
+ err = -ETIMEDOUT;
+ }
continue;
} else {
/* ldisc installed now */
pr_info("ldisc_install = 0");
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
NULL, "install");
+
+ /* wait for ldisc to be un-installed */
+ err = wait_for_completion_timeout(
+ &kim_gdata->ldisc_installed,
+ msecs_to_jiffies(1000));
+ if (!err) { /* timeout */
+ pr_err("uninstall ldisc timeout");
+ err = -ETIMEDOUT;
+ }
continue;
} else { /* on success don't retry */
break;
long err = 0;
struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
+ pr_info("%s", __func__);
INIT_COMPLETION(kim_gdata->ldisc_installed);
/* Flush any pending characters in the driver and discipline. */
struct kim_data_s *kim_gdata;
/* get kim_gdata reference from platform device */
pdev = st_get_plat_device(id);
- if (!pdev) {
- *core_data = NULL;
- return;
- }
kim_gdata = dev_get_drvdata(&pdev->dev);
*core_data = kim_gdata->core_data;
}
/* multiple devices could exist */
st_kim_devices[pdev->id] = pdev;
} else {
- /* platform's sure about existence of 1 device */
+ /* platform's sure about existance of 1 device */
st_kim_devices[0] = pdev;
}
/*
* Shared Transport driver
* HCI-LL module responsible for TI proprietary HCI_LL protocol
- * Copyright (C) 2009-2010 Texas Instruments
- * Author: Pavan Savoy <pavan_savoy@ti.com>
+ * Copyright (C) 2009 Texas Instruments
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
*
*/
+
#define pr_fmt(fmt) "(stll) :" fmt
#include <linux/skbuff.h>
#include <linux/module.h>
#include <linux/ti_wilink_st.h>
+#include <linux/pm_runtime.h>
+
+#ifndef DEBUG
+#ifdef pr_info
+#undef pr_info
+#define pr_info(fmt, arg...)
+#endif
+#endif
+
/**********************************************************************/
/* internal functions */
static void send_ll_cmd(struct st_data_s *st_data,
{
pr_debug("%s", __func__);
/* sanity check */
- if (st_data->ll_state != ST_LL_AWAKE)
- pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND"
+ if (st_data->ll_state != ST_LL_AWAKE) {
+ pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND "
"in state %ld", st_data->ll_state);
+ /* Since Driver is asked to go to sleep but not aware to be
+ * awake Runtime PM is not aware of the state change either
+ * Requesting the device has not been done, so we do it*/
+ pm_runtime_get(st_data->tty_dev);
+ }
send_ll_cmd(st_data, LL_SLEEP_ACK);
/* update state */
st_data->ll_state = ST_LL_ASLEEP;
case ST_LL_AWAKE:
/* duplicate wake_ind */
pr_err("duplicate wake_ind already AWAKE");
+ send_ll_cmd(st_data, LL_WAKE_UP_ACK); /* send wake_ack */
break;
case ST_LL_AWAKE_TO_ASLEEP:
/* duplicate wake_ind */
case LL_SLEEP_IND: /* sleep ind */
pr_debug("sleep indication recvd");
ll_device_want_to_sleep(st_data);
+ pm_runtime_put(st_data->tty_dev);
break;
case LL_SLEEP_ACK: /* sleep ack */
pr_err("sleep ack rcvd: host shouldn't");
break;
case LL_WAKE_UP_IND: /* wake ind */
pr_debug("wake indication recvd");
+ /* Getting the Device is done to avoid power gating the
+ * Interface (for example UART). This can be done
+ * asynchronously since low level driver is getting the device
+ * when doing a transfert */
+ pm_runtime_get(st_data->tty_dev);
ll_device_want_to_wakeup(st_data);
break;
case LL_WAKE_UP_ACK: /* wake ack */
pr_debug("wake ack rcvd");
+ pm_runtime_get(st_data->tty_dev);
st_data->ll_state = ST_LL_AWAKE;
break;
default:
--- /dev/null
+What: /sys/class/rfkill/rfkill%d/
+Date: March 22
+Contact: Pavan Savoy <pavan_savoy@ti.com>
+Description:
+ Creates the rfkill entries for Radio apps like
+ BT app, FM app or GPS app to toggle corresponding
+ cores of the chip
+
+What: /dev/rfkill
+Date: March 22
+Contact: Pavan Savoy <pavan_savoy@ti.com>
+Description:
+ A daemon which maintains the ldisc installation and
+ uninstallation would be ppolling on this device and listening
+ on events which would suggest either to install or un-install
+ line discipline
+
+What: /sys/kernel/debug/ti-st/version
+Contact: Pavan Savoy <pavan_savoy@ti.com>
+Description:
+ WiLink chip's ROM version exposed to user-space for some
+ proprietary protocol stacks to make use of.
+
+What: /sys/kernel/debug/ti-st/protocols
+Contact: Pavan Savoy <pavan_savoy@ti.com>
+Description:
+ The reason for chip being ON, the list of protocols registered.
+
unsigned long ll_state;
void *kim_data;
struct tty_struct *tty;
+ struct device *tty_dev;
};
/*
/* time in msec to wait for
* line discipline to be installed
*/
-#define LDISC_TIME 1000
-#define CMD_RESP_TIME 800
+#define LDISC_TIME 5000 /*1000*/
+#define CMD_RESP_TIME 4000 /*800*/
#define CMD_WR_TIME 5000
#define MAKEWORD(a, b) ((unsigned short)(((unsigned char)(a)) \
| ((unsigned short)((unsigned char)(b))) << 8))
#define LL_WAKE_UP_IND 0x32
#define LL_WAKE_UP_ACK 0x33
+#define HCILL_SLEEP_MODE_OPCODE 0xFD0C
/* initialize and de-init ST LL */
long st_ll_init(struct st_data_s *);
long st_ll_deinit(struct st_data_s *);
unsigned long baud_rate;
int (*suspend)(struct platform_device *, pm_message_t);
int (*resume)(struct platform_device *);
+ int (*chip_enable) (struct kim_data_s *kim_data);
+ int (*chip_disable) (struct kim_data_s *kim_data);
};
#endif /* TI_WILINK_ST_H */