Re: Touchpad stickiness on AMD laptops (was Dell Inspiron/XPS)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,
i have small status update.

First most important information:
On AMD is trackpoint connected to ASF bus (similar to SMBus, but with
other control registers).

This bus has interrupt. After boot always generates interrupts for each
transaction. After playing it stops generating interrupts for
transaction, i don't know exactly why. More important is, that it can
generate interrupts when receives message from slave to broadcast
address (0x08).

To enable interrupts we should set:

ListenAddr to 0x08 and ListenAddrEn to 1:

outb_p((0x08 << 1) | 0x01, 0x09 + piix4_smba);

Then SlaveIntrListenEn of SlaveEn should be set to 1:

outb_p(inb_p(0x15 + piix4_smba) | 0x02, 0x15 + piix4_smba);

Now funny part, how to read address of slave device
(0x2c for synaptics):

Important register is ASFx13 DataBankSel register. If interrupt is
generated from slave device, then DataBankxFull is set. Address can be
retrieved using block read from 0x07 (DataIndex) register. Before
reading register SetReadHostDataBank should be 0. After setting
DataBankSel i am reading HostControl (dummy read), then reading form
DataIndex value 0x08 (broadcast address) and 0x2c (device, that wanted
attention). I am using following code, but it don't work good. Sometimes
there is bad value, sometimes it's reversed, first read gives 0x2c,
second 0x10. Don't know why. I have looked on decompiled windows driver
from synaptics and it looks, that there is special handling for
different DataBankSel values. I don't know exactly why, but problems are
rare, for now i am ignoring problems.


static u8 read_asf_data_bank(unsigned short piix4_smba, u8 bank_number)
{
    outb_p(bank_number << 4, 0x13 + piix4_smba);
    inb_p(0x02 + piix4_smba); // reset DataIndex
    inb_p(0x07 + piix4_smba); // read SMBus broadcast address
    return inb_p(0x07 + piix4_smba);
}


static irqreturn_t piix4_isr(int irq, void *dev_id)
{
    //struct i2c_adapter *piix4_adapter = (struct i2c_adapter *)dev_id;
    //struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter);
    unsigned short piix4_smba = 0xb20;

    u8 bank_sel;
    u8 address[2] = {0x00, 0x00};
    u8 *current_address;

    current_address = &address[0];

    bank_sel = inb_p(0x13 + piix4_smba); // DataBankSel

    if ((bank_sel & 0x0c) == 0x00) { // bits DataBankxFull not set
        return IRQ_HANDLED;
    }

    printk(KERN_INFO "Bank=%02x\n", bank_sel);

    if ((bank_sel & 0x01) == 0) { // Last touched bank is 0
        if (bank_sel & 0x08) {
            *current_address = read_asf_data_bank(piix4_smba, 1);
            current_address++;
        }
        if (bank_sel & 0x04) {
            *current_address = read_asf_data_bank(piix4_smba, 0);
        }
    }
    else { // Last touched bank is 1
        if (bank_sel & 0x04) {
            *current_address = read_asf_data_bank(piix4_smba, 0);
            current_address++;
        }
        if (bank_sel & 0x08) {
            *current_address = read_asf_data_bank(piix4_smba, 1);
        }
    }

    outb_p(bank_sel & 0x0c, 0x13 + piix4_smba); // Clear DataBankxFull

    printk(KERN_INFO "Address=%02x %02x\n", address[0] >> 1, address[1] >> 1);

    if (address[0] != 0x00) {
        i2c_handle_smbus_host_notify(piix4_aux_adapter, address[0] >> 1);
    }
    if (address[1] != 0x00 && address[1] != address[0]) {
        i2c_handle_smbus_host_notify(piix4_aux_adapter, address[1] >> 1);
    }

    return IRQ_HANDLED;
}

Now, when i load module i see this in log:

i2c i2c-11: Error: no response!
rmi4_f12 rmi4-00.fn12: Failed to read object data. Code: -6.
Bank=8d
Address=2c 2c
input input92: rmi_2d_sensor_abs_report: obj[0]: type: 0x01 X: 323 Y: 301 Z: 79 WX: 9 WY: 2
Bank=8d
Address=2c 2c
input input92: rmi_2d_sensor_abs_report: obj[0]: type: 0x01 X: 271 Y: 378 Z: 73 WX: 8 WY: 4
Bank=8d
Address=2c 2c
input input92: rmi_2d_sensor_abs_report: obj[0]: type: 0x01 X: 468 Y: 378 Z: 72 WX: 7 WY: 3
Bank=8d
Address=2c 2c
i2c i2c-11: Bus collision! SMBus may be locked until next hard reset. (sorry!)
rmi4_f12 rmi4-00.fn12: Failed to read object data. Code: -5.
Bank=8d
Address=2c 2c
input input92: rmi_2d_sensor_abs_report: obj[0]: type: 0x01 X: 563 Y: 373 Z: 73 WX: 7 WY: 2
Bank=8d
Address=2c 2c
i2c i2c-11: Bus collision! SMBus may be locked until next hard reset. (sorry!)
rmi4_f12 rmi4-00.fn12: Failed to read object data. Code: -5.


There are too many bus collisions a no responses. This is my
implementation of piix4_access_asf

static s32 piix4_access_asf(struct i2c_adapter *adap, u16 addr,
         unsigned short flags, char read_write,
         u8 command, int size, union i2c_smbus_data *data)
{
    struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
    unsigned short piix4_smba = adapdata->smba;
    int timeout = 0;
    int retval;
    u8 temp;

    // Acquire IMC semaphore
    outb_p(0x01, 0x14 + piix4_smba);
    while ((++timeout < MAX_TIMEOUT) && (!((temp = inb_p(0x14 + piix4_smba)) & 0x01))) {
        usleep_range(250, 500);
    }
    if ((temp & 0x01) == 0) {
        printk(KERN_INFO "lock not acquired\n");
        return -EBUSY;
    }

    outb_p(0x80, 0x13 + piix4_smba); // Set DataBankSel to host bank

    retval = piix4_access(adap, addr, flags, read_write, command, size, data);

    // Release semphore
    outb_p(0x02, 0x14 + piix4_smba);

    return retval;
}

Before transaction i am requesting HostSemaphore. Semaphore is correctly
acquired. Always. I don't know how exactly i should avoid bus conflicts.

Interrupts are sometimes generated with low frequency, sometimes with
high frequency. I don't know exactly why. Frequency changes after
restart of psmouse driver. Frequency changes with touch activity too, if
starts generating with high frequency and then i don't touch anything,
then frequency goes down. After touchpad activity frequency again goes
up.

Here is video with current state:

https://youtu.be/tf850B7UTWA



[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux