brintos

brintos / linux-shallow public Read only

0
0
Text · 10.6 KiB · b1ce186 Raw
477 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2016 InforceComputing4 * Author: Vinay Simha BN <simhavcs@gmail.com>5 *6 * Copyright (C) 2016 Linaro Ltd7 * Author: Sumit Semwal <sumit.semwal@linaro.org>8 */9 10#include <linux/backlight.h>11#include <linux/delay.h>12#include <linux/gpio/consumer.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/regulator/consumer.h>16 17#include <video/mipi_display.h>18 19#include <drm/drm_crtc.h>20#include <drm/drm_mipi_dsi.h>21#include <drm/drm_modes.h>22#include <drm/drm_panel.h>23 24static const char * const regulator_names[] = {25	"vddp",26	"iovcc"27};28 29struct jdi_panel {30	struct drm_panel base;31	struct mipi_dsi_device *dsi;32 33	struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];34 35	struct gpio_desc *enable_gpio;36	struct gpio_desc *reset_gpio;37	struct gpio_desc *dcdc_en_gpio;38	struct backlight_device *backlight;39 40	const struct drm_display_mode *mode;41};42 43static inline struct jdi_panel *to_jdi_panel(struct drm_panel *panel)44{45	return container_of(panel, struct jdi_panel, base);46}47 48static int jdi_panel_init(struct jdi_panel *jdi)49{50	struct mipi_dsi_device *dsi = jdi->dsi;51	struct device *dev = &jdi->dsi->dev;52	int ret;53 54	dsi->mode_flags |= MIPI_DSI_MODE_LPM;55 56	ret = mipi_dsi_dcs_soft_reset(dsi);57	if (ret < 0)58		return ret;59 60	usleep_range(10000, 20000);61 62	ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);63	if (ret < 0) {64		dev_err(dev, "failed to set pixel format: %d\n", ret);65		return ret;66	}67 68	ret = mipi_dsi_dcs_set_column_address(dsi, 0, jdi->mode->hdisplay - 1);69	if (ret < 0) {70		dev_err(dev, "failed to set column address: %d\n", ret);71		return ret;72	}73 74	ret = mipi_dsi_dcs_set_page_address(dsi, 0, jdi->mode->vdisplay - 1);75	if (ret < 0) {76		dev_err(dev, "failed to set page address: %d\n", ret);77		return ret;78	}79 80	/*81	 * BIT(5) BCTRL = 1 Backlight Control Block On, Brightness registers82	 *                  are active83	 * BIT(3) BL = 1    Backlight Control On84	 * BIT(2) DD = 0    Display Dimming is Off85	 */86	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,87				 (u8[]){ 0x24 }, 1);88	if (ret < 0) {89		dev_err(dev, "failed to write control display: %d\n", ret);90		return ret;91	}92 93	/* CABC off */94	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE,95				 (u8[]){ 0x00 }, 1);96	if (ret < 0) {97		dev_err(dev, "failed to set cabc off: %d\n", ret);98		return ret;99	}100 101	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);102	if (ret < 0) {103		dev_err(dev, "failed to set exit sleep mode: %d\n", ret);104		return ret;105	}106 107	msleep(120);108 109	ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x00}, 2);110	if (ret < 0) {111		dev_err(dev, "failed to set mcap: %d\n", ret);112		return ret;113	}114 115	mdelay(10);116 117	/* Interface setting, video mode */118	ret = mipi_dsi_generic_write(dsi, (u8[])119				     {0xB3, 0x26, 0x08, 0x00, 0x20, 0x00}, 6);120	if (ret < 0) {121		dev_err(dev, "failed to set display interface setting: %d\n"122			, ret);123		return ret;124	}125 126	mdelay(20);127 128	ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x03}, 2);129	if (ret < 0) {130		dev_err(dev, "failed to set default values for mcap: %d\n"131			, ret);132		return ret;133	}134 135	return 0;136}137 138static int jdi_panel_on(struct jdi_panel *jdi)139{140	struct mipi_dsi_device *dsi = jdi->dsi;141	struct device *dev = &jdi->dsi->dev;142	int ret;143 144	dsi->mode_flags |= MIPI_DSI_MODE_LPM;145 146	ret = mipi_dsi_dcs_set_display_on(dsi);147	if (ret < 0)148		dev_err(dev, "failed to set display on: %d\n", ret);149 150	return ret;151}152 153static void jdi_panel_off(struct jdi_panel *jdi)154{155	struct mipi_dsi_device *dsi = jdi->dsi;156	struct device *dev = &jdi->dsi->dev;157	int ret;158 159	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;160 161	ret = mipi_dsi_dcs_set_display_off(dsi);162	if (ret < 0)163		dev_err(dev, "failed to set display off: %d\n", ret);164 165	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);166	if (ret < 0)167		dev_err(dev, "failed to enter sleep mode: %d\n", ret);168 169	msleep(100);170}171 172static int jdi_panel_disable(struct drm_panel *panel)173{174	struct jdi_panel *jdi = to_jdi_panel(panel);175 176	backlight_disable(jdi->backlight);177 178	return 0;179}180 181static int jdi_panel_unprepare(struct drm_panel *panel)182{183	struct jdi_panel *jdi = to_jdi_panel(panel);184	struct device *dev = &jdi->dsi->dev;185	int ret;186 187	jdi_panel_off(jdi);188 189	ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);190	if (ret < 0)191		dev_err(dev, "regulator disable failed, %d\n", ret);192 193	gpiod_set_value(jdi->enable_gpio, 0);194 195	gpiod_set_value(jdi->reset_gpio, 1);196 197	gpiod_set_value(jdi->dcdc_en_gpio, 0);198 199	return 0;200}201 202static int jdi_panel_prepare(struct drm_panel *panel)203{204	struct jdi_panel *jdi = to_jdi_panel(panel);205	struct device *dev = &jdi->dsi->dev;206	int ret;207 208	ret = regulator_bulk_enable(ARRAY_SIZE(jdi->supplies), jdi->supplies);209	if (ret < 0) {210		dev_err(dev, "regulator enable failed, %d\n", ret);211		return ret;212	}213 214	msleep(20);215 216	gpiod_set_value(jdi->dcdc_en_gpio, 1);217	usleep_range(10, 20);218 219	gpiod_set_value(jdi->reset_gpio, 0);220	usleep_range(10, 20);221 222	gpiod_set_value(jdi->enable_gpio, 1);223	usleep_range(10, 20);224 225	ret = jdi_panel_init(jdi);226	if (ret < 0) {227		dev_err(dev, "failed to init panel: %d\n", ret);228		goto poweroff;229	}230 231	ret = jdi_panel_on(jdi);232	if (ret < 0) {233		dev_err(dev, "failed to set panel on: %d\n", ret);234		goto poweroff;235	}236 237	return 0;238 239poweroff:240	ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);241	if (ret < 0)242		dev_err(dev, "regulator disable failed, %d\n", ret);243 244	gpiod_set_value(jdi->enable_gpio, 0);245 246	gpiod_set_value(jdi->reset_gpio, 1);247 248	gpiod_set_value(jdi->dcdc_en_gpio, 0);249 250	return ret;251}252 253static int jdi_panel_enable(struct drm_panel *panel)254{255	struct jdi_panel *jdi = to_jdi_panel(panel);256 257	backlight_enable(jdi->backlight);258 259	return 0;260}261 262static const struct drm_display_mode default_mode = {263		.clock = 155493,264		.hdisplay = 1200,265		.hsync_start = 1200 + 48,266		.hsync_end = 1200 + 48 + 32,267		.htotal = 1200 + 48 + 32 + 60,268		.vdisplay = 1920,269		.vsync_start = 1920 + 3,270		.vsync_end = 1920 + 3 + 5,271		.vtotal = 1920 + 3 + 5 + 6,272		.flags = 0,273};274 275static int jdi_panel_get_modes(struct drm_panel *panel,276			       struct drm_connector *connector)277{278	struct drm_display_mode *mode;279	struct jdi_panel *jdi = to_jdi_panel(panel);280	struct device *dev = &jdi->dsi->dev;281 282	mode = drm_mode_duplicate(connector->dev, &default_mode);283	if (!mode) {284		dev_err(dev, "failed to add mode %ux%ux@%u\n",285			default_mode.hdisplay, default_mode.vdisplay,286			drm_mode_vrefresh(&default_mode));287		return -ENOMEM;288	}289 290	drm_mode_set_name(mode);291 292	drm_mode_probed_add(connector, mode);293 294	connector->display_info.width_mm = 95;295	connector->display_info.height_mm = 151;296 297	return 1;298}299 300static int dsi_dcs_bl_get_brightness(struct backlight_device *bl)301{302	struct mipi_dsi_device *dsi = bl_get_data(bl);303	int ret;304	u16 brightness = bl->props.brightness;305 306	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;307 308	ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);309	if (ret < 0)310		return ret;311 312	dsi->mode_flags |= MIPI_DSI_MODE_LPM;313 314	return brightness & 0xff;315}316 317static int dsi_dcs_bl_update_status(struct backlight_device *bl)318{319	struct mipi_dsi_device *dsi = bl_get_data(bl);320	int ret;321 322	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;323 324	ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);325	if (ret < 0)326		return ret;327 328	dsi->mode_flags |= MIPI_DSI_MODE_LPM;329 330	return 0;331}332 333static const struct backlight_ops dsi_bl_ops = {334	.update_status = dsi_dcs_bl_update_status,335	.get_brightness = dsi_dcs_bl_get_brightness,336};337 338static struct backlight_device *339drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi)340{341	struct device *dev = &dsi->dev;342	struct backlight_properties props;343 344	memset(&props, 0, sizeof(props));345	props.type = BACKLIGHT_RAW;346	props.brightness = 255;347	props.max_brightness = 255;348 349	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,350					      &dsi_bl_ops, &props);351}352 353static const struct drm_panel_funcs jdi_panel_funcs = {354	.disable = jdi_panel_disable,355	.unprepare = jdi_panel_unprepare,356	.prepare = jdi_panel_prepare,357	.enable = jdi_panel_enable,358	.get_modes = jdi_panel_get_modes,359};360 361static const struct of_device_id jdi_of_match[] = {362	{ .compatible = "jdi,lt070me05000", },363	{ }364};365MODULE_DEVICE_TABLE(of, jdi_of_match);366 367static int jdi_panel_add(struct jdi_panel *jdi)368{369	struct device *dev = &jdi->dsi->dev;370	int ret;371	unsigned int i;372 373	jdi->mode = &default_mode;374 375	for (i = 0; i < ARRAY_SIZE(jdi->supplies); i++)376		jdi->supplies[i].supply = regulator_names[i];377 378	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(jdi->supplies),379				      jdi->supplies);380	if (ret < 0)381		return dev_err_probe(dev, ret,382				     "failed to init regulator, ret=%d\n", ret);383 384	jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);385	if (IS_ERR(jdi->enable_gpio)) {386		return dev_err_probe(dev, PTR_ERR(jdi->enable_gpio),387				     "cannot get enable-gpio %d\n", ret);388	}389 390	jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);391	if (IS_ERR(jdi->reset_gpio))392		return dev_err_probe(dev, PTR_ERR(jdi->reset_gpio),393				     "cannot get reset-gpios %d\n", ret);394 395	jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW);396	if (IS_ERR(jdi->dcdc_en_gpio))397		return dev_err_probe(dev, PTR_ERR(jdi->dcdc_en_gpio),398				     "cannot get dcdc-en-gpio %d\n", ret);399 400	jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi);401	if (IS_ERR(jdi->backlight))402		return dev_err_probe(dev, PTR_ERR(jdi->backlight),403				     "failed to register backlight %d\n", ret);404 405	drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs,406		       DRM_MODE_CONNECTOR_DSI);407 408	drm_panel_add(&jdi->base);409 410	return 0;411}412 413static void jdi_panel_del(struct jdi_panel *jdi)414{415	if (jdi->base.dev)416		drm_panel_remove(&jdi->base);417}418 419static int jdi_panel_probe(struct mipi_dsi_device *dsi)420{421	struct jdi_panel *jdi;422	int ret;423 424	dsi->lanes = 4;425	dsi->format = MIPI_DSI_FMT_RGB888;426	dsi->mode_flags =  MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |427			   MIPI_DSI_CLOCK_NON_CONTINUOUS;428 429	jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL);430	if (!jdi)431		return -ENOMEM;432 433	mipi_dsi_set_drvdata(dsi, jdi);434 435	jdi->dsi = dsi;436 437	ret = jdi_panel_add(jdi);438	if (ret < 0)439		return ret;440 441	ret = mipi_dsi_attach(dsi);442	if (ret < 0) {443		jdi_panel_del(jdi);444		return ret;445	}446 447	return 0;448}449 450static void jdi_panel_remove(struct mipi_dsi_device *dsi)451{452	struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);453	int ret;454 455	ret = mipi_dsi_detach(dsi);456	if (ret < 0)457		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",458			ret);459 460	jdi_panel_del(jdi);461}462 463static struct mipi_dsi_driver jdi_panel_driver = {464	.driver = {465		.name = "panel-jdi-lt070me05000",466		.of_match_table = jdi_of_match,467	},468	.probe = jdi_panel_probe,469	.remove = jdi_panel_remove,470};471module_mipi_dsi_driver(jdi_panel_driver);472 473MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");474MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");475MODULE_DESCRIPTION("JDI LT070ME05000 WUXGA");476MODULE_LICENSE("GPL v2");477