1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Ilitek ILI9806E core driver. 4 * 5 * Copyright (c) 2026 Amarula Solutions, Dario Binacchi <dario.binacchi@amarulasolutions.com> 6 */ 7 8 #include <drm/drm_panel.h> 9 10 #include <linux/delay.h> 11 #include <linux/export.h> 12 #include <linux/gpio/consumer.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/property.h> 16 #include <linux/regulator/consumer.h> 17 18 #include "panel-ilitek-ili9806e-core.h" 19 20 struct ili9806e { 21 void *transport; 22 struct drm_panel panel; 23 24 unsigned int num_supplies; 25 struct regulator_bulk_data supplies[2]; 26 struct gpio_desc *reset_gpio; 27 }; 28 29 void *ili9806e_get_transport(struct drm_panel *panel) 30 { 31 struct ili9806e *ctx = container_of(panel, struct ili9806e, panel); 32 33 return ctx->transport; 34 } 35 EXPORT_SYMBOL_GPL(ili9806e_get_transport); 36 37 int ili9806e_power_on(struct device *dev) 38 { 39 struct ili9806e *ctx = dev_get_drvdata(dev); 40 int ret; 41 42 gpiod_set_value(ctx->reset_gpio, 1); 43 44 ret = regulator_bulk_enable(ctx->num_supplies, ctx->supplies); 45 if (ret) { 46 dev_err(dev, "regulator bulk enable failed: %d\n", ret); 47 return ret; 48 } 49 50 usleep_range(10000, 20000); 51 gpiod_set_value(ctx->reset_gpio, 0); 52 usleep_range(10000, 20000); 53 54 return 0; 55 } 56 EXPORT_SYMBOL_GPL(ili9806e_power_on); 57 58 int ili9806e_power_off(struct device *dev) 59 { 60 struct ili9806e *ctx = dev_get_drvdata(dev); 61 int ret; 62 63 gpiod_set_value(ctx->reset_gpio, 1); 64 65 ret = regulator_bulk_disable(ctx->num_supplies, ctx->supplies); 66 if (ret) 67 dev_err(dev, "regulator bulk disable failed: %d\n", ret); 68 69 return ret; 70 } 71 EXPORT_SYMBOL_GPL(ili9806e_power_off); 72 73 int ili9806e_probe(struct device *dev, void *transport, 74 const struct drm_panel_funcs *funcs, 75 int connector_type) 76 { 77 struct ili9806e *ctx; 78 bool set_prepare_prev_first = false; 79 int ret; 80 81 ctx = devm_kzalloc(dev, sizeof(struct ili9806e), GFP_KERNEL); 82 if (!ctx) 83 return -ENOMEM; 84 85 dev_set_drvdata(dev, ctx); 86 ctx->transport = transport; 87 88 ctx->supplies[ctx->num_supplies++].supply = "vdd"; 89 if (of_device_is_compatible(dev->of_node, 90 "densitron,dmt028vghmcmi-1d") || 91 of_device_is_compatible(dev->of_node, 92 "ortustech,com35h3p70ulc")) { 93 ctx->supplies[ctx->num_supplies++].supply = "vccio"; 94 set_prepare_prev_first = true; 95 } 96 97 ret = devm_regulator_bulk_get(dev, ctx->num_supplies, ctx->supplies); 98 if (ret) 99 return dev_err_probe(dev, ret, "failed to get regulators\n"); 100 101 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 102 if (IS_ERR(ctx->reset_gpio)) 103 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 104 "Failed to get reset-gpios\n"); 105 106 drm_panel_init(&ctx->panel, dev, funcs, connector_type); 107 108 ret = drm_panel_of_backlight(&ctx->panel); 109 if (ret) 110 return dev_err_probe(dev, ret, "Failed to get backlight\n"); 111 112 if (set_prepare_prev_first) 113 ctx->panel.prepare_prev_first = true; 114 115 drm_panel_add(&ctx->panel); 116 117 return 0; 118 119 } 120 EXPORT_SYMBOL_GPL(ili9806e_probe); 121 122 void ili9806e_remove(struct device *dev) 123 { 124 struct ili9806e *ctx = dev_get_drvdata(dev); 125 126 drm_panel_remove(&ctx->panel); 127 } 128 EXPORT_SYMBOL_GPL(ili9806e_remove); 129 130 MODULE_AUTHOR("Dario Binacchi <dario.binacchi@amarulasolutions.com>"); 131 MODULE_AUTHOR("Gunnar Dibbern <gunnar.dibbern@lht.dlh.de>"); 132 MODULE_AUTHOR("Michael Walle <mwalle@kernel.org>"); 133 MODULE_DESCRIPTION("Ilitek ILI9806E Controller Driver"); 134 MODULE_LICENSE("GPL"); 135