summaryrefslogtreecommitdiff
path: root/drivers/staging/cg2900
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/cg2900')
-rw-r--r--drivers/staging/cg2900/bluetooth/btcg2900.c12
-rw-r--r--drivers/staging/cg2900/bluetooth/cg2900_uart.c32
-rw-r--r--drivers/staging/cg2900/devices-cg2900.c9
-rw-r--r--drivers/staging/cg2900/include/cg2900.h26
-rw-r--r--drivers/staging/cg2900/mfd/cg2900_audio.c76
-rw-r--r--drivers/staging/cg2900/mfd/cg2900_chip.c153
-rw-r--r--drivers/staging/cg2900/mfd/cg2900_chip.h22
-rw-r--r--drivers/staging/cg2900/mfd/cg2900_core.h1
8 files changed, 254 insertions, 77 deletions
diff --git a/drivers/staging/cg2900/bluetooth/btcg2900.c b/drivers/staging/cg2900/bluetooth/btcg2900.c
index 07aae9a32ca..cfeeb4a23c9 100644
--- a/drivers/staging/cg2900/bluetooth/btcg2900.c
+++ b/drivers/staging/cg2900/bluetooth/btcg2900.c
@@ -35,11 +35,6 @@
#define BT_HEADER_LENGTH 0x03
-#define STLC2690_HCI_REV 0x0600
-#define CG2900_PG1_HCI_REV 0x0101
-#define CG2900_PG2_HCI_REV 0x0200
-#define CG2900_PG1_SPECIAL_HCI_REV 0x0700
-
#define NAME "BTCG2900 "
/* Wait for 5 seconds for a response to our requests */
@@ -204,10 +199,11 @@ static struct sk_buff *get_bt_enable_cmd(struct btcg2900_info *info,
}
/* If connected chip does not support the command return NULL */
- if (CG2900_PG1_SPECIAL_HCI_REV != rev_data.revision &&
- CG2900_PG1_HCI_REV != rev_data.revision &&
- CG2900_PG2_HCI_REV != rev_data.revision)
+ if (!check_chip_revision_support(rev_data.revision)) {
+ BT_ERR(NAME "Unsupported Chip revision:0x%x\n",
+ rev_data.revision);
return NULL;
+ }
/* CG2900 used */
skb = pf_data->alloc_skb(sizeof(*cmd), GFP_KERNEL);
diff --git a/drivers/staging/cg2900/bluetooth/cg2900_uart.c b/drivers/staging/cg2900/bluetooth/cg2900_uart.c
index 3c88ed6d18f..6b577514ae6 100644
--- a/drivers/staging/cg2900/bluetooth/cg2900_uart.c
+++ b/drivers/staging/cg2900/bluetooth/cg2900_uart.c
@@ -7,6 +7,7 @@
* Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
* Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
* Lukasz Rymanowski (lukasz.rymanowski@tieto.com) for ST-Ericsson.
+ * Hemant Gupta (hemant.gupta@stericsson.com) for ST-Ericsson.
* License terms: GNU General Public License (GPL), version 2
*
* Linux Bluetooth UART Driver for ST-Ericsson CG2900 connectivity controller.
@@ -79,6 +80,7 @@
/* Size of the header in the different packets */
#define HCI_BT_EVT_HDR_SIZE 2
#define HCI_BT_ACL_HDR_SIZE 4
+#define HCI_NFC_HDR_SIZE 3
#define HCI_FM_RADIO_HDR_SIZE 1
#define HCI_GNSS_HDR_SIZE 3
@@ -109,6 +111,7 @@
#define CG2900_SKB_RESERVE HCI_H4_SIZE
/* Default H4 channels which may change depending on connected controller */
+#define HCI_NFC_H4_CHANNEL 0x05
#define HCI_FM_RADIO_H4_CHANNEL 0x08
#define HCI_GNSS_H4_CHANNEL 0x09
@@ -126,6 +129,15 @@
#define CG2900_BAUD_RATE_3250000 0x28
#define CG2900_BAUD_RATE_4000000 0x2B
+/* NFC: 1byte extra is recieved for checksum */
+#define NFC_CHECKSUM_DATA_LEN 0x01
+
+/* NFC */
+struct nfc_hci_hdr {
+ __u8 op_code;
+ __le16 plen;
+} __packed;
+
/**
* enum sleep_allowed_bits - bits indicating if sleep is allowed.
* @SLEEP_TTY_READY: Bit for checking if break can be applied using tty.
@@ -207,6 +219,7 @@ struct bt_vs_set_baud_rate_cmd {
* @W4_PACKET_TYPE: Waiting for packet type.
* @W4_EVENT_HDR: Waiting for BT event header.
* @W4_ACL_HDR: Waiting for BT ACL header.
+ * @W4_NFC_HDR: Waiting for NFC header.
* @W4_FM_RADIO_HDR: Waiting for FM header.
* @W4_GNSS_HDR: Waiting for GNSS header.
* @W4_DATA: Waiting for data in rest of the packet (after header).
@@ -215,6 +228,7 @@ enum uart_rx_state {
W4_PACKET_TYPE,
W4_EVENT_HDR,
W4_ACL_HDR,
+ W4_NFC_HDR,
W4_FM_RADIO_HDR,
W4_GNSS_HDR,
W4_DATA
@@ -1719,6 +1733,7 @@ static int cg2900_hu_receive(struct hci_uart *hu,
int len;
struct hci_event_hdr *evt;
struct hci_acl_hdr *acl;
+ struct nfc_hci_hdr *nfc;
union fm_leg_evt_or_irq *fm;
struct gnss_hci_hdr *gnss;
struct uart_info *uart_info = dev_get_drvdata(hu->proto->dev);
@@ -1790,6 +1805,20 @@ static int cg2900_hu_receive(struct hci_uart *hu,
/* Header read. Continue with next bytes */
continue;
+ case W4_NFC_HDR:
+ nfc = (struct nfc_hci_hdr *)tmp;
+ /*
+ * NFC Packet(s) have 1 extra byte for checksum.
+ * This is not indicated by the byte length determined
+ * from the received NFC Packet over HCI. So
+ * length of received NFC packet should be updated
+ * accordingly.
+ */
+ check_data_len(uart_info, le16_to_cpu(nfc->plen) +
+ NFC_CHECKSUM_DATA_LEN);
+ /* Header read. Continue with next bytes */
+ continue;
+
case W4_FM_RADIO_HDR:
fm = (union fm_leg_evt_or_irq *)tmp;
check_data_len(uart_info, fm->param_length);
@@ -1817,6 +1846,9 @@ check_h4_header:
} else if (*r_ptr == HCI_BT_ACL_H4_CHANNEL) {
uart_info->rx_state = W4_ACL_HDR;
uart_info->rx_count = HCI_BT_ACL_HDR_SIZE;
+ } else if (*r_ptr == HCI_NFC_H4_CHANNEL) {
+ uart_info->rx_state = W4_NFC_HDR;
+ uart_info->rx_count = HCI_NFC_HDR_SIZE;
} else if (*r_ptr == HCI_FM_RADIO_H4_CHANNEL) {
uart_info->rx_state = W4_FM_RADIO_HDR;
uart_info->rx_count = HCI_FM_RADIO_HDR_SIZE;
diff --git a/drivers/staging/cg2900/devices-cg2900.c b/drivers/staging/cg2900/devices-cg2900.c
index e6703c96aa9..4c5d4a22a77 100644
--- a/drivers/staging/cg2900/devices-cg2900.c
+++ b/drivers/staging/cg2900/devices-cg2900.c
@@ -40,11 +40,6 @@
#define H4_HEADER_LENGTH 0x01
#define BT_HEADER_LENGTH 0x03
-#define STLC2690_HCI_REV 0x0600
-#define CG2900_PG1_HCI_REV 0x0101
-#define CG2900_PG2_HCI_REV 0x0200
-#define CG2900_PG1_SPECIAL_HCI_REV 0x0700
-
struct vs_power_sw_off_cmd {
__le16 op_code;
u8 len;
@@ -65,9 +60,7 @@ static struct sk_buff *dcg2900_get_power_switch_off_cmd
int i;
/* If connected chip does not support the command return NULL */
- if (CG2900_PG1_SPECIAL_HCI_REV != dev->chip.hci_revision &&
- CG2900_PG1_HCI_REV != dev->chip.hci_revision &&
- CG2900_PG2_HCI_REV != dev->chip.hci_revision)
+ if (!check_chip_revision_support(dev->chip.hci_revision))
return NULL;
dev_dbg(dev->dev, "Generating PowerSwitchOff command\n");
diff --git a/drivers/staging/cg2900/include/cg2900.h b/drivers/staging/cg2900/include/cg2900.h
index 99ac90da58f..85b5e03eb3c 100644
--- a/drivers/staging/cg2900/include/cg2900.h
+++ b/drivers/staging/cg2900/include/cg2900.h
@@ -28,6 +28,15 @@
#define CG2900_CHAR_DEV_IOCTL_EVENT_IDLE 0
#define CG2900_CHAR_DEV_IOCTL_EVENT_RESET 1
+/* Specific chip version data */
+#define STLC2690_REV 0x0600
+#define CG2900_PG1_REV 0x0101
+#define CG2900_PG2_REV 0x0200
+#define CG2900_PG1_SPECIAL_REV 0x0700
+#define CG2905_PG1_1_REV 0x1805
+#define CG2910_PG1_REV 0x1004
+#define CG2910_PG2_REV 0x1008
+
/**
* struct cg2900_rev_data - Contains revision data for the local controller.
* @revision: Revision of the controller, e.g. to indicate that it is
@@ -39,8 +48,8 @@
* the manufacturer.
*/
struct cg2900_rev_data {
- int revision;
- int sub_version;
+ u16 revision;
+ u16 sub_version;
};
#ifdef __KERNEL__
@@ -273,6 +282,19 @@ static inline void cg2900_set_prv(struct cg2900_user_data *dev, void *data)
dev->private_data = data;
}
+static inline bool check_chip_revision_support(u16 hci_revision)
+{
+ if (hci_revision != CG2900_PG1_SPECIAL_REV &&
+ hci_revision != CG2900_PG1_REV &&
+ hci_revision != CG2900_PG2_REV &&
+ hci_revision != CG2905_PG1_1_REV &&
+ hci_revision != CG2910_PG1_REV &&
+ hci_revision != CG2910_PG2_REV)
+ return false;
+
+ return true;
+}
+
extern int cg2900_register_chip_driver(struct cg2900_id_callbacks *cb);
extern void cg2900_deregister_chip_driver(struct cg2900_id_callbacks *cb);
extern int cg2900_register_trans_driver(struct cg2900_chip_dev *dev);
diff --git a/drivers/staging/cg2900/mfd/cg2900_audio.c b/drivers/staging/cg2900/mfd/cg2900_audio.c
index 2f00d79ed1e..267e4bd8a02 100644
--- a/drivers/staging/cg2900/mfd/cg2900_audio.c
+++ b/drivers/staging/cg2900/mfd/cg2900_audio.c
@@ -3,6 +3,7 @@
* Authors:
* Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
* Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * Hemant Gupta (hemant.gupta@stericsson.com) for ST-Ericsson.
* License terms: GNU General Public License (GPL), version 2
*
* Linux Bluetooth Audio Driver for ST-Ericsson CG2900 controller.
@@ -50,8 +51,11 @@
/* Used to select proper API, ignoring subrevisions etc */
enum chip_revision {
- CHIP_REV_PG1,
- CHIP_REV_PG2
+ CG2900_CHIP_REV_PG1,
+ CG2900_CHIP_REV_PG2,
+ CG2905_CHIP_REV_PG1_1,
+ CG2910_CHIP_REV_PG1,
+ CG2910_CHIP_REV_PG2
};
/**
@@ -130,7 +134,7 @@ struct endpoint_config_node {
* @false otherwise.
* @endpoints: List containing the endpoint configurations.
* @stream_ids: Bitmask for in-use stream ids (only used with
- * PG2 chip API).
+ * CG2900 PG2 onwards chip API).
*/
struct audio_info {
struct list_head list;
@@ -880,7 +884,7 @@ static int send_vs_delete_stream(struct audio_user *audio_user,
struct audio_cb_info *cb_info = cg2900_get_usr(pf_data);
/* Now delete the stream - format command... */
- if (info->revision == CHIP_REV_PG1) {
+ if (info->revision == CG2900_CHIP_REV_PG1) {
struct bt_vs_reset_session_cfg_cmd *cmd;
dev_dbg(BT_DEV, "BT: HCI_VS_Reset_Session_Configuration\n");
@@ -933,12 +937,13 @@ static int send_vs_delete_stream(struct audio_user *audio_user,
}
/* wait for response */
- if (info->revision == CHIP_REV_PG1) {
+ if (info->revision == CG2900_CHIP_REV_PG1) {
err = receive_bt_cmd_complete(audio_user, opcode, NULL, 0);
} else {
u8 vs_err;
- /* All commands in PG2 API returns one byte extra status */
+ /* All commands on CG2900 PG2 onwards
+ * API returns one byte extra status */
err = receive_bt_cmd_complete(audio_user, opcode,
&vs_err, sizeof(vs_err));
@@ -1250,7 +1255,8 @@ static int send_vs_stream_ctrl(struct audio_user *user, u8 stream, u8 command)
goto finished;
}
- /* All commands in PG2 API returns one byte with extra status */
+ /* All commands on CG2900 PG2 onwards
+ * API returns one byte extra status */
err = receive_bt_cmd_complete(user,
CG2900_MC_VS_STREAM_CONTROL,
&vs_err, sizeof(vs_err));
@@ -1338,7 +1344,8 @@ static int send_vs_create_stream(struct audio_user *user, u8 inport,
goto finished_release_id;
}
- /* All commands in PG2 API returns one byte with extra status */
+ /* All commands on CG2900 PG2 onwards
+ * API returns one byte extra status */
err = receive_bt_cmd_complete(user,
CG2900_MC_VS_CREATE_STREAM,
&vs_err, sizeof(vs_err));
@@ -1423,7 +1430,8 @@ static int send_vs_port_cfg(struct audio_user *user, u8 port,
goto finished;
}
- /* All commands in PG2 API returns one byte with extra status */
+ /* All commands on CG2900 PG2 onwards
+ * API returns one byte extra status */
err = receive_bt_cmd_complete(user, CG2900_MC_VS_PORT_CONFIG,
&vs_err, sizeof(vs_err));
if (err)
@@ -1516,8 +1524,8 @@ static int set_dai_config_pg1(struct audio_user *audio_user,
i2s_pcm = &config->conf.i2s_pcm;
/*
- * PG1 chips don't support I2S over the PCM/I2S bus,
- * and PG2 chips don't use this command
+ * CG2900 PG1 chips don't support I2S over the PCM/I2S bus,
+ * and CG2900 PG2 onwards chips don't use this command
*/
if (i2s_pcm->protocol != PORT_PROTOCOL_PCM) {
dev_err(BT_DEV,
@@ -1583,13 +1591,15 @@ finished_unlock_mutex:
}
/**
- * set_dai_config_pg2() - Internal implementation of @cg2900_audio_set_dai_config for PG2 hardware.
+ * set_dai_config_pg2() - Internal implementation of
+ * cg2900_audio_set_dai_config for CG2900 PG2 onwards hardware.
* @audio_user: Pointer to audio user struct.
* @config: Pointer to the configuration to set.
*
- * Sets the Digital Audio Interface (DAI) configuration for PG2
- * hardware. This is an internal function and basic
- * argument-verification should have been done by the caller.
+ * Sets the Digital Audio Interface (DAI) configuration for
+ * CG2900 PG2 onwards hardware. This is an internal function
+ * and basic argument-verification should have been
+ * done by the caller.
*
* Returns:
* 0 if there is no error.
@@ -1831,7 +1841,7 @@ static int conn_start_i2s_to_fm_rx(struct audio_user *audio_user,
goto finished_unlock_mutex;
/* Set up the stream */
- if (info->revision == CHIP_REV_PG1) {
+ if (info->revision == CG2900_CHIP_REV_PG1) {
struct i2s_fm_stream_config_priv stream_priv;
/* Now send HCI_VS_Set_Session_Configuration command */
@@ -1868,7 +1878,7 @@ static int conn_start_i2s_to_fm_rx(struct audio_user *audio_user,
dev_dbg(FM_DEV, "stream_handle set to %d\n", *stream_handle);
/* Now start the stream */
- if (info->revision == CHIP_REV_PG1)
+ if (info->revision == CG2900_CHIP_REV_PG1)
err = send_vs_session_ctrl(audio_user, *stream_handle,
CG2900_BT_SESSION_START);
else
@@ -1964,7 +1974,7 @@ static int conn_start_i2s_to_fm_tx(struct audio_user *audio_user,
goto finished_unlock_mutex;
/* Set up the stream */
- if (info->revision == CHIP_REV_PG1) {
+ if (info->revision == CG2900_CHIP_REV_PG1) {
struct i2s_fm_stream_config_priv stream_priv;
/* Now send HCI_VS_Set_Session_Configuration command */
@@ -2001,7 +2011,7 @@ static int conn_start_i2s_to_fm_tx(struct audio_user *audio_user,
dev_dbg(FM_DEV, "stream_handle set to %d\n", *stream_handle);
/* Now start the stream */
- if (info->revision == CHIP_REV_PG1)
+ if (info->revision == CG2900_CHIP_REV_PG1)
err = send_vs_session_ctrl(audio_user, *stream_handle,
CG2900_BT_SESSION_START);
else
@@ -2112,7 +2122,7 @@ static int conn_start_pcm_to_sco(struct audio_user *audio_user,
mutex_lock(&info->bt_mutex);
/* Set up the stream */
- if (info->revision == CHIP_REV_PG1) {
+ if (info->revision == CG2900_CHIP_REV_PG1) {
err = send_vs_session_config(audio_user, config_pcm_sco_stream,
&bt_config->sco);
} else {
@@ -2143,7 +2153,7 @@ static int conn_start_pcm_to_sco(struct audio_user *audio_user,
dev_dbg(BT_DEV, "stream_handle set to %d\n", *stream_handle);
/* Now start the stream */
- if (info->revision == CHIP_REV_PG1)
+ if (info->revision == CG2900_CHIP_REV_PG1)
err = send_vs_session_ctrl(audio_user, *stream_handle,
CG2900_BT_SESSION_START);
else
@@ -2193,7 +2203,7 @@ static int conn_stop_stream(struct audio_user *audio_user,
mutex_lock(&info->bt_mutex);
/* Now stop the stream */
- if (info->revision == CHIP_REV_PG1)
+ if (info->revision == CG2900_CHIP_REV_PG1)
err = send_vs_session_ctrl(audio_user, stream_handle,
CG2900_BT_SESSION_STOP);
else
@@ -2357,11 +2367,23 @@ int cg2900_audio_open(unsigned int *session, struct device *parent)
switch (rev_data.revision) {
case CG2900_PG1_REV:
case CG2900_PG1_SPECIAL_REV:
- info->revision = CHIP_REV_PG1;
+ info->revision = CG2900_CHIP_REV_PG1;
break;
case CG2900_PG2_REV:
- info->revision = CHIP_REV_PG2;
+ info->revision = CG2900_CHIP_REV_PG2;
+ break;
+
+ case CG2905_PG1_1_REV:
+ info->revision = CG2905_CHIP_REV_PG1_1;
+ break;
+
+ case CG2910_PG1_REV:
+ info->revision = CG2910_CHIP_REV_PG1;
+ break;
+
+ case CG2910_PG2_REV:
+ info->revision = CG2910_CHIP_REV_PG2;
break;
default:
@@ -2501,10 +2523,10 @@ int cg2900_audio_set_dai_config(unsigned int session,
return -EIO;
}
- /* Different commands are used for PG1 and PG2 */
- if (info->revision == CHIP_REV_PG1)
+ /* Different command is used for CG2900 PG1 */
+ if (info->revision == CG2900_CHIP_REV_PG1)
err = set_dai_config_pg1(audio_user, config);
- else if (info->revision == CHIP_REV_PG2)
+ else
err = set_dai_config_pg2(audio_user, config);
return err;
diff --git a/drivers/staging/cg2900/mfd/cg2900_chip.c b/drivers/staging/cg2900/mfd/cg2900_chip.c
index 3ff07714508..3c8ea1e08e5 100644
--- a/drivers/staging/cg2900/mfd/cg2900_chip.c
+++ b/drivers/staging/cg2900/mfd/cg2900_chip.c
@@ -6,6 +6,7 @@
* Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
* Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
* Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * Hemant Gupta (hemant.gupta@stericsson.com) for ST-Ericsson.
* License terms: GNU General Public License (GPL), version 2
*
* Linux Bluetooth HCI H:4 Driver for ST-Ericsson CG2900 GPS/BT/FM controller.
@@ -81,6 +82,11 @@
*/
#define CHANNEL_BT_EVT 0x04
+/** CHANNEL_NFC - Bluetooth HCI H:4 channel
+ * for NFC in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_NFC 0x05
+
/** CHANNEL_FM_RADIO - Bluetooth HCI H:4 channel
* for FM radio in the ST-Ericsson connectivity controller.
*/
@@ -128,6 +134,10 @@
*/
#define CG2900_BT_EVT "cg2900_bt_evt"
+/** CG2900_NFC - Bluetooth HCI H4 channel for NFC.
+ */
+#define CG2900_NFC "cg2900_nfc"
+
/** CG2900_FM_RADIO - Bluetooth HCI H4 channel for FM radio.
*/
#define CG2900_FM_RADIO "cg2900_fm_radio"
@@ -386,7 +396,9 @@ struct cg2900_chip_info {
int nbr_of_polls;
bool startup;
int mfd_size;
+ int mfd_extra_size;
int mfd_char_size;
+ int mfd_extra_char_size;
};
/**
@@ -417,6 +429,8 @@ static DECLARE_WAIT_QUEUE_HEAD(clk_user_wait_queue);
static struct mfd_cell cg2900_devs[];
static struct mfd_cell cg2900_char_devs[];
+static struct mfd_cell cg2910_extra_devs[];
+static struct mfd_cell cg2910_extra_char_devs[];
static void chip_startup_finished(struct cg2900_chip_info *info, int err);
static void chip_shutdown(struct cg2900_user_data *user);
@@ -1031,7 +1045,7 @@ static void send_patch_file(struct cg2900_chip_dev *dev)
int err;
int bytes_sent;
struct cg2900_chip_info *info = dev->c_data;
- int file_name_size = strlen("CG2900_XXXX_XXXX_settings.fw");
+ int file_name_size = strlen("CG29XX_XXXX_XXXX_settings.fw");
bytes_sent = cg2900_read_and_send_file_part(info->user_in_charge,
info->logger,
@@ -1059,7 +1073,7 @@ static void send_patch_file(struct cg2900_chip_dev *dev)
* so add 1.
*/
err = snprintf(info->settings_file_name, file_name_size + 1,
- "CG2900_%04X_%04X_settings.fw", dev->chip.hci_revision,
+ "CG29XX_%04X_%04X_settings.fw", dev->chip.hci_revision,
dev->chip.hci_sub_version);
if (err == file_name_size) {
dev_dbg(BOOT_DEV, "Downloading settings file %s\n",
@@ -1178,16 +1192,16 @@ shut_down_chip:
int err;
err = mfd_add_devices(dev->dev, main_info->cell_base_id,
- cg2900_devs, info->mfd_size, NULL, 0);
+ cg2900_devs, info->mfd_size, NULL, 0);
if (err) {
dev_err(dev->dev, "Failed to add cg2900_devs (%d)\n",
- err);
+ err);
goto finished;
}
err = mfd_add_devices(dev->dev, main_info->cell_base_id,
- cg2900_char_devs, info->mfd_char_size,
- NULL, 0);
+ cg2900_char_devs, info->mfd_char_size,
+ NULL, 0);
if (err) {
dev_err(dev->dev, "Failed to add cg2900_char_devs (%d)"
"\n", err);
@@ -1199,8 +1213,39 @@ shut_down_chip:
* Increase base ID so next connected transport will not get the
* same device IDs.
*/
- main_info->cell_base_id += MAX(info->mfd_size,
- info->mfd_char_size);
+ main_info->cell_base_id +=
+ MAX(info->mfd_size, info->mfd_char_size);
+
+ if (dev->chip.hci_revision == CG2910_PG1_REV ||
+ dev->chip.hci_revision == CG2910_PG2_REV) {
+ err = mfd_add_devices(dev->dev, main_info->cell_base_id,
+ cg2910_extra_devs,
+ info->mfd_extra_size, NULL, 0);
+ if (err) {
+ dev_err(dev->dev, "Failed to add cg2910_extra_devs "
+ "(%d)\n", err);
+ goto finished;
+ }
+
+ err = mfd_add_devices(dev->dev, main_info->cell_base_id,
+ cg2910_extra_char_devs,
+ info->mfd_extra_char_size, NULL, 0);
+ if (err) {
+ dev_err(dev->dev, "Failed to add cg2910_extra_char_devs "
+ "(%d)\n", err);
+ mfd_remove_devices(dev->dev);
+ goto finished;
+ }
+
+ /*
+ * Increase base ID so next connected transport
+ * will not get the same device IDs.
+ */
+ main_info->cell_base_id +=
+ MAX(info->mfd_extra_size,
+ info->mfd_extra_char_size);
+ }
+
info->startup = false;
}
@@ -1266,7 +1311,7 @@ static void work_load_patch_and_settings(struct work_struct *work)
struct cg2900_work *my_work;
struct cg2900_chip_dev *dev;
struct cg2900_chip_info *info;
- int file_name_size = strlen("CG2900_XXXX_XXXX_patch.fw");
+ int file_name_size = strlen("CG29XX_XXXX_XXXX_patch.fw");
if (!work) {
dev_err(MAIN_DEV,
@@ -1288,7 +1333,7 @@ static void work_load_patch_and_settings(struct work_struct *work)
* so add 1.
*/
err = snprintf(info->patch_file_name, file_name_size + 1,
- "CG2900_%04X_%04X_patch.fw", dev->chip.hci_revision,
+ "CG29XX_%04X_%04X_patch.fw", dev->chip.hci_revision,
dev->chip.hci_sub_version);
if (err == file_name_size) {
dev_dbg(BOOT_DEV, "Downloading patch file %s\n",
@@ -1602,7 +1647,10 @@ static bool handle_vs_system_reset_cmd_complete(struct cg2900_chip_dev *dev,
status);
if (HCI_BT_ERROR_NO_ERROR == status) {
- if (dev->chip.hci_revision == CG2900_PG2_REV) {
+ if (dev->chip.hci_revision == CG2900_PG2_REV &&
+ dev->chip.hci_revision == CG2905_PG1_1_REV &&
+ dev->chip.hci_revision == CG2910_PG1_REV &&
+ dev->chip.hci_revision == CG2910_PG2_REV) {
/*
* We must now wait for the selftest results. They will
* take a certain amount of time to finish so start a
@@ -1859,6 +1907,29 @@ static bool handle_rx_data_bt_evt(struct cg2900_chip_dev *dev,
else if (op_code == CG2900_BT_OP_VS_BT_ENABLE)
pkt_handled = handle_vs_bt_enable_cmd_status
(dev, cmd_status->status);
+ } else if (HCI_EV_VENDOR_SPECIFIC == evt->evt) {
+ /*
+ * In the new versions of CG29xx i.e. after CG2900 we
+ * will recieve HCI_Event_VS_Write_File_Block_Complete
+ * instead of Command Complete while downloading
+ * the patches/settings file
+ */
+ struct bt_vs_evt *cmd_evt;
+ cmd_evt = (struct bt_vs_evt *)data;
+
+ if (cmd_evt->evt_id == CG2900_EV_VS_WRITE_FILE_BLOCK_COMPLETE) {
+ struct bt_vs_write_file_block_evt *write_block_evt;
+ write_block_evt =
+ (struct bt_vs_write_file_block_evt *)
+ cmd_evt->data;
+ dev_dbg(dev->dev, "Received VS write file block complete\n");
+ pkt_handled = handle_vs_write_file_block_cmd_complete(
+ dev, &write_block_evt->status);
+ } else {
+ dev_err(dev->dev, "Vendor Specific Event 0x%x"
+ "Not Supported\n", cmd_evt->evt_id);
+ return false;
+ }
} else if (HCI_EV_HW_ERROR == evt->evt) {
struct hci_ev_hw_error *hw_error;
@@ -3128,6 +3199,9 @@ static struct cg2900_user_data btacl_data = {
static struct cg2900_user_data btevt_data = {
.h4_channel = CHANNEL_BT_EVT,
};
+static struct cg2900_user_data nfc_data = {
+ .h4_channel = CHANNEL_NFC,
+};
static struct cg2900_user_data fm_data = {
.h4_channel = CHANNEL_FM_RADIO,
};
@@ -3232,6 +3306,14 @@ static struct mfd_cell cg2900_devs[] = {
},
};
+static struct mfd_cell cg2910_extra_devs[] = {
+ {
+ .name = "cg2900-nfc",
+ .platform_data = &nfc_data,
+ .pdata_size = sizeof(nfc_data)
+ }
+};
+
static struct cg2900_user_data char_btcmd_data = {
.channel_data = {
.char_dev_name = CG2900_BT_CMD,
@@ -3250,6 +3332,12 @@ static struct cg2900_user_data char_btevt_data = {
},
.h4_channel = CHANNEL_BT_EVT,
};
+static struct cg2900_user_data char_nfc_data = {
+ .channel_data = {
+ .char_dev_name = CG2900_NFC,
+ },
+ .h4_channel = CHANNEL_NFC,
+};
static struct cg2900_user_data char_fm_data = {
.channel_data = {
.char_dev_name = CG2900_FM_RADIO,
@@ -3390,6 +3478,15 @@ static struct mfd_cell cg2900_char_devs[] = {
},
};
+static struct mfd_cell cg2910_extra_char_devs[] = {
+ {
+ .name = "cg2900-chardev",
+ .id = 12,
+ .platform_data = &char_nfc_data,
+ .pdata_size = sizeof(char_nfc_data)
+ }
+};
+
/**
* set_plat_data() - Initializes data for an MFD cell.
* @cell: MFD cell.
@@ -3438,20 +3535,14 @@ static bool check_chip_support(struct cg2900_chip_dev *dev)
dev_dbg(dev->dev, "check_chip_support\n");
/*
- * Check if this is a CG2900 revision.
+ * Check if this is a CG29XX revision.
* We do not care about the sub-version at the moment. Change this if
* necessary.
*/
- if ((dev->chip.manufacturer != CG2900_SUPP_MANUFACTURER) ||
- (dev->chip.hci_revision != CG2900_PG1_SPECIAL_REV &&
- (dev->chip.hci_revision < CG2900_SUPP_REVISION_MIN ||
- dev->chip.hci_revision > CG2900_SUPP_REVISION_MAX))) {
- dev_dbg(dev->dev, "Chip not supported by CG2900 driver\n"
- "\tMan: 0x%02X\n"
- "\tRev: 0x%04X\n"
- "\tSub: 0x%04X\n",
- dev->chip.manufacturer, dev->chip.hci_revision,
- dev->chip.hci_sub_version);
+ if (dev->chip.manufacturer != CG2900_SUPP_MANUFACTURER
+ || !(check_chip_revision_support(dev->chip.hci_revision))) {
+ dev_err(dev->dev, "Unsupported Chip revision:0x%x\n",
+ dev->chip.hci_revision);
return false;
}
@@ -3516,15 +3607,27 @@ static bool check_chip_support(struct cg2900_chip_dev *dev)
btacl_data.channel_data.bt_bus = pf_data->bus;
btevt_data.channel_data.bt_bus = pf_data->bus;
+ /* Set the Platform data based on supported chip */
for (i = 0; i < ARRAY_SIZE(cg2900_devs); i++)
set_plat_data(&cg2900_devs[i], dev);
for (i = 0; i < ARRAY_SIZE(cg2900_char_devs); i++)
set_plat_data(&cg2900_char_devs[i], dev);
-
- info->startup = true;
info->mfd_size = ARRAY_SIZE(cg2900_devs);
info->mfd_char_size = ARRAY_SIZE(cg2900_char_devs);
+ if (dev->chip.hci_revision == CG2910_PG1_REV ||
+ dev->chip.hci_revision == CG2910_PG2_REV) {
+ for (i = 0; i < ARRAY_SIZE(cg2910_extra_devs); i++)
+ set_plat_data(&cg2910_extra_devs[i], dev);
+ for (i = 0; i < ARRAY_SIZE(cg2910_extra_char_devs); i++)
+ set_plat_data(&cg2910_extra_char_devs[i], dev);
+ info->mfd_extra_size = ARRAY_SIZE(cg2910_extra_devs);
+ info->mfd_extra_char_size = ARRAY_SIZE(cg2910_extra_char_devs);
+ }
+
+
+ info->startup = true;
+
/*
* The devices will be registered when chip has been powered down, i.e.
* when the system startup is ready.
@@ -3532,7 +3635,7 @@ static bool check_chip_support(struct cg2900_chip_dev *dev)
mutex_unlock(&main_info->man_mutex);
- dev_info(dev->dev, "Chip supported by the CG2900 chip driver\n");
+ dev_info(dev->dev, "Chip supported by the CG2900 driver\n");
/* Finish by turning off the chip */
cg2900_create_work_item(info->wq, work_power_off_chip, dev);
diff --git a/drivers/staging/cg2900/mfd/cg2900_chip.h b/drivers/staging/cg2900/mfd/cg2900_chip.h
index b3fd556b7d7..5db655903a8 100644
--- a/drivers/staging/cg2900/mfd/cg2900_chip.h
+++ b/drivers/staging/cg2900/mfd/cg2900_chip.h
@@ -6,6 +6,7 @@
* Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
* Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
* Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * Hemant Gupta (hemant.gupta@stericsson.com) for ST-Ericsson.
* License terms: GNU General Public License (GPL), version 2
*
* Linux Bluetooth HCI H:4 Driver for ST-Ericsson CG2900 GPS/BT/FM controller.
@@ -39,13 +40,6 @@ static inline void store_bit(__u8 *var, size_t bit, __u8 value)
/* Supported chips */
#define CG2900_SUPP_MANUFACTURER 0x30
-#define CG2900_SUPP_REVISION_MIN 0x0100
-#define CG2900_SUPP_REVISION_MAX 0x0200
-
-/* Specific chip version data */
-#define CG2900_PG1_REV 0x0101
-#define CG2900_PG2_REV 0x0200
-#define CG2900_PG1_SPECIAL_REV 0x0700
/*
* Bluetooth
@@ -81,6 +75,20 @@ struct bt_vs_store_in_fs_cmd {
#define CG2900_VS_STORE_IN_FS_USR_ID_BD_ADDR 0xFE
+#define HCI_EV_VENDOR_SPECIFIC 0xFF
+#define CG2900_EV_VS_WRITE_FILE_BLOCK_COMPLETE 0x60
+/* BT VS Event */
+struct bt_vs_evt {
+ __u8 evt_id;
+ __u8 data[];
+} __packed;
+
+/* BT VS Write File Block Event */
+struct bt_vs_write_file_block_evt {
+ __u8 status;
+ __u8 file_blk_id;
+} __packed;
+
/* BT VS Write File Block command */
#define CG2900_BT_OP_VS_WRITE_FILE_BLOCK 0xFC2E
struct bt_vs_write_file_block_cmd {
diff --git a/drivers/staging/cg2900/mfd/cg2900_core.h b/drivers/staging/cg2900/mfd/cg2900_core.h
index bdd951a501d..a0615fa0e46 100644
--- a/drivers/staging/cg2900/mfd/cg2900_core.h
+++ b/drivers/staging/cg2900/mfd/cg2900_core.h
@@ -38,6 +38,7 @@
/* Bluetooth error codes */
#define HCI_BT_ERROR_NO_ERROR 0x00
+#define HCI_BT_WRONG_SEQ_ERROR 0xF1
/* Bluetooth lengths */
#define HCI_BT_SEND_FILE_MAX_CHUNK_SIZE 254