diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 2da54f781e3b94..9644922a989cb6 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -5324,6 +5324,8 @@ Params: 2_8_inch 2.8" 480x640 8_0_inch 8.0" 1280x800 10_1_inch 10.1" 1280x800 11_9_inch 11.9" 320x1480 + 13_3_inch_4lane 13.3" 1920x1080 4lane + 13_3_inch_2lane 13.3" 1920x1080 2lane i2c1 Use i2c-1 with jumper wires from GPIOs 2&3 disable_touch Disable the touch controller rotation Set the panel orientation property diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts index 3b03ef09cdb9e8..46feb1434d856d 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts @@ -51,6 +51,11 @@ reg = <0x14>; compatible = "goodix,gt911"; }; + + touch2: ilitek@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; + }; }; }; @@ -120,6 +125,8 @@ <&touch>, "touchscreen-inverted-x?", <&touch>, "touchscreen-inverted-y?"; 8_8_inch = <&panel>, "compatible=waveshare,8.8inch-panel"; + 13_3_inch_4lane = <&panel>, "compatible=waveshare,13.3inch-4lane-panel"; + 13_3_inch_2lane = <&panel>, "compatible=waveshare,13.3inch-2lane-panel"; i2c1 = <&i2c_frag>, "target:0=",<&i2c1>, <0>, "-3-4+5"; disable_touch = <&touch>, "status=disabled"; diff --git a/drivers/gpu/drm/panel/panel-waveshare-dsi.c b/drivers/gpu/drm/panel/panel-waveshare-dsi.c index 2cca27e4ecc8a3..4041d31c71a270 100644 --- a/drivers/gpu/drm/panel/panel-waveshare-dsi.c +++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c @@ -32,6 +32,12 @@ struct ws_panel { enum drm_panel_orientation orientation; }; +struct ws_panel_data { + const struct drm_display_mode *mode; + int lanes; + unsigned long mode_flags; +}; + /* 2.8inch 480x640 * https://www.waveshare.com/product/raspberry-pi/displays/2.8inch-dsi-lcd.htm */ @@ -47,6 +53,12 @@ static const struct drm_display_mode ws_panel_2_8_mode = { .vtotal = 640 + 150 + 50 + 150, }; +static const struct ws_panel_data ws_panel_2_8_data = { + .mode = &ws_panel_2_8_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + /* 3.4inch 800x800 Round * https://www.waveshare.com/product/displays/lcd-oled/3.4inch-dsi-lcd-c.htm */ @@ -62,6 +74,12 @@ static const struct drm_display_mode ws_panel_3_4_mode = { .vtotal = 800 + 8 + 4 + 16, }; +static const struct ws_panel_data ws_panel_3_4_data = { + .mode = &ws_panel_3_4_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + /* 4.0inch 480x800 * https://www.waveshare.com/product/raspberry-pi/displays/4inch-dsi-lcd.htm */ @@ -77,6 +95,12 @@ static const struct drm_display_mode ws_panel_4_0_mode = { .vtotal = 800 + 20 + 100 + 20, }; +static const struct ws_panel_data ws_panel_4_0_data = { + .mode = &ws_panel_4_0_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + /* 7.0inch C 1024x600 * https://www.waveshare.com/product/raspberry-pi/displays/lcd-oled/7inch-dsi-lcd-c-with-case-a.htm */ @@ -92,6 +116,12 @@ static const struct drm_display_mode ws_panel_7_0_c_mode = { .vtotal = 600 + 10 + 10 + 10, }; +static const struct ws_panel_data ws_panel_7_0_c_data = { + .mode = &ws_panel_7_0_c_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + /* 7.9inch 400x1280 * https://www.waveshare.com/product/raspberry-pi/displays/7.9inch-dsi-lcd.htm */ @@ -107,6 +137,12 @@ static const struct drm_display_mode ws_panel_7_9_mode = { .vtotal = 1280 + 20 + 10 + 20, }; +static const struct ws_panel_data ws_panel_7_9_data = { + .mode = &ws_panel_7_9_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + /* 8.0inch or 10.1inch 1280x800 * https://www.waveshare.com/product/raspberry-pi/displays/8inch-dsi-lcd-c.htm * https://www.waveshare.com/product/raspberry-pi/displays/10.1inch-dsi-lcd-c.htm @@ -123,6 +159,12 @@ static const struct drm_display_mode ws_panel_10_1_mode = { .vtotal = 800 + 40 + 48 + 40, }; +static const struct ws_panel_data ws_panel_10_1_data = { + .mode = &ws_panel_10_1_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + /* 11.9inch 320x1480 * https://www.waveshare.com/product/raspberry-pi/displays/11.9inch-dsi-lcd.htm */ @@ -138,6 +180,12 @@ static const struct drm_display_mode ws_panel_11_9_mode = { .vtotal = 1480 + 60 + 60 + 60, }; +static const struct ws_panel_data ws_panel_11_9_data = { + .mode = &ws_panel_11_9_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + static const struct drm_display_mode ws_panel_4_mode = { .clock = 50000, .hdisplay = 720, @@ -150,6 +198,12 @@ static const struct drm_display_mode ws_panel_4_mode = { .vtotal = 720 + 8 + 4 + 16, }; +static const struct ws_panel_data ws_panel_4_data = { + .mode = &ws_panel_4_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + /* 5.0inch 720x1280 * https://www.waveshare.com/5inch-dsi-lcd-d.htm */ @@ -165,6 +219,12 @@ static const struct drm_display_mode ws_panel_5_0_mode = { .vtotal = 1280 + 20 + 20 + 20, }; +static const struct ws_panel_data ws_panel_5_0_data = { + .mode = &ws_panel_5_0_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + /* 6.25inch 720x1560 * https://www.waveshare.com/6.25inch-dsi-lcd.htm */ @@ -180,6 +240,12 @@ static const struct drm_display_mode ws_panel_6_25_mode = { .vtotal = 1560 + 20 + 20 + 20, }; +static const struct ws_panel_data ws_panel_6_25_data = { + .mode = &ws_panel_6_25_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + /* 8.8inch 480x1920 * https://www.waveshare.com/8.8inch-dsi-lcd.htm */ @@ -195,6 +261,48 @@ static const struct drm_display_mode ws_panel_8_8_mode = { .vtotal = 1920 + 20 + 20 + 20, }; +static const struct ws_panel_data ws_panel_8_8_data = { + .mode = &ws_panel_8_8_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + +static const struct drm_display_mode ws_panel_13_3_4lane_mode = { + .clock = 148500, + .hdisplay = 1920, + .hsync_start = 1920 + 88, + .hsync_end = 1920 + 88 + 44, + .htotal = 1920 + 88 + 44 + 148, + .vdisplay = 1080, + .vsync_start = 1080 + 4, + .vsync_end = 1080 + 4 + 5, + .vtotal = 1080 + 4 + 5 + 36, +}; + +static const struct ws_panel_data ws_panel_13_3_4lane_data = { + .mode = &ws_panel_13_3_4lane_mode, + .lanes = 4, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM, +}; + +static const struct drm_display_mode ws_panel_13_3_2lane_mode = { + .clock = 83333, + .hdisplay = 1920, + .hsync_start = 1920 + 88, + .hsync_end = 1920 + 88 + 44, + .htotal = 1920 + 88 + 44 + 148, + .vdisplay = 1080, + .vsync_start = 1080 + 4, + .vsync_end = 1080 + 4 + 5, + .vtotal = 1080 + 4 + 5 + 36, +}; + +static const struct ws_panel_data ws_panel_13_3_2lane_data = { + .mode = &ws_panel_13_3_2lane_mode, + .lanes = 2, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM, +}; + static struct ws_panel *panel_to_ts(struct drm_panel *panel) { return container_of(panel, struct ws_panel, base); @@ -232,7 +340,10 @@ static int ws_panel_enable(struct drm_panel *panel) { struct ws_panel *ts = panel_to_ts(panel); - ws_panel_i2c_write(ts, 0xad, 0x01); + if (ts->mode == &ws_panel_13_3_2lane_mode) + ws_panel_i2c_write(ts, 0xad, 0x02); + else + ws_panel_i2c_write(ts, 0xad, 0x01); return 0; } @@ -328,13 +439,18 @@ static int ws_panel_probe(struct i2c_client *i2c) .channel = 0, .node = NULL, }; + const struct ws_panel_data *_ws_panel_data; int ret; ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); if (!ts) return -ENOMEM; - ts->mode = of_device_get_match_data(dev); + _ws_panel_data = of_device_get_match_data(dev); + if (!_ws_panel_data) + return -EINVAL; + + ts->mode = _ws_panel_data->mode; if (!ts->mode) return -EINVAL; @@ -396,10 +512,9 @@ static int ws_panel_probe(struct i2c_client *i2c) */ drm_panel_add(&ts->base); - ts->dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | - MIPI_DSI_CLOCK_NON_CONTINUOUS; + ts->dsi->mode_flags = _ws_panel_data->mode_flags; ts->dsi->format = MIPI_DSI_FMT_RGB888; - ts->dsi->lanes = 2; + ts->dsi->lanes = _ws_panel_data->lanes; ret = devm_mipi_dsi_attach(dev, ts->dsi); @@ -432,40 +547,46 @@ static void ws_panel_shutdown(struct i2c_client *i2c) static const struct of_device_id ws_panel_of_ids[] = { { .compatible = "waveshare,2.8inch-panel", - .data = &ws_panel_2_8_mode, + .data = &ws_panel_2_8_data, }, { .compatible = "waveshare,3.4inch-panel", - .data = &ws_panel_3_4_mode, + .data = &ws_panel_3_4_data, }, { .compatible = "waveshare,4.0inch-panel", - .data = &ws_panel_4_0_mode, + .data = &ws_panel_4_0_data, }, { .compatible = "waveshare,7.0inch-c-panel", - .data = &ws_panel_7_0_c_mode, + .data = &ws_panel_7_0_c_data, }, { .compatible = "waveshare,7.9inch-panel", - .data = &ws_panel_7_9_mode, + .data = &ws_panel_7_9_data, }, { .compatible = "waveshare,8.0inch-panel", - .data = &ws_panel_10_1_mode, + .data = &ws_panel_10_1_data, }, { .compatible = "waveshare,10.1inch-panel", - .data = &ws_panel_10_1_mode, + .data = &ws_panel_10_1_data, }, { .compatible = "waveshare,11.9inch-panel", - .data = &ws_panel_11_9_mode, + .data = &ws_panel_11_9_data, }, { .compatible = "waveshare,4inch-panel", - .data = &ws_panel_4_mode, + .data = &ws_panel_4_data, }, { .compatible = "waveshare,5.0inch-panel", - .data = &ws_panel_5_0_mode, + .data = &ws_panel_5_0_data, }, { .compatible = "waveshare,6.25inch-panel", - .data = &ws_panel_6_25_mode, + .data = &ws_panel_6_25_data, }, { .compatible = "waveshare,8.8inch-panel", - .data = &ws_panel_8_8_mode, + .data = &ws_panel_8_8_data, + }, { + .compatible = "waveshare,13.3inch-4lane-panel", + .data = &ws_panel_13_3_4lane_data, + }, { + .compatible = "waveshare,13.3inch-2lane-panel", + .data = &ws_panel_13_3_2lane_data, }, { /* sentinel */ } diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 6a77babcf7228e..654c1bafaf4b7d 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -67,6 +67,8 @@ struct ili210x { u8 version_proto[2]; u8 ic_mode[2]; bool stop; + struct timer_list poll_timer; + struct work_struct poll_work; }; static int ili210x_read_reg(struct i2c_client *client, @@ -360,6 +362,34 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data) return IRQ_HANDLED; } +static void ili210x_poll_work(struct work_struct *work) +{ + struct ili210x *priv = container_of(work, struct ili210x, poll_work); + struct i2c_client *client = priv->client; + const struct ili2xxx_chip *chip = priv->chip; + u8 touchdata[ILI210X_DATA_SIZE] = { 0 }; + bool touch; + int error; + + error = chip->get_touch_data(client, touchdata); + if (error) { + dev_err(&client->dev, "Unable to get touch data: %d\n", error); + return; + } + + touch = ili210x_report_events(priv, touchdata); +} + +static void ili210x_poll_timer_callback(struct timer_list *t) +{ + struct ili210x *priv = from_timer(priv, t, poll_timer); + + schedule_work(&priv->poll_work); + + if (!priv->stop) + mod_timer(&priv->poll_timer, jiffies + msecs_to_jiffies(ILI2XXX_POLL_PERIOD)); +} + static int ili251x_firmware_update_resolution(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -945,11 +975,6 @@ static int ili210x_i2c_probe(struct i2c_client *client) return -ENODEV; } - if (client->irq <= 0) { - dev_err(dev, "No IRQ!\n"); - return -EINVAL; - } - reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(reset_gpio)) return PTR_ERR(reset_gpio); @@ -1001,12 +1026,17 @@ static int ili210x_i2c_probe(struct i2c_client *client) return error; } - error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq, - IRQF_ONESHOT, client->name, priv); - if (error) { - dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", - error); - return error; + if (client->irq) { + error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq, + IRQF_ONESHOT, client->name, priv); + if (error) { + dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", error); + return error; + } + } else { + timer_setup(&priv->poll_timer, ili210x_poll_timer_callback, 0); + mod_timer(&priv->poll_timer, jiffies + msecs_to_jiffies(ILI2XXX_POLL_PERIOD)); + INIT_WORK(&priv->poll_work, ili210x_poll_work); } error = devm_add_action_or_reset(dev, ili210x_stop, priv); @@ -1029,6 +1059,16 @@ static int ili210x_i2c_probe(struct i2c_client *client) return 0; } +static void ili210x_i2c_remove(struct i2c_client *client) +{ + struct ili210x *tsdata = i2c_get_clientdata(client); + + if (!client->irq) { + del_timer(&tsdata->poll_timer); + cancel_work_sync(&tsdata->poll_work); + } +} + static const struct i2c_device_id ili210x_i2c_id[] = { { "ili210x", (long)&ili210x_chip }, { "ili2117", (long)&ili211x_chip }, @@ -1054,6 +1094,7 @@ static struct i2c_driver ili210x_ts_driver = { }, .id_table = ili210x_i2c_id, .probe = ili210x_i2c_probe, + .remove = ili210x_i2c_remove, }; module_i2c_driver(ili210x_ts_driver);