AndroidTP驅動之(二)裝置樹解析

0. 前情提要

上文中我們已經初步搭好了TP驅動的框架。當然我們還缺了重要的部分input子系統,這個不急,我們下一篇文章再敘。
本文我們來完成TP driver中對裝置樹的解析。

1. probe函式

我們知道驅動匹配有四種方式:裝置樹匹配、裝置名稱匹配、裝置ID匹配、ACPI方式匹配。
這裡我們只用裝置樹匹配,這也是Android驅動中最常用的匹配方式。
我們知道當驅動和裝置樹匹配的時候,probe函式就會被執行。
這時一般首先進行裝置樹的解析,從裝置樹中獲取裝置的硬體資訊。

    struct mytp_platform_data *pdata;
    int err;

    if (client->dev.of_node)
    {
        pdata = devm_kzalloc(&client->dev,
                sizeof(struct mytp_platform_data),
                GFP_KERNEL);
        if (!pdata)
        {
            PRINT_INFO("[MEMORY]Failed to allocate memory");
            return -ENOMEM;
        }
        err = mytp_parse_dt(&client->dev, pdata);
        if (err)
        {
            PRINT_INFO("[DTS]DT parsing failed");
        }
    }
    else
    {
        return -1;
    }

    if (!pdata)
    {
        PRINT_INFO("Invalid pdata");
        return -EINVAL;
    }

從程式碼中我們很清晰的看到,我們先是定義了一個結構體指標pdata。這是用來存放平臺數據。
接著,我們為這結構體申請了記憶體,並做異常處理。
之後呼叫mytp_parse_dt函式對裝置樹進行解析。也做了相應的異常處理。

1.1 mytp_platform_data結構體

struct mytp_platform_data
{
    u32 irq_gpio;
    u32 irq_gpio_flags;
    u32 reset_gpio;
    u32 reset_gpio_flags;
    bool have_key;
    u32 key_number;
    u32 keys[4];
    u32 key_y_coord;
    u32 key_x_coords[4];
    u32 x_max;
    u32 y_max;
    u32 x_min;
    u32 y_min;
    u32 max_touch_number;
};

頭四個結構體成員變數,分別是兩個gpio所使用的,一個是irq中斷,一個是TP的reset復位引腳。
之後的bool變數,是TP按鍵的標誌,表示是否支援TP按鍵。
緊接著的四個key_打頭的變數是提供給TP按鍵處理函式用的。
x_max、x_min、y_max、y_min限定了tp的觸控範圍。
最後的一個變數限定了tp支援的最大多點觸控數目。

1.2 mytp_parse_dt函式

這個函式就是用來解析裝置樹的。
其中的mytp_get_dt_coords函式是自己實現的,用來解析裝置樹中的陣列的。具體實現見1.3小節。

static int mytp_parse_dt(struct device *dev, struct mytp_platform_data *pdata)
{
    int rc;
    struct device_node *np = dev->of_node;
    u32 temp_val;

    rc = mytp_get_dt_coords(dev, "focaltech,display-coords", pdata);
    if (rc)
        PRINT_INFO("Unable to get display-coords");

    /* key */
    pdata->have_key = of_property_read_bool(np, "focaltech,have-key");
    if (pdata->have_key)
    {
        rc = of_property_read_u32(np, "focaltech,key-number", &pdata->key_number);
        if (rc)
        {
            PRINT_INFO("Key number undefined!");
        }
        rc = of_property_read_u32_array(np, "focaltech,keys",
                pdata->keys, pdata->key_number);
        if (rc)
        {
            PRINT_INFO("Keys undefined!");
        }
        rc = of_property_read_u32(np, "focaltech,key-y-coord", &pdata->key_y_coord);
        if (rc)
        {
            PRINT_INFO("Key Y Coord undefined!");
        }
        rc = of_property_read_u32_array(np, "focaltech,key-x-coords",
                pdata->key_x_coords, pdata->key_number);
        if (rc)
        {
            PRINT_INFO("Key X Coords undefined!");
        }
        PRINT_INFO("%d: (%d, %d, %d), [%d, %d, %d][%d]",
                pdata->key_number, pdata->keys[0], pdata->keys[1], pdata->keys[2],
                pdata->key_x_coords[0], pdata->key_x_coords[1], pdata->key_x_coords[2],
                pdata->key_y_coord);
    }

    /* reset, irq gpio info */
    pdata->reset_gpio = of_get_named_gpio_flags(np, "focaltech,reset-gpio", 0, &pdata->reset_gpio_flags);
    if (pdata->reset_gpio < 0)
    {
        PRINT_INFO("Unable to get reset_gpio");
    }

    pdata->irq_gpio = of_get_named_gpio_flags(np, "focaltech,irq-gpio", 0, &pdata->irq_gpio_flags);
    if (pdata->irq_gpio < 0)
    {
        PRINT_INFO("Unable to get irq_gpio");
    }

    rc = of_property_read_u32(np, "focaltech,max-touch-number", &temp_val);
    if (!rc)
    {
        pdata->max_touch_number = temp_val;
        PRINT_INFO("max_touch_number=%d", pdata->max_touch_number);
    }
    else
    {
        PRINT_INFO("Unable to get max-touch-number");
        pdata->max_touch_number = MYTP_MAX_POINTS;
    }

    return 0;
}

1.3 mytp_get_dt_coords函式

static int mytp_get_dt_coords(struct device *dev, char *name,
        struct mytp_platform_data *pdata)
{
    u32 coords[MYTP_COORDS_ARR_SIZE];
    struct property *prop;
    struct device_node *np = dev->of_node;
    int coords_size, rc;

    prop = of_find_property(np, name, NULL);
    if (!prop)
        return -EINVAL;
    if (!prop->value)
        return -ENODATA;

    coords_size = prop->length / sizeof(u32);
    if (coords_size != MYTP_COORDS_ARR_SIZE)
    {
        PRINT_INFO("invalid %s", name);
        return -EINVAL;
    }

    rc = of_property_read_u32_array(np, name, coords, coords_size);
    if (rc && (rc != -EINVAL))
    {
        PRINT_INFO("Unable to read %s", name);
        return rc;
    }

    if (!strcmp(name, "focaltech,display-coords"))
    {
        pdata->x_min = coords[0];
        pdata->y_min = coords[1];
        pdata->x_max = coords[2];
        pdata->y_max = coords[3];
    }
    else
    {
        PRINT_INFO("unsupported property %s", name);
        return -EINVAL;
    }

    return 0;
}

End

至此我們完成了對裝置樹的解析。