欧美亚洲一区二区三区,午夜欧美艳情视频免费看,欧美XXXXX又粗又大,国精品产露脸偷拍视频

技術(shù)文摘

input子系統(tǒng)(二)——GSC3280一線觸摸屏驅(qū)動












一、系統(tǒng)簡介

本文介紹友善之臂一線觸摸屏接到GSC3280開發(fā)板的驅(qū)動。本文中,首先講述GSC3280內(nèi)部定時器驅(qū)動,該驅(qū)動作為一線觸摸屏數(shù)據(jù)傳送時的采樣定時器。然后講述一線觸摸屏協(xié)議驅(qū)動。最后講述通過一線觸摸屏的協(xié)議,控制觸摸屏的背光,并且通過滑動變阻器來線性控制觸摸屏的背光,提供了底層和應(yīng)用層程序。

二、GSC3280內(nèi)部定時器驅(qū)動

GSC3280芯片包含一個TIMER定時器模塊,TIMER定時器模塊包含TIMER0~TIMER3共4個相對獨立的32bit 定時器,每一個定時器都有自己獨立的時鐘源,均支持循環(huán)定時模式和單次定時模式兩種工作模式,每個定時器都有各自的中斷,TIMER定時器模塊將4個中斷合并為一個中斷輸出給中斷控制器,并額外提供一個int_for_adc中斷。

首先看下定時器模塊初始化函數(shù)gsc3280_timer_init():

1.  struct gsc3280_timer {

2.      bool in_use;

3.      void __iomem *base;

4.      unsigned long rate;

5.      struct gsc3280_hard_timer *h_timer;

6.      char *name;

7.  };

8.  static struct gsc3280_timer gsc3280_timer_priv[GSC3280_H_TIMER_NR] = {

9.      {false, (__iomem void *)GSC3280_TIMER_BASEADDR + 0x00,    0, NULL, "Timer0"},

10.    {false, (__iomem void *)GSC3280_TIMER_BASEADDR + 0x14,    0, NULL, "Timer1"},

11.    {false, (__iomem void *)GSC3280_TIMER_BASEADDR + 0x28,    0, NULL, "Timer2"},

12.    {false, (__iomem void *)GSC3280_TIMER_BASEADDR + 0x3C,    0, NULL, "Timer3"}

13.};

14.static int __init gsc3280_timer_init(void)

15.{

16.    int i = 0;

17.    struct clk *clk = NULL;

18.    timer_tcr_u tcr = {.w32 = 0};

19. 

20.    DBG("############");

21.    DBG("gsc3280 timer init start\n");

22.    //enable timer modules

23.    sysctl_mod_enable(SYSCTL_MOD_TIMER0);

24.    sysctl_mod_enable(SYSCTL_MOD_TIMER1);

25.    sysctl_mod_enable(SYSCTL_MOD_TIMER2);

26.    sysctl_mod_enable(SYSCTL_MOD_TIMER3);

27.    //get 4 timer rate, use this cal LC

28.    clk = clk_get(NULL, "timer0");

29.    gsc3280_timer_priv[TIMER0].rate = clk_get_rate(clk);

30.    clk = clk_get(NULL, "timer1");

31.    gsc3280_timer_priv[TIMER1].rate = clk_get_rate(clk);

32.    clk = clk_get(NULL, "timer2");

33.    gsc3280_timer_priv[TIMER2].rate = clk_get_rate(clk);

34.    clk = clk_get(NULL, "timer3");

35.    gsc3280_timer_priv[TIMER3].rate = clk_get_rate(clk);

36.    for (i = 0; i < GSC3280_H_TIMER_NR; i++) {

37.        if (gsc3280_timer_priv[i].rate == 0) {

38.            DBG("GSC3280 TIMER%d Get Rate Failed!", i);

39.            return -EAGAIN;

40.        }

41.        DBG("timer[%d] = %ld\n", i, gsc3280_timer_priv[i].rate);

42.        tcr.w32 = __raw_readl(gsc3280_timer_priv[i].base + TIMER_CR);

43.        tcr.b.enable = 0;    //disable timer

44.        tcr.b.irq_mask = 1;        //mask timer irq

45.        __raw_writel(tcr.w32, gsc3280_timer_priv[i].base + TIMER_CR);

46.    }

47.    printk(KERN_INFO "GSC3280 TIMER0~3 Enable Success!");

48.    DBG("############");

49.    return 0;

50.}

51.core_initcall(gsc3280_timer_init);


說明:

1) 首先在系統(tǒng)控制模塊中使能四個定時器模塊。

2) 分別獲取定時器的時鐘頻率。

3) 最后,分別初始化定時器的控制寄存器。

4) 注意此處初始化使用的是core_initcall()宏,具有很高的執(zhí)行優(yōu)先級。

然后看下申請定時器函數(shù),該函數(shù)即為一線觸摸屏驅(qū)動中使用的申請定時器函數(shù)。

1.  int gsc3280_request_hard_timer(struct gsc3280_hard_timer *h_timer)

