0001
0002
0003
0004
0005
0006
0007
0008 #include <drm/drm_mipi_dbi.h>
0009 #include <drm/drm_modes.h>
0010 #include <drm/drm_panel.h>
0011
0012 #include <linux/delay.h>
0013 #include <linux/gpio/consumer.h>
0014 #include <linux/init.h>
0015 #include <linux/kernel.h>
0016 #include <linux/media-bus-format.h>
0017 #include <linux/module.h>
0018 #include <linux/of.h>
0019 #include <linux/regulator/consumer.h>
0020 #include <linux/spi/spi.h>
0021
0022 #include <video/mipi_display.h>
0023
0024 #define DB7430_ACCESS_PROT_OFF 0xb0
0025 #define DB7430_UNKNOWN_B4 0xb4
0026 #define DB7430_USER_SELECT 0xb5
0027 #define DB7430_UNKNOWN_B7 0xb7
0028 #define DB7430_UNKNOWN_B8 0xb8
0029 #define DB7430_PANEL_DRIVING 0xc0
0030 #define DB7430_SOURCE_CONTROL 0xc1
0031 #define DB7430_GATE_INTERFACE 0xc4
0032 #define DB7430_DISPLAY_H_TIMING 0xc5
0033 #define DB7430_RGB_SYNC_OPTION 0xc6
0034 #define DB7430_GAMMA_SET_RED 0xc8
0035 #define DB7430_GAMMA_SET_GREEN 0xc9
0036 #define DB7430_GAMMA_SET_BLUE 0xca
0037 #define DB7430_BIAS_CURRENT_CTRL 0xd1
0038 #define DB7430_DDV_CTRL 0xd2
0039 #define DB7430_GAMMA_CTRL_REF 0xd3
0040 #define DB7430_UNKNOWN_D4 0xd4
0041 #define DB7430_DCDC_CTRL 0xd5
0042 #define DB7430_VCL_CTRL 0xd6
0043 #define DB7430_UNKNOWN_F8 0xf8
0044 #define DB7430_UNKNOWN_FC 0xfc
0045
0046 #define DATA_MASK 0x100
0047
0048
0049
0050
0051
0052 struct db7430 {
0053
0054 struct device *dev;
0055
0056 struct mipi_dbi dbi;
0057
0058 struct drm_panel panel;
0059
0060 u32 width;
0061
0062 u32 height;
0063
0064 struct gpio_desc *reset;
0065
0066 struct regulator_bulk_data regulators[2];
0067 };
0068
0069 static const struct drm_display_mode db7430_480_800_mode = {
0070
0071
0072
0073
0074 .clock = 32258,
0075 .hdisplay = 480,
0076 .hsync_start = 480 + 10,
0077 .hsync_end = 480 + 10 + 4,
0078 .htotal = 480 + 10 + 4 + 40,
0079 .vdisplay = 800,
0080 .vsync_start = 800 + 6,
0081 .vsync_end = 800 + 6 + 1,
0082 .vtotal = 800 + 6 + 1 + 7,
0083 .width_mm = 53,
0084 .height_mm = 87,
0085 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
0086 };
0087
0088 static inline struct db7430 *to_db7430(struct drm_panel *panel)
0089 {
0090 return container_of(panel, struct db7430, panel);
0091 }
0092
0093 static int db7430_power_on(struct db7430 *db)
0094 {
0095 struct mipi_dbi *dbi = &db->dbi;
0096 int ret;
0097
0098
0099 ret = regulator_bulk_enable(ARRAY_SIZE(db->regulators),
0100 db->regulators);
0101 if (ret) {
0102 dev_err(db->dev, "failed to enable regulators: %d\n", ret);
0103 return ret;
0104 }
0105 msleep(50);
0106
0107
0108 gpiod_set_value_cansleep(db->reset, 1);
0109 usleep_range(1000, 5000);
0110
0111 gpiod_set_value_cansleep(db->reset, 0);
0112
0113 msleep(10);
0114 dev_dbg(db->dev, "de-asserted RESET\n");
0115
0116
0117
0118
0119
0120
0121
0122 mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, 0x0a);
0123 mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, 0x0a);
0124 mipi_dbi_command(dbi, DB7430_ACCESS_PROT_OFF, 0x00);
0125 mipi_dbi_command(dbi, DB7430_PANEL_DRIVING, 0x28, 0x08);
0126 mipi_dbi_command(dbi, DB7430_SOURCE_CONTROL,
0127 0x01, 0x30, 0x15, 0x05, 0x22);
0128 mipi_dbi_command(dbi, DB7430_GATE_INTERFACE,
0129 0x10, 0x01, 0x00);
0130 mipi_dbi_command(dbi, DB7430_DISPLAY_H_TIMING,
0131 0x06, 0x55, 0x03, 0x07, 0x0b,
0132 0x33, 0x00, 0x01, 0x03);
0133
0134
0135
0136
0137 mipi_dbi_command(dbi, DB7430_RGB_SYNC_OPTION, 0x01);
0138 mipi_dbi_command(dbi, DB7430_GAMMA_SET_RED,
0139 0x00,
0140 0x0A, 0x31, 0x3B, 0x4E, 0x58, 0x59, 0x5B, 0x58, 0x5E, 0x62,
0141 0x60, 0x61, 0x5E, 0x62, 0x55, 0x55, 0x7F, 0x08,
0142 0x00,
0143 0x0A, 0x31, 0x3B, 0x4E, 0x58, 0x59, 0x5B, 0x58, 0x5E, 0x62,
0144 0x60, 0x61, 0x5E, 0x62, 0x55, 0x55, 0x7F, 0x08);
0145 mipi_dbi_command(dbi, DB7430_GAMMA_SET_GREEN,
0146 0x00,
0147 0x25, 0x15, 0x28, 0x3D, 0x4A, 0x48, 0x4C, 0x4A, 0x52, 0x59,
0148 0x59, 0x5B, 0x56, 0x60, 0x5D, 0x55, 0x7F, 0x0A,
0149 0x00,
0150 0x25, 0x15, 0x28, 0x3D, 0x4A, 0x48, 0x4C, 0x4A, 0x52, 0x59,
0151 0x59, 0x5B, 0x56, 0x60, 0x5D, 0x55, 0x7F, 0x0A);
0152 mipi_dbi_command(dbi, DB7430_GAMMA_SET_BLUE,
0153 0x00,
0154 0x48, 0x10, 0x1F, 0x2F, 0x35, 0x38, 0x3D, 0x3C, 0x45, 0x4D,
0155 0x4E, 0x52, 0x51, 0x60, 0x7F, 0x7E, 0x7F, 0x0C,
0156 0x00,
0157 0x48, 0x10, 0x1F, 0x2F, 0x35, 0x38, 0x3D, 0x3C, 0x45, 0x4D,
0158 0x4E, 0x52, 0x51, 0x60, 0x7F, 0x7E, 0x7F, 0x0C);
0159 mipi_dbi_command(dbi, DB7430_BIAS_CURRENT_CTRL, 0x33, 0x13);
0160 mipi_dbi_command(dbi, DB7430_DDV_CTRL, 0x11, 0x00, 0x00);
0161 mipi_dbi_command(dbi, DB7430_GAMMA_CTRL_REF, 0x50, 0x50);
0162 mipi_dbi_command(dbi, DB7430_DCDC_CTRL, 0x2f, 0x11, 0x1e, 0x46);
0163 mipi_dbi_command(dbi, DB7430_VCL_CTRL, 0x11, 0x0a);
0164
0165 return 0;
0166 }
0167
0168 static int db7430_power_off(struct db7430 *db)
0169 {
0170
0171 gpiod_set_value_cansleep(db->reset, 1);
0172 return regulator_bulk_disable(ARRAY_SIZE(db->regulators),
0173 db->regulators);
0174 }
0175
0176 static int db7430_unprepare(struct drm_panel *panel)
0177 {
0178 return db7430_power_off(to_db7430(panel));
0179 }
0180
0181 static int db7430_disable(struct drm_panel *panel)
0182 {
0183 struct db7430 *db = to_db7430(panel);
0184 struct mipi_dbi *dbi = &db->dbi;
0185
0186 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
0187 msleep(25);
0188 mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE);
0189 msleep(120);
0190
0191 return 0;
0192 }
0193
0194 static int db7430_prepare(struct drm_panel *panel)
0195 {
0196 return db7430_power_on(to_db7430(panel));
0197 }
0198
0199 static int db7430_enable(struct drm_panel *panel)
0200 {
0201 struct db7430 *db = to_db7430(panel);
0202 struct mipi_dbi *dbi = &db->dbi;
0203
0204
0205 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
0206 msleep(20);
0207
0208
0209 mipi_dbi_command(dbi, DB7430_UNKNOWN_D4, 0x52, 0x5e);
0210 mipi_dbi_command(dbi, DB7430_UNKNOWN_F8, 0x01, 0xf5, 0xf2, 0x71, 0x44);
0211 mipi_dbi_command(dbi, DB7430_UNKNOWN_FC, 0x00, 0x08);
0212 msleep(150);
0213
0214
0215 mipi_dbi_command(dbi, DB7430_UNKNOWN_B4, 0x0f, 0x00, 0x50);
0216 mipi_dbi_command(dbi, DB7430_USER_SELECT, 0x80);
0217 mipi_dbi_command(dbi, DB7430_UNKNOWN_B7, 0x24);
0218 mipi_dbi_command(dbi, DB7430_UNKNOWN_B8, 0x01);
0219
0220
0221 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
0222
0223 return 0;
0224 }
0225
0226
0227
0228
0229
0230
0231 static int db7430_get_modes(struct drm_panel *panel,
0232 struct drm_connector *connector)
0233 {
0234 struct db7430 *db = to_db7430(panel);
0235 struct drm_display_mode *mode;
0236 static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0237
0238 mode = drm_mode_duplicate(connector->dev, &db7430_480_800_mode);
0239 if (!mode) {
0240 dev_err(db->dev, "failed to add mode\n");
0241 return -ENOMEM;
0242 }
0243
0244 connector->display_info.bpc = 8;
0245 connector->display_info.width_mm = mode->width_mm;
0246 connector->display_info.height_mm = mode->height_mm;
0247 connector->display_info.bus_flags =
0248 DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
0249 drm_display_info_set_bus_formats(&connector->display_info,
0250 &bus_format, 1);
0251
0252 drm_mode_set_name(mode);
0253 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0254
0255 drm_mode_probed_add(connector, mode);
0256
0257 return 1;
0258 }
0259
0260 static const struct drm_panel_funcs db7430_drm_funcs = {
0261 .disable = db7430_disable,
0262 .unprepare = db7430_unprepare,
0263 .prepare = db7430_prepare,
0264 .enable = db7430_enable,
0265 .get_modes = db7430_get_modes,
0266 };
0267
0268 static int db7430_probe(struct spi_device *spi)
0269 {
0270 struct device *dev = &spi->dev;
0271 struct db7430 *db;
0272 int ret;
0273
0274 db = devm_kzalloc(dev, sizeof(*db), GFP_KERNEL);
0275 if (!db)
0276 return -ENOMEM;
0277 db->dev = dev;
0278
0279
0280
0281
0282
0283 db->regulators[0].supply = "vci";
0284 db->regulators[1].supply = "vccio";
0285 ret = devm_regulator_bulk_get(dev,
0286 ARRAY_SIZE(db->regulators),
0287 db->regulators);
0288 if (ret)
0289 return dev_err_probe(dev, ret, "failed to get regulators\n");
0290
0291 db->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
0292 if (IS_ERR(db->reset)) {
0293 ret = PTR_ERR(db->reset);
0294 return dev_err_probe(dev, ret, "no RESET GPIO\n");
0295 }
0296
0297 ret = mipi_dbi_spi_init(spi, &db->dbi, NULL);
0298 if (ret)
0299 return dev_err_probe(dev, ret, "MIPI DBI init failed\n");
0300
0301 drm_panel_init(&db->panel, dev, &db7430_drm_funcs,
0302 DRM_MODE_CONNECTOR_DPI);
0303
0304
0305 ret = drm_panel_of_backlight(&db->panel);
0306 if (ret)
0307 return dev_err_probe(dev, ret, "failed to add backlight\n");
0308
0309 spi_set_drvdata(spi, db);
0310
0311 drm_panel_add(&db->panel);
0312 dev_dbg(dev, "added panel\n");
0313
0314 return 0;
0315 }
0316
0317 static void db7430_remove(struct spi_device *spi)
0318 {
0319 struct db7430 *db = spi_get_drvdata(spi);
0320
0321 drm_panel_remove(&db->panel);
0322 }
0323
0324
0325
0326
0327
0328 static const struct of_device_id db7430_match[] = {
0329 { .compatible = "samsung,lms397kf04", },
0330 {},
0331 };
0332 MODULE_DEVICE_TABLE(of, db7430_match);
0333
0334 static struct spi_driver db7430_driver = {
0335 .probe = db7430_probe,
0336 .remove = db7430_remove,
0337 .driver = {
0338 .name = "db7430-panel",
0339 .of_match_table = db7430_match,
0340 },
0341 };
0342 module_spi_driver(db7430_driver);
0343
0344 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
0345 MODULE_DESCRIPTION("Samsung DB7430 panel driver");
0346 MODULE_LICENSE("GPL v2");