Re: Chipone icn85xx support in x86 linux kernel

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

 



Hi ALL.
Gathered all answers to the received questions in the code.
What I did: Using my experience of gsl1680 (userspace) on Chuwi Vi8
and reviewing code
https://github.com/bbelos/rk3188-kernel/blob/master/drivers/input/touchscreen/ICN8503/icn85xx.c
mentioned in the 1st my message (icn85xx.c) - I have created simple
module i2c client without ACPI that is using define constants for
manually setuping i2cbus (i2c-devX), i2cport and gpio pin then it
trying to wake up icn8528 chip and after trying to read main registers
according mentioned above specs for the chip.

0x000a - IcVersion, should be according Android data (i2cget -f 4 0x48
0x000a b) = 0x85 and is major chip version
0x000c - firmware version, according  Android (i2cget 4 0x48 0x000c b)
it is 0x38


Main goal of this module - just to wakeup chip and read some data from
it to ensure that it is working as expected.
For Gregor: in the code there is hw_init - this is my way (actually
attempt) to wake up the chip, also in the code there is the same but
in kernel space I've sent to you (userspace version) of using gpio.
For simplicity and discussing (read at once)  I have created "all in
one file" without includes and code splitting.

QUESTIONS:

 1) It is strange, but it looks that via Vanilla custom x8_64 Linux
4.4.2 ArchLinux   Baytrail on Chuwi Vi10 the Touchscreen Control Chip
probably resides not on 0x48  and it is resides on i2c-3 0x30. This
confused me completely, AFAIK chip could switch buses but not its
address.
Will be happy if anyone helps with this - whether it is possible for
chip to be i2c-4, 0x48 on Android and switched in Linux to i2c-3 0x30?

Also my discovering:
1.1)  On Chuwi Vi8 for gsl1680 it was only such Android: i2c-4, 0x40
and in Linux: i2c-3, 0x40 - only bus! But not address switching!

1.2) Taking into account decoded ACPI DSDT for Chipone icn8528
(CHPN0001) we see that  I2cSerialBus (0x0030, ControllerInitiated,
0x00061A80,
                            AddressingMode7Bit, "\\_SB.I2C4",
                            0x00, ResourceConsumer, ,
                            )

this makes sence of provided information into item 1.

2) I have not got positive results with my code - and still under
guessing whether I am not successful in waking up the chip or
something other wrong. :( I could not even read correct Chip version
in checking whether hw initialized correct.


3) Results of testing my code with different variations of i2cbus,
port  will be provided in next letter.

4) For Dmitry Torokhov : GPL or not included in main line of the
kernel according mentioned by you conditions for Chipone - I do not
care at the moment - my main goal is very simple - make myself happy
and at least get working touch on my Chuwi Vi10 rev 11 under ArchLinux
and help others owners of Baytrail tablets with TS on chipone icn85xx
to add OS Linux on their tablets.
The most important is very simple thing - to have driver for TS. May
be Chipone even approve farther adding it to the mainline (if it will
be created).
It is sad but Linux in contrast to Android has a lack of drivers for
touchscreen and many other hw of the tablets and this is to my mind is
very strange and reminding early times of 2.xx kernel. ;-) I am trying
to join and change this situation!

Regards,
                 Serge Kolotylo.




---------------- Testing Code:  ------------------------


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/i2c.h>

#define TS_I2C_BUS 4
#define TS_I2C_ADDR 0x30
#define CTP_RST_PORT 393
#define DRIVER_VERSION "0.0.1"
#define CTP_NAME "chipone-ts"
#define ICN85XX_PROG_IIC_ADDR (0x30)


#define POINT_NUM                   5

#define ICN85XX_WITHOUT_FLASH           0x11
#define ICN85XX_WITH_FLASH              0x22

#define IIC_RETRY_NUM 3


typedef struct _POINT_INFO
{
    unsigned char  u8ID;
    unsigned short u16PosX;     // coordinate X, plus 4 LSBs for
precision extension
    unsigned short u16PosY;     // coordinate Y, plus 4 LSBs for
precision extension
    unsigned char  u8Pressure;
    unsigned char  u8EventId;
}POINT_INFO;


