# CG2900 Driver

Henrik
Possung

          henrik.possung@stericsson.com

Par-Gunnar
Hjalmdahl

          par-gunnar.p.hjalmdahl@stericsson.com

2010
ST-Ericsson SA
Connectivity

This documentation is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

For more details see the file COPYING in the source distribution of Linux.

## Introduction

This documentation describes the functions provided by the ST-Ericsson CG2900 Driver for enabling ST-Ericsson CG2900 Combo Controller Hardware.

## Getting Started

There are no special compilation flags needed to build the CG2900 driver.

There must be patch and settings files that match the used chip version inside the firmware folder. The files:

- CG2900_XXXX_YYYY_patch.fw

- CG2900_XXXX_YYYY_settings.fw

where XXXX is chip revision and YYYY is chip sub-version returned from the HCI Read Local Version command.

### Basic Tutorial

To enable the ST-Ericsson CG2900 driver using KConfig go to `Device Drivers -> Staging Drivers` and enable the CG2900 Driver. If BlueZ shall be used as Bluetooth stack also enable the CG2900 Bluetooth driver. Depending on choice the driver will either be included as LKM or built into the Kernel. If building as LKM, several files will be generated:

- cg2900.ko which contains the main driver

- cg2900_char_devices.ko which contains the character devices

- cg2900_uart.ko which contains the UART driver

- cg2900_chip.ko which contains the CG2900 chip specific driver

- stlc2690_chip.ko which contains the STLC2690 chip specific driver

- cg2900_audio.ko which contains the CG2900 audio driver

- btcg2900.ko which contains the registration and mapping towards the BlueZ Bluetooth stack

## Concepts

The ST-Ericsson CG2900 driver works as a multiplexer between different users, such as a Bluetooth stack and a FM driver, and the connectivity chip. The driver supports multiple physical transports, although currently only UART is implemented. Apart from just transporting data between stacks and the chip, the ST-Ericsson CG2900 driver also deals with power handling, powering up and down the chip and also downloading necessary patches and settings for the chip to start up properly.

## Tasks

Platform device handling

  Each H:4 channel is created as a multifunction device. The driver for each channel must register as a platform driver for this channel, supplying `probe` and `remove` functions. When a transport is opened to the chip, the CG2900 chip driver will allocate and instantiate a platform device for each channel. This means that at this point the device framework in the Kernel will call the `probe` function for the platform driver. It is then the responsibility for the platform driver to register its callback functions and save its device to the platform data structure inside the probed device.

  When the transport is removed the CG2900 chip driver will free each platform device and the the platform driver's `remove` function will then be called.

  For user space, the user space character device will not exist until the character device driver has been probed. The character devices will be removed when the character device driver is removed, i.e. when the transport is removed.

Opening a channel

  In order to be able to send and receive data on an H:4 channel, the user (i.e. respective stack) must open the channel. Opening a channel will make it possible to send data to and receive data from the connectivity controller. If the controller were earlier powered down, opening a channel will also cause the controller to be powered up. When chip is powered up, patches and settings for the ARM subsystem will be downloaded as well. Other IPs within the controller must however download each respective patches and settings. If chip was already powered up when opening the channel no patch will be automatically downloaded.

  Opening a channel from Kernel space

    When a stack is placed in Kernel space, it shall open a channel by calling the API function `open` inside the platform data of the device.

  Opening a channel from User space

    When a stack is placed in User space, it shall open a channel by calling the syscall function `open` on the corresponding file. The files are located in folder `/dev/` and are named `cg2900_gnss` and similar. Each file corresponds to one H:4 channel.

Closing a channel

  When a user, i.e. a stack has no need for a functionality, it should close the corresponding H:4 channel. This is usually done when a user disables a certain feature, for example Bluetooth. The reason why the channels need to be closed is that the ST-E CG2900 driver will free the resources and also shutdown the controller if there are no more active users of the chip. This will lower the power consumption thereby increasing battery life.

  Closing a channel from Kernel space

    When a stack is placed in Kernel space, it shall close a channel by calling the API function `close` inside the platform data of the device.

  Closing a channel from User space

    When a stack is placed in User space, it shall close a channel by calling the syscall function `close` on the corresponding file.