2.  {

3.      int i = 0, ret = 0;

4.   

5.      for (i = 0; i < GSC3280_H_TIMER_NR; i++) {

6.          if (gsc3280_timer_priv[i].h_timer == NULL) {

7.              gsc3280_timer_priv[i].h_timer = h_timer;

8.              ret = request_irq(EXT_GSC3280_TIMER_IRQ, &gsc3280_timer_interrupt, 

9.                                  IRQF_SHARED, gsc3280_timer_priv[i].name, 

10.                                &gsc3280_timer_priv[i]);

11.            if (ret) {

12.                printk(KERN_ERR "Start hard Timer request irq failed!\n");

13.                return ret;

14.            }

15.            DBG("GSC3280 Request Timer Success.");

16.            return 0;

17.        }

18.    }

19.    DBG("GSC3280 Request Timer error!");

20.    return -EBUSY;

21.}

22.EXPORT_SYMBOL(gsc3280_request_hard_timer);


說明:

1) 首先通過for循環(huán)找到第一個沒有被使用的硬件定時器。

2) 找到后,申請中斷。由前面介紹可知,四個定時器共享中斷。該中斷函數(shù)接下里會講述。

3) 如果申請中斷失敗,直接退出。

gsc3280_timer_interrupt()函數(shù)如下所示:

1.  static irqreturn_t gsc3280_timer_interrupt(int irq, void *_ptr)

2.  {

3.      irqreturn_t ret = IRQ_NONE;

4.      struct gsc3280_timer *timer = (struct gsc3280_timer *)_ptr;

5.   

6.      if (__raw_readl(timer->base + TIMER_IS) & 0x01) {

7.          //is real interrupt

8.          timer->h_timer->function(timer->h_timer->data);

9.          ret = IRQ_HANDLED;

10.    }

11.    //clr interrupt bit

12.    __raw_readl(timer->base + TIMER_EOI);

13.    return ret;

14.}


說明:

1) 進(jìn)入中斷后,首先讀取中斷狀態(tài)寄存器查看是否真的有中斷,不是誤觸發(fā)。

2) 如果是真的中斷,執(zhí)行中斷回調(diào)函數(shù)。

3) 通過讀取方式清除中斷標(biāo)志,以便下次能夠再次進(jìn)入中斷。       

釋放硬件定時器函數(shù)如下所示:

1.  void gsc3280_free_hard_timer(struct gsc3280_hard_timer *h_timer)

2.  {

3.      int i = 0;

4.   

5.      for (i = 0; i < GSC3280_H_TIMER_NR; i++) {

6.          if (gsc3280_timer_priv[i].h_timer == h_timer) {

7.              if (gsc3280_timer_priv[i].in_use)

8.                  gsc3280_timer_stop(h_timer);

9.              free_irq(EXT_GSC3280_TIMER_IRQ, &gsc3280_timer_priv[i]);

10.            gsc3280_timer_priv[i].h_timer = NULL;

11.        }

12.    }

13.}

14.EXPORT_SYMBOL(gsc3280_free_hard_timer);


說明:

1) 通過for循環(huán)和傳入的形參找到釋放的定時器

2) 判斷定時器是否在使用,如果使用,停止定時器。

3) 釋放定時器中斷。

4) 定時器變量清除。

接下來講述比較重要的函數(shù),開啟定時器gsc3280_timer_start():
1.  static void start_hard_timer(struct gsc3280_timer *timer)

2.  {

3.      unsigned long tlc = 0;

4.      timer_tcr_u tcr = {.w32 = 0};

5.      

6.      if (timer->h_timer->value_type == 0)

7.          tlc = (timer->rate * timer->h_timer->expires) /1000;

8.      else

9.          tlc = timer->rate / timer->h_timer->bps - 1;

10.    tcr.w32 = __raw_readl(timer->base + TIMER_CR);

11.    if (timer->h_timer->type == LOOP)

12.        tcr.b.mode = 1;

13.    else

14.        tcr.b.mode = 0;

15.    __raw_writel(tcr.w32, timer->base + TIMER_CR);

16.    __raw_writel(tlc, timer->base + TIMER_LC);

17.    //Enable Timer Interupt

18.    tcr.w32 = __raw_readl(timer->base + TIMER_CR);

19.    tcr.b.irq_mask = 0;        //not mask timer irq

20.    tcr.b.enable = 1;    //enable timer

21.    __raw_writel(tcr.w32, timer->base + TIMER_CR);

22.    __raw_readl(timer->base + TIMER_EOI);

23.    timer->in_use = true;

24.}

25.int gsc3280_timer_start(struct gsc3280_hard_timer *h_timer)

26.{

27.    int i =0;

28. 

29.    if ((h_timer->data == 0) || (h_timer->function == NULL)) {

30.        printk(KERN_ERR "GSC3280 Request Timer, But The Param Wrong!");

31.        return -EINVAL;

32.    }

33.    for (i = 0; i < GSC3280_H_TIMER_NR; i++) {

34.        if (gsc3280_timer_priv[i].h_timer == h_timer) {

35.            if (!gsc3280_timer_priv[i].in_use)

36.                start_hard_timer(&gsc3280_timer_priv[i]);

37.            return 0;

38.        }

39.    }

40.    DBG("gsc3280_timer_start error!!!!\n");

41.    return -EBUSY;

42.}

