{"id":650,"date":"2025-02-26T19:26:43","date_gmt":"2025-02-26T11:26:43","guid":{"rendered":"https:\/\/www.yanwenkai.com\/?p=650"},"modified":"2025-02-26T19:26:43","modified_gmt":"2025-02-26T11:26:43","slug":"lcd%e8%a7%a6%e6%8e%a7%e5%b1%8f%e7%a7%bb%e6%a4%8d%e4%b9%8blcd%e8%a7%a6%e6%91%b8%e9%a9%b1%e5%8a%a8%e7%af%87","status":"publish","type":"post","link":"https:\/\/www.yanwenkai.com\/?p=650","title":{"rendered":"LCD\u89e6\u63a7\u5c4f\u79fb\u690d\u4e4bLCD\u89e6\u6478\u9a71\u52a8\u7bc7"},"content":{"rendered":"<h1>1 \u524d\u8a00<\/h1>\n<p>&emsp;&emsp;lcd\u663e\u793a\u9a71\u52a8\u79fb\u690d\u5b8c\u540e\uff0c\u4ee5\u4e3a\u8df3\u51fa\u6df1\u5751\u4e86\uff1b\u6ca1\u60f3\u5230\u89e6\u6478\u5c4f\u9a71\u52a8\u6765\u4e86\u4e2a\u5927\u7684\u3002\u770b\u4ea7\u54c1\u624b\u518c\u548c\u767e\u5ea6\u7684\u6559\u7a0b\u53d1\u73b0\u6574\u4f53\u6846\u67b6\u5f88\u7b80\u5355\uff0c\u5c31\u662f\u4e2d\u65ad\u52a0spi\u5b50\u7cfb\u7edf\u4e24\u4e2a\u6a21\u5757\u800c\u5df2\uff1b\u89e6\u6478\u82af\u7247xpt2046\u7684\u521d\u59cb\u5316\u547d\u4ee4\u4e5f\u5f88\u7b80\u5355\uff0c\u5c31\u662f\u5355\u7eaf\u7684\u8f93\u51650x90\u30010xd0\u5373\u53ef\u83b7\u53d6xy\u8f74\u6570\u636e\u4e86\uff1b\u4f46\u5c31\u662f\u8fd9\u4e48\u7b80\u5355\u7684\u9a71\u52a8\uff0c\u5374\u5361\u4e86\u6211\u597d\u4e45\u7684\u65f6\u95f4\u3002<br \/>\n&emsp;&emsp;\u9996\u5148\u5c31\u9047\u5230\u4e86spi\u5b50\u7cfb\u7edf\u4e0e\u4e2d\u65ad\u51b2\u7a81\u7684\u95ee\u9898\u3002\u8fd9\u4e2a\u95ee\u9898\u56f0\u6270\u6211\u5f88\u4e45\uff0c\u56e0\u4e3a\u65e0\u8bba\u662f\u4ece\u4ee3\u7801\u903b\u8f91\u8fd8\u662f\u65f6\u5e8f\u4e0a\u90fd\u627e\u4e0d\u51fa\u6765\u9519\u8bef\uff0c\u4f46\u5c31\u662f\u5bfc\u81f4spi\u65e0\u6cd5\u83b7\u53d6\u6709\u6548\u6570\u636e\u3002\u540e\u6765\u4e5f\u662f\u8bfb\u5b98\u65b9\u9a71\u52a8\u548c\u5176\u4ed6\u5927\u4f6c\u7684\u9a71\u52a8\u4ee3\u7801\uff0c\u5bf9\u6bd4\u5185\u5bb9\u627e\u5dee\u5f02\uff0c\u624d\u53d1\u73b0\u95ee\u9898\u7684\u5173\u952e\u70b9\u5728\u4e8e\u6211\u6ca1\u52a0\u4e2d\u65ad\u89e6\u53d1\u9501\u5bfc\u81f4\u7684\u3002<br \/>\n&emsp;&emsp;\u5206\u6790\u539f\u56e0\u5e94\u8be5\u662f\u4e2d\u65ad\u4e0d\u65ad\u5730\u89e6\u53d1\u5bfc\u81f4\u5199\u51fd\u6570\u4e0d\u505c\u5730\u7ed9\u89e6\u6478\u5c4f\u53d1\u9001\u8bfb\u53d6\u6307\u4ee4\uff0c\u800c\u6211\u7684\u4f20\u8f93\u6570\u636e\u53c8\u6ca1\u4f20\u8f93\u5b8c\u6210\uff0c\u4e8c\u8005\u51b2\u7a81\u5bfc\u81f4\u6211\u65e0\u6cd5\u83b7\u53d6\u6709\u6548\u6570\u636e\u3002\u6211\u7684\u521d\u59cb\u7248\u672c\u9a71\u52a8\u4ee3\u7801\u662f\u4eff\u7167\u5b98\u65b9spi\u9a71\u52a8\u7f16\u5199\u7684\uff0c\u5b98\u65b9\u9a71\u52a8\u4e2d\u65ad\u5904\u7406\u90e8\u5206\u662f\u901a\u8fc7sysfs\u65b9\u5f0f\u5728\u5e94\u7528\u5c42\u63a7\u5236\uff0c\u6240\u4ee5\u9a71\u52a8\u4e0d\u5b58\u5728\u4e2d\u65ad\u89e6\u53d1\u9501\u7684\u95ee\u9898\uff1b\u4e14\u53ef\u80fd\u662f\u5728\u5e94\u7528\u5c42\u5904\u7406\u4e2d\u65ad\u903b\u8f91\uff0c\u6709\u4e86\u64cd\u4f5c\u5ef6\u65f6\uff0c\u6240\u4ee5\u907f\u514d\u4e86\u6b64\u95ee\u9898\u3002\u800c\u5b98\u65b9\u7684ads7846\u9a71\u52a8\u548c\u5176\u4ed6\u89e6\u6478\u9a71\u52a8\u4e2d\u5747\u6709\u4e2d\u65ad\u89e6\u53d1\u9501\u7684\u5b58\u5728\u3002<br \/>\n&emsp;&emsp;\u81ea\u5df1\u7f16\u5199\u7684\u7b80\u5355\u7248\u89e6\u6478\u4ee3\u7801\u6ca1\u95ee\u9898\u540e\uff0c\u9002\u914d\u5b98\u65b9\u7684\u89e6\u6478\u9a71\u52a8\u3002\u67e5\u9605\u8d44\u6599\u53d1\u73b0xpt2046\u88abads7846\u9a71\u52a8\u6240\u517c\u5bb9\u3002\u7167\u846b\u82a6\u753b\u74e2\u9002\u914d\u8bbe\u5907\u6811\uff0c\u5339\u914d\u8bbe\u5907\u6811\u65e0\u8bef\u540e\uff0c\u53c8\u662f\u5361\u5728\u4e86\u4e2d\u65ad\u65e0\u6cd5\u89e6\u53d1\u7684\u95ee\u9898\u4e0a\u3002<br \/>\n&emsp;&emsp;\u5206\u6790\u4ee3\u7801\uff0c\u6700\u7ec8\u53d1\u73b0\u8fd8\u662f\u5361\u5728spi\u5b50\u7cfb\u7edf\u548c\u4e2d\u65ad\u7684\u914d\u5408\u4e0a\uff0c\u67e5\u9605\u8d44\u6599\u5404\u79cd\u9002\u914d\u4fee\u6539\uff0c\u4f46\u7ed3\u679c\u662f\u8981\u4e48\u65e0\u6cd5\u89e6\u53d1\u9a71\u52a8\uff0c\u8981\u4e48\u65e0\u6cd5\u83b7\u53d6\u6709\u6548\u6570\u636e\u3002\u53c8\u5728\u7f51\u4e0a\u627e\u4e86\u4e13\u95e8\u7684xpt2046\u9a71\u52a8\uff0c\u4e5f\u662f\u65e0\u6cd5\u76f4\u63a5\u4f7f\u7528\uff0c\u5b83\u7684spi\u5904\u7406\u6570\u636e\u90e8\u5206\u4e5f\u662f\u4f1a\u5bfc\u81f4\u4e2d\u65ad\u65e0\u6cd5\u89e6\u53d1\u3002\u5230\u8fd9\u60f3\u7701\u4e8b\u76f4\u63a5\u4f7f\u7528\u5b98\u65b9\u9a71\u52a8\u7684\u8def\u662f\u5835\u6b7b\u4e86\uff0c\u76f4\u63a5\u91cd\u5199\u4e86spi\u4f20\u8f93\u6570\u636e\u7684\u903b\u8f91\u89e3\u51b3\u4e86\u8fd9\u4e2a\u95ee\u9898\u3002<br \/>\n&emsp;&emsp;\u6700\u540e\u4ee5xpt2046\u9a71\u52a8\u4e3a\u57fa\u7840\uff0c\u4fee\u6539\u4e862\u4e2a\u6a21\u5757\u7684\u903b\u8f91\uff1a\u4fee\u6539\u4e86spi\u5b50\u7cfb\u7edf\u5904\u7406\u6570\u636e\u7684\u903b\u8f91\u3001\u628a\u5b9a\u65f6\u5668\u4e2d\u65ad\u6539\u4e3a\u5de5\u4f5c\u961f\u5217\u4e2d\u65ad\u5b8c\u6210\u4e86\u89e6\u6478\u9a71\u52a8\u7684\u9002\u914d\u5de5\u4f5c\u3002<\/p>\n<h1>2 \u89e6\u6478\u9a71\u52a8\u51fd\u6570\u4ecb\u7ecd<\/h1>\n<p>&emsp;&emsp;\u9996\u5148\u89e6\u6478\u5c4f\u786c\u4ef6\u90e8\u5206\u5df2\u7ecf\u5728\u786c\u4ef6\u7684\u90a3\u7bc7\u7b14\u8bb0\u4e2d\u8bb2\u89e3\u8fc7\u4e86\uff0c\u5176\u6b21\u4e2d\u65ad\u90e8\u5206\u5728\u4e2d\u65ad\u7684\u7b14\u8bb0\u4e2d\u4e5f\u8bb2\u89e3\u8fc7\u4e86\uff0c\u8fd9\u91cc\u5c31\u4e0d\u5bf9\u8fd9\u4e24\u4e2a\u6a21\u5757\u8fdb\u884c\u91cd\u590d\u5206\u6790\u4e86\u3002\u4e3b\u8981\u5206\u6790\u4e86\u4e00\u4e0b\u6570\u636e\u4f20\u8f93\u4ee5\u53cainput\u5b50\u7cfb\u7edf\u3002<\/p>\n<h2>2.1 \u89e6\u6478\u9a71\u52a8\u7ed3\u6784\u4f53<\/h2>\n<p>&emsp;&emsp;\u56e0\u4e3a\u662f\u5728\u5b98\u65b9\u9a71\u52a8\u7684\u57fa\u7840\u4e0a\u6539\u5199\u7684\uff0c\u53ea\u7528\u5230\u4e86\u4e00\u4e9b\u57fa\u7840\u7684\u53d8\u91cf\uff08\u5269\u4f59\u7684\u53d8\u91cf\u6ca1\u5220\u9664\uff0c\u6284\u7684\u65f6\u5019\u6ce8\u610f\u4e00\u4e0b\uff09\u3002<\/p>\n<pre><code class=\"language-c\">struct xpt2046\n{\n    struct input_dev *input; \/\/ \u8f93\u5165\u8bbe\u5907\u7684\u6838\u5fc3\u7ed3\u6784\u4f53\uff0c\u4fdd\u5b58\u5404\u79cd\u4fe1\u606f\u5c5e\u6027\u7b49\n    char phys[32];\n    char name[32];\n    char pendown_iomux_name[IOMUX_NAME_SIZE];\n    struct spi_device *spi;  \/\/spi\u6307\u9488\n\n    u16 model; \/\/\u6a21\u5f0f\n    u16 x_min, x_max;\n    u16 y_min, y_max;\n\n    struct xpt2046_packet *packet; \/\/ \u907f\u514d\u7f13\u5b58\u884c\u5171\u4eab\u7684\u95ee\u9898\uff0c\u5355\u72ec\u8bbe\u7f6e\u7684\u53d8\u91cf\n\n    spinlock_t lock;\n    struct hrtimer timer;  \/\/\u5b9a\u65f6\u5668\u7684\u53d8\u91cf\n    void (*wait_for_sync)(void);\n};<\/code><\/pre>\n<h2>2.2 input\u5b50\u7cfb\u7edf<\/h2>\n<p>&emsp;&emsp;\u8fd9\u4e2a\u5b50\u7cfb\u7edf\u5176\u5b9e\u548cframmebuffer\u5b50\u7cfb\u7edf\u6709\u4e9b\u7c7b\u4f3c\uff0c\u5c31\u662f\u4f1a\u5728\/dev\/input\/\u6ce8\u518c\u4e00\u4e2aevent0\/1\u7684\u8bbe\u5907\u8282\u70b9\uff1b\u7136\u540e\u5728\u9a71\u52a8\u4e2d\u4f7f\u7528input\u5b50\u7cfb\u7edf\uff0c\u5f53\u89e6\u6478\u5c4f\u88ab\u6309\u4e0b\u65f6event\u8282\u70b9\u8f93\u51fa\u5750\u6807\u4fe1\u606f\uff0c\u5e94\u7528\u5c42\u53ef\u4ee5\u83b7\u53d6\u8f93\u51fa\u7684\u6570\u636e\u8fdb\u800c\u786e\u5b9a\u6309\u4e0b\u7684\u5750\u6807\u503c\u3002<br \/>\n\uff08\u5173\u4e8e\u5e94\u7528\u5c42\u4e0e\u9a71\u52a8\u5c42\u4f20\u9012\u5750\u6807\u503c\u7684\u65b9\u6cd5\u6211\u770b\u6709\u597d\u51e0\u79cd\uff0c\u8fd9\u4e2axpt2046\u7684\u9a71\u52a8\u5c31\u6ca1\u50cfads7846\u9a71\u52a8\u4e00\u6837\u4f7f\u7528input\u5b50\u7cfb\u7edf\uff0c\u800c\u662f\u5229\u7528\u4e86ioctl\u65b9\u6cd5\u5411\u5e94\u7528\u5c42\u4f20\u8f93\u6570\u636e\u3002\u8bf4\u4e0d\u4e0a\u6765\u54ea\u4e2a\u65b9\u6cd5\u66f4\u597d\uff0c\u770b\u5b9e\u9645\u60c5\u51b5\u81ea\u5df1\u4f7f\u7528\u5373\u53ef\u3002\uff09<\/p>\n<pre><code class=\"language-c\">    ts->wait_for_sync = null_wait_for_sync; \/\/ \u7a7a\u51fd\u6570\uff0c\u4f5c\u7528\u4e0d\u660e\n    ts->x_min = 0;                          \/\/ pdata->x_min;   \/\/\u5c4f\u5e55x\u7684\u6700\u5c0f\u503c\n    ts->x_max = SCREEN_MAX_X;               \/\/ pdata->x_max;  \/\/\u5c4f\u5e55x\u7684\u6700\u5927\u503c\n    ts->y_min = 0;                          \/\/ pdata->y_min;   \/\/\u5c4f\u5e55y\u7684\u6700\u5c0f\u503c\n    ts->y_max = SCREEN_MAX_Y;               \/\/ pdata->y_max;   \/\/\u5c4f\u5e55y\u7684\u6700\u5927\u503c<\/code><\/pre>\n<p>&emsp;&emsp;\u914d\u7f6einput\u5b50\u7cfb\u7edf\u7684\u4e8b\u4ef6\uff1b<\/p>\n<pre><code class=\"language-c\">\/\/ \u8bbe\u7f6e\u8f93\u5165\u8bbe\u5907\u652f\u6301\u7684\u4e8b\u4ef6\u7c7b\u578b\u548c\u5177\u4f53\u6309\u952e\u6216\u89e6\u6478\u4e8b\u4ef6\ninput_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); \/\/ \u8bbe\u7f6e\u8f93\u5165\u8bbe\u5907\u652f\u6301\u7684\u4e8b\u4ef6\u7c7b\u578b\uff0c\u6309\u952e\u4e8b\u4ef6\uff0c\u7edd\u5bf9\u5750\u6807\u4e8b\u4ef6\n\/\/ \u8ba1\u7b97 BTN_TOUCH\u7684\u503c\uff0c\u8bbe\u7f6e\u5230keybit\u6570\u7ec4\u4e2d\u7684\u4f4d\u7f6e\uff0c\u4e00\u822c\u4e3a0\ninput_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); \/\/ \u8bbe\u7f6e\u8f93\u5165\u8bbe\u5907\u652f\u6301\u7684\u5177\u4f53\u4e8b\u4ef6\uff0c\u89e6\u6478\u4e8b\u4ef6\uff0c\n\/\/ \u8bbe\u7f6e\u7edd\u5bf9\u5750\u6807\u8f74\uff08X \u8f74\u548c Y \u8f74\uff09\u7684\u53c2\u6570\uff0c\u786e\u5b9a\u5c4f\u5e55\u7684\u5750\u6807\u8303\u56f4\ninput_set_abs_params(input_dev, ABS_X,\n                         ts->x_min ?: 0,\n                         ts->x_max ?: MAX_12BIT, \/\/ MAX_12BIT\u6700\u5927\u503c\u662f4095\n                         0, 0);\n    input_set_abs_params(input_dev, ABS_Y,\n                         ts->y_min ?: 0,\n                         ts->y_max ?: MAX_12BIT,\n                         0, 0);<\/code><\/pre>\n<p>&emsp;&emsp;\u6ce8\u518cevent\u8282\u70b9\uff1b<\/p>\n<pre><code class=\"language-c\">err = input_register_device(input_dev); \/\/ \u6ce8\u518cevent\u8282\u70b9<\/code><\/pre>\n<p>&emsp;&emsp;\u89e6\u53d1\u4e2d\u65ad\u5411\u7ec8\u7aef\u6253\u5370\u4fe1\u606f\u3002<\/p>\n<pre><code class=\"language-c\">    input_report_abs(input_dev, ABS_X, x);\n    input_report_abs(input_dev, ABS_Y, y);\n    input_report_key(input_dev, BTN_TOUCH, 1);\n    input_sync(input_dev);<\/code><\/pre>\n<h2>2.3 spi\u5b50\u7cfb\u7edf<\/h2>\n<p>&emsp;&emsp;spi\u5b50\u7cfb\u7edf\u521d\u59cb\u5316\uff1b<\/p>\n<pre><code class=\"language-c\">    if (spi->max_speed_hz > (125000 * SAMPLE_BITS))\n    {\n        xpt2046printDebug(\"f(sample) %d KHz?\\n\",\n                          (spi->max_speed_hz \/ SAMPLE_BITS) \/ 1000);\n        return -EINVAL;\n    }\n\/\/ \u5c06tx\u548crx\u90fd\u8bbe\u7f6e\u4e3a8\u4f4d\n    spi->bits_per_word = 8;\n    spi->mode = SPI_MODE_0;\n    err = spi_setup(spi);\n    if (err < 0)\n        return err;<\/code><\/pre>\n<p>&emsp;&emsp;spi\u8bfb\u53d6\u6570\u636e\u7684\u51fd\u6570\uff1b<\/p>\n<pre><code class=\"language-c\">uint16_t touch_buf = 0;\nuint16_t value_re;\nvolatile int num;\nstatic int read_spi(uint8_t tcmd)\n{\n    int ret;\n    unsigned char txdata;\n    struct spi_message m;\n    struct spi_transfer *t;\n    struct spi_device *spi = ts_tmp->spi;\n\n    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL); \/* \u7533\u8bf7\u5185\u5b58 *\/\n\n    \/* \u7b2c1\u6b21\uff0c\u53d1\u9001\u8981\u8bfb\u53d6\u7684\u5bc4\u5b58\u5730\u5740 *\/\n    txdata = tcmd;\n    t->tx_buf = &txdata;  \/* \u8981\u53d1\u9001\u7684\u6570\u636e *\/\n    t->len = 1;           \/* 1\u4e2a\u5b57\u8282 *\/\n    spi_message_init(&m); \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m); \/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);     \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    mdelay(1);\n\n    \/* \u7b2c2\u6b21\uff0c\u8bfb\u53d6\u6570\u636e *\/\n    txdata = 0x00;               \/* \u968f\u4fbf\u4e00\u4e2a\u503c\uff0c\u6b64\u5904\u65e0\u610f\u4e49 *\/\n    t->rx_buf = &touch_buf;      \/* \u8bfb\u53d6\u5230\u7684\u6570\u636e *\/\n    t->len = 1;                  \/* \u8981\u8bfb\u53d6\u7684\u6570\u636e\u957f\u5ea6 *\/\n    spi_message_init(&m);        \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m); \/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);     \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    value_re = touch_buf << 8;\n\n    \/* \u7b2c3\u6b21\uff0c\u8bfb\u53d6\u6570\u636e *\/\n    txdata = 0x00;               \/* \u968f\u4fbf\u4e00\u4e2a\u503c\uff0c\u6b64\u5904\u65e0\u610f\u4e49 *\/\n    t->rx_buf = &touch_buf;      \/* \u8bfb\u53d6\u5230\u7684\u6570\u636e *\/\n    t->len = 1;                  \/* \u8981\u8bfb\u53d6\u7684\u6570\u636e\u957f\u5ea6 *\/\n    spi_message_init(&m);        \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m); \/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);     \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    value_re |= touch_buf;\n    value_re >>= 3;\n    value_re -= 4096;\n\n    if (value_re == 4095 || value_re == 0)\n    {\n        value_re = 0;\n    }\n    \/*\n    else\n    {\n        num++;\n        printk(\"333333333x-write = [%d]-[%x]\\n\", tcmd, tcmd);\n        printk(\"333333333x-value = [%d]-[%x]\\n\", value_re, value_re);\n        printk(\"333333333---num = [%d]\\n\", num);\n    }\n    *\/\n    udelay(200);\n    kfree(t); \/* \u91ca\u653e\u5185\u5b58 *\/\n    return value_re;\n}<\/code><\/pre>\n<h2>2.4 \u6d88\u6296\u903b\u8f91<\/h2>\n<p>&emsp;&emsp;\u89e6\u6478\u5c4f\u6700\u91cd\u8981\u7684\u5c31\u662f\u6d88\u6296\u903b\u8f91\u3002\u5750\u6807\u4e0d\u51c6\u4e5f\u5c31\u662f\u591a\u6309\u51e0\u6b21\u7684\u4e8b\uff0c\u8981\u662f\u6d88\u6296\u6ca1\u505a\u597d\uff0c\u5c4f\u5e55\u76f4\u63a5\u5c31\u662f\u4e71\u8df3\u8f6c\uff0c\u5404\u79cdbug\u9891\u51fa\u3002\u5982\u4e0b\u662f\u7f16\u5199\u7684\u6d88\u6296\u903b\u8f91\uff1a<\/p>\n<pre><code class=\"language-c\">       \/\/ Request GPIO  \/\/ \u8bf7\u6c42\u4f7f\u7528 GPIO\n    if (!gpio_is_valid(GPIO_BUTTON)) {\n        printk(KERN_INFO \"Invalid GPIO\\n\");\n        return -ENODEV;\n    }\n\ngpio_request(GPIO_BUTTON, \"tsc2046\"); \/\/ \u8bf7\u6c42\u4f7f\u7528\u6307\u5b9a\u7684GPIO\u5f15\u811a\u3002\u5982\u679c\u8bf7\u6c42\u6210\u529f\uff0c\u8be5\u5f15\u811a\u5c06\u88ab\u4fdd\u7559\uff0c\u4ee5\u9632\u6b62\u5176\u4ed6\u5185\u6838\u4ee3\u7801\u4f7f\u7528\u5b83\u3002\ngpio_direction_input(GPIO_BUTTON); \/\/ \u5c06\u6307\u5b9a\u7684GPIO\u5f15\u811a\u8bbe\u7f6e\u4e3a\u8f93\u5165\u65b9\u5411\u3002\u8fd9\u610f\u5473\u7740\u5b83\u5c06\u8bfb\u53d6\u5916\u90e8\u8bbe\u5907\u7684\u4fe1\u53f7\uff0c\u4f8b\u5982\u6309\u952e\u7684\u72b6\u6001\u3002\ngpio_set_debounce(GPIO_BUTTON, 200); \/\/ \u8bbe\u7f6eGPIO\u5f15\u811a\u7684\u53bb\u6296\u52a8\u65f6\u95f4\u3002\u53bb\u6296\u52a8\u662f\u4e3a\u4e86\u8fc7\u6ee4\u6389\u6309\u952e\u6309\u4e0b\u65f6\u53ef\u80fd\u4ea7\u751f\u7684\u6296\u52a8\u4fe1\u53f7\uff0c200\u8868\u793a\u53bb\u6296\u52a8\u65f6\u95f4\u4e3a200\u6beb\u79d2\u3002\ngpio_export(GPIO_BUTTON, false); \/\/ \u5c06\u6307\u5b9a\u7684GPIO\u5f15\u811a\u5bfc\u51fa\u5230\u7528\u6237\u7a7a\u95f4\uff0c\u4f7f\u5f97\u7528\u6237\u7a7a\u95f4\u7684\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u901a\u8fc7sysfs\u6587\u4ef6\u7cfb\u7edf\u8bbf\u95ee\u548c\u63a7\u5236\u8fd9\u4e2a\u5f15\u811a\u3002\u7b2c\u4e8c\u4e2a\u53c2\u6570false\u8868\u793a\u4e0d\u5141\u8bb8\u901a\u8fc7sysfs\u4fee\u6539\u5f15\u811a\u7684\u65b9\u5411\uff08\u5177\u4f53\u5982\u4f55\u4f7f\u7528sysfs\u6587\u4ef6\u7cfb\u7edf\u63a7\u5236\u5f15\u811a\u67e5\u770b\u6211\u7684\u4e0a\u4e00\u7bc7\u663e\u793a\u9a71\u52a8\u535a\u5ba2\uff09<\/code><\/pre>\n<p>&emsp;&emsp;\u81f3\u6b64\u7f16\u5199\u89e6\u6478\u9a71\u52a8\u9700\u8981\u4f7f\u7528\u7684\u4e3b\u8981\u51fd\u6570\u90fd\u4ecb\u7ecd\u5b8c\u4e86\u3002<\/p>\n<h1>3 \u89e6\u6478\u9a71\u52a8<\/h1>\n<h2>3.1 \u7f16\u5199\u7b80\u5355\u7248\u9a71\u52a8<\/h2>\n<p>&emsp;&emsp;\u5982\u524d\u8a00\u6240\u793a\uff0c\u4e3a\u4e86\u7cbe\u76ca\u6c42\u7cbe\u5728\u4f7f\u7528\u7ebf\u7a0b\u65b9\u5f0f\u521d\u6b65\u5b9e\u73b0\u89e6\u6478\u529f\u80fd\u540e\uff0c\u5c31\u7814\u7a76\u8d77\u4e86\u4e2d\u65ad\u89e6\u53d1\u5b9e\u73b0\u89e6\u6478\u529f\u80fd\uff1b\u6240\u4ee5\u6211\u7f16\u5199\u7684\u89e6\u6478\u9a71\u52a8\u529f\u80fd\u4f7f\u7528\u4e86\u7ebf\u7a0b\u548c\u4e2d\u65ad\u4e24\u79cd\u65b9\u5f0f\u5b9e\u73b0\u3002<\/p>\n<h3>3.1.1 \u7ebf\u7a0b\u6b7b\u5faa\u73af\u8bfb\u53d6\u89e6\u6478\u6570\u636e<\/h3>\n<p>&emsp;&emsp;\u5982\u4e0b\u662f\u6211\u4f7f\u7528\u7ebf\u7a0b\u65b9\u5f0f\u6765\u5b9e\u73b0\u89e6\u6478\u9a71\u52a8\u529f\u80fd\u7684\u4ee3\u7801\uff0c\u6ca1\u5565\u503c\u5f97\u8bf4\u7684\uff0c\u5c31\u662f\u521b\u5efa\u3001\u6dfb\u52a0\u3001\u521d\u59cb\u5316\u3001\u542f\u52a8\u7ebf\u7a0b\u51fd\u6570\u3001\u6700\u540e\u8c03\u7528spi\u5b50\u7cfb\u7edf\u4f20\u8f93\u6570\u636e\u3002<\/p>\n<pre><code class=\"language-c\">static struct task_struct *oled_kthread;\/\/\u5b9a\u4e49\u7ebf\u7a0b\u6307\u9488\n\nstatic int oled_thread(void *data){\/\/\u521b\u5efa\u7ebf\u7a0b\u51fd\u6570\n    while(1){\n        \/\/\u628a\u6570\u636e\u5237\u65b0\u5230OLED\uff1a\n        \/\/if(gpio_get_value(mylcddev.dc_gpio) == 0)\n            read_spi(data, 0x90);\n\n        set_current_state(TASK_INTERRUPTIBLE);\/\/\u5c06\u7ebf\u7a0b\u4e2d\u914d\u7f6e\u4e3a\u53ef\u4e2d\u65ad\u7684\u7761\u7720\u72b6\u6001\u3002\u5728\u8fd9\u79cd\u72b6\u6001\u4e0b\uff0c\u8fdb\u7a0b\u4f1a\u6682\u505c\u6267\u884c\uff0c\u76f4\u5230\u88ab\u5524\u9192\n        schedule_timeout(HZ\/10);\/\/\u8ba9\u5f53\u524d\u7ebf\u7a0b\u8fdb\u5165\u7761\u7720\u72b6\u6001\uff0c\u65f6\u957f\u4e3a100ms\u3002\n        if(kthread_should_stop()){\/\/\u68c0\u67e5\u662f\u5426\u6709\u505c\u6b62\u8bf7\u6c42\u53d1\u9001\u7ed9\u5f53\u524d\u7ebf\u7a0b\u3002 \n            set_current_state(TASK_RUNNING);\/\/\u51c6\u5907\u9000\u51fa\u7ebf\u7a0b\u4e4b\u524d\uff0c\u5c06\u7ebf\u7a0b\u72b6\u6001\u8bbe\u7f6e\u4e3a\u53ef\u8fd0\u884c\u72b6\u6001\u3002\n            break;\/\/\u6536\u5230\u505c\u6b62\u7ebf\u7a0b\u4fe1\u53f7\u540e\uff0c\u4f1a\u8df3\u51fa\u6b7b\u5faa\u73af\n        }\n    }\n    return 0;\n}\n\noled_kthread = kthread_create(oled_thread, NULL, \"my_touch_thread\");\/\/\u521b\u5efa\u7ebf\u7a0b\nwake_up_process(oled_kthread);\/\/\u5524\u8d77\u7ebf\u7a0b<\/code><\/pre>\n<h3>3.1.2 \u4e2d\u65ad\u8bfb\u53d6\u89e6\u6478\u6570\u636e<\/h3>\n<p>&emsp;&emsp;\u5982\u4e0b\u6240\u793a\u662f\u6211\u4f7f\u7528\u4e2d\u65ad\u89e6\u53d1\u6765\u5b9e\u73b0\u89e6\u6478\u529f\u80fd\u7684\u4ee3\u7801\u3002\u521d\u59cb\u5316\u4e2d\u65ad\u3001\u4f7f\u7528\u4e2d\u65ad\u5e95\u534a\u90e8\u8c03\u7528\u51fd\u6570\u7b49\u64cd\u4f5c\u5728\u4e2d\u65ad\u7bc7\u90fd\u5df2\u7ecf\u5199\u8fc7\u4e86\uff0c\u5c24\u51763.5.3\u7ae0\u8282\u662f\u6211\u603b\u7ed3\u7684\u7ecf\u9a8c\uff0c\u4e00\u5b9a\u8981\u6ce8\u610f\u770b\uff0c\u8fd9\u91cc\u6211\u5c31\u4e0d\u591a\u89e3\u91ca\u4e86\u3002<\/p>\n<pre><code class=\"language-c\">struct device_node *node;\nunsigned int irqno;\n#define my_irq_name \"my_irq\"\nint tp_cs_pin;\n\/\/ \u5e95\u534a\u90e8\u5904\u7406\u51fd\u6570\n void irq_work_func(struct work_struct *mwork)\n {\n    printk(\"\u8fdb\u5165\u8f6f\u4e2d\u65ad\uff0c\u5de5\u4f5c\u961f\u5217\\n\");\n    gpio_set_value(tp_cs_pin, 0); \n    disable_irq_nosync(irqno);\/\/\u7981\u6b62\u6307\u5b9a\u7ec8\u7aef\u53f7\u7684\u4e2d\u65ad\n    read_spi(data, 0xd0);\/\/\u8c03\u7528spi\u5904\u7406\u6570\u636e\u7684\u51fd\u6570\n    enable_irq(irqno);\/\/\u542f\u52a8\u6307\u5b9a\u7ec8\u7aef\u53f7\u7684\u4e2d\u65ad\n    disable_irq_nosync(irqno);\n    read_spi(data, 0x90);\n    enable_irq(irqno);\n    gpio_set_value(tp_cs_pin, 1);\n }\n \/\/ \u4e2d\u65ad\u9876\u534a\u90e8\n irqreturn_t key_irq_handle(int irq, void *dev)\n {\n     printk(\"\u8fdb\u5165\u4e2d\u65ad\u4e0a\u534a\u90e8\\n\");\n     if (schedule_work(&data->work))\n     {\n         printk(\"\u8c03\u7528\u4e2d\u65ad\u4e0b\u534a\u90e8\u5b8c\u6210\\n\");\n     }else{\n         printk(\"\u8c03\u7528\u4e2d\u65ad\u4e0b\u534a\u90e8\u5931\u8d25\\n\");\n     }\n     return IRQ_HANDLED;\n}\n\/\/\u521d\u59cb\u5316\u4e2d\u65ad\u5e95\u534a\u90e8\n INIT_WORK(&data->work, irq_work_func);\n\/\/\u89e6\u6478\u7247\u9009\u5f15\u811a\u521d\u59cb\u5316\n    tp_cs_pin = of_get_named_gpio(node, \"tpcs\", 0);\n    if (tp_cs_pin < 0)\n    {\n        ret = tp_cs_pin;\n        return tp_cs_pin;\n    }\n\/\/\u521d\u59cb\u5316cs\u5f15\u811a\u4e3a\u9ad8\u7535\u5e73\u72b6\u6001\n    if ((ret = gpio_request(tp_cs_pin, NULL)) != 0)\n    {\n        return ret;\n    }\n\/\/ \u8bbe\u7f6e\u5f15\u811a\u4e3a\u8f93\u51fa\u6a21\u5f0f\u5e76\u521d\u59cb\u5316\u4e3a\u9ad8\u7535\u5e73\n    ret = gpio_direction_output(tp_cs_pin, 1);\n    if (ret)\n    {\n        return ret;\n    }\nprintk(\"\u83b7\u53d6cs\u5f15\u811a\u6210\u529f\\n\");\n\/\/\u6620\u5c04\u5f97\u5230\u8f6f\u4e2d\u65ad\u53f7\n     irqno = irq_of_parse_and_map(node, 0);\n     if (irqno == 0)\n     {\n         printk(\"get irqno error\\n\");\n         return -EAGAIN;\n     }\nprintk(\"\u83b7\u53d6\u4e2d\u65ad\u53f7\u6210\u529f\\n\");\n\/\/\u6ce8\u518c\u4e2d\u65ad\n     ret = devm_request_irq(&#038;spi->dev, irqno, key_irq_handle,\n                            IRQF_TRIGGER_FALLING, my_irq_name, (void *)data);\n     if (ret)\n     {\n         printk(\"request irq error\\n\");\n         return ret;\n     }\n printk(\"\u6ce8\u518c\u4e2d\u65ad\u6210\u529f\\n\");<\/code><\/pre>\n<h3>3.1.3 \u7f16\u5199\u81ea\u5df1\u7684\u9a71\u52a8<\/h3>\n<p>&emsp;&emsp;\u5982\u4e0b\u662f\u6211\u81ea\u5df1\u7f16\u5199\u7684\u89e6\u6478\u9a71\u52a8\u4ee3\u7801\u3002\u56e0\u4e3a\u662f\u5728\u6d4b\u8bd5\u9636\u6bb5\uff0c\u53ea\u9700\u8981\u5728\u5185\u6838\u6253\u5370\u6570\u636e\u5c31\u884c\uff1b\u6240\u4ee5\u6ca1\u5b9e\u73b0\u64cd\u4f5c\u65b9\u6cd5\u7ed3\u6784\u4f53\u6216\u8005input\u5b50\u7cfb\u7edf\u8fd9\u90e8\u5206\u548c\u5e94\u7528\u5c42\u4ea4\u4e92\u7684\u529f\u80fd\u3002<\/p>\n<pre><code class=\"language-c\">#include < linux\/init.h >\n#include < linux\/interrupt.h >\n#include < linux\/module.h >\n#include < linux\/of.h >\n#include < linux\/of_irq.h >\n#include < linux\/of_gpio.h >\n#include < linux\/delay.h >\n#include < linux\/spi\/spi.h >\n#include < linux\/platform_device.h >\n\nstruct device_node *node;\nunsigned int irqno;\n#define my_irq_name \"my_irq\"\n\nint tp_cs_pin;\n\nstruct my_touch_data\n{\n    struct spi_device *spi;\n    struct work_struct work;\n    void *private_data;         \/* \u79c1\u6709\u6570\u636e *\/\n};\n\nuint16_t touch_buf = 0;\n\/\/u8            *tx_buf, *rx_buf;\nuint16_t value_re;\nstruct my_touch_data *data;\n\nstatic struct task_struct *oled_kthread;\nvoid read_spi(struct my_touch_data *data,  uint8_t tcmd)\n{\n    \/**************************************************************\/\n    int ret;\n    unsigned char txdata;\n    struct spi_message m;\n    struct spi_transfer *t;\n    struct spi_device *spi = (struct spi_device *)data->private_data;\n\n    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);   \/* \u7533\u8bf7\u5185\u5b58 *\/\n\n    \/* \u7b2c1\u6b21\uff0c\u53d1\u9001\u8981\u8bfb\u53d6\u7684\u5bc4\u5b58\u5730\u5740 *\/\n    txdata = tcmd;\n    t->speed_hz = 5000000;\n    t->tx_buf = &txdata;            \/* \u8981\u53d1\u9001\u7684\u6570\u636e *\/\n    t->rx_buf = &touch_buf;         \/* \u8bfb\u53d6\u5230\u7684\u6570\u636e *\/\n    t->len = 1;                 \/* 1\u4e2a\u5b57\u8282 *\/\n    spi_message_init(&m);       \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m);\/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);    \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    mdelay(1);\n\n    \/\/ printk(\"11111x-1 = [%d]-[%x]\\n\", value_re,value_re);\n     printk(\"1111111x-2 = [%d]-[%x]\\n\", touch_buf,touch_buf);\n\n    \/* \u7b2c2\u6b21\uff0c\u8bfb\u53d6\u6570\u636e *\/\n    txdata = 0x00;          \/* \u968f\u4fbf\u4e00\u4e2a\u503c\uff0c\u6b64\u5904\u65e0\u610f\u4e49 *\/\n    t->tx_buf = &txdata;\n    t->rx_buf = &touch_buf;         \/* \u8bfb\u53d6\u5230\u7684\u6570\u636e *\/\n    t->len = 1;             \/* \u8981\u8bfb\u53d6\u7684\u6570\u636e\u957f\u5ea6 *\/\n    spi_message_init(&m);       \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m);\/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);    \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    value_re = touch_buf<<8;\n    \/\/ printk(\"22222222x-1 = [%d]-[%x]\\n\", value_re,value_re);\n     printk(\"2222222222x-2 = [%d]-[%x]\\n\", touch_buf,touch_buf);\n\n    \/* \u7b2c3\u6b21\uff0c\u8bfb\u53d6\u6570\u636e *\/\n    txdata = 0x00;          \/* \u968f\u4fbf\u4e00\u4e2a\u503c\uff0c\u6b64\u5904\u65e0\u610f\u4e49 *\/\n    t->tx_buf = &txdata;\n    t->rx_buf = &touch_buf;         \/* \u8bfb\u53d6\u5230\u7684\u6570\u636e *\/\n    t->len = 1;             \/* \u8981\u8bfb\u53d6\u7684\u6570\u636e\u957f\u5ea6 *\/\n    spi_message_init(&m);       \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m);\/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);    \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    value_re |= touch_buf;\n    value_re >>= 3;\n    if(value_re != 255 && value_re != 248 && value_re != 128){\n        printk(\"333333333x-write = [%d]-[%x]\\n\", tcmd,tcmd);\n        printk(\"333333333x-value = [%d]-[%x]\\n\", value_re,value_re);\n        printk(\"333333333x-read = [%d]-[%x]\\n\", touch_buf,touch_buf);\n      }\n\n    udelay(200);\n    kfree(t);                                   \/* \u91ca\u653e\u5185\u5b58 *\/\n}\n\n\/\/ \/\/ \u5e95\u534a\u90e8\u5904\u7406\u51fd\u6570\n\/\/ void irq_work_func(struct work_struct *mwork)\n\/\/ {\n\/\/     printk(\"\u8fdb\u5165\u8f6f\u4e2d\u65ad\uff0c\u5de5\u4f5c\u961f\u5217\\n\");\n\/\/     gpio_set_value(tp_cs_pin, 0); \n\/\/    disable_irq_nosync(irqno);\n\/\/    read_spi(data, 0xd0);\n\/\/    enable_irq(irqno);\n\/\/    disable_irq_nosync(irqno);\n\/\/    read_spi(data, 0x90);\n\/\/    enable_irq(irqno);\n\/\/     gpio_set_value(tp_cs_pin, 1); \n\/\/ } \n\/\/ \/\/ \u4e2d\u65ad\u9876\u534a\u90e8\n\/\/ irqreturn_t key_irq_handle(int irq, void *dev)\n\/\/ {\n\n\/\/     printk(\"\u8fdb\u5165\u4e2d\u65ad\u4e0a\u534a\u90e8\\n\");\n\/\/     if (schedule_work(&data->work))\n\/\/     {\n\/\/         printk(\"\u8c03\u7528\u4e2d\u65ad\u4e0b\u534a\u90e8\u5b8c\u6210\\n\");\n\/\/     }else{\n\/\/         printk(\"\u8c03\u7528\u4e2d\u65ad\u4e0b\u534a\u90e8\u5931\u8d25\\n\");\n\/\/     }\n\/\/     return IRQ_HANDLED;\n\/\/ }\n\nstatic int oled_thread(void *data){\n    while(1){\n        \/\/\u628a\u6570\u636e\u5237\u65b0\u5230OLED\uff1a\n        \/\/if(gpio_get_value(mylcddev.dc_gpio) == 0)\n            read_spi(data, 0x90);\n\n        set_current_state(TASK_INTERRUPTIBLE);\n        schedule_timeout(HZ\/10);\n        if(kthread_should_stop()){\n            set_current_state(TASK_RUNNING);\n            break;\n        }\n    }\n    return 0;\n}\n\nint my_touch_probe(struct spi_device *spi)\n{\n    int ret;\n    data = devm_kzalloc(&spi->dev, sizeof(struct my_touch_data), GFP_KERNEL);\n    \/\/ \u4f7f\u7528 devm_kzalloc \u5206\u914d\u7684\u5185\u5b58\u7a7a\u95f4\u662f\u7531\u8bbe\u5907\u7ba1\u7406\u5668\uff08device manager\uff09\u81ea\u52a8\u7ba1\u7406\u7684\u3002\n    \/\/ \u5f53\u8bbe\u5907\u88ab\u5378\u8f7d\u65f6\uff0c\u5206\u914d\u7684\u5185\u5b58\u4f1a\u81ea\u52a8\u91ca\u653e\uff0c\u4e0d\u9700\u8981\u624b\u52a8\u91ca\u653e\u3002\n    \/\/ \u8fd9\u662f devm_ \u7cfb\u5217\u51fd\u6570\u7684\u4e00\u4e2a\u91cd\u8981\u7279\u6027\uff0c\u4f7f\u9a71\u52a8\u5f00\u53d1\u66f4\u7b80\u6d01\uff0c\u51cf\u5c11\u4e86\u5185\u5b58\u6cc4\u6f0f\u7684\u98ce\u9669\u3002\n    if (!data)\n        return -ENOMEM;\n    \/*******************************************************************\/\n    \/\/ 0.tasklet_setup\u521d\u59cb\u5316\n    spi->mode = SPI_MODE_0; \/*MODE0\uff0cCPOL=0\uff0cCPHA=0*\/\n    spi->max_speed_hz = 5000000;\n    spi_setup(spi);\n    data->private_data = spi; \/* \u8bbe\u7f6e\u79c1\u6709\u6570\u636e *\/\n\n    \/\/ tx_buf = kmalloc(sizeof(char), GFP_KERNEL);\n    \/\/ rx_buf = kmalloc(sizeof(char), GFP_KERNEL);\n\n   \/\/ INIT_WORK(&data->work, irq_work_func);\n    \/*******************\u6ce8\u518c\u4e2d\u65ad********************************\/\n    \/\/ 1.\u83b7\u53d6\u8bbe\u5907\u6811\u4e2d\u7684\u8282\u70b9\n    node = of_find_compatible_node(NULL, NULL, \"ilitek,ili9488\");\n    if (node == NULL)\n    {\n        printk(\"get node error\\n\");\n        return -EINVAL;\n    }\n    printk(\"\u5339\u914d\u8bbe\u5907\u6811\u6210\u529f\\n\");\n    \/******************************************************************\/\n    tp_cs_pin = of_get_named_gpio(node, \"tpcs\", 0);\n    if (tp_cs_pin < 0)\n    {\n        ret = tp_cs_pin;\n        return tp_cs_pin;\n    }\n\n    \/\/ 2.\u521d\u59cb\u5316cs\u5f15\u811a\u4e3a\u9ad8\u7535\u5e73\u72b6\u6001\n    if ((ret = gpio_request(tp_cs_pin, NULL)) != 0)\n    {\n        return ret;\n    }\n\n    \/\/ \u8bbe\u7f6e\u5f15\u811a\u4e3a\u8f93\u51fa\u6a21\u5f0f\u5e76\u521d\u59cb\u5316\u4e3a\u9ad8\u7535\u5e73\n    ret = gpio_direction_output(tp_cs_pin, 1);\n    if (ret)\n    {\n        return ret;\n    }\n    printk(\"\u83b7\u53d6cs\u5f15\u811a\u6210\u529f\\n\");\n    \/***********************************************************\/\n    \/\/ \/\/ 2.\u6620\u5c04\u5f97\u5230\u8f6f\u4e2d\u65ad\u53f7\n    \/\/ irqno = irq_of_parse_and_map(node, 0);\n    \/\/ if (irqno == 0)\n    \/\/ {\n    \/\/     printk(\"get irqno error\\n\");\n    \/\/     return -EAGAIN;\n    \/\/ }\n    \/\/ printk(\"\u83b7\u53d6\u4e2d\u65ad\u53f7\u6210\u529f\\n\");\n    \/\/ \/\/ 3.\u6ce8\u518c\u4e2d\u65ad\n    \/\/ ret = devm_request_irq(&#038;spi->dev, irqno, key_irq_handle,\n    \/\/                        IRQF_TRIGGER_FALLING, my_irq_name, (void *)data);\n    \/\/ if (ret)\n    \/\/ {\n    \/\/     printk(\"request irq error\\n\");\n    \/\/     return ret;\n    \/\/ }\n\n    \/\/ printk(\"\u6ce8\u518c\u4e2d\u65ad\u6210\u529f\\n\");\n    \/******************\u4e2d\u65ad\u6ce8\u518c\u5b8c\u6210*******************************\/\n    oled_kthread = kthread_create(oled_thread, NULL, \"my_touch_thread\");\n    \/\/\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u7ebf\u7a0b\u51fd\u6570\uff0c\u5b57\u7b26\u4e32\u662f\u8c03\u8bd5\u65f6\u5728\u5404\u79cd\u65e5\u5fd7\u4e2d\u7684\u7ebf\u7a0b\u540d\u5b57\uff0c\n    wake_up_process(oled_kthread);\n    return 0;\n}\nint my_touch_remove(struct spi_device *spi)\n{\n    cancel_work_sync(&data->work);\n    free_irq(irqno, 0);\n    return 0;\n}\nconst struct of_device_id of_match[] = {\n    {\n        .compatible = \"ilitek,ili9488\",\n    },\n    {},\n};\nMODULE_DEVICE_TABLE(of, of_match);\n\nstruct spi_driver my_touch = {\n    .probe = my_touch_probe,\n    .remove = my_touch_remove,\n    .driver = {\n        .name = \"my_touch\",\n        .of_match_table = of_match,\n    },\n};\nmodule_spi_driver(my_touch);\nMODULE_LICENSE(\"GPL\");<\/code><\/pre>\n<h2>3.2 \u6539\u5199\u5b98\u65b9\u9a71\u52a8<\/h2>\n<p>&emsp;&emsp;\u5bf9\u6bd4\u5185\u6838\u5b98\u65b9\u9a71\u52a8\u4ee3\u7801\u53ef\u4ee5\u770b\u51fa\u6211\u5199\u7684\u9a71\u52a8\u592a\u8fc7\u7b80\u5355\u4e86\uff0c\u5065\u58ee\u6027\u80af\u5b9a\u6bd4\u4e0d\u4e0a\u7cfb\u7edf\u91cc\u5b98\u65b9\u9a71\u52a8\uff0c\u6240\u4ee5\u8fd8\u662f\u8981\u4ee5\u5b98\u65b9\u9a71\u52a8\u4e3a\u57fa\u7840\u4fee\u6539\u9002\u914d\u81ea\u5df1\u7684\u5f00\u53d1\u677f\u3002\u4f46\u5b98\u65b9\u7684ads7846\u9a71\u52a8\u592a\u8fc7\u590d\u6742\uff0c\u6211\u624b\u5934\u6709\u4e2a\u4e13\u95e8\u7684xpt2046\u7684\u9a71\u52a8\u4ee3\u7801\u66f4\u9002\u5408\u6539\u52a8\uff0c\u56e0\u6b64\u5c31\u4ee5xpt2046\u4e3a\u57fa\u7840\uff0c\u4fee\u6539\u7f16\u5199\u4e86\u6211\u7684\u9a71\u52a8\u4ee3\u7801\u3002\u4fee\u6539\u7684\u4e3b\u8981\u90e8\u5206\u662f\u628a\u539f\u6765\u7684\u5b9a\u65f6\u5668\u4e2d\u65ad\u65b9\u5f0f\u6539\u4e3a\u5de5\u4f5c\u961f\u5217\uff0c\u7136\u540e\u628a\u5b98\u65b9spi\u5b50\u7cfb\u7edf\u4f20\u8f93\u5904\u7406\u6570\u636e\u90e8\u5206\u4ee3\u7801\u903b\u8f91\u8fdb\u884c\u4e86\u4fee\u6539\u3002<\/p>\n<h3>3.2.1 \u5b9a\u65f6\u5668\u89e6\u53d1\u6539\u4e3a\u5de5\u4f5c\u961f\u5217<\/h3>\n<p>&emsp;&emsp;\u66ff\u6362\u4e2d\u65ad\u65b9\u5f0f\u662f\u56e0\u4e3a\u524d\u671f\u6392\u67e5\u65f6\u6211\u6000\u7591\u5b9a\u65f6\u5668\u4e2d\u65ad\u6709\u95ee\u9898\uff0c\u5c31\u628a\u5b9a\u65f6\u5668\u4e2d\u65ad\u6a21\u5757\u6574\u4f53\u66ff\u6362\u6210\u5de5\u4f5c\u961f\u5217\u4e2d\u65ad\u6a21\u5757\u3002\u95ee\u9898\u89e3\u51b3\u540e\u518d\u6539\u52a8\u56de\u53bb\u592a\u7e41\u7410\u4e86\uff0c\u5c31\u6ca1\u6539\u52a8\u56de\u53bb\uff0c\u5012\u662f\u6ca1\u6709\u522b\u7684\u4ec0\u4e48\u539f\u56e0\u3002<\/p>\n<pre><code class=\"language-c\">struct work_struct work; \/\/ \u5de5\u4f5c\u961f\u5217\nstruct xpt2046 *ts_tmp;  \/\/ \u4e2d\u8f6c\u53d8\u91cf\n\n\/*--------------------------------------------------------------------------*\/\n\/\/ \u83b7\u53d6\u4e2d\u65ad\u5f15\u811a\u72b6\u6001\nstatic int get_pendown_state(struct xpt2046 *ts)\n{\n    if (ts->get_pendown_state)          \/\/ \u68c0\u6d4b\u53c2\u6570\u662f\u5426\u521d\u59cb\u5316\n        return ts->get_pendown_state(); \/\/ \u5982\u679c\u521d\u59cb\u5316\uff0c\u5219\u8c03\u7528\u51fd\u6570\u6307\u9488\u6307\u5411\u5bf9\u5e94\u7684\u51fd\u6570\n\n    return !gpio_get_value(ts->gpio_pendown); \/\/ \u672a\u521d\u59cb\u5316\uff0c\u8fd4\u56de\u4e2d\u65ad\u5f15\u811a\u7684\u72b6\u6001\uff0c\u53d6\u53cd\u5219\u662f\u4e2d\u65ad\u5f15\u811a\u4f4e\u7535\u5e73\u6709\u6548\uff0c\n}\n\/\/ \u5de5\u4f5c\u961f\u5217\u4e0b\u534a\u90e8\nvoid irq_work_func(struct work_struct *mwork)\n{\n    struct xpt2046 *ts = ts_tmp;\n    int status = 0;\n    int point_x = 0, point_y = 0;\n\n    spin_lock(&ts->lock);\n    printk(\"\u8fdb\u5165\u5de5\u4f5c\u961f\u5217\u4e2d\u65ad\\n\");\n    struct input_dev *input = ts->input;\n\n    xpt2046printDebug(\"%s:delay 15 ms!!!\\n\", __FUNCTION__);\n    mdelay(15);\n\n    \/* pen is still down, continue with the measurement *\/\n    xpt2046printInfo(\"%s:pen is still down, continue with the measurement\\n\", __FUNCTION__);\n\n    disable_irq_nosync(ts->spi->irq);\n    point_x = read_spi(0xd0);\n    enable_irq(ts->spi->irq);\n\n    disable_irq_nosync(ts->spi->irq);\n    point_y = read_spi(0x90);\n    enable_irq(ts->spi->irq);\n    if (point_y == 4095 || point_y == 0 || point_x == 4095 || point_x == 0)\n    {\n        point_y = 0;\n        point_x = 0;\n    }\n    else\n    {\n        report_touch_event(input, point_x, point_y);\n    }\n\n    spin_unlock(&ts->lock);\n}\n\/\/\u89e6\u53d1\u4e2d\u65ad\nstatic irqreturn_t xpt2046_irq(int irq, void *handle)\n{\n    struct xpt2046 *ts = handle;\n    unsigned long flags;\n    printk(\"\u8fdb\u5165\u786c\u4e2d\u65ad\\n\");\n    \/\/ xpt2046printInfo(\"%s.....%s.....%d\\n\", __FILE__, __FUNCTION__, __LINE__);\n\n    spin_lock_irqsave(&ts->lock, flags);\n    if (likely(get_pendown_state(ts))) \/\/ \u83b7\u53d6\u4e2d\u65ad\u5f15\u811a\u7684\u72b6\u6001\uff0c\u4f4e\u7535\u5e73\u89e6\u53d1\uff0c\u5728\u51fd\u6570\u4e2d\u5df2\u53d6\u53cd\uff0c\u5728likely\u4e2d\u52a0\u901f\u5224\u65ad\n    {\n        if (!ts->irq_disabled)\n        {\n            \/* The ARM do_simple_IRQ() dispatcher doesn't act\n             * like the other dispatchers:  it will report IRQs\n             * even after they've been disabled.  We work around\n             * that here.  (The \"generic irq\" framework may help...)\n             *\/\n            disable_irq_nosync(ts->spi->irq);\n            schedule_work(&work);\n            enable_irq(ts->spi->irq);\n        }\n    }\n    spin_unlock_irqrestore(&ts->lock, flags);\n    return IRQ_HANDLED;\n}\n\n\/*--------------------------------------------------------------------------*\/\n\/\/ \u521d\u59cb\u5316\u4e2d\u65ad\u5f15\u811a\nstatic int setup_pendown(struct spi_device *spi, struct xpt2046 *ts)\n{\n    \/\/ struct xpt2046_platform_data *pdata = spi->dev.platform_data;\n    int err;\n\n    \/* REVISIT when the irq can be triggered active-low, or if for some\n     * reason the touchscreen isn't hooked up, we don't need to access\n     * the pendown state.\n     *\/\n    if (!gpio_is_valid(ts->gpio_pendown \/*pdata->gpio_pendown*\/)) \/\/ \u68c0\u6d4b\u4e2d\u65ad\u5f15\u811a\u662f\u5426\u6709\u6548\n    {\n        dev_err(&spi->dev, \"no get_pendown_state nor gpio_pendown?\\n\");\n        return -EINVAL;\n    }\n\n    \/\/ printk(KERN_ERR \"===============%s:%d==============\\n\", __func__, __LINE__);\n\n    err = gpio_request(ts->gpio_pendown, \"xpt2046_pendown\"); \/\/ \u7533\u8bf7\u4e2d\u65ad\u5f15\u811a\n    if (err)\n    {\n        dev_err(&spi->dev, \"failed to request pendown GPIO%d\\n\",\n                ts->gpio_pendown);\n        return err;\n    }\n\n    err = gpio_direction_input(ts->gpio_pendown); \/\/ \u5c06\u4e2d\u65ad\u5f15\u811a\u8bbe\u7f6e\u4e3a\u8f93\u5165\n    if (err)\n    {\n        dev_err(&spi->dev, \"failed to set input pendown GPIO%d\\n\",\n                ts->gpio_pendown);\n        return err;\n    }\n\n    return 0;\n}\n\/\/ \u521d\u59cb\u5316\u5de5\u4f5c\u961f\u5217\nINIT_WORK(&work, irq_work_func); \n\n    if (devm_request_irq(&spi->dev, spi->irq, xpt2046_irq,\n                         IRQF_TRIGGER_FALLING, spi->dev.driver->name, ts))\n    {\n        xpt2046printDebug(\"%s:trying pin change workaround on irq %d\\n\", __FUNCTION__, spi->irq);\n        err = devm_request_irq(&spi->dev, spi->irq, xpt2046_irq,\n                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, spi->dev.driver->name, ts);\n        if (err)\n        {\n            dev_dbg(&spi->dev, \"irq %d busy?\\n\", spi->irq);\n            goto err_free_gpio;\n        }\n    }<\/code><\/pre>\n<h3>3.2.2 spi\u5b50\u7cfb\u7edf\u4f20\u8f93\u6570\u636e\u903b\u8f91<\/h3>\n<p>&emsp;&emsp;\u524d\u9762\u8bf4\u4e86\u6211\u81ea\u5df1\u5199\u7684\u4e2d\u65ad\u9a71\u52a8\u83b7\u53d6\u6570\u636e\u5931\u8d25\u539f\u56e0\u662f\u6ca1\u52a0\u4e2d\u65ad\u9501\uff1b\u800c\u540e\u5728\u9002\u914d\u5b98\u65b9\u9a71\u52a8\u65f6\uff0c\u6dfb\u52a0\u4e2d\u65ad\u9501\u8fd8\u662f\u4f1a\u5b58\u5728\u4e2d\u65ad\u65e0\u6cd5\u89e6\u53d1\u7684\u95ee\u9898\u3002\u901a\u8bfb\u6574\u4e2a\u4ee3\u7801\uff0c\u4e0d\u65ad\u7684\u5220\u51cf\u975e\u6838\u5fc3\u4ee3\u7801\uff0c\u6700\u540e\u5b9a\u4f4d\u6570\u636e\u4f20\u8f93\u5931\u8d25\u7684\u539f\u56e0\u662fspi\u5b50\u7cfb\u7edf\u4e0e\u4e2d\u65ad\u51b2\u7a81\u95ee\u9898\u3002<br \/>\n&emsp;&emsp;\u5b98\u65b9\u7684\u90a3\u4fe9\u9a71\u52a8spi\u4f20\u8f93\u6570\u636e\u7684\u65b9\u5f0f\u5c31\u662f\u4f1a\u548c\u4e2d\u65ad\u6709\u51b2\u7a81\u3002\u6211\u5728\u4e2d\u65ad\u7bc7\u5199\u4e86\u6211\u4e3a\u4e86\u5254\u9664\u4e2d\u65ad\u5b50\u7cfb\u7edf\u7684\u95ee\u9898\uff0c\u66ff\u6362\u4e86\u597d\u51e0\u79cd\u4e2d\u65ad\u5b9e\u73b0\u65b9\u5f0f\uff0c\u6700\u540e\u786e\u5b9a\u95ee\u9898\u4e0d\u5728\u4e2d\u65ad\u7cfb\u7edf\u3002<br \/>\n&emsp;&emsp;\u53c8\u5206\u6790\u4fe9\u5b98\u65b9\u9a71\u52a8\u7684spi\u5b50\u7cfb\u7edf\u4ee3\u7801\u4e5f\u6ca1\u95ee\u9898\uff08\u5176\u5b9e\u4e0d\u7528\u60f3\u80af\u5b9a\u6ca1\u95ee\u9898\uff0c\u90fd\u88ab\u7528\u8fc7\u591a\u5c11\u5e74\u4e86\uff0c\u6709\u95ee\u9898\u65e9\u6539\u4e86\uff09\u3002\u5bf9\u6bd4\u53d1\u73b0\uff0c\u5b98\u65b9\u5728\u8fd9\u90e8\u5206\u5904\u7406\u4ee3\u7801\u7684\u903b\u8f91\u662f\u5c06\u8981\u5904\u7406\u7684\u6570\u636e\u7ec4\u6210\u4e00\u4e2a\u7ed3\u6784\u4f53\uff0c\u4e00\u6b21\u4f20\u8f93\u63a5\u6536\u591a\u4e2a\u5b57\u8282\u7684\u6570\u636e\uff1b\u800c\u6211\u7684\u9a71\u52a8\u5904\u7406\u662f\u9010\u6b21\u53d1\u9001\u548c\u63a5\u6536\uff0c\u6700\u540e\u518d\u6570\u636e\u5904\u7406\u7ec4\u6210\u4e00\u4e2a\u6709\u6548\u6570\u636e\u3002\u5c31\u662f\u8fd9\u4e2a\u5dee\u5f02\u5bfc\u81f4\u5b98\u65b9\u9a71\u52a8\u59cb\u7ec8\u65e0\u6cd5\u83b7\u53d6\u6709\u6548\u6570\u636e\uff0c\u4fee\u6539\u540e\u5b8c\u7f8e\u89e3\u51b3\u3002\uff08\u5355\u5355\u662f\u6570\u636e\u4f20\u8f93\u683c\u5f0f\u4e0d\u540c\u5c31\u5bfc\u81f4\u6570\u636e\u63a5\u6536\u5931\u8d25\uff1f\u6211\u89c9\u5f97\u8fd9\u4e0d\u53ef\u80fd\u662f\u4ee3\u7801\u7684\u95ee\u9898\uff0c\u6240\u4ee5\u6700\u540e\u6211\u6000\u7591\u53ef\u80fd\u662f\u745e\u82af\u5fae\u7684\u8fd9\u4e2a\u82af\u7247\u7684\u95ee\u9898\u3002)<br \/>\n\u5982\u4e0b\u662f\u6211\u81ea\u5df1\u5b9e\u73b0\u7684spi\u4f20\u8f93\u51fd\u6570\uff1a<\/p>\n<pre><code class=\"language-c\">static int read_spi(uint8_t tcmd)\n{\n    \/**************************************************************\/\n    int ret;\n    unsigned char txdata;\n    struct spi_message m;\n    struct spi_transfer *t;\n    struct spi_device *spi = ts_tmp->spi;\n\n    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL); \/* \u7533\u8bf7\u5185\u5b58 *\/\n\n    \/* \u7b2c1\u6b21\uff0c\u53d1\u9001\u8981\u8bfb\u53d6\u7684\u5bc4\u5b58\u5730\u5740 *\/\n    txdata = tcmd;\n    \/\/ t->speed_hz = 5000000;\n    t->tx_buf = &txdata;  \/* \u8981\u53d1\u9001\u7684\u6570\u636e *\/\n    t->len = 1;           \/* 1\u4e2a\u5b57\u8282 *\/\n    spi_message_init(&m); \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m); \/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);     \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    mdelay(1);\n\n    \/* \u7b2c2\u6b21\uff0c\u8bfb\u53d6\u6570\u636e *\/\n    txdata = 0x00;               \/* \u968f\u4fbf\u4e00\u4e2a\u503c\uff0c\u6b64\u5904\u65e0\u610f\u4e49 *\/\n    t->rx_buf = &touch_buf;      \/* \u8bfb\u53d6\u5230\u7684\u6570\u636e *\/\n    t->len = 1;                  \/* \u8981\u8bfb\u53d6\u7684\u6570\u636e\u957f\u5ea6 *\/\n    spi_message_init(&m);        \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m); \/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);     \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    value_re = touch_buf << 8;\n\n    \/* \u7b2c3\u6b21\uff0c\u8bfb\u53d6\u6570\u636e *\/\n    txdata = 0x00;               \/* \u968f\u4fbf\u4e00\u4e2a\u503c\uff0c\u6b64\u5904\u65e0\u610f\u4e49 *\/\n    t->rx_buf = &touch_buf;      \/* \u8bfb\u53d6\u5230\u7684\u6570\u636e *\/\n    t->len = 1;                  \/* \u8981\u8bfb\u53d6\u7684\u6570\u636e\u957f\u5ea6 *\/\n    spi_message_init(&m);        \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m); \/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);     \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    value_re |= touch_buf;\n    value_re >>= 3;\n    value_re -= 4096;\n\n    if (value_re == 4095 || value_re == 0)\n    {\n        value_re = 0;\n    }\n    else\n    {\n        num++;\n        printk(\"333333333x-write = [%d]-[%x]\\n\", tcmd, tcmd);\n        printk(\"333333333x-value = [%d]-[%x]\\n\", value_re, value_re);\n        printk(\"333333333---num = [%d]\\n\", num);\n    }\n    \/\/ printk(\"333333333x-read = [%d]-[%x]\\n\", touch_buf,touch_buf);\n    udelay(200);\n    kfree(t); \/* \u91ca\u653e\u5185\u5b58 *\/\n    return value_re;\n}<\/code><\/pre>\n<h2>3.3 \u89e6\u6478\u9a71\u52a8\u4ee3\u7801<\/h2>\n<p>&emsp;&emsp;\u4fee\u6539\u5b8c\u6210\u540e\u7684\u9a71\u52a8\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n<pre><code class=\"language-c\">\/*\n * drivers\/input\/touchscreen\/xpt2046_ts.c - driver for rk29 spi xpt2046 device and console\n *\n * Copyright (C) 2011 ROCKCHIP, Inc.\n *\n * This software is licensed under the terms of the GNU General Public\n * License version 2, as published by the Free Software Foundation, and\n * may be copied, distributed, and modified under those terms.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\/\n#include < linux\/module.h >\n#include < linux\/delay.h >\n#include < linux\/hrtimer.h >\n#include < linux\/input.h >\n#include < linux\/interrupt.h >\n#include < linux\/io.h >\n#include < linux\/platform_device.h >\n#include < linux\/async.h >\n#include < linux\/irq.h >\n#include < linux\/workqueue.h >\n#include < linux\/proc_fs.h >\n#include < linux\/input\/mt.h >\n#include < linux\/gpio.h >\n#include < linux\/of_gpio.h >\n#include < linux\/spi\/spi.h >\n#include < asm\/uaccess.h >\n\n#include < linux\/kernel.h >\n#include < linux\/module.h >\n#include < linux\/cdev.h >\n#include < linux\/fs.h >\n#include < linux\/errno.h >\n#include < linux\/uaccess.h >\n#include < linux\/device.h >\n#include < linux\/ioport.h >\n#include < linux\/io.h >\n#include \" calibration_ts.h \"\n#include < linux\/types.h >\n#include < linux\/init.h >\n\n#include \" xpt2046_ts.h \"\nextern volatile struct adc_point gADPoint;\nstruct work_struct work; \/\/ \u5de5\u4f5c\u961f\u5217\nstruct xpt2046 *ts_tmp;  \/\/ \u4e2d\u8f6c\u53d8\u91cf\n\n\/*\n * This code has been heavily tested on a Nokia 770, and lightly\n * tested on other xpt2046 devices (OSK\/Mistral, Lubbock).\n * TSC2046 is just newer xpt2046 silicon.\n * Support for ads7843 tested on Atmel at91sam926x-EK.\n * Support for ads7845 has only been stubbed in.\n *\n * IRQ handling needs a workaround because of a shortcoming in handling\n * edge triggered IRQs on some platforms like the OMAP1\/2. These\n * platforms don't handle the ARM lazy IRQ disabling properly, thus we\n * have to maintain our own SW IRQ disabled status. This should be\n * removed as soon as the affected platform's IRQ handling is fixed.\n *\n * app note sbaa036 talks in more detail about accurate sampling...\n * that ought to help in situations like LCDs inducing noise (which\n * can also be helped by using synch signals) and more generally.\n * This driver tries to utilize the measures described in the app\n * note. The strength of filtering can be set in the board-* specific\n * files.\n *\/\n#define XPT2046_DEBUG 1\n#if XPT2046_DEBUG\n#define xpt2046printInfo(msg...) printk(msg);\n#define xpt2046printDebug(msg...) printk(KERN_ERR msg);\n#else\n#define xpt2046printInfo(msg...)\n#define xpt2046printDebug(msg...)\n#endif\n\n#define TS_POLL_DELAY (10 * 1000000)  \/* ns delay before the first sample *\/\n#define TS_POLL_PERIOD (20 * 1000000) \/* ns delay between samples *\/\n\n\/* this driver doesn't aim at the peak continuous sample rate *\/\n#define SAMPLE_BITS (8 \/*cmd*\/ + 16 \/*sample*\/ + 2 \/* before, after *\/)\n\n\/\/---------------------------zdx\n#define TAG \"tp:\"\n\n#define DEVICE_NAME \"TPModule\"\n#define DEVICE_COUNT 1\n\n#define SET_Calibration _IO('S', 2)\n#define SAVE_X _IO('S', 1)\n#define SAVE_Y _IO('S', 0)\n\nstruct chr_dev\n{\n    struct cdev tp_cdev;\n    dev_t dev_nr;\n    struct class *tp_class;\n    struct device *tp_device;\n    int TK_uncali_x[5];\n    int TK_uncali_y[5];\n    int TK_flag;\n};\nstruct chr_dev *chr_devp;\n\nstatic int my_open(struct inode *inode, struct file *filefp)\n{\n    chr_devp->TK_flag = 0;\n\n    xpt2046printDebug(\"open the char device\\n\");\n    return 0; \/\/ success\n}\nstatic int my_release(struct inode *inode, struct file *filefp)\n{\n    xpt2046printDebug(\"close the char device\\n\");\n    return 0;\n}\nstatic ssize_t my_read(struct file *filefp, char __user *buf, size_t count, loff_t *off)\n{\n    int ret;\n    int msg[2];\n    \/\/ xpt2046printDebug(\"=====enter my_read\\n\");\n    msg[0] = gADPoint.x;\n    msg[1] = gADPoint.y;\n    \/\/ xpt2046printDebug(\"------ msg[0]=%d msg[1]=%d\\n\",msg[0],msg[1]);\n    ret = copy_to_user(buf, msg, count);\n    if (ret != 0)\n    {\n        xpt2046printDebug(\"copy_to_user ERR\\n\");\n        return -EFAULT;\n    }\n    \/\/  xpt2046printDebug(\"enter read.ret=%d\\n\",ret);\n\n    return 0;\n}\n\nstatic ssize_t my_write(struct file *filefp, const char __user *buf, size_t count, loff_t *off)\n{\n    \/\/ unsigned char ret;\n    \/\/ xpt2046printDebug(\"=====enter my_write  chr_devp.TK_flag = %d\\n\",chr_devp->TK_flag);\n    if (chr_devp->TK_flag == 1) \/\/ save x\n    {\n        printk(KERN_ERR \"write: enter save x.\\n\");\n        if (copy_from_user(chr_devp->TK_uncali_x, buf, count))\n        {\n            xpt2046printDebug(\"copy_from_user  ERR\\n\");\n            return -EFAULT;\n        }\n    }\n    else if (chr_devp->TK_flag == 2) \/\/ save y\n    {\n        printk(KERN_ERR \"write: enter save y.\\n\");\n        if (copy_from_user(chr_devp->TK_uncali_y, buf, count))\n        {\n            xpt2046printDebug(\"copy_from_user  ERR\\n\");\n            return -EFAULT;\n        }\n    }\n    else\n        return -EFAULT;\n    return 0;\n}\n\nstatic long my_ioctl(struct file *filefp, unsigned int cmd, unsigned long arg)\n{\n    \/\/ xpt2046printDebug(\"%s:=====enter my_ioctl!!\\n\",__FUNCTION__);\n    if (cmd == SAVE_X)\n    {\n        chr_devp->TK_flag = 1;\n        return 0;\n    }\n    else if (cmd == SAVE_Y)\n    {\n        chr_devp->TK_flag = 2;\n        return 0;\n    }\n    else\n        return -1;\n}\n\nstatic struct file_operations tp_flops = {\n    .owner = THIS_MODULE,\n    .open = my_open,\n    .release = my_release,\n    .read = my_read,\n    .write = my_write,\n    .compat_ioctl = my_ioctl,\n};\nstruct ts_event\n{\n    \/* For portability, we can't read 12 bit values using SPI (which\n     * would make the controller deliver them as native byteorder u16\n     * with msbs zeroed).  Instead, we read them as two 8-bit values,\n     * *** WHICH NEED BYTESWAPPING *** and range adjustment.\n     *\/\n    u16 x;\n    u16 y;\n    int ignore;\n};\n\n\/*\n * We allocate this separately to avoid cache line sharing issues when\n * driver is used with DMA-based SPI controllers (like atmel_spi) on\n * systems where main memory is not DMA-coherent (most non-x86 boards).\n *\/\nstruct xpt2046_packet\n{\n    u8 read_x, read_y, pwrdown;\n    u16 dummy; \/* for the pwrdown read *\/\n    struct ts_event tc;\n};\n\nstruct xpt2046\n{\n    struct input_dev *input;\n    char phys[32];\n    char name[32];\n    char pendown_iomux_name[IOMUX_NAME_SIZE];\n    struct spi_device *spi;\n\n    u16 model;\n    u16 x_min, x_max;\n    u16 y_min, y_max;\n    u16 debounce_max;\n    u16 debounce_tol;\n    u16 debounce_rep;\n    u16 penirq_recheck_delay_usecs;\n    bool swap_xy;\n\n    struct xpt2046_packet *packet;\n\n    struct spi_transfer xfer[18];\n    struct spi_message msg[5];\n    struct spi_message *last_msg;\n    int msg_idx;\n    int read_cnt;\n    int read_rep;\n    int last_read;\n    int pendown_iomux_mode;\n    int touch_virtualkey_length;\n\n    spinlock_t lock;\n    struct hrtimer timer;\n    unsigned pendown : 1;                    \/* P: lock *\/\n    unsigned pending : 1; \/* P: lock *\/      \/\/ \u5728\u6211\u4ee3\u7801\u4e2d\u6ca1\u7528\u5230\n                                             \/\/  FIXME remove \"irq_disabled\"\n    unsigned irq_disabled : 1; \/* P: lock *\/ \/\/ \u548c\u4e2d\u65ad\u7684\u9501\u611f\u89c9\u51b2\u7a81\u4e86\uff0c\u5148\u4e0d\u7528\uff0c\u4fee\u6539\u4e86\u81ea\u5df1\u7684\u903b\u8f91\uff0c\u521d\u59cb\u503c\u5728prob\u4e2d\u7f6e0\n    unsigned disabled : 1;\n    unsigned is_suspended : 1;\n\n    int (*filter)(void *data, int data_idx, int *val);\n    void *filter_data;\n    void (*filter_cleanup)(void *data);\n    int (*get_pendown_state)(void);\n    int gpio_pendown;\n\n    void (*wait_for_sync)(void);\n};\n\n\/* leave chip selected when we're done, for quicker re-select? *\/\n#if 0\n#define CS_CHANGE(xfer) ((xfer).cs_change = 1)\n#else\n#define CS_CHANGE(xfer) ((xfer).cs_change = 0)\n#endif\n\/*--------------------------------------------------------------------------*\/\n\n\/* The xpt2046 has touchscreen and other sensors.\n * Earlier xpt2046 chips are somewhat compatible.\n *\/\n#define XPT2046_START (1 << 7)\n#define XPT2046_A2A1A0_d_y (1 << 4)   \/* differential *\/\n#define XPT2046_A2A1A0_d_z1 (3 << 4)  \/* differential *\/\n#define XPT2046_A2A1A0_d_z2 (4 << 4)  \/* differential *\/\n#define XPT2046_A2A1A0_d_x (5 << 4)   \/* differential *\/\n#define XPT2046_A2A1A0_temp0 (0 << 4) \/* non-differential *\/\n#define XPT2046_A2A1A0_vbatt (2 << 4) \/* non-differential *\/\n#define XPT2046_A2A1A0_vaux (6 << 4)  \/* non-differential *\/\n#define XPT2046_A2A1A0_temp1 (7 << 4) \/* non-differential *\/\n#define XPT2046_8_BIT (1 << 3)\n#define XPT2046_12_BIT (0 << 3)\n#define XPT2046_SER (1 << 2)                      \/* non-differential *\/\n#define XPT2046_DFR (0 << 2)                      \/* differential *\/\n#define XPT2046_PD10_PDOWN (0 << 0)               \/* lowpower mode + penirq *\/\n#define XPT2046_PD10_ADC_ON (0 << 0) \/* ADC on *\/ \/\/ \u539f\u503c\u662f1\n#define XPT2046_PD10_REF_ON (2 << 0)              \/* vREF on + penirq *\/\n#define XPT2046_PD10_ALL_ON (3 << 0)              \/* ADC + vREF on *\/\n\n#define MAX_12BIT ((1 << 12) - 1)\n\n\/* leave ADC powered up (disables penirq) between differential samples *\/\n#define READ_12BIT_DFR(x, adc, vref) (XPT2046_START | XPT2046_A2A1A0_d_##x | XPT2046_12_BIT | XPT2046_DFR | \\\n                                      (adc ? XPT2046_PD10_ADC_ON : 0) | (vref ? XPT2046_PD10_REF_ON : 0))\n\n#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))\n\/\/ #define  READ_Y(vref)    (READ_12BIT_DFR(y,  0, 0))\n\n#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))\n#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))\n\n\/\/ #define  READ_X(vref)    (READ_12BIT_DFR(x,  0, 0))\n#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))\n\n#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) \/* LAST *\/\n\n\/* single-ended samples need to first power up reference voltage;\n * we leave both ADC and VREF powered\n *\/\n#define READ_12BIT_SER(x) (XPT2046_START | XPT2046_A2A1A0_##x | XPT2046_12_BIT | XPT2046_SER)\n\n#define REF_ON (READ_12BIT_DFR(x, 1, 1))\n#define REF_OFF (READ_12BIT_DFR(y, 0, 0))\n\n#define DEBOUNCE_MAX 10              \/\/ \u6d88\u6296\u8fc7\u7a0b\u4e2d\u5141\u8bb8\u91c7\u6837\u7684\u6700\u5927\u6b21\u6570\n#define DEBOUNCE_REP 5               \/\/ \u5b9a\u4e49\u6d88\u6296\u8fc7\u7a0b\u4e2d\u9700\u8981\u8fde\u7eed\u68c0\u6d4b\u5230\u76f8\u540c\u72b6\u6001\u7684\u6b21\u6570\n#define DEBOUNCE_TOL 10              \/\/ \u8f93\u5165\u4fe1\u53f7\u8fc7\u7a0b\u4e2d\u4f1a\u4ea7\u751f\u8f7b\u5fae\u6ce2\u52a8\uff0c\u8fd9\u4e2a\u503c\u662f\u5141\u8bb8\u6ce2\u52a8\u7684\u6b21\u6570\u6216\u8303\u56f4\n#define PENIRQ_RECHECK_DELAY_USECS 1 \/\/ \u89e6\u53d1\u4e2d\u65ad\u540e\uff0c\u7b49\u5f85\u7684\u65f6\u957f\uff0c\u4ee5\u907f\u514d\u8bef\u5224\n#define PRESS_MAX 255                \/\/ \u68c0\u6d4b\u7684\u6700\u5927\u538b\u529b\u503c\n\n\/*--------------------------------------------------------------------------*\/\n\/*\n * touchscreen sensors  use differential conversions.\n *\/\n\nstruct dfr_req\n{\n    u8 command;\n    u8 pwrdown;\n    u16 dummy; \/* for the pwrdown read *\/\n    __be16 sample;\n    struct spi_message msg;\n    struct spi_transfer xfer[4];\n};\n\nvolatile struct adc_point gADPoint;\nvolatile int gFirstIrq;\n\n\/\/ static void xpt2046_enable(struct xpt2046 *ts);\n\/\/ static void xpt2046_disable(struct xpt2046 *ts);\n\/\/ \u9a8c\u8bc1\u8f93\u5165\u7684\u5750\u6807\u503c\u662f\u5426\u5728\u5c3a\u5bf8\u8303\u56f4\u5185\nstatic int xpt2046_verifyAndConvert(struct xpt2046 *ts, int adx, int ady, int *x, int *y)\n{\n\n    xpt2046printInfo(\"%s:(%d,%d)(%d\/%d)\\n\", __FUNCTION__, adx, ady, *x, *y);\n\n    if ((*x < ts->x_min) || (*x > ts->x_max))\n        return 1;\n\n    if ((*y < ts->y_min) || (*y > ts->y_max + ts->touch_virtualkey_length))\n        return 1;\n\n    return 0;\n}\n\n\/*--------------------------------------------------------------------------*\/\n\/\/ \u83b7\u53d6\u4e2d\u65ad\u5f15\u811a\u72b6\u6001\nstatic int get_pendown_state(struct xpt2046 *ts)\n{\n    if (ts->get_pendown_state)          \/\/ \u68c0\u6d4b\u53c2\u6570\u662f\u5426\u521d\u59cb\u5316\n        return ts->get_pendown_state(); \/\/ \u5982\u679c\u521d\u59cb\u5316\uff0c\u5219\u8c03\u7528\u51fd\u6570\u6307\u9488\u6307\u5411\u5bf9\u5e94\u7684\u51fd\u6570\n\n    return !gpio_get_value(ts->gpio_pendown); \/\/ \u672a\u521d\u59cb\u5316\uff0c\u8fd4\u56de\u4e2d\u65ad\u5f15\u811a\u7684\u72b6\u6001\uff0c\u53d6\u53cd\u5219\u662f\u4e2d\u65ad\u5f15\u811a\u4f4e\u7535\u5e73\u6709\u6548\uff0c\n}\n\/\/ \u7a7a\u51fd\u6570\uff0c\u4f5c\u7528\u4e0d\u660e\nstatic void null_wait_for_sync(void)\n{\n}\nstatic void report_touch_event(struct input_dev *input_dev, int x, int y)\n{\n    input_report_abs(input_dev, ABS_X, x);\n    input_report_abs(input_dev, ABS_Y, y);\n    input_report_key(input_dev, BTN_TOUCH, 1);\n    input_sync(input_dev);\n}\n\nuint16_t touch_buf = 0;\nuint16_t value_re;\nvolatile int num;\nstatic int read_spi(uint8_t tcmd)\n{\n    \/**************************************************************\/\n    int ret;\n    unsigned char txdata;\n    struct spi_message m;\n    struct spi_transfer *t;\n    struct spi_device *spi = ts_tmp->spi;\n\n    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL); \/* \u7533\u8bf7\u5185\u5b58 *\/\n\n    \/* \u7b2c1\u6b21\uff0c\u53d1\u9001\u8981\u8bfb\u53d6\u7684\u5bc4\u5b58\u5730\u5740 *\/\n    txdata = tcmd;\n    \/\/ t->speed_hz = 5000000;\n    t->tx_buf = &txdata;  \/* \u8981\u53d1\u9001\u7684\u6570\u636e *\/\n    t->len = 1;           \/* 1\u4e2a\u5b57\u8282 *\/\n    spi_message_init(&m); \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m); \/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);     \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    mdelay(1);\n\n    \/* \u7b2c2\u6b21\uff0c\u8bfb\u53d6\u6570\u636e *\/\n    txdata = 0x00;               \/* \u968f\u4fbf\u4e00\u4e2a\u503c\uff0c\u6b64\u5904\u65e0\u610f\u4e49 *\/\n    t->rx_buf = &touch_buf;      \/* \u8bfb\u53d6\u5230\u7684\u6570\u636e *\/\n    t->len = 1;                  \/* \u8981\u8bfb\u53d6\u7684\u6570\u636e\u957f\u5ea6 *\/\n    spi_message_init(&m);        \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m); \/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);     \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    value_re = touch_buf << 8;\n\n    \/* \u7b2c3\u6b21\uff0c\u8bfb\u53d6\u6570\u636e *\/\n    txdata = 0x00;               \/* \u968f\u4fbf\u4e00\u4e2a\u503c\uff0c\u6b64\u5904\u65e0\u610f\u4e49 *\/\n    t->rx_buf = &touch_buf;      \/* \u8bfb\u53d6\u5230\u7684\u6570\u636e *\/\n    t->len = 1;                  \/* \u8981\u8bfb\u53d6\u7684\u6570\u636e\u957f\u5ea6 *\/\n    spi_message_init(&m);        \/* \u521d\u59cb\u5316spi_message *\/\n    spi_message_add_tail(t, &m); \/* \u5c06spi_transfer\u6dfb\u52a0\u5230spi_message\u961f\u5217 *\/\n    ret = spi_sync(spi, &m);     \/* \u540c\u6b65\u53d1\u9001 *\/\n\n    value_re |= touch_buf;\n    value_re >>= 3;\n    value_re -= 4096;\n\n    if (value_re == 4095 || value_re == 0)\n    {\n        value_re = 0;\n    }\n    else\n    {\n        num++;\n        printk(\"333333333x-write = [%d]-[%x]\\n\", tcmd, tcmd);\n        printk(\"333333333x-value = [%d]-[%x]\\n\", value_re, value_re);\n        printk(\"333333333---num = [%d]\\n\", num);\n    }\n    \/\/ printk(\"333333333x-read = [%d]-[%x]\\n\", touch_buf,touch_buf);\n    udelay(200);\n    kfree(t); \/* \u91ca\u653e\u5185\u5b58 *\/\n    return value_re;\n}\n\n\/\/ \u5de5\u4f5c\u961f\u5217\u4e0b\u534a\u90e8\nvoid irq_work_func(struct work_struct *mwork)\n{\n    struct xpt2046 *ts = ts_tmp;\n    int status = 0;\n    int point_x = 0, point_y = 0;\n\n    spin_lock(&ts->lock);\n    printk(\"\u8fdb\u5165\u5de5\u4f5c\u961f\u5217\u4e2d\u65ad\\n\");\n    struct input_dev *input = ts->input;\n\n    xpt2046printDebug(\"%s:delay 15 ms!!!\\n\", __FUNCTION__);\n    mdelay(15);\n\n    \/* pen is still down, continue with the measurement *\/\n    xpt2046printInfo(\"%s:pen is still down, continue with the measurement\\n\", __FUNCTION__);\n\n    disable_irq_nosync(ts->spi->irq);\n    point_x = read_spi(0xd0);\n    enable_irq(ts->spi->irq);\n\n    disable_irq_nosync(ts->spi->irq);\n    point_y = read_spi(0x90);\n    enable_irq(ts->spi->irq);\n    if (point_y == 4095 || point_y == 0 || point_x == 4095 || point_x == 0)\n    {\n        point_y = 0;\n        point_x = 0;\n    }\n    else\n    {\n        report_touch_event(input, point_x, point_y);\n    }\n\n    spin_unlock(&ts->lock);\n}\nstatic irqreturn_t xpt2046_irq(int irq, void *handle)\n{\n    struct xpt2046 *ts = handle;\n    unsigned long flags;\n    printk(\"\u8fdb\u5165\u786c\u4e2d\u65ad\\n\");\n    \/\/ xpt2046printInfo(\"%s.....%s.....%d\\n\", __FILE__, __FUNCTION__, __LINE__);\n\n    spin_lock_irqsave(&ts->lock, flags);\n    if (likely(get_pendown_state(ts))) \/\/ \u83b7\u53d6\u4e2d\u65ad\u5f15\u811a\u7684\u72b6\u6001\uff0c\u4f4e\u7535\u5e73\u89e6\u53d1\uff0c\u5728\u51fd\u6570\u4e2d\u5df2\u53d6\u53cd\uff0c\u5728likely\u4e2d\u52a0\u901f\u5224\u65ad\n    {\n        if (!ts->irq_disabled)\n        {\n            \/* The ARM do_simple_IRQ() dispatcher doesn't act\n             * like the other dispatchers:  it will report IRQs\n             * even after they've been disabled.  We work around\n             * that here.  (The \"generic irq\" framework may help...)\n             *\/\n            disable_irq_nosync(ts->spi->irq);\n            schedule_work(&work);\n            enable_irq(ts->spi->irq);\n        }\n    }\n    spin_unlock_irqrestore(&ts->lock, flags);\n    return IRQ_HANDLED;\n}\n\/*--------------------------------------------------------------------------*\/\n\/\/ \u521d\u59cb\u5316\u4e2d\u65ad\u5f15\u811a\nstatic int setup_pendown(struct spi_device *spi, struct xpt2046 *ts)\n{\n    \/\/ struct xpt2046_platform_data *pdata = spi->dev.platform_data;\n    int err;\n\n    \/* REVISIT when the irq can be triggered active-low, or if for some\n     * reason the touchscreen isn't hooked up, we don't need to access\n     * the pendown state.\n     *\/\n    if (!gpio_is_valid(ts->gpio_pendown \/*pdata->gpio_pendown*\/)) \/\/ \u68c0\u6d4b\u4e2d\u65ad\u5f15\u811a\u662f\u5426\u6709\u6548\n    {\n        dev_err(&spi->dev, \"no get_pendown_state nor gpio_pendown?\\n\");\n        return -EINVAL;\n    }\n\n    \/\/ printk(KERN_ERR \"===============%s:%d==============\\n\", __func__, __LINE__);\n\n    err = gpio_request(ts->gpio_pendown, \"xpt2046_pendown\"); \/\/ \u7533\u8bf7\u4e2d\u65ad\u5f15\u811a\n    if (err)\n    {\n        dev_err(&spi->dev, \"failed to request pendown GPIO%d\\n\",\n                ts->gpio_pendown);\n        return err;\n    }\n\n    err = gpio_direction_input(ts->gpio_pendown); \/\/ \u5c06\u4e2d\u65ad\u5f15\u811a\u8bbe\u7f6e\u4e3a\u8f93\u5165\n    if (err)\n    {\n        dev_err(&spi->dev, \"failed to set input pendown GPIO%d\\n\",\n                ts->gpio_pendown);\n        return err;\n    }\n\n    return 0;\n}\n\/\/ \u521b\u5efa\u8bbe\u5907\u8282\u70b9\nstatic int tp_init(void)\n{\n    int res;\n    chr_devp = (struct chr_dev *)kmalloc(sizeof(struct chr_dev), GFP_KERNEL);\n\n    \/\/ xpt2046printDebug(\"==>tp_init!\\n\");\n    res = alloc_chrdev_region(&chr_devp->dev_nr, 0, 1, \"tp_chrdev\");\n    if (res)\n    {\n        xpt2046printDebug(\"==>alloc chrdev region failed!\\n\");\n        goto chrdev_err;\n    }\n    \/\/ xpt2046printDebug(\"==>alloc_chrdev_region!\\n\");\n    cdev_init(&chr_devp->tp_cdev, &tp_flops);\n    \/\/ xpt2046printDebug(\"==>cdev_init!\\n\");\n    res = cdev_add(&chr_devp->tp_cdev, chr_devp->dev_nr, DEVICE_COUNT);\n    if (res)\n    {\n        xpt2046printDebug(\"==>cdev add failed!\\n\");\n        goto cdev_err;\n    }\n    \/\/ xpt2046printDebug(\"==>cdev_add!\\n\");\n\n    chr_devp->tp_class = class_create(THIS_MODULE, \"tp_class\");\n    if (IS_ERR(&chr_devp->tp_class))\n    {\n        res = PTR_ERR(chr_devp->tp_class);\n        goto class_err;\n    }\n    \/\/ xpt2046printDebug(\"==>class_create!\\n\");\n\n    chr_devp->tp_device = device_create(chr_devp->tp_class, NULL, chr_devp->dev_nr, NULL, \"tp_device\");\n    if (IS_ERR(&chr_devp->tp_device))\n    {\n        res = PTR_ERR(&chr_devp->tp_device);\n        goto device_err;\n    }\n    \/\/ xpt2046printDebug(\"==>device_create!\\n\");\n\n    \/\/ xpt2046printDebug(\"==>tp begin.\\n\");\n    xpt2046printDebug(DEVICE_NAME \" initialized.\\n\");\n\n    return 0;\n\ndevice_err:\n    device_destroy(chr_devp->tp_class, chr_devp->dev_nr);\n    class_destroy(chr_devp->tp_class);\n\nclass_err:\n    cdev_del(&chr_devp->tp_cdev);\n\ncdev_err:\n    unregister_chrdev_region(chr_devp->dev_nr, DEVICE_COUNT);\n\nchrdev_err:\n\n    return res;\n}\nstatic int xpt2046_probe(struct spi_device *spi)\n{\n    struct xpt2046 *ts;            \/\/ \u603b\u7684\u6570\u636e\u7ed3\u6784\u4f53\n    struct xpt2046_packet *packet; \/\/ \u907f\u514d\u7f13\u5b58\u884c\u5171\u4eab\u7684\u95ee\u9898\n    struct input_dev *input_dev;   \/\/ \u8f93\u5165\u8bbe\u5907\u7684\u6838\u5fc3\u7ed3\u6784\u4f53\uff0c\u4fdd\u5b58\u5404\u79cd\u4fe1\u606f\u5c5e\u6027\u7b49\n    struct spi_message *m;         \/\/ \u4f20\u8f93\u6570\u636e\u7684\u7ed3\u6784\u4f53\n    struct spi_transfer *x;        \/\/ \u4fdd\u5b58\u6570\u636e\u7684\u7ed3\u6784\u4f53\n    int vref;\n    int err;\n    struct device_node *np = spi->dev.of_node; \/\/ node\u8282\u70b9\n    unsigned long irq_flags;\n\n    spi->irq = of_get_named_gpio_flags(np, \"pendown-gpio\", 0, (enum of_gpio_flags *)&irq_flags); \/\/ \u83b7\u53d6gpio\u5f15\u811a\n\n    printk(KERN_ERR \"===============%s:%d:spi->irq=%d==============\\n\", __func__, __LINE__, spi->irq);\n\n    \/* don't exceed max specified sample rate *\/ \/\/ \u9632\u6b62\u8bbe\u7f6e\u8d85\u51fa\u6700\u5927\u91c7\u6837\u7387\n    if (spi->max_speed_hz > (125000 * SAMPLE_BITS))\n    {\n        xpt2046printDebug(\"f(sample) %d KHz?\\n\",\n                          (spi->max_speed_hz \/ SAMPLE_BITS) \/ 1000);\n        return -EINVAL;\n    }\n\n    \/* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except\n     * that even if the hardware can do that, the SPI controller driver\n     * may not.  So we stick to very-portable 8 bit words, both RX and TX.\n     * \u5c06tx\u548crx\u90fd\u8bbe\u7f6e\u4e3a8\u4f4d\n     *\/\n    spi->bits_per_word = 8;\n    spi->mode = SPI_MODE_0;\n    err = spi_setup(spi);\n    if (err < 0)\n        return err;\n\n    ts = kzalloc(sizeof(struct xpt2046), GFP_KERNEL);\n    packet = kzalloc(sizeof(struct xpt2046_packet), GFP_KERNEL); \/\/ \u5355\u72ec\u5206\u914d\u7f13\u5b58\u7684\u6570\u636e\n    input_dev = input_allocate_device();                         \/\/ \u521d\u59cb\u5316\u4e00\u4e2a\u65b0\u7684input_dev\u7684\u7ed3\u6784\u4f53\n    if (!ts || !packet || !input_dev)\n    {\n        err = -ENOMEM;\n        goto err_free_mem;\n    }\n\n    dev_set_drvdata(&#038;spi->dev, ts); \/\/ \u5c06ts\u548cspi->dev\u7684\u7ed3\u6784\u4f53\u5173\u8054\u8d77\u6765\n\n    \/\/ printk(KERN_ERR \"===============%s:%d==============\\n\", __func__, __LINE__);\n\n    ts->packet = packet;\n    ts->spi = spi;\n    ts->input = input_dev;\n    ts->swap_xy = 0; \/\/ pdata->swap_xy;\n\n    \/\/ printk(KERN_ERR \"===============%s:%d==============\\n\", __func__, __LINE__);\n\n    gFirstIrq = 1; \/\/ \u6807\u5fd7\u4f4d\n    \/\/ ts->irq_disabled = 0;   \/\/\u76f8\u5f53\u4e8e\u9501\uff0c\u5728\u786c\u4e2d\u65ad\u4e2d\u4fdd\u8bc1\u89e6\u53d1\u540e\u8fdb\u5165\u5de5\u4f5c\u961f\u5217\n    ts->pendown = 0;              \/\/ \u6807\u5fd7\u4f4d\uff0c\u5224\u65ad\u6570\u636e\u8bfb\u53d6\u6210\u529f\u540e\u8fdb\u5165event\u7684\u6807\u5fd7\n    ts->gpio_pendown = spi->irq;  \/\/ \u5c06\u5f15\u811a\u53f7\u8d4b\u7ed9\u7ed3\u6784\u4f53\u7684\u5f15\u811a\u4e0a\n    err = setup_pendown(spi, ts); \/\/ \u7528\u4e8e\u68c0\u6d4b\u89e6\u6478\u4e8b\u4ef6\u7684 GPIO \u5f15\u811a\u3002\u4f8b\u5982\uff0c\u5b83\u4f1a\u5c06\u4e00\u4e2a\u7279\u5b9a\u7684 GPIO \u5f15\u811a\u8bbe\u7f6e\u4e3a\u8f93\u5165\u6a21\u5f0f\uff0c\u7528\u4e8e\u68c0\u6d4b\u89e6\u6478\u7b14\u662f\u5426\u6309\u4e0b\n    if (err)\n        goto err_free_mem;\n\n    if (!spi->irq)\n    {\n        dev_err(&spi->dev, \"%s:no IRQ?\\n\", __func__);\n        goto err_free_mem;\n    }\n    else\n    {\n        spi->irq = gpio_to_irq(spi->irq); \/\/ \u5c06gpio\u53f7\u8f6c\u6362\u4e3a\u4e2d\u65ad\u53f7\n        dev_err(&spi->dev, \"%s:IRQ=%d\\n\", __func__, spi->irq);\n    }\n\n    \/\/ printk(KERN_ERR \"===============%s:%d==============\\n\", __func__, __LINE__);\n\n    \/\/ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); \/\/ \u521d\u59cb\u5316\u65f6\u949f\n    \/\/ ts->timer.function = xpt2046_timer;\n\n    spin_lock_init(&ts->lock); \/\/ \u521d\u59cb\u5316\u9501\n\n    ts->model = 2046; \/\/ \u6a21\u5f0f2046,\u7528\u4e8esprintf\u586b\u5199\u4fe1\u606f\n\n    \/\/ printk(KERN_ERR \"===============%s:%d==============\\n\", __func__, __LINE__);\n\n    ts->debounce_max = DEBOUNCE_MAX;     \/\/ \u6d88\u6296\u6700\u5927\u91c7\u6837\u6b21\u6570\n    if (ts->debounce_max < DEBOUNCE_REP) \/\/ \u8fde\u7eed\u68c0\u6d4b\u76f8\u540c\u72b6\u6001\u6b21\u6570\n        ts->debounce_max = DEBOUNCE_REP;\n    ts->debounce_tol = DEBOUNCE_TOL; \/\/ \u5141\u8bb8\u503c\u6ce2\u52a8\u7684\u8303\u56f4\u6216\u6b21\u6570,\u8303\u56f4\u5185\u4e3a\u76f8\u540c\n    ts->debounce_rep = DEBOUNCE_REP;\n    \/\/ts->filter = xpt2046_debounce; \/\/ \u5904\u7406 XPT2046 \u89e6\u6478\u5c4f\u63a7\u5236\u5668\u7684\u53bb\u6296\u52a8\n    ts->filter_data = ts;\n    ts->penirq_recheck_delay_usecs = PENIRQ_RECHECK_DELAY_USECS; \/\/ \u91c7\u6837\u95f4\u6b47\u65f6\u957f\n\n    ts->wait_for_sync = null_wait_for_sync; \/\/ \u7a7a\u51fd\u6570\uff0c\u4f5c\u7528\u4e0d\u660e\n    ts->x_min = 0;                          \/\/ pdata->x_min;   \/\/\u5c4f\u5e55x\u7684\u6700\u5c0f\u503c\n    ts->x_max = SCREEN_MAX_X;               \/\/ pdata->x_max;  \/\/\u5c4f\u5e55x\u7684\u6700\u5927\u503c\n    ts->y_min = 0;                          \/\/ pdata->y_min;   \/\/\u5c4f\u5e55y\u7684\u6700\u5c0f\u503c\n    ts->y_max = SCREEN_MAX_Y;               \/\/ pdata->y_max;   \/\/\u5c4f\u5e55y\u7684\u6700\u5927\u503c\n\n    ts->touch_virtualkey_length = 0; \/\/ \u89e6\u6478\u865a\u62df\u6309\u952e\u957f\u5ea6\uff0c\u4f5c\u7528\u4e0d\u660e\uff0c\u53ef\u89c6\u4f5c\u4e00\u4e2a\u989d\u5916\u503c\u53d8\u91cf\uff0c\u8c03\u8282xy\u7684\u957f\u5ea6\n\n    snprintf(ts->phys, sizeof(ts->phys), \"%s\/input0\", dev_name(&spi->dev)); \/\/ \u5c06dev_name(&spi->dev\u7684\u503c\u8d4b\u7ed9phys\n    snprintf(ts->name, sizeof(ts->name), \"xpt%d-touchscreen\", ts->model);   \/\/ \u5c06mode\u7684\u503c\u7ec4\u5408\u540e\u8d4b\u7ed9ts->name\n\n    input_dev->name = ts->name;        \/\/ \u8d4b\u503c\n    input_dev->phys = ts->phys;        \/\/ \u8d4b\u503c\n    input_dev->dev.parent = &spi->dev; \/\/ \u7236\u8282\u70b9\u8d4b\u503c\uff0c\u8fd9\u70b9\u610f\u4e49\u672a\u77e5\n#if 1\n    \/\/ \u8bbe\u7f6e\u8f93\u5165\u8bbe\u5907\u652f\u6301\u7684\u4e8b\u4ef6\u7c7b\u578b\u548c\u5177\u4f53\u6309\u952e\u6216\u89e6\u6478\u4e8b\u4ef6\n    input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); \/\/ \u8bbe\u7f6e\u8f93\u5165\u8bbe\u5907\u652f\u6301\u7684\u4e8b\u4ef6\u7c7b\u578b\uff0c\u6309\u952e\u4e8b\u4ef6\uff0c\u7edd\u5bf9\u5750\u6807\u4e8b\u4ef6\n    \/\/ \u8ba1\u7b97 BTN_TOUCH\u7684\u503c\uff0c\u8bbe\u7f6e\u5230keybit\u6570\u7ec4\u4e2d\u7684\u4f4d\u7f6e\uff0c\u4e00\u822c\u4e3a0\n    input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); \/\/ \u8bbe\u7f6e\u8f93\u5165\u8bbe\u5907\u652f\u6301\u7684\u5177\u4f53\u4e8b\u4ef6\uff0c\u89e6\u6478\u4e8b\u4ef6\uff0c\n    \/\/ \u8bbe\u7f6e\u7edd\u5bf9\u5750\u6807\u8f74\uff08X \u8f74\u548c Y \u8f74\uff09\u7684\u53c2\u6570\uff0c\u786e\u5b9a\u5c4f\u5e55\u7684\u5750\u6807\u8303\u56f4\n    input_set_abs_params(input_dev, ABS_X,\n                         ts->x_min ?: 0,\n                         ts->x_max ?: MAX_12BIT, \/\/ MAX_12BIT\u6700\u5927\u503c\u662f4095\n                         0, 0);\n    input_set_abs_params(input_dev, ABS_Y,\n                         ts->y_min ?: 0,\n                         ts->y_max ?: MAX_12BIT,\n                         0, 0);\n#endif\n    \/\/ m->complete = xpt2046_rx_val; \/\/\u6d88\u606f\u5b8c\u6210\u65f6\u7684\u56de\u8c03\u51fd\u6570\n    \/\/ m->context = ts;  \/\/\u56de\u8c03\u51fd\u6570\u7684\u4e0a\u4e0b\u6587\u53c2\u6570\n\n    \/\/ ts->last_msg = m;\n    xpt2046printInfo(\"%s:READ_X(1):value=10-[%d]-16-[%x]\\n\", __FUNCTION__, READ_X(vref), READ_X(vref));\n\n    INIT_WORK(&work, irq_work_func); \/\/ \u521d\u59cb\u5316\u5de5\u4f5c\u961f\u5217\n\n    if (devm_request_irq(&spi->dev, spi->irq, xpt2046_irq,\n                         IRQF_TRIGGER_FALLING, spi->dev.driver->name, ts))\n    {\n        xpt2046printDebug(\"%s:trying pin change workaround on irq %d\\n\", __FUNCTION__, spi->irq);\n        err = devm_request_irq(&spi->dev, spi->irq, xpt2046_irq,\n                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, spi->dev.driver->name, ts);\n        if (err)\n        {\n            dev_dbg(&spi->dev, \"irq %d busy?\\n\", spi->irq);\n            goto err_free_gpio;\n        }\n    }\n\n    xpt2046printInfo(\"%s:touchscreen irq %d\\n\", __FUNCTION__, spi->irq);\n\n    \/* take a first sample, leaving nPENIRQ active and vREF off; avoid\n     * the touchscreen, in case it's not connected.\n     *\/\n\n    err = input_register_device(input_dev); \/\/ \u6ce8\u518cevent\u8282\u70b9\n    if (err)\n        goto err_remove_attr_group;\n\n    tp_init(); \/\/ \u521b\u5efa\u8bbe\u5907\u8282\u70b9\n    xpt2046printDebug(\"======xpt2046_tp initerface: driver initialized======\\n\");\n    xpt2046printDebug(\"======xpt2046_ts: driver initialized======\\n\");\n    ts_tmp = ts; \/\/ \u4e2d\u95f4\u503c\uff0c\u4f20\u9012ts\u6307\u9488\n    return 0;\n\nerr_remove_attr_group:\n    free_irq(spi->irq, ts);\nerr_free_gpio:\n    if (ts->gpio_pendown != -1)\n        gpio_free(ts->gpio_pendown);\nerr_free_mem:\n    input_free_device(input_dev);\n    kfree(packet);\n    kfree(ts);\n    return err;\n}\n\nstatic int xpt2046_remove(struct spi_device *spi)\n{\n    struct xpt2046 *ts = dev_get_drvdata(&spi->dev);\n\n    input_unregister_device(ts->input);\n    cancel_work_sync(&work);\n\n    free_irq(ts->spi->irq, ts);\n    \/* suspend left the IRQ disabled *\/\n    enable_irq(ts->spi->irq);\n\n    if (ts->gpio_pendown != -1)\n        gpio_free(ts->gpio_pendown);\n\n    if (ts->filter_cleanup)\n        ts->filter_cleanup(ts->filter_data);\n\n    kfree(ts->packet);\n    kfree(ts);\n\n    \/\/ tp_calib_iface_exit();\n\n    dev_dbg(&spi->dev, \"unregistered touchscreen\\n\");\n    return 0;\n}\n\nstatic struct of_device_id xpt2046_dt_ids[] = {\n    {.compatible = \"ti,tsc2046\"},\n    {}};\n\nstatic struct spi_driver xpt2046_driver = {\n    .driver = {\n        .name = \"xpt2046_ts\",\n        .bus = &spi_bus_type,\n        .owner = THIS_MODULE,\n        .of_match_table = xpt2046_dt_ids,\n    },\n    .probe = xpt2046_probe,\n    .remove = xpt2046_remove,\n};\n\nstatic int __init xpt2046_init(void)\n{\n    int ret;\n    gADPoint.x = 0;\n    gADPoint.y = 0;\n\n    ret = spi_register_driver(&xpt2046_driver);\n    if (ret)\n    {\n        printk(KERN_ERR \"Register XPT2046 driver failed.\\n\");\n        return ret;\n    }\n    else\n        \/\/  xpt2046printDebug(\"Touch panel drive XPT2046 driver init...\\n\");\n\n        return 0;\n}\n\nstatic void __exit xpt2046_exit(void)\n{\n    xpt2046printDebug(\"Touch panel drive XPT2046 driver exit...\\n\");\n    spi_unregister_driver(&xpt2046_driver);\n}\nmodule_init(xpt2046_init);\nmodule_exit(xpt2046_exit);\n\nMODULE_DESCRIPTION(\"spi xpt2046 TouchScreen Driver\");\nMODULE_LICENSE(\"GPL\");\nMODULE_ALIAS(\"spi:xpt2046\");<\/code><\/pre>\n<h1>4 \u8bbe\u5907\u6811<\/h1>\n<p>&emsp;&emsp;\u53c2\u7167\u5b98\u65b9ultar\u677f\u5b50\u7684\u4e2d\u65ad\u8bbe\u5907\u6811\u7f16\u5199\u81ea\u5df1\u7684\u8bbe\u5907\u6811\u3002\u5b98\u65b9\u7684\u89e6\u6478\u8bbe\u5907\u662f\u57fa\u4e8ei2c\u603b\u7ebf\u9a71\u52a8\u7684\uff0c\u6240\u4ee5\u88ab\u52a8\u7814\u7a76\u4e86\u4e00\u4e0bi2c\u8bbe\u5907\u6811\u7684\u5199\u6cd5\u3002<\/p>\n<h2>4.1 i2c\u8bbe\u5907\u6811\u7b80\u4ecb<\/h2>\n<p>&emsp;&emsp;\u5176\u4ed6\u5c5e\u6027\u6ca1\u5565\u592a\u5927\u95ee\u9898\uff0c\u4f46\u5176\u4e2d\u6709\u4e2areg\u5c5e\u6027\u548cspi\u5199\u6cd5\u4e0d\u592a\u4e00\u6837\u3002\u5e73\u65f6\u4f7f\u7528spi\u7684\u534f\u8bae\u4e2d\u8fd9\u91cc\u7684\u503c\u4e00\u822c\u4e3a0\uff0c\u800c\u5728i2c\u534f\u8bae\u4e0b\u503c\u53d8\u4e3a\u4e860x14\uff1f<br \/>\n&emsp;&emsp;\u67e5\u4e86\u4e00\u4e0b\u53d1\u73b0\u539f\u56e0\u5f88\u7b80\u5355\uff0cspi\u534f\u8bae\u6709cs\u7247\u9009\u7ebf\uff0c\u6240\u4ee5\u4e3b\u4ece\u673a\u4e4b\u95f4\u901a\u4fe1\u53ef\u4ee5\u6839\u636e\u7247\u9009\u7ebf\u786e\u5b9a\u662f\u54ea\u4e00\u53f0\u4ece\u673a\u3002\u800ci2c\u53ea\u67092\u6839\u7ebf\uff0c\u65e0\u6cd5\u786e\u5b9a\u662f\u54ea\u4e2a\u4ece\u673a\uff0c\u8fd9\u5c31\u9700\u8981\u901a\u4fe1\u5730\u5740\u4e86\uff0c\u56e0\u6b640x14\u5c31\u662f\u7528\u6765\u533a\u5206\u4ece\u673a\u7684\uff0c\u4e0d\u540c\u7c7b\u578b\u7684i2c\u5668\u4ef6\u90fd\u4f1a\u5b9a\u4e49\u81ea\u5df1\u72ec\u7279\u7684i2c\u5730\u5740\u3002\u6709\u591a\u4e2a\u76f8\u540c\u7684i2c\u8bbe\u5907\u65f6\uff0c\u5b83\u4eec\u7684\u5730\u5740\u76f8\u540c\uff0c\u8fd9\u79cd\u60c5\u51b5\u4e0b\u4f9d\u9760i2c\u590d\u7528\u5668PCA9548\u89e3\u51b3,\u8fd9\u4e2a\u65f6\u5019\u6bcf\u4e2a\u8282\u70b9\u4e0b\u7684\u7b2c\u4e00\u4e2areg\u503c\u7528\u4e8ePCA9548\u533a\u5206\u3002<\/p>\n<pre><code class=\"language-c\">&i2c3 {\n    status  = \"okay\";\n    clock-frequency = <100000>;\n    pinctrl-0 = <&#038;i2c3m2_xfer &#038;tp_rst &#038;tp_irq>;\n\n    pca9548: i2c-mux@70 {\n        compatible = \"nxp,pca9548\";\n        reg = <0x70>;\n\n        #address-cells = <1>;\n        #size-cells = <0>;\n\n        i2c@0 {\n            reg = <0>;\/\/\u7528\u4e8epca9548\u533a\u5206\u591a\u4e2a\u76f8\u540c\u7684\u8bbe\u5907\n            touchscreen1: touchscreen@14 {\n                compatible = \"goodix,gt911\";\n                reg = <0x14>;\/\/\u7279\u5b9a\u7c7b\u578b\u7684i2c\u8bbe\u5907\n                interrupt-parent = <&#038;gpio0>;\n                interrupts = <RK_PA3 IRQ_TYPE_EDGE_FALLING>;\n                reset-gpios = <&#038;gpio0 RK_PA4 GPIO_ACTIVE_LOW>;\n                pinctrl-names = \"default\";\n            };\n        };\n\n        i2c@1 {\n            reg = <1>;\n            touchscreen2: touchscreen@14 {\n                compatible = \"goodix,gt911\";\n                reg = <0x14>;\n                interrupt-parent = <&#038;gpio0>;\n                interrupts = <RK_PA5 IRQ_TYPE_EDGE_FALLING>;\n                reset-gpios = <&#038;gpio0 RK_PA6 GPIO_ACTIVE_LOW>;\n                pinctrl-names = \"default\";\n            };\n        };\n    };\n};\n\n&pinctrl {\n    touchscreen {\n        tp_rst: tp-rst {\n            rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &#038;pcfg_pull_up>;\n        };\n\n        tp_irq: tp-irq {\n            rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &#038;pcfg_pull_none>;\n        };\n\n        tp_rst2: tp-rst2 {\n            rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &#038;pcfg_pull_up>;\n        };\n\n        tp_irq2: tp-irq2 {\n            rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &#038;pcfg_pull_none>;\n        };\n    };\n};<\/code><\/pre>\n<h2>4.2 \u8bbe\u5907\u6811\u7684\u4e2d\u65ad\u5b8f<\/h2>\n<p>&emsp;&emsp;\u9009\u62e9\u5408\u9002\u7684\u4e2d\u65ad\u89e6\u53d1\u7c7b\u578b\u53ef\u4ee5\u786e\u4fdd\u8bbe\u5907\u5728\u9884\u671f\u7684\u4fe1\u53f7\u53d8\u5316\u6216\u72b6\u6001\u65f6\u6b63\u786e\u54cd\u5e94\uff0c\u8fd9\u5bf9\u4e8e\u5b9e\u73b0\u53ef\u9760\u7684\u786c\u4ef6\u9a71\u52a8\u7a0b\u5e8f\u5f88\u91cd\u8981\u3002\u4f8b\u5982\u6211\u7684\u9a71\u52a8\u4ee3\u7801\u4f7f\u7528\u7684IRQ_TYPE_LEVEL_HIGH\u662f\u9ad8\u7535\u5e73\u89e6\u53d1\uff1b\u5728Linux\u5185\u6838\u4ee3\u7801\u4e2d\uff0cIRQ_TYPE_LEVEL_HIGH\u8fd9\u7c7b\u5b8f\u5b9a\u4e49\u5728include\/linux\/irq.h\u5934\u6587\u4ef6\u4e2d\uff0c\u6709\u9700\u8981\u53ef\u4ee5\u67e5\u770b\u5185\u6838\u6587\u4ef6\u6311\u9009\u3002\u5177\u4f53\u4f5c\u7528\u53ca\u5176\u9002\u7528\u8bbe\u5907\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<ol>\n<li>IRQ_TYPE_EDGE_RISING<br \/>\n&emsp;&emsp;\u5728\u4fe1\u53f7\u7684\u4e0a\u5347\u6cbf\uff08\u4ece\u4f4e\u7535\u5e73\u5230\u9ad8\u7535\u5e73\uff09\u89e6\u53d1\u4e2d\u65ad\u3002\u9002\u7528\u4e8e\u9700\u8981\u5728\u4fe1\u53f7\u7531\u4f4e\u5230\u9ad8\u53d8\u5316\u65f6\u54cd\u5e94\u7684\u8bbe\u5907\u6216\u4f20\u611f\u5668\u3002<\/p>\n<pre><code class=\"language-c\">#define IRQ_TYPE_EDGE_RISING 0x01<\/code><\/pre>\n<\/li>\n<li>IRQ_TYPE_EDGE_BOTH<br \/>\n&emsp;&emsp;\u5728\u4fe1\u53f7\u7684\u4efb\u4e00\u8fb9\u6cbf\uff08\u65e0\u8bba\u662f\u4e0a\u5347\u6cbf\u8fd8\u662f\u4e0b\u964d\u6cbf\uff09\u90fd\u89e6\u53d1\u4e2d\u65ad\u3002\u9002\u7528\u4e8e\u9700\u8981\u6355\u83b7\u4fe1\u53f7\u7684\u4efb\u4f55\u53d8\u5316\uff08\u4e0a\u5347\u6216\u4e0b\u964d\uff09\u4e8b\u4ef6\u7684\u573a\u666f\u3002<\/p>\n<pre><code class=\"language-c\">#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)<\/code><\/pre>\n<\/li>\n<li>IRQ_TYPE_LEVEL_HIGH<br \/>\n&emsp;&emsp;\u5728\u4fe1\u53f7\u4fdd\u6301\u9ad8\u7535\u5e73\u65f6\u89e6\u53d1\u4e2d\u65ad\uff0c\u4e14\u5728\u4fe1\u53f7\u7ef4\u6301\u9ad8\u7535\u5e73\u671f\u95f4\uff0c\u4e2d\u65ad\u4f1a\u4e00\u76f4\u89e6\u53d1\uff08\u6216\u4fdd\u6301\u89e6\u53d1\u72b6\u6001\uff09\u3002\u9002\u7528\u4e8e\u9700\u8981\u5728\u4fe1\u53f7\u4fdd\u6301\u9ad8\u7535\u5e73\u671f\u95f4\u54cd\u5e94\u7684\u8bbe\u5907\uff0c\u5982\u7535\u5e73\u654f\u611f\u7684\u8bbe\u5907\u6216\u72b6\u6001\u76d1\u63a7\u3002<\/p>\n<pre><code class=\"language-c\">#define IRQ_TYPE_LEVEL_HIGH 0x04<\/code><\/pre>\n<\/li>\n<li>IRQ_TYPE_LEVEL_LOW<br \/>\n&emsp;&emsp;\u5728\u4fe1\u53f7\u4fdd\u6301\u4f4e\u7535\u5e73\u65f6\u89e6\u53d1\u4e2d\u65ad\uff0c\u4e14\u5728\u4fe1\u53f7\u7ef4\u6301\u4f4e\u7535\u5e73\u671f\u95f4\uff0c\u4e2d\u65ad\u4f1a\u4e00\u76f4\u89e6\u53d1\uff08\u6216\u4fdd\u6301\u89e6\u53d1\u72b6\u6001\uff09\u3002\u9002\u7528\u4e8e\u9700\u8981\u5728\u4fe1\u53f7\u4fdd\u6301\u4f4e\u7535\u5e73\u671f\u95f4\u54cd\u5e94\u7684\u8bbe\u5907\uff0c\u5982\u7535\u5e73\u654f\u611f\u7684\u8bbe\u5907\u6216\u72b6\u6001\u76d1\u63a7\u3002<\/p>\n<pre><code class=\"language-c\">#define IRQ_TYPE_LEVEL_LOW 0x08<\/code><\/pre>\n<\/li>\n<li>IRQ_TYPE_NONE<br \/>\n&emsp;&emsp;\u8868\u793a\u6ca1\u6709\u6307\u5b9a\u4e2d\u65ad\u89e6\u53d1\u7c7b\u578b\uff0c\u901a\u5e38\u7528\u4f5c\u521d\u59cb\u5316\u6216\u9ed8\u8ba4\u503c\u3002\u9002\u7528\u4e8e\u4e0d\u9700\u8981\u7279\u5b9a\u89e6\u53d1\u7c7b\u578b\u6216\u5728\u521d\u59cb\u5316\u671f\u95f4\u4e0d\u8bbe\u7f6e\u89e6\u53d1\u7c7b\u578b\u7684\u60c5\u51b5\u3002<\/p>\n<pre><code class=\"language-c\">#define IRQ_TYPE_NONE 0x00000000<\/code><\/pre>\n<\/li>\n<li>\n<p>IRQ_TYPE_SENSE_MASK<br \/>\n&emsp;&emsp;\u7528\u4e8e\u63a9\u7801\u4e2d\u65ad\u7c7b\u578b\u7684\u4f4d\u5b57\u6bb5\uff0c\u901a\u5e38\u7528\u4e8e\u68c0\u6d4b\u548c\u5904\u7406\u4e2d\u65ad\u89e6\u53d1\u7c7b\u578b\u3002\u9002\u7528\u4e8e\u5185\u6838\u4e2d\u9700\u8981\u5904\u7406\u4e0d\u540c\u4e2d\u65ad\u7c7b\u578b\u7684\u4ee3\u7801\u903b\u8f91\u3002<\/p>\n<pre><code class=\"language-c\">#define IRQ_TYPE_SENSE_MASK 0x0000000f<\/code><\/pre>\n<p>\u5982\u4e0b\u662f\u5b9e\u9645\u4f7f\u7528\u7684\u793a\u4f8b\uff1a<\/p>\n<pre><code>\u8bbe\u5907\u6811\u7aef\uff1a\nmy_device: my_device@0 {\ncompatible = \"my,device\";\ninterrupt-parent = <&#038;gpio>;\ninterrupts = <17 IRQ_TYPE_LEVEL_HIGH>;\n};<\/code><\/pre>\n<pre><code class=\"language-c\">\u9a71\u52a8\u7aef\uff1a\nint irq_number;\nirq_number = gpio_to_irq(gpio_number);\nret = request_irq(irq_number, my_irq_handler, IRQ_TYPE_LEVEL_HIGH, \"my_device\", dev);\nif (ret) {\npr_err(\"Failed to request IRQ: %d\\n\", ret);\nreturn ret;\n}<\/code><\/pre>\n<h2>4.3 \u7f16\u5199\u81ea\u5df1\u7684\u8bbe\u5907\u6811<\/h2>\n<p>&emsp;&emsp;\u5982\u4e0b\u662f\u7f16\u5199\u7684\u89e6\u6478\u5c4f\u4e2d\u65ad\u8bbe\u5907\u6811\uff0c\u56e0\u4e3a\u548c\u663e\u793a\u9a71\u52a8\u5171\u7528\u4e00\u4e2aspi\u63a5\u53e3\uff0c\u6240\u4ee5\u5199\u5230\u4e86\u4e00\u8d77\u3002\u522b\u770b\u6700\u540e\u7cbe\u7b80\u6210\u4e86\u8fd9\u51e0\u884c\uff1b\u5f53\u521d\u4e2d\u65ad\u548cspi\u5b50\u7cfb\u7edf\u51b2\u7a81\u7684\u65f6\u5019\uff0c\u6ca1\u5c11\u7814\u7a76\u5206\u6790\u662f\u5426\u662f\u8bbe\u5907\u6811\u7684\u95ee\u9898\uff0c\u4e5f\u662f\u88ab\u6298\u78e8\u7684\u6b32\u6b7b\u6b32\u4ed9\u3002<\/p>\n<pre><code class=\"language-c\">&spi0 {\nstatus = \"okay\";\npinctrl-names = \"default\";\npinctrl-0 = <&#038;spi0m0_pins ,&#038;tp_irq>;\n#address-cells = <1>;\n#size-cells = <0>;\nspidev@0 {\n          status = \"disabled\";\n  };\nili9488@0{\n   status = \"okay\";\n   compatible = \"ilitek,ili9488\";\n   reg = <0>;\n   spi-max-frequency = <20000000>;\n   fps = <30>;\n   bpp = <24>;\n   buswidth = <8>;\n   debug = <0x7>;\n   led-gpios = <&#038;gpio0 RK_PA4 GPIO_ACTIVE_LOW>;\/\/BL\n   dc = <&#038;gpio1 RK_PA2 GPIO_ACTIVE_HIGH>;      \/\/DC\n   reset = <&#038;gpio1 RK_PD1 GPIO_ACTIVE_LOW>;    \/\/RES-ili9488\n   lcd_cs = <&#038;gpio1 RK_PC0 GPIO_ACTIVE_LOW>;  \/\/CS\n \/\/  reset = <&#038;gpio1 RK_PC3 GPIO_ACTIVE_LOW>;    \/\/RES-st7789v\n};\ntsc2046@0 {\nstatus = \"okay\";\ncompatible = \"ti,tsc2046\";\n\nspi-max-frequency = <1500000>;\nreg = <1>;  \/* CS0 *\/\n\ntp_cs = <&#038;gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;    \/\/tp-cs\n\ninterrupt-parent = <&#038;gpio3>;\ninterrupts = <RK_PA7 0>;    \/* GPIO 29 *\/\npendown-gpio = <&#038;gpio3 RK_PA7 GPIO_ACTIVE_HIGH>;\n};\n};<\/code><\/pre>\n<p>&emsp;&emsp;\u81f3\u6b64\u89e6\u6478\u9a71\u52a8\u7f16\u5199\u5b8c\u6210\uff0c\u5269\u4f59\u90e8\u5206\u5c31\u662f\u548clvgl\u8fdb\u884c\u9002\u914d\u4e86\uff01<\/p>\n<h1>5 \u603b\u7ed3<\/h1>\n<p>&emsp;&emsp;\u603b\u7ed3\u7684\u8bdd\u524d\u8a00\u90fd\u8bf4\u4e86\uff0c\u5269\u4e0b\u7684\u53ea\u60f3\u5410\u69fd\u3002\u5d4c\u5165\u5f0f\u679c\u7136\u662f\u4e2a\u5927\u6df1\u5751\uff0c\u5404\u79cd\u5947\u8469\u95ee\u9898\u90fd\u4f1a\u9047\u5230\uff0c\u4e0d\u50cf\u76f4\u63a5\u7528\u522b\u4eba\u6210\u719f\u7684\u6d41\u7a0b\uff0c\u53ef\u4ee5\u8f7b\u677e\u70b9\u4eae\u5c4f\u5e55\uff1b\u4e0d\u8fc7\u6700\u6709\u610f\u601d\u548c\u6210\u5c31\u611f\u7684\u6070\u6070\u4e5f\u662f\u89e3\u51b3\u8fd9\u4e9b\u95ee\u9898\u3002<br \/>\n&emsp;&emsp;\u6700\u540e\u8bf4\u4e86\u534a\u5929\u603b\u8981\u770b\u770b\u9a71\u52a8\u6267\u884c\u6210\u529f\u7684\u6210\u679c\uff0c\u56e0\u6b64\u6211\u5728\u4e13\u95e8\u5b9e\u73b0\u4e86input\u5b50\u7cfb\u7edf\uff0c\u5982\u4e0b\u662f\u5b9e\u73b0\u89e6\u6478\u529f\u80fd\u540e\u5728\u7ec8\u7aef\u6253\u5370\u7684\u89e6\u6478\u4fe1\u606f\u3002<\/p>\n<p><center><br \/>\n<div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/www.yanwenkai.com:7777\/images\/2025\/02\/26\/20250226-1.png'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  loading=\"lazy\" decoding=\"async\" data-original=\"https:\/\/www.yanwenkai.com:7777\/images\/2025\/02\/26\/20250226-1.png\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" width=\"600\" height=\"400\"><\/div><br \/>\n<\/center>\n<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>1 \u524d\u8a00 &emsp;&emsp;lcd\u663e\u793a\u9a71\u52a8\u79fb\u690d\u5b8c\u540e\uff0c\u4ee5\u4e3a\u8df3\u51fa\u6df1\u5751\u4e86\uff1b\u6ca1\u60f3\u5230\u89e6\u6478\u5c4f\u9a71\u52a8\u6765\u4e86\u4e2a\u5927\u7684\u3002\u770b\u4ea7\u54c1\u624b [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":691,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[53,13,38,16,33],"class_list":["post-650","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-flushbonading-lcd","tag-input","tag-spi","tag-38","tag-16","tag-33"],"_links":{"self":[{"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=\/wp\/v2\/posts\/650","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=650"}],"version-history":[{"count":39,"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=\/wp\/v2\/posts\/650\/revisions"}],"predecessor-version":[{"id":690,"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=\/wp\/v2\/posts\/650\/revisions\/690"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=\/wp\/v2\/media\/691"}],"wp:attachment":[{"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=650"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=650"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.yanwenkai.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=650"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}