GSL1680

From linux-sunxi.org
Jump to navigation Jump to search

The GSL1680 is a chip designed to add capacitive, multitactile capabilities to LCD screens. Is used in several devices.

See also Touchscreen#Silead

GPIO

The chip has four main pins to communicate with a CPU:

  • SDA and SCL: these two pins conform an I2C bus, allowing to exchange data between the chip and the main CPU.
  • IOCNTL: this pin, when active (logic 1) enables the chip, making it to answer to I2C commands and read the touch screen. When inactive (logic 0), the chip is in Low Power state.
  • INT: when there is data available (a press) or in other cases (not sure, not have enough documentation), this pin gets active to signal this to the CPU.

Linux driver

There is a driver in the mainline kernel.

Currently, there is no driver in sunxi-3.4, but the driver is available from multiple 3rd party locations:

Eventually the support for this device appeared as two different drivers in A23 SDK:

There is also an user-space driver (which uses the UFILE system to link to the INPUT subsystem) available at https://github.com/rastersoft/gsl1680. Since it works like a true INPUT driver, it is fully compatible with Xorg and any other program in Linux compatible with a mouse. This driver has the advantage of emulating the mouse wheel when moving two fingers over the screen, allowing to use standard applications. It also emulates Ctrl+MENU when touching with three fingers, which allows to integrate with TabletWM.

I2C communication

The communication between the chip and the CPU is done using an I2C bus. The GSL1680 always answers at the address 0x40. This allows to know if our device has a GSL1680 chip by using, under Linux, the command

   i2cdetect X

with X a number between 0 and the number of I2C buses in our system. If there isn't a device at address 0x40 in any of the buses, the device doesn't have a GSL1680.

The CPU can read or write in several eight-bit registers, allocated inside the GSL1680. Each time an I2C transmission starts, the first byte contains a register number, and the other bytes contain data to be stored in that register and the next ones. This is, if we send:

   START(W) 0x10 0x00 0x01 0xF5 0x41 0xFF STOP

the chip will store a 0x00 value in register 0x10; a 0x01 value in register 0x11; a 0xF5 value in register 0x12, and so on.

To read from the chip, just write a single byte with the register number to start to read, and then do as many reads as registers to read.