43.EXPORT_SYMBOL(gsc3280_timer_start);


說明:

1) 首先檢查形參變量,如果變量錯誤,直接返回。

2) 根據(jù)形參變量尋找相應(yīng)的定時器,調(diào)用start_hard_timer()函數(shù)開啟定時器。

3) start_hard_timer()函數(shù)首先根據(jù)需要定時的類型,計算定時器的重載值。對于本定時器驅(qū)動,支持兩種分辨率的定時時間。第一種為毫秒級,該方法定時誤差較大。第二種為bit每秒,即高精度定時,本文所使用的即是此種定時方法。然后操作控制寄存器,打開中斷,使能定時器,讓定時器開始工作。        

接下來講述停止定時器函數(shù)gsc3280_timer_stop():

1.  static void stop_hard_timer(struct gsc3280_timer *timer)

2.  {

3.      timer_tcr_u tcr = {.w32 = 0};

4.   

5.      tcr.w32 = __raw_readl(timer->base + TIMER_CR);

6.      tcr.b.irq_mask = 1;        //mask timer irq

7.      tcr.b.enable = 0;    //disable timer

8.      __raw_writel(tcr.w32, timer->base + TIMER_CR);

9.      timer->in_use = false;

10.}

11.void gsc3280_timer_stop(struct gsc3280_hard_timer *h_timer)

12.{

13.    int i= 0;

14. 

15.    for (i = 0; i < GSC3280_H_TIMER_NR; i++) {

16.        if (gsc3280_timer_priv[i].h_timer == h_timer) {

17.            if (gsc3280_timer_priv[i].in_use) {

18.                stop_hard_timer(&gsc3280_timer_priv[i]);

19.                break;

20.            }

21.        }

22.    }

23.}

24.EXPORT_SYMBOL(gsc3280_timer_stop);


說明:

1) 首先根據(jù)形參尋找相應(yīng)的定時器。

2) 找到后,判斷定時器是否在使用,如果在使用,調(diào)用函數(shù)stop_hard_timer()停止定時器。

3) stop_hard_timer()函數(shù)中,就是操作控制寄存器,屏蔽中斷,禁止定時器。       

最后介紹重新啟動定時器函數(shù)gsc3280_mod_timer():

1.  int gsc3280_mod_timer(struct gsc3280_hard_timer *h_timer)

2.  {

3.      int i = 0;

4.   

5.      for (i = 0; i < GSC3280_H_TIMER_NR; i++) {

6.          if (gsc3280_timer_priv[i].h_timer == h_timer) {

7.              if (gsc3280_timer_priv[i].in_use) {

8.                  stop_hard_timer(&gsc3280_timer_priv[i]);

9.                  start_hard_timer(&gsc3280_timer_priv[i]);

10.            }

11.        }

12.    }

13.    return 0;

14.}

15.EXPORT_SYMBOL(gsc3280_mod_timer);


說明:

1) 該函數(shù)首先通過形參尋找相應(yīng)的定時器。

2) 找到后,判斷定時器是否在使用,如果在使用,首先停止定時器,然后再一次開啟。







三、一線觸摸屏協(xié)議驅(qū)動

3.1、一線觸摸屏協(xié)議的基本內(nèi)容

一線觸摸屏首先定義一個軟定時器,該定時器每隔25ms執(zhí)行一次,在該定時器的中斷函數(shù)中,會判斷此次是什么類型的數(shù)據(jù)傳輸,包括初始化一線觸摸屏、控制背光命令或者讀取觸摸屏位置信息命令。命令設(shè)置成功后,進(jìn)入測量函數(shù),在測量函數(shù)中,打開硬件定時器,使用位速率為9600和一線觸摸屏通信,最后取得有效數(shù)據(jù)后,如果是測量位置信息,通過input子系統(tǒng)將其報告給應(yīng)用層,如果是控制背光,則什么也不做。






3.2、一線觸摸屏系統(tǒng)初始化和退出函數(shù)

1.  #if defined(CONFIG_GSC3280_1WIRE_TS)

2.  static struct platform_device ts_1wire_device = {

3.      .name    = "ts_1wire_device",

4.      .id        = -1,

5.  };

6.  #endif

7.  static struct platform_driver ts_1wire_device_driver = {

8.      .probe    = ts_1wire_probe,

9.      .remove    = __devexit_p(ts_1wire_remove),

10.    .driver    = {

11.        .name    = "ts_1wire_device",

12.        .owner    = THIS_MODULE,

13.    }

14.};

15. 

16.static int __init ts_1wire_init(void)

17.{

18.    return platform_driver_register(&ts_1wire_device_driver);

19.}

20.static void __exit ts_1wire_exit(void)

