Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2020 Marek Vasut <marex@denx.de>
0004  *
0005  * Based on tc358764.c by
0006  *  Andrzej Hajda <a.hajda@samsung.com>
0007  *  Maciej Purski <m.purski@samsung.com>
0008  *
0009  * Based on rpi_touchscreen.c by
0010  *  Eric Anholt <eric@anholt.net>
0011  */
0012 
0013 #include <linux/delay.h>
0014 #include <linux/module.h>
0015 #include <linux/of_graph.h>
0016 #include <linux/regulator/consumer.h>
0017 
0018 #include <video/mipi_display.h>
0019 
0020 #include <drm/drm_atomic_helper.h>
0021 #include <drm/drm_crtc.h>
0022 #include <drm/drm_fb_helper.h>
0023 #include <drm/drm_mipi_dsi.h>
0024 #include <drm/drm_of.h>
0025 #include <drm/drm_panel.h>
0026 #include <drm/drm_print.h>
0027 #include <drm/drm_probe_helper.h>
0028 
0029 /* PPI layer registers */
0030 #define PPI_STARTPPI        0x0104 /* START control bit */
0031 #define PPI_LPTXTIMECNT     0x0114 /* LPTX timing signal */
0032 #define PPI_D0S_ATMR        0x0144
0033 #define PPI_D1S_ATMR        0x0148
0034 #define PPI_D0S_CLRSIPOCOUNT    0x0164 /* Assertion timer for Lane 0 */
0035 #define PPI_D1S_CLRSIPOCOUNT    0x0168 /* Assertion timer for Lane 1 */
0036 #define PPI_START_FUNCTION  1
0037 
0038 /* DSI layer registers */
0039 #define DSI_STARTDSI        0x0204 /* START control bit of DSI-TX */
0040 #define DSI_LANEENABLE      0x0210 /* Enables each lane */
0041 #define DSI_RX_START        1
0042 
0043 /* LCDC/DPI Host Registers */
0044 #define LCDCTRL         0x0420
0045 
0046 /* SPI Master Registers */
0047 #define SPICMR          0x0450
0048 #define SPITCR          0x0454
0049 
0050 /* System Controller Registers */
0051 #define SYSCTRL         0x0464
0052 
0053 /* System registers */
0054 #define LPX_PERIOD      3
0055 
0056 /* Lane enable PPI and DSI register bits */
0057 #define LANEENABLE_CLEN     BIT(0)
0058 #define LANEENABLE_L0EN     BIT(1)
0059 #define LANEENABLE_L1EN     BIT(2)
0060 
0061 struct tc358762 {
0062     struct device *dev;
0063     struct drm_bridge bridge;
0064     struct regulator *regulator;
0065     struct drm_bridge *panel_bridge;
0066     bool pre_enabled;
0067     int error;
0068 };
0069 
0070 static int tc358762_clear_error(struct tc358762 *ctx)
0071 {
0072     int ret = ctx->error;
0073 
0074     ctx->error = 0;
0075     return ret;
0076 }
0077 
0078 static void tc358762_write(struct tc358762 *ctx, u16 addr, u32 val)
0079 {
0080     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0081     ssize_t ret;
0082     u8 data[6];
0083 
0084     if (ctx->error)
0085         return;
0086 
0087     data[0] = addr;
0088     data[1] = addr >> 8;
0089     data[2] = val;
0090     data[3] = val >> 8;
0091     data[4] = val >> 16;
0092     data[5] = val >> 24;
0093 
0094     ret = mipi_dsi_generic_write(dsi, data, sizeof(data));
0095     if (ret < 0)
0096         ctx->error = ret;
0097 }
0098 
0099 static inline struct tc358762 *bridge_to_tc358762(struct drm_bridge *bridge)
0100 {
0101     return container_of(bridge, struct tc358762, bridge);
0102 }
0103 
0104 static int tc358762_init(struct tc358762 *ctx)
0105 {
0106     tc358762_write(ctx, DSI_LANEENABLE,
0107                LANEENABLE_L0EN | LANEENABLE_CLEN);
0108     tc358762_write(ctx, PPI_D0S_CLRSIPOCOUNT, 5);
0109     tc358762_write(ctx, PPI_D1S_CLRSIPOCOUNT, 5);
0110     tc358762_write(ctx, PPI_D0S_ATMR, 0);
0111     tc358762_write(ctx, PPI_D1S_ATMR, 0);
0112     tc358762_write(ctx, PPI_LPTXTIMECNT, LPX_PERIOD);
0113 
0114     tc358762_write(ctx, SPICMR, 0x00);
0115     tc358762_write(ctx, LCDCTRL, 0x00100150);
0116     tc358762_write(ctx, SYSCTRL, 0x040f);
0117     msleep(100);
0118 
0119     tc358762_write(ctx, PPI_STARTPPI, PPI_START_FUNCTION);
0120     tc358762_write(ctx, DSI_STARTDSI, DSI_RX_START);
0121 
0122     msleep(100);
0123 
0124     return tc358762_clear_error(ctx);
0125 }
0126 
0127 static void tc358762_post_disable(struct drm_bridge *bridge)
0128 {
0129     struct tc358762 *ctx = bridge_to_tc358762(bridge);
0130     int ret;
0131 
0132     /*
0133      * The post_disable hook might be called multiple times.
0134      * We want to avoid regulator imbalance below.
0135      */
0136     if (!ctx->pre_enabled)
0137         return;
0138 
0139     ctx->pre_enabled = false;
0140 
0141     ret = regulator_disable(ctx->regulator);
0142     if (ret < 0)
0143         dev_err(ctx->dev, "error disabling regulators (%d)\n", ret);
0144 }
0145 
0146 static void tc358762_pre_enable(struct drm_bridge *bridge)
0147 {
0148     struct tc358762 *ctx = bridge_to_tc358762(bridge);
0149     int ret;
0150 
0151     ret = regulator_enable(ctx->regulator);
0152     if (ret < 0)
0153         dev_err(ctx->dev, "error enabling regulators (%d)\n", ret);
0154 
0155     ret = tc358762_init(ctx);
0156     if (ret < 0)
0157         dev_err(ctx->dev, "error initializing bridge (%d)\n", ret);
0158 
0159     ctx->pre_enabled = true;
0160 }
0161 
0162 static int tc358762_attach(struct drm_bridge *bridge,
0163                enum drm_bridge_attach_flags flags)
0164 {
0165     struct tc358762 *ctx = bridge_to_tc358762(bridge);
0166 
0167     return drm_bridge_attach(bridge->encoder, ctx->panel_bridge,
0168                  bridge, flags);
0169 }
0170 
0171 static const struct drm_bridge_funcs tc358762_bridge_funcs = {
0172     .post_disable = tc358762_post_disable,
0173     .pre_enable = tc358762_pre_enable,
0174     .attach = tc358762_attach,
0175 };
0176 
0177 static int tc358762_parse_dt(struct tc358762 *ctx)
0178 {
0179     struct drm_bridge *panel_bridge;
0180     struct device *dev = ctx->dev;
0181 
0182     panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
0183     if (IS_ERR(panel_bridge))
0184         return PTR_ERR(panel_bridge);
0185 
0186     ctx->panel_bridge = panel_bridge;
0187 
0188     return 0;
0189 }
0190 
0191 static int tc358762_configure_regulators(struct tc358762 *ctx)
0192 {
0193     ctx->regulator = devm_regulator_get(ctx->dev, "vddc");
0194     if (IS_ERR(ctx->regulator))
0195         return PTR_ERR(ctx->regulator);
0196 
0197     return 0;
0198 }
0199 
0200 static int tc358762_probe(struct mipi_dsi_device *dsi)
0201 {
0202     struct device *dev = &dsi->dev;
0203     struct tc358762 *ctx;
0204     int ret;
0205 
0206     ctx = devm_kzalloc(dev, sizeof(struct tc358762), GFP_KERNEL);
0207     if (!ctx)
0208         return -ENOMEM;
0209 
0210     mipi_dsi_set_drvdata(dsi, ctx);
0211 
0212     ctx->dev = dev;
0213     ctx->pre_enabled = false;
0214 
0215     /* TODO: Find out how to get dual-lane mode working */
0216     dsi->lanes = 1;
0217     dsi->format = MIPI_DSI_FMT_RGB888;
0218     dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
0219               MIPI_DSI_MODE_LPM;
0220 
0221     ret = tc358762_parse_dt(ctx);
0222     if (ret < 0)
0223         return ret;
0224 
0225     ret = tc358762_configure_regulators(ctx);
0226     if (ret < 0)
0227         return ret;
0228 
0229     ctx->bridge.funcs = &tc358762_bridge_funcs;
0230     ctx->bridge.type = DRM_MODE_CONNECTOR_DPI;
0231     ctx->bridge.of_node = dev->of_node;
0232 
0233     drm_bridge_add(&ctx->bridge);
0234 
0235     ret = mipi_dsi_attach(dsi);
0236     if (ret < 0) {
0237         drm_bridge_remove(&ctx->bridge);
0238         dev_err(dev, "failed to attach dsi\n");
0239     }
0240 
0241     return ret;
0242 }
0243 
0244 static int tc358762_remove(struct mipi_dsi_device *dsi)
0245 {
0246     struct tc358762 *ctx = mipi_dsi_get_drvdata(dsi);
0247 
0248     mipi_dsi_detach(dsi);
0249     drm_bridge_remove(&ctx->bridge);
0250 
0251     return 0;
0252 }
0253 
0254 static const struct of_device_id tc358762_of_match[] = {
0255     { .compatible = "toshiba,tc358762" },
0256     { }
0257 };
0258 MODULE_DEVICE_TABLE(of, tc358762_of_match);
0259 
0260 static struct mipi_dsi_driver tc358762_driver = {
0261     .probe = tc358762_probe,
0262     .remove = tc358762_remove,
0263     .driver = {
0264         .name = "tc358762",
0265         .of_match_table = tc358762_of_match,
0266     },
0267 };
0268 module_mipi_dsi_driver(tc358762_driver);
0269 
0270 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
0271 MODULE_DESCRIPTION("MIPI-DSI based Driver for TC358762 DSI/DPI Bridge");
0272 MODULE_LICENSE("GPL v2");