struct icn85xx_ts_data {
    struct i2c_client        *client;
    struct input_dev         *input_dev;
    struct work_struct       pen_event_work;
    struct workqueue_struct  *ts_workqueue;
    struct hrtimer           timer;
    spinlock_t               irq_lock;
    struct semaphore         sem;
    int         ictype;
    int         code_loaded_flag;
    POINT_INFO  point_info[POINT_NUM+1];
    int         point_num;
    int         irq;
    int         irq_is_disable;
    int         use_irq;
    int         work_mode;
    int         screen_max_x;
    int         screen_max_y;
    int         revert_x_flag;
    int         revert_y_flag;
    int         exchange_x_y_flag;
};

static struct i2c_client *this_client;

/***********************************************************************************************
Name    :   icn85xx_i2c_rxdata
Input   :   addr
            *rxdata
            length
Output  :   ret
function    : read data from icn85xx, normal mode
***********************************************************************************************/
int icn85xx_i2c_rxdata(unsigned short addr, char *rxdata, int length){
    int ret = -1;
    int retries = 0;

    unsigned char tmp_buf[2];
    struct i2c_msg msgs[] = {
        {
            .addr   = this_client->addr,
            .flags  = 0,
            .len    = 2,
            .buf    = tmp_buf,
        },
        {
            .addr   = this_client->addr,
            .flags  = I2C_M_RD,
            .len    = length,
            .buf    = rxdata,
        },
    };

    tmp_buf[0] = (unsigned char)(addr>>8);
    tmp_buf[1] = (unsigned char)(addr);
    while(retries < IIC_RETRY_NUM){
        ret = i2c_transfer(this_client->adapter, msgs, 2);
        if(ret == 2)break;
        retries++;
    }

    if (retries >= IIC_RETRY_NUM)
    printk("from %s: i2c read error: %d\n", __func__, ret);

    return ret;

}

/***********************************************************************************************
Name    :   icn85xx_read_reg
Input   :   addr
            pdata
Output  :
function    :   read register of icn85xx, normal mode
***********************************************************************************************/
int icn85xx_read_reg(unsigned short addr, char *pdata)
{
    int ret = -1;
    ret = icn85xx_i2c_rxdata(addr, pdata, 1);
    printk("From %s -  addr: 0x%x: 0x%x\n", __func__,addr, *pdata);
    return ret;
}



/***********************************************************************************************
Name    :   icn85xx_iic_test
Input   :   void
Output  :
function    : 0 success,
***********************************************************************************************/
static int icn85xx_iic_test(void){
    struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client);
    int  ret = -1;
    char value = 0;
    int  retry = 0;
    int  flashid;
    icn85xx_ts->ictype = 0;
//    icn85xx_ts->ictype = ICN85XX_WITHOUT_FLASH;
//    return 1;
    printk("\nbegin %s",__func__);
    printk("\n BEGIN test another way of reading CurrFW ver");
    char mtmp[2];
    ret = icn85xx_i2c_rxdata(0x000c, mtmp, 2);
    short CurVersion;
    CurVersion = (mtmp[0]<<8) | mtmp[1];
    printk("\n CurrFW ver=%hu",CurVersion);

    printk("\n END test another way of reading CurrFW ver");

    while(retry++ < 3)
    {
        ret = icn85xx_read_reg(0xa, &value);
        if( (ret > 0) && (value == 0x85) ){
                icn85xx_ts->ictype = ICN85XX_WITH_FLASH;
            return ret;

        }
        ///////////////////////
        printk("\nBegin read fw ver from iictest");
        ret = icn85xx_read_reg(0xc, &value);
        printk("\nEnd read fw ver from iictest");

        printk("\nBegin read IC subver  from iictest");
        ret = icn85xx_read_reg(0xb, &value);
        printk("\nEnd read IC subver from iictest");

        ///////////////////////
        printk("iic test error! %d in %s\n", retry,__func__);
        msleep(3);
    }

    printk("\nend %s",__func__);
    return ret;
}