21.{

22.    platform_driver_unregister(&ts_1wire_device_driver);

23.}

24.module_init(ts_1wire_init);

25.module_exit(ts_1wire_exit);

26. 

27.MODULE_AUTHOR("Davied<apple_guet@126.com>");

28.MODULE_DESCRIPTION("GSC3280 one wire ts Driver");

29.MODULE_LICENSE("GPL");

30.MODULE_ALIAS("gsc3280 one wire ts")

       
說明:

1) 將一線觸摸屏定義為平臺設(shè)備,因為它不操作任何CPU內(nèi)部資源,所以平臺設(shè)備的定義中只有名稱和id。

2) 使用平臺設(shè)備的注冊和注銷函數(shù)對其進(jìn)行操作。

接下來講述平臺設(shè)備的探測函數(shù)ts_1wire_probe(),程序如下:

1.  static int ts_1wire_probe(struct platform_device *pdev)

2.  {

3.      int ret = 0;

4.      struct ts_1wire_t *ts = NULL;

5.      struct input_dev *input = NULL;

6.   

7.      DBG("############\n");

8.      printk(KERN_INFO "ts 1wire probe start.\n");

9.      ts = kzalloc(sizeof(struct ts_1wire_t), GFP_KERNEL);

10.    if (!ts) {

11.        DBG("kzalloc error\n");

12.        return -ENOMEM;

13.    }

14.    input = input_allocate_device();

15.    if (!input) {

16.        ret = -ENOMEM;

17.        goto err_free_mem;

18.    }

19.    spin_lock_init(&ts->slock);

20.    ts->dev = &pdev->dev;

21.    snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(ts->dev));

22.    input->name = "h3600_ts";

23.    input->phys = ts->phys;

24.    input->dev.parent = ts->dev;

25.    input->id.vendor = 0x00;    //tsdev->vendor;

26.    input->id.version = 0x00;    //tsdev->rev;

27.    input->id.product = 0x03;    //tsdev->rev;

28.    input->id.bustype = BUS_HOST;    //should be spi 

29.    input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);

30.    input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);

31.    ts->input = input;

32.    input_set_abs_params(ts->input, ABS_X, GSC_X_MIN, GSC_X_MAX, GSC_X_FUZZ, 0);

33.    input_set_abs_params(ts->input, ABS_Y, GSC_Y_MIN, GSC_Y_MAX, GSC_Y_FUZZ, 0);

34.    input_set_abs_params(ts->input, ABS_PRESSURE, GSC_PRESSURE_MIN, GSC_PRESSURE_MAX, 0, 0);

35.    ret = input_register_device(ts->input);

36.    if (ret) {

37.        DBG("!!!!input register device error!\n");

38.        goto err_free_input;

39.    }

40.    strlcpy(ts->name, TS_1WIRE_NAME, sizeof(ts->name));

41.    ret = gpio_request(TS_1WIRE_DATA_PIN, "TS_1WIRE_DATA_PIN");

42.    if (ret) {

43.        DBG("gpio request error!\n");

44.        goto err_free_input;

45.    }

46.    set_pin_up();

47.    set_pin_value(1);

48.    set_pin_as_output();

49.    

50.    init_hard_timer_for_1wire(ts);

51.    ret = gsc3280_request_hard_timer(&ts->ts_hard_timer);

52.    if (ret) {

53.        DBG("gsc3280 request hard timer error\n");

54.        goto err_gpio_req;

55.    }

56.    ret = misc_register(&bl_misc);

57.    if (ret != 0) {

58.        DBG("misc_register bl_misc error!\n");

59.        goto err_hard_timer_req;

60.    }

61.    ts->one_wire_status = IDLE;

62.    init_timer(&ts_1wire_timer);

63.    ts_1wire_timer.data = (unsigned long)ts;

64.    ts_1wire_timer.expires = jiffies + TIMER_DELAY;

65.    ts_1wire_timer.function = one_wire_timer_callback;

66.    add_timer(&ts_1wire_timer);

67.    mutex_lock(&wire1_ts_list_lock);

68.    list_add(&ts->device_entry, &wire1_ts_list);

69.    mutex_unlock(&wire1_ts_list_lock);

70.    platform_set_drvdata(pdev, ts);

71.    printk(KERN_INFO "ts 1wire probe success.\n");

72.    DBG("############\n");

73.    return 0;

74. 

75.err_hard_timer_req:

76.    gsc3280_free_hard_timer(&ts->ts_hard_timer);

77.err_gpio_req:

78.    gpio_free(TS_1WIRE_DATA_PIN);

79.err_free_input:

80.    input_free_device(input);

81.err_free_mem:

82.    kfree(ts);

83.    printk(KERN_INFO "!!!!ts 1wire probe error!!!!!\n");

84.    return ret;

85.}

說明:

1) 首先申請一線觸摸屏結(jié)構(gòu)體內(nèi)存。

2) 然后申請input設(shè)備內(nèi)存。

3) 接下來初始化一線觸摸屏結(jié)構(gòu)體成員變量,包括自旋鎖、IO申請等。