Writing to a channel

  When a stack (Bluetooth, FM, or GNSS) wants to send a packet it shall perform a write operation. The packet shall not contain the H:4 header since this is added by the CG2900 driver. All other data in the packet shall however exist in the packet in the format correct for that HCI channel. The CG2900 users need to perform flow control over channels so any ticket handling or similar must be handled by respective stack.

  Writing to a channel from Kernel space

    When a stack is placed in Kernel space, it shall start with allocating a packet of the correct size using `alloc_skb` inside the platform data of the device. This function will return an sk_buff (Socket buffer) structure that has necessary space reserved for CG2900 driver operation. The stack shall then copy the data, preferrably using `skb_put`, and then call `write` inside the platform data of the device to perform the write operation. When the function returns, the buffer has been transferred and there is no need for the calling function to free the buffer. If the operation fails, i.e. an error code is returned, the caller must however free the buffer.

  Writing to a channel from User space

    When a stack is placed in User space, it shall call the `write` function on the corresponding file to perform a transmit operation. After function returns the data has been copied and is considered sent. The caller does not need to preserve the data.

  Writing to FM_Radio and FM_Audio channel

    CG2900 driver only supports FM legacy commands. The reason is that the FM_Radio and FM_Audio uses the same H4 channel aginst the chip, in order to multiplex the FM user commands the data pakets are parsed by the CG2900 driver.

Reading from a channel

  When a stack (Bluetooth, FM, or GNSS) wants to receive a packet it shall perform a receive operation. The packet returned does not contain the H:4 header since this is removed by the CG2900 driver. All other data in the packet in the packet is in the format correct for that HCI channel. The CG2900 driver does not perform any flow control over the H:4 channel so any ticket handling or similar must be handled by respective stack.

  Reading from a channel from Kernel space

    When a stack is placed in Kernel space, it has to supply a callback function for the receive functionality when being probed. This callback function will be called when the ST-E CG2900 driver has received a packet. The packet received will always be a complete HCI packet, i.e. no fragmention on HCI layer. When the packet has been received it is the responsability of the receiver to see to that the packet is freed using `kfree_skb` when it is no more needed.

  Reading from a channel from User space

    When a stack is placed in User space, it shall call the `read` function on the corresponding file to perform a receive operation. This function will read as many bytes as there are present up to the size of the supplied buffer. If no data is available the function will hang until data becomes available, reset occurs, or the channel is closed. For smooth operation it is recommended to use the `poll` functionality on the file, preferrably from a dedicated thread. This way one thread can monitor both read and reset operations in one common thread while transmit operations may continue unblocked in a separate thread.

Reset handling

  The stacks shall always try to avoid performing Reset operations. The Reset will result in a hardware reset of the controller and will therefore cause all existing links and settings to be lost. All stacks using the controller must also be informed about the reset and handle it in a proper way. The reset operation should only be used when there is no other option to get the controller into a working state, for example if the controller has stopped answering to commands. After the hardware reset, the ST-E CG2900 driver will automatically perform deregister the channel so it has to be reopened again.

  Reset handling from Kernel space

    When a stack is placed in Kernel space, it initiates a Reset operation by calling `reset` inside the platform data of the device. This will trigger a hardware reset of the controller. When the hardware reset is finished all registered users will be called through respective reset callback. When the callback function is finished the registered device will be closed and when all opened users have been informed and closed, the chip is shutdown. This is similar to a closure of all opened channels. The stack will then have to open the channel in order to use the channel once again.

  Reset handling from User space

    When a stack is placed in User space, it shall call the `ioctl` function on the corresponding file to perform a reset operation. The command parameter `CG2900_CHAR_DEV_IOCTL_RESET` shall be used when calling `ioctl`. When the `ioctl` returns, the stack shall close the channel and then re-open it again. This must be done so the channel is registered correctly in Kernel space. For smooth operation it is recommended to use the `poll` functionality on the file, preferrably from a dedicated thread. This way one thread can monitor both read and reset operations in one common thread while transmit operations may continue unblocked in a separate thread.

