diff options
Diffstat (limited to 'drivers/staging/cg2900')
-rw-r--r-- | drivers/staging/cg2900/bluetooth/btcg2900.c | 12 | ||||
-rw-r--r-- | drivers/staging/cg2900/bluetooth/cg2900_uart.c | 32 | ||||
-rw-r--r-- | drivers/staging/cg2900/devices-cg2900.c | 9 | ||||
-rw-r--r-- | drivers/staging/cg2900/include/cg2900.h | 26 | ||||
-rw-r--r-- | drivers/staging/cg2900/mfd/cg2900_audio.c | 76 | ||||
-rw-r--r-- | drivers/staging/cg2900/mfd/cg2900_chip.c | 153 | ||||
-rw-r--r-- | drivers/staging/cg2900/mfd/cg2900_chip.h | 22 | ||||
-rw-r--r-- | drivers/staging/cg2900/mfd/cg2900_core.h | 1 |
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 |