4) 申請硬件定時器。將控制背光定義為混雜設(shè)備。

5) 申請軟件定時器,包括設(shè)置數(shù)據(jù)、延時時間和回調(diào)函數(shù),然后將這個軟定時器加入到系統(tǒng)中。




3.3、軟定時器程序分析

根據(jù)前面的一線電阻觸摸屏原理分析,首先看下回調(diào)函數(shù)one_wire_timer_callback():

1.  static void one_wire_timer_callback(unsigned long data)

2.  {

3.      unsigned long flags = 0;

4.      struct ts_1wire_t *ts = (struct ts_1wire_t *)data;

5.   

6.      //mod_timer(&ts_1wire_timer, jiffies + TIMER_DELAY);

7.      spin_lock_irqsave(&ts->slock, flags);

8.      if (ts->lcd_type == 0) {

9.          //DBG("REQ_INFO\n");

10.        ts->req = REQ_INFO;

11.    }

12.    else if (!ts->backlight_init_success) {

13.        //DBG("backlight_init_success\n");

14.        ts->backlight_init_success = 1;

15.        ts->req = BL_INIT;

16.    }

17.    else if (ts->backlight_req) {

18.        //DBG("backlight_req\n");

19.        ts->req = ts->backlight_req;

20.        ts->backlight_req = 0;

21.    } else {

22.        //DBG("REQ_TS\n");

23.        ts->req = REQ_TS;

24.    }

25.    spin_unlock_irqrestore(&ts->slock, flags);

26.    start_one_wire_session(ts);

27.}

說明:

1) 首先上自旋鎖,防止多個CPU在執(zhí)行此函數(shù)。

2) 根據(jù)不同的類型,賦值不同的命令。獲取觸摸屏位置信息是默認(rèn)命令。系統(tǒng)啟動后,REQ_INFO和BL_INIT命令一般只執(zhí)行一次。

3) 釋放自旋鎖,開始一次會話。

會話函數(shù)start_one_wire_session(ts)如下所示:

1.  static void start_one_wire_session(struct ts_1wire_t *ts)

2.  {

3.      u8 crc = 0;

4.      unsigned long flags = 0;

5.      

6.      if (ts->one_wire_status != IDLE) {

7.          DBG("one_wire_status: %d error!!!!\n", ts->one_wire_status);

8.          return;

9.      }

10.    spin_lock_irqsave(&ts->slock, flags);

11.    ts->one_wire_status = START;    //IDLE to START

12.    set_pin_value(1);

13.    set_pin_as_output();

14.    crc8_init(crc);

15.    crc8(crc, ts->req);

16.    ts->io_data = (ts->req << 8) + crc;

17.    ts->io_data <<= 16;

18.    ts->io_bit_count = 1;

19.    set_pin_as_output();

20.    spin_unlock_irqrestore(&ts->slock, flags);

21.    

22.    local_irq_save(flags);

23.    gsc3280_timer_start(&ts->ts_hard_timer);

24.    set_pin_value(0);

25.    local_irq_restore(flags);

26.}

說明:

1) 首先判斷觸摸屏狀態(tài),如果是不是IDLE,錯誤退出。

2) 上自旋鎖,初始化觸摸屏狀態(tài)為開始,設(shè)置一線IO管腳狀態(tài),計算crc,組裝數(shù)據(jù)。

3) 解自旋鎖,開啟硬件定時器,啟動傳輸。


        


3.4、硬件定時器傳輸數(shù)據(jù)

1.  static void init_hard_timer_for_1wire(struct ts_1wire_t *ts)

2.  {

3.      ts->ts_hard_timer.type = LOOP;

4.      ts->ts_hard_timer.value_type = 1;

5.      ts->ts_hard_timer.bps = SAMPLE_BPS;

6.      ts->ts_hard_timer.function = ts_1wire_hardtimer_callback;

7.      ts->ts_hard_timer.data = (unsigned long)ts;

8.  }

9.  static void ts_1wire_hardtimer_callback(unsigned long data)