Example code Kernel space

  This example will open the FM channel, write a packet, read a packet and then close the channel.

                   bool event_received;

                   void read_cb(struct cg2900_user_data *dev, struct sk_buff *skb)
                   {
                     event_received = true;
                     kfree_skb(skb);
                   }

                   void reset_cb(struct cg2900_user_data *dev)
                   {
                     /* Handle reset. Device will be automatically closed by the CG2900 driver */
                   }

                   void example_open(struct my_info *info)
                   {
                     struct cg2900_user_data *user = dev_get_platdata(info->dev);
                     int err;

                     if (user->opened) {
                       dev_err(info->dev, "Error! Channel already opened!\n");
                       return;
                     }

                     err = user->open(user);
                     if (err) {
                       dev_err(info->dev, "Error (%d)! Couldn't register!\n", err);
                     }
                   }

                   void example_close(struct my_info *info)
                   {
                     struct cg2900_user_data *user = dev_get_platdata(info->dev);

                     if (user->opened)
                       user->close(user);
                   }

                   void example_write_and_read(struct my_info *info, uint8_t *data, int len)
                   {
                     int err;
                     struct cg2900_user_data *user = dev_get_platdata(info->dev);
                     struct sk_buff *skb = user->alloc_skb(len, GFP_KERNEL);

                     if (skb) {
                       memcpy(skb_put(skb, len), data, len);
                       err = user->write(user, skb);
                       if (!err) {
                         event_received = false;

                         while (!event_received) {
                           /* Wait for ack event. Received in read_cb() above */
                           schedule_timeout_interruptible(jiffies + 50);
                         }
                       } else {
                         dev_err(info->dev, "Couldn't write to controller (%d)\n", err);
                         kfree_skb(skb);
                       }
                     }
                   }

                   static int __devinit my_probe(struct platform_device *pdev)
                   {
                     struct my_info *info;
                     struct cg2900_user_data *pf_data;

                     info = kzalloc(sizeof(*info));
                     if (!info)
                       return -ENOMEM;

                     dev_set_drvdata(&pdev->dev, info);
                     info->dev = &pdev->dev;

                     pf_data = dev_get_platdata(&pdev->dev);
                     pf_data->dev = &pdev->dev;
                     pf_data->read_cb = read_cb;
                     pf_data->reset_cb = reset_cb;

                     /*
                      * Alert my user that we are ready to start and give
                      * it my info pointer.
                      */
                     return my_user_start(info);
                   }

                   static int __devexit my_remove(struct platform_device *pdev)
                   {
                     struct my_info *info;

                     info = dev_get_drvdata(&pdev->dev);
                     my_user_stop(info);
                     kfree(info);
                     return 0;
                   }

                   static struct platform_driver my_driver = {
                     .driver = {
                       .name	= "cg2900-fm",
                       .owner	= THIS_MODULE,
                     },
                     .probe	= my_probe,
                     .remove	= __devexit_p(my_remove),
                   };

                   static int __init my_init(void)
                   {
                     return platform_driver_register(&my_driver);
                   }

                   static void __exit my_exit(void)
                   {
                     platform_driver_unregister(&my_driver);
                   }

                   module_init(my_init);
                   module_exit(my_exit);

Example code User space

  This example will open the GNSS channel, write a packet, read a packet and then close the channel. In this example all functions are performed in the same thread. It is however adviced to perform `read` and `ioctl` read through a separate thread, preferrably using `poll`.

                   struct my_info_t {
                     int fd;
                   };

                   static struct my_info_t my_info;

                   /* This is a fake command and has nothing to do with real GNSS commands.
                    * Note that the command does NOT contain the H:4 header.
                    * The header is added by the ST-E CG2900 driver.
                    */
                   static const uint8_t tx_cmd[] = {0x12, 0x34, 0x56};

                   int main(int argc, char **argv)
                   {
                     uint8_t rx_buffer[100];
                     int rx_bytes = 0;
                     int err;

                     my_info.fd = open("/dev/cg2900_gnss", O_RDWR);
                     if (my_info.fd < 0) {
                       printf("Error on open file: %d (%s)\n", errno, strerror(errno));
                       return errno;
                     }
                     if (0 > write(my_info.fd, tx_cmd, sizeof(tx_cmd))) {
                       printf("Error on write file: %d (%s)\n", errno, strerror(errno));
                       return errno;
                     }
                     /* Read will sleep until there is data available */
                     rx_bytes = read(my_info.fd, rx_buffer, 100);
                     if (rx_bytes >= 0) {
                       printf("Received %d bytes\n", rx_bytes);
                     } else {
                       printf("Error on read file: %d (%s)\n", errno, strerror(errno));
                       return errno;
                     }
                     err = close(my_info.fd);
                     if (err) {
                       printf("Error on close file: %d (%s)\n", errno, strerror(errno));
                       return errno;
                     }
                     return 0;
                   }

## Driver Configuration and Interaction

N/A

### Implemented operations in driver

#### Supported device driver operations when using character device

open | Opening a character device will register the caller to that HCI channel.
release | Releasing a character device will deregister the caller from that HCI channel
poll | Polling a character device will check if there is data to read on that HCI channel
read | Reading from a character device reads from that HCI channel
write | Writing to a character device writes to that HCI channel
unlocked_ioctl | Performing IO control on a character device will perform special operations such as reset on that HCI channel

### Driver loading parameters

uart_default_baud

  Parameter type

        int

  Default value

    115200

  Runtime readable/modifiable

    Readable

  Description

    The parameter uart_default_baud in cg2900_uart.c defines the baud rate used after a chip has just been powered up. It shall be set to the default baud rate of the controller. For ST-Ericsson controllers STLC2690 and CG2900 this value shall be 115200.

uart_high_baud

  Parameter type

        int

  Default value

    3000000

  Runtime readable/modifiable

    Modifiable

  Description

    The parameter uart_high_baud in cg2900_uart.c defines the baud rate to use for normal data transfer. This should normally be the highest allowed by the system with regards to flow control, clocks, etc. For ST-Ericsson controllers STLC2690 and CG2900 the following values are supported:

    - 57600

    - 115200

    - 230400

    - 460800

    - 921600

    - 2000000

    - 3000000

    - 4000000

uart_debug

  Parameter type

        int

  Default value

    0

  Runtime readable/modifiable

    Modifiable

  Description

    The parameter uart_debug in cg2900_uart.c enables or disables dumping of all data transmitted and received through the UART. 0 means disabled and non-zero value means enabled.

bd_address

  Parameter type

        array (Entered as comma separated value)

  Default value

    0x00 0x80 0xDE 0xAD 0xBE 0x00

  Runtime readable/modifiable

    Modifiable

  Description

    The parameter bd_address in cg2900_core.c defines the Bluetooth device address to use for the current device. The value is an array of 6 bytes and shall be entered as a comma separated value.

sleep_timeout_ms

  Parameter type

        int

  Default value

    10000

  Runtime readable/modifiable

    Modifiable

  Description

    The parameter sleep_timeout_ms in cg2900_core.c defines the sleep timeout for data transmission in milliseconds.

### Driver IO Control

`CG2900_CHAR_DEV_IOCTL_RESET`
  Direction

    Set

  Parameter

        int

  Description

    The `CG2900_CHAR_DEV_IOCTL_RESET` IOCTL starts a reset of the connectivity chip. This will affect the current open channel and all other open channels as well.

    IOCTL value created using `_IOW('U', 210, int)`.

    Returned values are:

    - If reset is performed without errors the IOCTL function will return 0.

    - A negative value will indicate error.

`CG2900_CHAR_DEV_IOCTL_CHECK4RESET`
  Direction

    Query

  Parameter

        int

  Description

    The `CG2900_CHAR_DEV_IOCTL_CHECK4RESET` IOCTL checks if a reset has been performed on a device.

    IOCTL value created using `_IOR('U', 212, int)`.

    Returned values are:

    - If device is still open the IOCTL function will return 0.

    - If reset has occurred the IOCTL function will return 1.

    - If device has been closed the IOCTL function will return 2.

    - A negative value will indicate error.

`CG2900_CHAR_DEV_IOCTL_GET_REVISION`
  Direction

    Query

  Parameter

        struct cg2900_rev_data

  Description

    The `CG2900_CHAR_DEV_IOCTL_GET_REVISION` IOCTL returns the revision value and the sub-version value of the local connectivity controller if such information is available.

    IOCTL value created using `_IOR('U', 213, struct cg2900_rev_data)`.

    Returned values are according to information that may be retrieved from chip manufacturer. One example is ST-Ericsson CG2900 PG2.0 which have revision 0x0200 and sub-version 0x0000.

### Driver Interaction with Sysfs

Not Applicable

### Driver Interaction using /proc filesystem

Not Applicable

### Other means for Driver Interaction

Not Applicable

### Driver Node File

CG2900 main device
  File

    `/dev/cg2900_driver0`

  Description

    The cg2900_driver represents the main parent node for all other character devices supplied in the ST-Ericsson CG2900 driver except for the Test device. It does not support any operations such as read or write.

BT Command
  File

    `/dev/cg2900_bt_cmd`

  Description

    The cg2900_bt_cmd is the device for the HCI Bluetooth command channel.

BT ACL
  File

    `/dev/cg2900_bt_acl`

  Description

    The cg2900_bt_acl is the device for the HCI Bluetooth ACL channel.

BT Event
  File

    `/dev/cg2900_bt_evt`

  Description

    The cg2900_bt_evt is the device for the HCI Bluetooth event channel.

FM Radio
  File

    `/dev/cg2900_fm_radio`

  Description

    The cg2900_fm_radio is the device for the HCI FM Radio channel.

GNSS
  File

    `/dev/cg2900_gnss`

  Description

    The cg2900_gnss is the device for the HCI GNSS channel.

Debug
  File

    `/dev/cg2900_debug`

  Description

    The cg2900_debug is the device for the HCI Debug channel.

ST-Ericsson Tools
  File

    `/dev/cg2900_ste_tools`

  Description

    The cg2900_ste_tools is the device for the HCI ST-Ericsson tools channel.

HCI Logger
  File

    `/dev/cg2900_hci_logger`

  Description

    The cg2900_hci_logger is the device for the HCI logger channel.

Test stub
  File

    `/dev/cg2900_test`

  Description

    The cg2900_test is the device for performing module tests of the ST-Ericsson CG2900 driver. It acts as a stub replacing the transport towards the chip. It is of the type Misc devices.

BT Audio
  File

    `/dev/cg2900_bt_audio`

  Description

    The cg2900_bt_audio is the device for sending HCI BT Audio controll commands to the chip.

FM Audio
  File

    `/dev/cg2900_fm_audio`

  Description

    The cg2900_fm_audio is the device for sending HCI BT Audio controll commands to the chip.

Core
  File

    `/dev/cg2900_core`

  Description

    The cg2900_core is a device for turn on/off the chip. NOTE other devices will also turn on/off the chip if needed.

CG2900 Audio
  File

    `/dev/cg2900_audio`

  Description

    The cg2900_audio is a device for testing the CG2900 Audio driver from User space. It replicates the normal CG2900 Audio interface through `write/read` operations. The `write` command is used as following:

    - 4 byte op code (see below)

    - Data field according to respective CG2900 Audio function (no session ID needed)

    If the operation fails the `write` command operation will return the error. Op codes are (4 bytes size):

    - 0x00000001 = CHAR_DEV_OP_CODE_SET_DAI_CONF

    - 0x00000002 = CHAR_DEV_OP_CODE_GET_DAI_CONF

    - 0x00000003 = CHAR_DEV_OP_CODE_CONFIGURE_ENDPOINT

    - 0x00000004 = CHAR_DEV_OP_CODE_CONNECT_AND_START_STREAM

    - 0x00000005 = CHAR_DEV_OP_CODE_STOP_STREAM

    The `read` command is used for the commands `CHAR_DEV_OP_CODE_GET_DAI_CONF` and `CHAR_DEV_OP_CODE_CONNECT_AND_START_STREAM` if the corresponding commands are successful. The returned data will be formatted accordingly:

    - 4 byte op code (see below)

    - Data field according to normal CG2900 Audio functions, e.g. stream handle or configuration

    The `CHAR_DEV_OP_CODE_GET_DAI_CONF` is a bit special since it require an endpoint in-parameter (when calling `write`) to return the corresponding DAI configuration when calling `read`.
HCI Raw
  File

    `/dev/cg2900_hci_raw`

  Description

    The cg2900_hci_raw is the device for raw access to HCI interface.

## Known Bugs And Assumptions

Driver supports only one user per HCI channel.

  To simplify design and limitation as well as keeping the API simple and reliable, the driver only supports one user per HCI channel.

HCI Raw channel requires exclusive access to chip.

  cg2900_hci_raw channel cannot be opened if there are any other channels already opened except hci_logger channel. Also any other channels cannot be opened except hci_logger channel when cg2900_hci_raw is already opened. This is to guarantee that different users won't interfere with each other and prevent flow control issues.

## Public Functions Provided

List of public functions.

### cg2900.h

!Edrivers/staging/cg2900/mfd/cg2900_core.c !Idrivers/staging/cg2900/include/cg2900.h

### cg2900_audio.h

!Edrivers/staging/cg2900/mfd/cg2900_audio.c

## Internal Functions Provided

List of internal functions.

### cg2900_lib.h

!Edrivers/staging/cg2900/mfd/cg2900_lib.c