The known registers are:

  • 0x00-0x7F: these registers are used to load portions of the firmware
  • 0x80: contains the number of touches in the screen. If zero, the user isn't touching the screen; if one, only one finger is on the screen; if two, there are two fingers; and so on.
  • 0x84-0x87: contains the coordinates for the first touch.
  • 0x88-0x8B: contains the coordinates for the second touch.
  • 0x8C-0xAB: contains the coordinates for the third, fourth, and so on (up to five in some devices, up to ten in other), touches, in the same format than the previous ones (four bytes for each touch).
  • 0xE0: STATUS register
  • 0xE4, 0xBC-0xBF: some kind of control registers. Needed for uploading the firmware and soft resetting the chip (there's not more data available about them).
  • 0xF0: PAGE register. Contains the memory page number currently mapped in the 0x00-0x7F registers.

Touch coordinates format

The four bytes of each group of coordinates contains the X and Y values, and also the finger.

The first two bytes contains, in little endian format, the X coordinate in the 12 lower bits. The other two bytes contains, in little endian format, the Y coordinate in the 12 lower bits.

The 4 upper bits in the Y coordinate contains the finger identifier that did the touch.

Example:

Let's say that the user touches the screen with one finger. The register 0x80 will contain 1, and registers 0x84 to 0x87 will contain the X and Y coordinates, and the finger identifier will be 1.

Now the user, without removing the first finger, touches the screen with a second finger. The register 0x80 will contain 2. Registers 0x84 to 0x87 will contain the X and Y coordinates of the first touch and the finger identifier in them will be 1. Registers 0x88 to 0x8B will contain the X and Y coordinates of the second touch and the finger identifier in them will be 2.

Now the user removes the first finger, keeping the second one. The register 0x80 will contain 1. Registers 0x84 to 0x87 will contain the X and Y coordinates, but the finger identifier will be 2, because that's the finger that remains in the screen.

Chip initialization

The driver shows a quite obscure initialization procedure:

  • Enable the chip (set IOCTNL to 1)
  • Reset the chip (explained later)
  • Upload the firmware (explained later)
  • Startup chip (set STATUS register to 0)
  • Reset the chip
  • Disable the chip (set IOCTNL to 0)
  • Wait 50 ms
  • Enable the chip (set IOCTNL to 1)
  • Wait 30 ms
  • Disable the chip (set IOCTNL to 0)
  • Wait 5 ms
  • Enable the chip (set IOCTNL to 1)
  • Wait 20 ms
  • Reset the chip
  • Startup chip (set STATUS register to 0)

After this procedure, the chip will start to read touches and sending events.

To reset the chip, as requested in the previous process, follow this procedure:

  • set the STATUS register to 0x88
  • wait 10 ms
  • set register 0xE4 to 0x04
  • wait 10 ms
  • set registers 0xBC-0xBF to 0x00
  • wait 10 ms.

Firmware

This chip needs a firmware to be loaded before it would be able to work. This firmware seems specific to each device model, so it is mandatory to find it in your device. In the Szenio 1207 tablet, these files are available in /system/etc.

Sometimes the firmware is included in the driver module file, for instance: /system/vendor/modules/gslx680.ko.

To extract the firmware you can use fw_extractor or manually find it from the register sequence and dd it out.


The user-space driver supports both a binary format or a plain-text format for the firmware. In the later case, it is divided in chunks, each of a maximum size of 128 bytes. Each chunk must be stored in a different page. Here is an example of one chunk:

   {0xf0,0x3},
   {0x00,0xa5a5ffc0},
   {0x04,0x00000000},
   {0x08,0xe810c4e1},
   {0x0c,0xd3dd7f4d},
   {0x10,0xd7c56634},
   {0x14,0xe3505a2a},
   {0x18,0x514d494f},
   {0x1c,0x5836e48b},
   {0x20,0x00000000},
   {0x24,0x00000000},
   {0x28,0x00000000},
   {0x2c,0x00000000},
   {0x30,0x00001000},
   {0x34,0x00000000},
   {0x38,0x00000000},
   {0x3c,0x00000000},
   {0x40,0x00000001},
   {0x44,0x00000000},
   {0x48,0x00000000},
   {0x4c,0x00000000},
   {0x50,0x00000000},
   {0x54,0x01020304},
   {0x58,0x05060708},
   {0x5c,0x090a0b0c},
   {0x60,0x0d0e0e0f},
   {0x64,0x10111213},
   {0x68,0x14151617},
   {0x6c,0x18191a1b},
   {0x70,0x1b1c1e1f},
   {0x74,0x00000000},
   {0x78,0x00010000},
   {0x7c,0x8c846af3},

Each line contains a pair of elements. The first one is the register number where the data must be stored; the second one is the data itself.

The first line has 0xF0 as register number. This is the PAGE register. This line specifies the page where this chunk must be stored. In this example it is the page number 0x03.

The other 32 lines contains the firmware itself, preceded by the offset for each 4-byte value. In this example, our code must write 0xC0 into the register 0x00; 0xFF into the register 0x01; 0xA5 into the register 0x02 and 0x05 again into the register 0x03 (remember that the values in ARM are stored in little endian format). Since 0x03 is stored in the PAGE register, the register 0x00 maps to the position 0x180 in memory, register 0x01 to position 0x181, and so on.

Since sending several bytes stores them in correlative registers, in theory the code has to set only 0x00 as the destination register, and send all the bytes of this chunk in one single transfer. Unfortunately, there is usually a limit in the size of a I2C transfer, so it is recommended to not build very large packets, sending each chunk in smaller parts.

Datasheet