10.{

11.    struct ts_1wire_t *ts = (struct ts_1wire_t *)data;

12. 

13.    //DBG("ts_1wire_hardtimer_callback start\n");

14.    ts->io_bit_count--;

15.    switch(ts->one_wire_status) {

16.    case START:

17.        //DBG("START\n");

18.        if (ts->io_bit_count == 0) {

19.            ts->io_bit_count = 16;

20.            ts->one_wire_status = REQUEST;

21.        }

22.        break;

23.    case REQUEST:

24.        //Send a bit

25.        //DBG("REQUEST\n");

26.        set_pin_value(ts->io_data & (1U << 31));

27.        ts->io_data <<= 1;

28.        if (ts->io_bit_count == 0) {

29.            ts->io_bit_count = 2;

30.            ts->one_wire_status = WAITING;

31.        }

32.        break;

33.    case WAITING:

34.        //DBG("WAITING\n");

35.        if (ts->io_bit_count == 0) {

36.            ts->io_bit_count = 32;

37.            ts->one_wire_status = RESPONSE;

38.        }

39.        else if (ts->io_bit_count == 1) {

40.            set_pin_as_input();

41.            set_pin_value(1);

42.        }

43.        break;

44.    case RESPONSE:

45.        //Get a bit

46.        //DBG("RESPONSE\n");

47.        ts->io_data = (ts->io_data << 1) | get_pin_value();

48.        if (ts->io_bit_count == 0) {

49.            ts->io_bit_count = 2;

50.            ts->one_wire_status = STOPING;

51.            set_pin_value(1);

52.            set_pin_as_output();

53.            one_wire_session_complete(ts);

54.        }

55.        break;

56.    case STOPING:

57.        //DBG("STOPING\n");

58.        if (ts->io_bit_count == 0) {

59.            ts->one_wire_status = IDLE;

60.            gsc3280_timer_stop(&ts->ts_hard_timer);

61.            mod_timer(&ts_1wire_timer, jiffies + TIMER_DELAY);

62.        }

63.        break;

64.    default:

65.        //DBG("default\n");

66.        gsc3280_timer_stop(&ts->ts_hard_timer);

67.        mod_timer(&ts_1wire_timer, jiffies + TIMER_DELAY);

68.        break;

69.    }

70.}

說明:

1) 硬件定時器初始化init_hard_timer_for_1wire()函數(shù)在驅(qū)動探測函數(shù)中執(zhí)行,此函數(shù)定義了硬件定時器工作在循環(huán)模式,數(shù)據(jù)類型為位速率,位速率為9600,定義了硬件定時器的回調(diào)函數(shù)。

2) 在硬件定時函數(shù)中,通過一個switch-case結(jié)構(gòu)來區(qū)分不同的工作狀態(tài)。啟動一次會話后,其工作狀態(tài)分別經(jīng)過:START->REQUEST->WAITING->RESPONSE->STOPING。

3) 在START中,首先設(shè)置REQUEST中需要傳送的位數(shù)為16位。在REQUEST中傳送完16位數(shù)據(jù)后,設(shè)置進(jìn)入兩次WAITING狀態(tài)。第一次WAITING將IO管腳設(shè)置為輸入,準(zhǔn)備接收數(shù)據(jù)。第二次WAITING設(shè)置當(dāng)前狀態(tài)為RESPONSE,接收數(shù)據(jù)長度為32位。在RESPONSE中,接收到32位數(shù)據(jù)后,設(shè)置進(jìn)入兩次STOPING,并且調(diào)用one_wire_session_complete(ts);函數(shù)表示一次會話完成。第二次進(jìn)入STOPING后,停止硬件定時器,重新啟動軟件定時器。

one_wire_session_complete(ts);函數(shù)如下所示:

1.  static inline void notify_info_data(struct ts_1wire_t *ts, unsigned char lcd_type, 

2.                                      unsigned char ver_year, unsigned char week)

3.  {

4.      if (lcd_type != 0xFF) {

5.          ts->lcd_type = lcd_type;

6.          //firmware_ver = ver_year * 100 + week;

7.      }

8.  }

9.  static inline void notify_bl_data(struct ts_1wire_t *ts, u8 a, u8 b, u8 c)

10.{

11.    ts->bl_ready = 1;

12.    wake_up_interruptible(&bl_waitq);

13.}

14.static void one_wire_session_complete(struct ts_1wire_t *ts)

15.{

16.    u8 crc = 0;

17.    const unsigned char *p = (const u8*)&(ts->io_data);

18. 

19.    crc8_init(crc);

20.    crc8(crc, p[3]);

21.    crc8(crc, p[2]);

22.    crc8(crc, p[1]);

23.    if (crc != p[0]) {

24.        DBG("one_wire_session_complete crc error\n");

25.        return;

26.    }

27.    switch(ts->req) {

28.    case REQ_TS:

29.        ts->x = ((p[3] >> 4U) << 8U) + p[2];

30.        ts->y = ((p[3] & 0xFU) << 8U) + p[1];

31.        ts->z = (ts->x != 0xFFFU) && (ts->y != 0xFFFU);

32.        notify_ts_data(ts);

33.        break;

34.    case REQ_INFO:

35.        notify_info_data(ts, p[3], p[2], p[1]);

36.        break;

37.    default:

38.        notify_bl_data(ts, p[3], p[2], p[1]);

39.        break;

40.    }

41.}

說明:

1) 函數(shù)首先進(jìn)行crc校驗,如果crc錯誤,則直接退出。

2) 如果校驗正確,根據(jù)不同的命令,進(jìn)入不同的報告類型。其中REQ_TS和REQ_INFO不需要向應(yīng)用層報告數(shù)據(jù)。notify_info_data()函數(shù)通過修改ts->lcd_type變量來保證系統(tǒng)起來以后,一線觸摸屏執(zhí)行REQ_INFO命令只有一次。


notify_ts_data(ts);函數(shù)如下所示:

1.  static void gsc3280_report_event(struct ts_1wire_t *ts, u32 z)

2.  {

3.  #ifdef CONFIG_GSC3280_POS_PRINT

4.      printk(KERN_INFO "x = %d\n", ts->x);

5.      printk(KERN_INFO "y = %d\n", ts->y);

6.      printk(KERN_INFO "z = %d\n", z);

7.  #endif

8.   

9.      input_report_abs(ts->input, ABS_PRESSURE, z);

10.    input_report_abs(ts->input, ABS_X, ts->x);

11.    input_report_abs(ts->input, ABS_Y, ts->y);

12.    if (z > 0)

13.        input_report_key(ts->input, BTN_TOUCH, 1);

14.    else

15.        input_report_key(ts->input, BTN_TOUCH, 0);

16.    input_sync(ts->input);

17.}

18.static inline void notify_ts_data(struct ts_1wire_t *ts)

19.{

20.    if (ts->z == 1) {

21.        ts->x = ((ts->x -285) * gXres) / (3944 - 285);

22.        ts->y = ((3936 - ts->y) * gYres) / (3936 - 102);

23.        if ((ts->x > 0) && (ts->x < gXres) && (ts->y > 0) && (ts->y < gYres)) {

24.            if (ts->flg == 0) {

25.                ts->flg = 1;

26.                gsc3280_report_event(ts, 0);

27.            }

28.            gsc3280_report_event(ts, ts->z);

29.        }

30.    } else if (ts->z == 0) {

31.        if (ts->flg == 1) {

32.            ts->flg = 0;

33.            gsc3280_report_event(ts, 0);

34.        }

35.    }

36.}

說明:

1) 首先根據(jù)公式計算觸摸點的絕對坐標(biāo),如果該坐標(biāo)值在正確的范圍內(nèi),則上報該位置信息。

2) 由于是電阻觸摸屏,其電阻值和位置是線性的,公式為:(電壓- 0) / (總電壓) = (分辨?zhèn)€數(shù)- 0) / (總個數(shù))。即分辨?zhèn)€數(shù)= 總個數(shù)* (電壓) / (總電壓)。通過測量觸摸屏四個腳點的電壓值,分別得到X和Y方向上的最大總電壓,然后在實際測量中,根據(jù)測得的電壓值,帶入公式中的電壓項,分別計算出X和Y方向的絕對坐標(biāo)。本文使用的觸摸屏分辨率為800*480,所以X方向的總個數(shù)為800,Y方向的為480。

3) 位置報告函數(shù)將在第三篇文章----input核心中講述。

4) 本文設(shè)計的程序可以通過make menuconfig命令輸入分辨率,Kconfig程序如下:

1.  config INPUT_TSDEV_SCREEN_X

2.      int "Horizontal screen resolution"

3.      depends on INPUT_TOUCHSCREEN

4.      default "800"

5.      help

6.       If you're using a digitizer, this is the X window screen resolution you are 

7.       using to correctly scale the data. If you're not using a digitizer, this value 

8.       is ignored.

9.   

10.config INPUT_TSDEV_SCREEN_Y

11.    int "Vertical screen resolution"

12.    depends on INPUT_TOUCHSCREEN

13.    default "480"

14.    help

15.     If you're using a digitizer, this is the Y window screen resolution you are 

16.     using to correctly scale the data. If you're not using a digitizer, this value 

17.     is ignored.

        在.c文件中通過下列程序獲得輸入的值:

1.  #ifndef CONFIG_INPUT_TSDEV_SCREEN_X

2.  #define CONFIG_INPUT_TSDEV_SCREEN_X    800

3.  #endif

4.  #ifndef CONFIG_INPUT_TSDEV_SCREEN_Y

5.  #define CONFIG_INPUT_TSDEV_SCREEN_Y    480

6.  #endif

7.   

8.  static const int gXres = CONFIG_INPUT_TSDEV_SCREEN_X;

9.  static const int gYres = CONFIG_INPUT_TSDEV_SCREEN_Y;




四、控制背光驅(qū)動和應(yīng)用層程序

4.1、驅(qū)動程序

在系統(tǒng)探測函數(shù)中,將控制背光驅(qū)動定義為混雜設(shè)備并進(jìn)行注冊,定義混雜設(shè)備的源碼如下:

1.  static struct file_operations bl_fops = {

2.      owner    : THIS_MODULE,

3.      write    : bl_write,

4.      open    : bl_open,

5.  };

6.  static struct miscdevice bl_misc = {

7.      .minor    = MISC_DYNAMIC_MINOR,

8.      .name    = BACKLIGHT_DEVICE_NAME,

9.      .fops    = &bl_fops,

10.};

說明:

1) 混雜設(shè)備的文件操作函數(shù)中有打開和寫,首先看下打開函數(shù):

1.  static int bl_open(struct inode *inode, struct file *filp)