static int icn85xx_ts_probe(struct i2c_client *client, const struct
i2c_device_id *id){
    printk("\nhello from i2cprobe,%s",__func__);
    struct icn85xx_ts_data *icn85xx_ts;
    short fwVersion = 0;
    short curVersion = 0;
    int err = 0;
    int retry;

    printk("\n====%s begin=====.  \n", __func__);
    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
    {
        printk("I2C check functionality failed from %s.\n",__func__);
        return -ENODEV;
    }

    //memdata
    icn85xx_ts = kzalloc(sizeof(*icn85xx_ts), GFP_KERNEL);
    if (!icn85xx_ts)
    {
        printk("Alloc icn85xx_ts memory failed. %s\n",__func__);
        return -ENOMEM;
    }
    memset(icn85xx_ts, 0, sizeof(*icn85xx_ts));
    this_client = client;
    this_client->addr = client->addr;
    i2c_set_clientdata(client, icn85xx_ts);

    icn85xx_ts->work_mode = 0;
    spin_lock_init(&icn85xx_ts->irq_lock);
//    icn85xx_ts->irq_lock = SPIN_LOCK_UNLOCKED;
    err = icn85xx_iic_test();
    if (err <= 0){
        printk("func %s: icn85xx_iic_test  failed.\n",__func__);
        return -1;
    }
    else
        printk("iic communication ok: 0x%x\n", icn85xx_ts->ictype);


    printk("\nBye from i2cprobe,%s",__func__);
return 0;
}


static int  icn85xx_ts_remove(struct i2c_client *client){
return 0;
}



static const struct i2c_device_id icn85xx_ts_id[] = {
    { CTP_NAME, 0 },
    {}
};

MODULE_DEVICE_TABLE(i2c, icn85xx_ts_id);

static struct i2c_driver icn85xx_ts_driver = {
    .class      = I2C_CLASS_HWMON,
    .probe      = icn85xx_ts_probe,
    .remove     = icn85xx_ts_remove,
    .id_table   = icn85xx_ts_id,
    .driver = {
        .name   = CTP_NAME,
        .owner  = THIS_MODULE,
    },
};

static struct i2c_board_info ts_info = {
    .type    = CTP_NAME,
    .addr    =  TS_I2C_ADDR,
};



static int icn85xx_hw_init(void){
    int err = 0;
    err = gpio_request(CTP_RST_PORT, CTP_NAME);
    if ( err ) {
    printk("\nError CTP_RST_PORTgpio in %s ",__func__);
    err = -EINVAL;
    return err;
    }
    err = gpio_direction_output(CTP_RST_PORT, 1);
    if ( err ) {
    printk("\nError CTP_RST_PORTgpiodirection in %s ",__func__);
    err = -EINVAL;
    return err;
    }
    msleep(20);
    gpio_set_value_cansleep(CTP_RST_PORT, 0);
    msleep(100);
    gpio_set_value_cansleep(CTP_RST_PORT, 1);
    msleep(300);
return err;
}

static int __init ts_init(void){
    printk("\nINIT icn MODULE,func %s",__func__);
    printk("\n get pwr gpio in func %s",__func__);
    icn85xx_hw_init();

    struct i2c_adapter *adap = i2c_get_adapter(TS_I2C_BUS);
    printk(KERN_ERR "==icn85xx ts_init %d at i2cbus:
%d!!!!!!!!\n",__LINE__,TS_I2C_BUS);
    i2c_new_device(adap, &ts_info);
    //i2c client reg
    int ret = -1;
    ret = i2c_add_driver(&icn85xx_ts_driver);


return 0;
}



static void __exit ts_exit(void){
    printk("\nEXIT icn MODULE,func:  %s",__func__);
    gpio_free(CTP_RST_PORT);
    i2c_del_driver(&icn85xx_ts_driver);

}


module_init(ts_init);
module_exit(ts_exit);
MODULE_DESCRIPTION("MyICN touchscreen controller driver");
MODULE_AUTHOR("Serge Kolotylo sergk.admin@xxxxxxxxx>");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");







On Wed, Mar 2, 2016 at 11:06 PM, sergk sergk2mail <sergk.admin@xxxxxxxxx> wrote:
> Would like to add that specs are located
> https://gitlab.com/antruziliak/icn8528.git
> The main question - how to wake up chip.
> Looks that 2 gpios are used INT/WAKE + RST.
> Regards,
>                Serge Kolotylo.
>
> On Tue, Mar 1, 2016 at 10:07 AM, Gregor Riepl <onitake@xxxxxxxxx> wrote:
>>> 2) Could be icn8318 by Hans de Goede be adopted for icn85xx?
>>
>> chipone_icn8318.c lacks ACPI support. It may not be difficult to add though.
>>
>> The question is if both chips are sufficiently compatible.
>>
>>> how it is possible to use atmel_mxt_ts module for chipone? or what is the trick?
>>
>> That sounds very odd. Perhaps they share the same control interface?
>> Or perhaps Chipone just cloned the Atmel chips...
>>
>> I'm pretty certain that a specific firmware is required for your chip, though.
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux