brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · 169c629 Raw
363 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Synaptics R63353 Controller driver4 *5 * Copyright (C) 2020 BSH Hausgerate GmbH6 */7 8#include <linux/delay.h>9#include <linux/device.h>10#include <linux/err.h>11#include <linux/errno.h>12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/media-bus-format.h>16 17#include <linux/gpio/consumer.h>18#include <linux/regulator/consumer.h>19 20#include <drm/drm_mipi_dsi.h>21#include <drm/drm_modes.h>22#include <drm/drm_panel.h>23 24#include <video/mipi_display.h>25 26#define R63353_INSTR(...) { \27		.len = sizeof((u8[]) {__VA_ARGS__}), \28		.data = (u8[]){__VA_ARGS__} \29	}30 31struct r63353_instr {32	size_t len;33	const u8 *data;34};35 36static const struct r63353_instr sharp_ls068b3sx02_init[] = {37	R63353_INSTR(0x51, 0xff),38	R63353_INSTR(0x53, 0x0c),39	R63353_INSTR(0x55, 0x00),40	R63353_INSTR(0x84, 0x00),41	R63353_INSTR(0x29),42};43 44struct r63353_desc {45	const char *name;46	const struct r63353_instr *init;47	const size_t init_length;48	const struct drm_display_mode *mode;49	u32 width_mm;50	u32 height_mm;51};52 53struct r63353_panel {54	struct drm_panel base;55	struct mipi_dsi_device *dsi;56 57	struct gpio_desc *reset_gpio;58	struct regulator *dvdd;59	struct regulator *avdd;60 61	struct r63353_desc *pdata;62};63 64static inline struct r63353_panel *to_r63353_panel(struct drm_panel *panel)65{66	return container_of(panel, struct r63353_panel, base);67}68 69static int r63353_panel_power_on(struct r63353_panel *rpanel)70{71	struct mipi_dsi_device *dsi = rpanel->dsi;72	struct device *dev = &dsi->dev;73	int ret;74 75	ret = regulator_enable(rpanel->avdd);76	if (ret) {77		dev_err(dev, "Failed to enable avdd regulator (%d)\n", ret);78		return ret;79	}80 81	usleep_range(15000, 25000);82 83	ret = regulator_enable(rpanel->dvdd);84	if (ret) {85		dev_err(dev, "Failed to enable dvdd regulator (%d)\n", ret);86		regulator_disable(rpanel->avdd);87		return ret;88	}89 90	usleep_range(300000, 350000);91	gpiod_set_value(rpanel->reset_gpio, 1);92	usleep_range(15000, 25000);93 94	return 0;95}96 97static int r63353_panel_power_off(struct r63353_panel *rpanel)98{99	gpiod_set_value(rpanel->reset_gpio, 0);100	regulator_disable(rpanel->dvdd);101	regulator_disable(rpanel->avdd);102 103	return 0;104}105 106static int r63353_panel_activate(struct r63353_panel *rpanel)107{108	struct mipi_dsi_device *dsi = rpanel->dsi;109	struct device *dev = &dsi->dev;110	int i, ret;111 112	ret = mipi_dsi_dcs_soft_reset(dsi);113	if (ret < 0) {114		dev_err(dev, "Failed to do Software Reset (%d)\n", ret);115		goto fail;116	}117 118	usleep_range(15000, 17000);119 120	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);121	if (ret < 0) {122		dev_err(dev, "Failed to enter sleep mode (%d)\n", ret);123		goto fail;124	}125 126	for (i = 0; i < rpanel->pdata->init_length; i++) {127		const struct r63353_instr *instr = &rpanel->pdata->init[i];128 129		ret = mipi_dsi_dcs_write_buffer(dsi, instr->data, instr->len);130		if (ret < 0)131			goto fail;132	}133 134	msleep(120);135 136	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);137	if (ret < 0) {138		dev_err(dev, "Failed to exit sleep mode (%d)\n", ret);139		goto fail;140	}141 142	usleep_range(5000, 10000);143 144	ret = mipi_dsi_dcs_set_display_on(dsi);145	if (ret < 0) {146		dev_err(dev, "Failed to set display ON (%d)\n", ret);147		goto fail;148	}149 150	return 0;151 152fail:153	gpiod_set_value(rpanel->reset_gpio, 0);154 155	return ret;156}157 158static int r63353_panel_prepare(struct drm_panel *panel)159{160	struct r63353_panel *rpanel = to_r63353_panel(panel);161	struct mipi_dsi_device *dsi = rpanel->dsi;162	struct device *dev = &dsi->dev;163	int ret;164 165	dev_dbg(dev, "Preparing\n");166 167	ret = r63353_panel_power_on(rpanel);168	if (ret)169		return ret;170 171	ret = r63353_panel_activate(rpanel);172	if (ret) {173		r63353_panel_power_off(rpanel);174		return ret;175	}176 177	dev_dbg(dev, "Prepared\n");178	return 0;179}180 181static int r63353_panel_deactivate(struct r63353_panel *rpanel)182{183	struct mipi_dsi_device *dsi = rpanel->dsi;184	struct device *dev = &dsi->dev;185	int ret;186 187	ret = mipi_dsi_dcs_set_display_off(dsi);188	if (ret < 0) {189		dev_err(dev, "Failed to set display OFF (%d)\n", ret);190		return ret;191	}192 193	usleep_range(5000, 10000);194 195	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);196	if (ret < 0) {197		dev_err(dev, "Failed to enter sleep mode (%d)\n", ret);198		return ret;199	}200 201	return 0;202}203 204static int r63353_panel_unprepare(struct drm_panel *panel)205{206	struct r63353_panel *rpanel = to_r63353_panel(panel);207 208	r63353_panel_deactivate(rpanel);209	r63353_panel_power_off(rpanel);210 211	return 0;212}213 214static const struct drm_display_mode sharp_ls068b3sx02_timing = {215	.clock = 70000,216	.hdisplay = 640,217	.hsync_start = 640 + 35,218	.hsync_end = 640 + 35 + 2,219	.htotal = 640 + 35 + 2 + 150,220	.vdisplay = 1280,221	.vsync_start = 1280 + 2,222	.vsync_end = 1280 + 2 + 4,223	.vtotal = 1280 + 2 + 4 + 0,224};225 226static int r63353_panel_get_modes(struct drm_panel *panel,227				  struct drm_connector *connector)228{229	struct r63353_panel *rpanel = to_r63353_panel(panel);230	struct drm_display_mode *mode;231	static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;232 233	mode = drm_mode_duplicate(connector->dev, rpanel->pdata->mode);234	if (!mode)235		return -ENOMEM;236 237	drm_mode_set_name(mode);238	drm_mode_probed_add(connector, mode);239 240	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;241	connector->display_info.width_mm = rpanel->pdata->width_mm;242	connector->display_info.height_mm = rpanel->pdata->height_mm;243 244	drm_display_info_set_bus_formats(&connector->display_info,245					 &bus_format, 1);246 247	return 1;248}249 250static const struct drm_panel_funcs r63353_panel_funcs = {251	.prepare = r63353_panel_prepare,252	.unprepare = r63353_panel_unprepare,253	.get_modes = r63353_panel_get_modes,254};255 256static int r63353_panel_probe(struct mipi_dsi_device *dsi)257{258	int ret = 0;259	struct device *dev = &dsi->dev;260	struct r63353_panel *panel;261 262	panel = devm_kzalloc(&dsi->dev, sizeof(*panel), GFP_KERNEL);263	if (!panel)264		return -ENOMEM;265 266	mipi_dsi_set_drvdata(dsi, panel);267	panel->dsi = dsi;268	panel->pdata = (struct r63353_desc *)of_device_get_match_data(dev);269 270	dev_info(dev, "Panel %s\n", panel->pdata->name);271 272	dsi->lanes = 2;273	dsi->format = MIPI_DSI_FMT_RGB888;274	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |275			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM |276			  MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_NO_EOT_PACKET;277 278	panel->dvdd = devm_regulator_get(dev, "dvdd");279	if (IS_ERR(panel->dvdd))280		return PTR_ERR(panel->dvdd);281	panel->avdd = devm_regulator_get(dev, "avdd");282	if (IS_ERR(panel->avdd))283		return PTR_ERR(panel->avdd);284 285	panel->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);286	if (IS_ERR(panel->reset_gpio)) {287		dev_err(dev, "failed to get RESET GPIO\n");288		return PTR_ERR(panel->reset_gpio);289	}290 291	drm_panel_init(&panel->base, dev, &r63353_panel_funcs,292		       DRM_MODE_CONNECTOR_DSI);293 294	panel->base.prepare_prev_first = true;295	ret = drm_panel_of_backlight(&panel->base);296	if (ret)297		return ret;298 299	drm_panel_add(&panel->base);300 301	ret = mipi_dsi_attach(dsi);302	if (ret < 0) {303		dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);304		drm_panel_remove(&panel->base);305		return ret;306	}307 308	return ret;309}310 311static void r63353_panel_remove(struct mipi_dsi_device *dsi)312{313	struct r63353_panel *rpanel = mipi_dsi_get_drvdata(dsi);314	struct device *dev = &dsi->dev;315	int ret;316 317	ret = mipi_dsi_detach(dsi);318	if (ret < 0)319		dev_err(dev, "Failed to detach from host (%d)\n", ret);320 321	drm_panel_remove(&rpanel->base);322}323 324static void r63353_panel_shutdown(struct mipi_dsi_device *dsi)325{326	struct r63353_panel *rpanel = mipi_dsi_get_drvdata(dsi);327 328	r63353_panel_unprepare(&rpanel->base);329}330 331static const struct r63353_desc sharp_ls068b3sx02_data = {332	.name = "Sharp LS068B3SX02",333	.mode = &sharp_ls068b3sx02_timing,334	.init = sharp_ls068b3sx02_init,335	.init_length = ARRAY_SIZE(sharp_ls068b3sx02_init),336	.width_mm = 68,337	.height_mm = 159,338};339 340static const struct of_device_id r63353_of_match[] = {341	{ .compatible = "sharp,ls068b3sx02", .data = &sharp_ls068b3sx02_data },342	{ }343};344 345MODULE_DEVICE_TABLE(of, r63353_of_match);346 347static struct mipi_dsi_driver r63353_panel_driver = {348	.driver = {349		   .name = "r63353-dsi",350		   .of_match_table = r63353_of_match,351	},352	.probe = r63353_panel_probe,353	.remove = r63353_panel_remove,354	.shutdown = r63353_panel_shutdown,355};356 357module_mipi_dsi_driver(r63353_panel_driver);358 359MODULE_AUTHOR("Matthias Proske <Matthias.Proske@bshg.com>");360MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");361MODULE_DESCRIPTION("Synaptics R63353 Controller Driver");362MODULE_LICENSE("GPL");363