2.  {

3.      int status = -ENXIO;

4.      struct ts_1wire_t *ts = NULL;

5.   

6.      mutex_lock(&wire1_ts_list_lock);

7.      list_for_each_entry(ts, &wire1_ts_list, device_entry) {

8.          if(strcmp(ts->name, TS_1WIRE_NAME) == 0) {

9.              status = 0;

10.            break;

11.        }

12.    }

13.    mutex_unlock(&wire1_ts_list_lock);

14.    if (status == 0) {

15.        filp->private_data = ts;

16.    } else {

17.        return status;

18.    }

19.    return nonseekable_open(inode, filp);

20.}

說明:

1) 首先通過本地全局鏈表和鎖獲得在探測函數(shù)中定義的設(shè)備結(jié)構(gòu)體內(nèi)存指針。

2) 然后調(diào)用無定位打開函數(shù)返回。

寫數(shù)據(jù)即發(fā)送命令控制背光,程序如下:

1.  static ssize_t bl_write(struct file *filp, const char __user *buffer, size_t count, loff_t *ppos)

2.  {

3.      int ret = 0;

4.      u8 bl_data = 0;

5.      struct ts_1wire_t *ts = filp->private_data;

6.   

7.      DBG("bl_write start\n");

8.      if (get_user(bl_data, (u8 __user *)buffer)) {

9.          printk(KERN_INFO "get_user error!\n");

10.        return -EFAULT;

11.    }

12.    if (bl_data > 127) {

13.        bl_data = 127;

14.    }

15.    ts->bl_ready = 0;

16.    ts->backlight_req = bl_data + 0x80U;

17.    ret = wait_event_interruptible_timeout(bl_waitq, ts->bl_ready, HZ);

18.    if (ret < 0) {

19.        printk(KERN_INFO "wait_event_interruptible_timeout error!\n");

20.        return ret;

21.    } else if (ret == 0) {

22.        printk(KERN_INFO "time out error!\n");

23.        return -ETIMEDOUT;

24.    } else {

25.        return count;

26.    }

27.}

說明:

1) 首先從應(yīng)用層獲取寫入背光值。

2) 組合數(shù)據(jù),形成背光控制命令。

3) 在會話函數(shù)中由于ts->backlight_req不為0,即可發(fā)送背光控制命令。







4.2、應(yīng)用層程序

通過滑動變阻器來控制背光。根據(jù)協(xié)議,背光總共可以分為0~127個檔位,滑動變阻器的測量值范圍為2010~4010,也就是說,背光每變化一個檔位,滑動變阻器電阻值變化:(4010 - 2010) / 128 = 16。那么我們給背光發(fā)送的檔位值即為:(x - 2010) / 16。應(yīng)用層程序如下:

1.  #include <fcntl.h>

2.  #include <stdio.h>

3.  #include <stdlib.h>

4.  #include <sys/ioctl.h>

5.  #include <linux/ioctl.h>

6.   

7.   

8.  #define ADC_DEV_IOC_MAGIC        'a'

9.  #define ADC_DEV_IOC_MAXNR        2

10.#define ADC_DEV_CON_PBAT        _IOR(ADC_DEV_IOC_MAGIC, 0, int)

11.#define ADC_DEV_CON_CHX            _IOWR(ADC_DEV_IOC_MAGIC, 1, int)

12. 

13.int main(int argc, char **argv)

14.{

15.    unsigned int idCmd = 0;

16.    //unsigned char buffer[4] = {0};

17.    unsigned char bl_data = 0;

18.    int fd1 = 0, fd2 = 0, ret = 0, data = 0;

19.    

20.    //以阻塞方式打開設(shè)備文件,非阻塞時flags=O_NONBLOCK

21.    fd1 = open("/dev/adc0", 0);

22.    if (fd1 < 0) {

23.        printf("Open ADC Device Faild!\n");

24.        exit(1);

25.    }

26.    fd2 = open("/dev/backlight-1wire", O_RDWR);

27.    if (fd2 < 0) {

28.        printf("Open wire1 backlight Device Faild!\n");

29.        exit(1);

30.    }

31.    while(1) {

32.        data = 1;

33.        idCmd = ADC_DEV_CON_CHX;

34.        ret = ioctl(fd1, idCmd, &data);

35.        if (ret != 0) {

36.            printf("Read ADC Device Faild!\n");

37.            break;

38.        }

39.        //printf("data = %d\n", data);

40.        bl_data = (data - 2010) /16;

41.        //printf("bl_data = %d\n", bl_data);

42.        ret = write(fd2, &bl_data, 1);

43.        if (ret < 0) {

44.            printf("wire1 backlight ret = %d\n", ret);

45.            //break;

46.        }

47.        //sleep(1);

48.        for (ret = 0; ret < 655360; ret++)

49.            ;;;;

50.    }

51.    close(fd1);

52.    close(fd2);

53.    return 0;

54.}

編譯后,將程序設(shè)為后臺執(zhí)行,系統(tǒng)啟動后,任何時間滑動變阻器,一線觸摸屏的背光都會根據(jù)電阻的位置而做相應(yīng)的變化。







原文參見:http://blog.chinaunix.net/uid-25445243-id-4111354.html