brintos

brintos / linux-shallow public Read only

0
0
Text · 13.1 KiB · a0fc457 Raw
607 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * LCD driver for MIPI DBI-C / DCS compatible LCDs4 *5 * Copyright (C) 2006 Nokia Corporation6 * Author: Imre Deak <imre.deak@nokia.com>7 */8#include <linux/device.h>9#include <linux/delay.h>10#include <linux/gpio/consumer.h>11#include <linux/slab.h>12#include <linux/workqueue.h>13#include <linux/spi/spi.h>14#include <linux/module.h>15 16#include <linux/platform_data/lcd-mipid.h>17 18#include "omapfb.h"19 20#define MIPID_MODULE_NAME		"lcd_mipid"21 22#define MIPID_CMD_READ_DISP_ID		0x0423#define MIPID_CMD_READ_RED		0x0624#define MIPID_CMD_READ_GREEN		0x0725#define MIPID_CMD_READ_BLUE		0x0826#define MIPID_CMD_READ_DISP_STATUS	0x0927#define MIPID_CMD_RDDSDR		0x0F28#define MIPID_CMD_SLEEP_IN		0x1029#define MIPID_CMD_SLEEP_OUT		0x1130#define MIPID_CMD_DISP_OFF		0x2831#define MIPID_CMD_DISP_ON		0x2932 33#define MIPID_ESD_CHECK_PERIOD		msecs_to_jiffies(5000)34 35#define to_mipid_device(p)		container_of(p, struct mipid_device, \36						panel)37struct mipid_device {38	int		enabled;39	int		revision;40	unsigned int	saved_bklight_level;41	unsigned long	hw_guard_end;		/* next value of jiffies42						   when we can issue the43						   next sleep in/out command */44	unsigned long	hw_guard_wait;		/* max guard time in jiffies */45	struct gpio_desc	*reset;46 47	struct omapfb_device	*fbdev;48	struct spi_device	*spi;49	struct mutex		mutex;50	struct lcd_panel	panel;51 52	struct delayed_work	esd_work;53	void			(*esd_check)(struct mipid_device *m);54};55 56static void mipid_transfer(struct mipid_device *md, int cmd, const u8 *wbuf,57			   int wlen, u8 *rbuf, int rlen)58{59	struct spi_message	m;60	struct spi_transfer	*x, xfer[4];61	u16			w;62	int			r;63 64	BUG_ON(md->spi == NULL);65 66	spi_message_init(&m);67 68	memset(xfer, 0, sizeof(xfer));69	x = &xfer[0];70 71	cmd &=  0xff;72	x->tx_buf		= &cmd;73	x->bits_per_word	= 9;74	x->len			= 2;75	spi_message_add_tail(x, &m);76 77	if (wlen) {78		x++;79		x->tx_buf		= wbuf;80		x->len			= wlen;81		x->bits_per_word	= 9;82		spi_message_add_tail(x, &m);83	}84 85	if (rlen) {86		x++;87		x->rx_buf	= &w;88		x->len		= 1;89		spi_message_add_tail(x, &m);90 91		if (rlen > 1) {92			/* Arrange for the extra clock before the first93			 * data bit.94			 */95			x->bits_per_word = 9;96			x->len		 = 2;97 98			x++;99			x->rx_buf	 = &rbuf[1];100			x->len		 = rlen - 1;101			spi_message_add_tail(x, &m);102		}103	}104 105	r = spi_sync(md->spi, &m);106	if (r < 0)107		dev_dbg(&md->spi->dev, "spi_sync %d\n", r);108 109	if (rlen)110		rbuf[0] = w & 0xff;111}112 113static inline void mipid_cmd(struct mipid_device *md, int cmd)114{115	mipid_transfer(md, cmd, NULL, 0, NULL, 0);116}117 118static inline void mipid_write(struct mipid_device *md,119			       int reg, const u8 *buf, int len)120{121	mipid_transfer(md, reg, buf, len, NULL, 0);122}123 124static inline void mipid_read(struct mipid_device *md,125			      int reg, u8 *buf, int len)126{127	mipid_transfer(md, reg, NULL, 0, buf, len);128}129 130static void set_data_lines(struct mipid_device *md, int data_lines)131{132	u16 par;133 134	switch (data_lines) {135	case 16:136		par = 0x150;137		break;138	case 18:139		par = 0x160;140		break;141	case 24:142		par = 0x170;143		break;144	}145	mipid_write(md, 0x3a, (u8 *)&par, 2);146}147 148static void send_init_string(struct mipid_device *md)149{150	u16 initpar[] = { 0x0102, 0x0100, 0x0100 };151 152	mipid_write(md, 0xc2, (u8 *)initpar, sizeof(initpar));153	set_data_lines(md, md->panel.data_lines);154}155 156static void hw_guard_start(struct mipid_device *md, int guard_msec)157{158	md->hw_guard_wait = msecs_to_jiffies(guard_msec);159	md->hw_guard_end = jiffies + md->hw_guard_wait;160}161 162static void hw_guard_wait(struct mipid_device *md)163{164	unsigned long wait = md->hw_guard_end - jiffies;165 166	if ((long)wait > 0 && time_before_eq(wait,  md->hw_guard_wait)) {167		set_current_state(TASK_UNINTERRUPTIBLE);168		schedule_timeout(wait);169	}170}171 172static void set_sleep_mode(struct mipid_device *md, int on)173{174	int cmd, sleep_time = 50;175 176	if (on)177		cmd = MIPID_CMD_SLEEP_IN;178	else179		cmd = MIPID_CMD_SLEEP_OUT;180	hw_guard_wait(md);181	mipid_cmd(md, cmd);182	hw_guard_start(md, 120);183	/*184	 * When we enable the panel, it seems we _have_ to sleep185	 * 120 ms before sending the init string. When disabling the186	 * panel we'll sleep for the duration of 2 frames, so that the187	 * controller can still provide the PCLK,HS,VS signals.188	 */189	if (!on)190		sleep_time = 120;191	msleep(sleep_time);192}193 194static void set_display_state(struct mipid_device *md, int enabled)195{196	int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;197 198	mipid_cmd(md, cmd);199}200 201static int mipid_set_bklight_level(struct lcd_panel *panel, unsigned int level)202{203	struct mipid_device *md = to_mipid_device(panel);204	struct mipid_platform_data *pd = md->spi->dev.platform_data;205 206	if (pd->get_bklight_max == NULL || pd->set_bklight_level == NULL)207		return -ENODEV;208	if (level > pd->get_bklight_max(pd))209		return -EINVAL;210	if (!md->enabled) {211		md->saved_bklight_level = level;212		return 0;213	}214	pd->set_bklight_level(pd, level);215 216	return 0;217}218 219static unsigned int mipid_get_bklight_level(struct lcd_panel *panel)220{221	struct mipid_device *md = to_mipid_device(panel);222	struct mipid_platform_data *pd = md->spi->dev.platform_data;223 224	if (pd->get_bklight_level == NULL)225		return -ENODEV;226	return pd->get_bklight_level(pd);227}228 229static unsigned int mipid_get_bklight_max(struct lcd_panel *panel)230{231	struct mipid_device *md = to_mipid_device(panel);232	struct mipid_platform_data *pd = md->spi->dev.platform_data;233 234	if (pd->get_bklight_max == NULL)235		return -ENODEV;236 237	return pd->get_bklight_max(pd);238}239 240static unsigned long mipid_get_caps(struct lcd_panel *panel)241{242	return OMAPFB_CAPS_SET_BACKLIGHT;243}244 245static u16 read_first_pixel(struct mipid_device *md)246{247	u16 pixel;248	u8 red, green, blue;249 250	mutex_lock(&md->mutex);251	mipid_read(md, MIPID_CMD_READ_RED, &red, 1);252	mipid_read(md, MIPID_CMD_READ_GREEN, &green, 1);253	mipid_read(md, MIPID_CMD_READ_BLUE, &blue, 1);254	mutex_unlock(&md->mutex);255 256	switch (md->panel.data_lines) {257	case 16:258		pixel = ((red >> 1) << 11) | (green << 5) | (blue >> 1);259		break;260	case 24:261		/* 24 bit -> 16 bit */262		pixel = ((red >> 3) << 11) | ((green >> 2) << 5) |263			(blue >> 3);264		break;265	default:266		pixel = 0;267		BUG();268	}269 270	return pixel;271}272 273static int mipid_run_test(struct lcd_panel *panel, int test_num)274{275	struct mipid_device *md = to_mipid_device(panel);276	static const u16 test_values[4] = {277		0x0000, 0xffff, 0xaaaa, 0x5555,278	};279	int i;280 281	if (test_num != MIPID_TEST_RGB_LINES)282		return MIPID_TEST_INVALID;283 284	for (i = 0; i < ARRAY_SIZE(test_values); i++) {285		int delay;286		unsigned long tmo;287 288		omapfb_write_first_pixel(md->fbdev, test_values[i]);289		tmo = jiffies + msecs_to_jiffies(100);290		delay = 25;291		while (1) {292			u16 pixel;293 294			msleep(delay);295			pixel = read_first_pixel(md);296			if (pixel == test_values[i])297				break;298			if (time_after(jiffies, tmo)) {299				dev_err(&md->spi->dev,300					"MIPI LCD RGB I/F test failed: "301					"expecting %04x, got %04x\n",302					test_values[i], pixel);303				return MIPID_TEST_FAILED;304			}305			delay = 10;306		}307	}308 309	return 0;310}311 312static void ls041y3_esd_recover(struct mipid_device *md)313{314	dev_err(&md->spi->dev, "performing LCD ESD recovery\n");315	set_sleep_mode(md, 1);316	set_sleep_mode(md, 0);317}318 319static void ls041y3_esd_check_mode1(struct mipid_device *md)320{321	u8 state1, state2;322 323	mipid_read(md, MIPID_CMD_RDDSDR, &state1, 1);324	set_sleep_mode(md, 0);325	mipid_read(md, MIPID_CMD_RDDSDR, &state2, 1);326	dev_dbg(&md->spi->dev, "ESD mode 1 state1 %02x state2 %02x\n",327		state1, state2);328	/* Each sleep out command will trigger a self diagnostic and flip329	* Bit6 if the test passes.330	*/331	if (!((state1 ^ state2) & (1 << 6)))332		ls041y3_esd_recover(md);333}334 335static void ls041y3_esd_check_mode2(struct mipid_device *md)336{337	int i;338	u8 rbuf[2];339	static const struct {340		int	cmd;341		int	wlen;342		u16	wbuf[3];343	} *rd, rd_ctrl[7] = {344		{ 0xb0, 4, { 0x0101, 0x01fe, } },345		{ 0xb1, 4, { 0x01de, 0x0121, } },346		{ 0xc2, 4, { 0x0100, 0x0100, } },347		{ 0xbd, 2, { 0x0100, } },348		{ 0xc2, 4, { 0x01fc, 0x0103, } },349		{ 0xb4, 0, },350		{ 0x00, 0, },351	};352 353	rd = rd_ctrl;354	for (i = 0; i < 3; i++, rd++)355		mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);356 357	udelay(10);358	mipid_read(md, rd->cmd, rbuf, 2);359	rd++;360 361	for (i = 0; i < 3; i++, rd++) {362		udelay(10);363		mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);364	}365 366	dev_dbg(&md->spi->dev, "ESD mode 2 state %02x\n", rbuf[1]);367	if (rbuf[1] == 0x00)368		ls041y3_esd_recover(md);369}370 371static void ls041y3_esd_check(struct mipid_device *md)372{373	ls041y3_esd_check_mode1(md);374	if (md->revision >= 0x88)375		ls041y3_esd_check_mode2(md);376}377 378static void mipid_esd_start_check(struct mipid_device *md)379{380	if (md->esd_check != NULL)381		schedule_delayed_work(&md->esd_work,382				   MIPID_ESD_CHECK_PERIOD);383}384 385static void mipid_esd_stop_check(struct mipid_device *md)386{387	if (md->esd_check != NULL)388		cancel_delayed_work_sync(&md->esd_work);389}390 391static void mipid_esd_work(struct work_struct *work)392{393	struct mipid_device *md = container_of(work, struct mipid_device,394					       esd_work.work);395 396	mutex_lock(&md->mutex);397	md->esd_check(md);398	mutex_unlock(&md->mutex);399	mipid_esd_start_check(md);400}401 402static int mipid_enable(struct lcd_panel *panel)403{404	struct mipid_device *md = to_mipid_device(panel);405 406	mutex_lock(&md->mutex);407 408	if (md->enabled) {409		mutex_unlock(&md->mutex);410		return 0;411	}412	set_sleep_mode(md, 0);413	md->enabled = 1;414	send_init_string(md);415	set_display_state(md, 1);416	mipid_set_bklight_level(panel, md->saved_bklight_level);417	mipid_esd_start_check(md);418 419	mutex_unlock(&md->mutex);420	return 0;421}422 423static void mipid_disable(struct lcd_panel *panel)424{425	struct mipid_device *md = to_mipid_device(panel);426 427	/*428	 * A final ESD work might be called before returning,429	 * so do this without holding the lock.430	 */431	mipid_esd_stop_check(md);432	mutex_lock(&md->mutex);433 434	if (!md->enabled) {435		mutex_unlock(&md->mutex);436		return;437	}438	md->saved_bklight_level = mipid_get_bklight_level(panel);439	mipid_set_bklight_level(panel, 0);440	set_display_state(md, 0);441	set_sleep_mode(md, 1);442	md->enabled = 0;443 444	mutex_unlock(&md->mutex);445}446 447static int panel_enabled(struct mipid_device *md)448{449	u32 disp_status;450	int enabled;451 452	mipid_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);453	disp_status = __be32_to_cpu(disp_status);454	enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));455	dev_dbg(&md->spi->dev,456		"LCD panel %senabled by bootloader (status 0x%04x)\n",457		enabled ? "" : "not ", disp_status);458	return enabled;459}460 461static int mipid_init(struct lcd_panel *panel,462			    struct omapfb_device *fbdev)463{464	struct mipid_device *md = to_mipid_device(panel);465 466	md->fbdev = fbdev;467	INIT_DELAYED_WORK(&md->esd_work, mipid_esd_work);468	mutex_init(&md->mutex);469 470	md->enabled = panel_enabled(md);471 472	if (md->enabled)473		mipid_esd_start_check(md);474	else475		md->saved_bklight_level = mipid_get_bklight_level(panel);476 477	return 0;478}479 480static void mipid_cleanup(struct lcd_panel *panel)481{482	struct mipid_device *md = to_mipid_device(panel);483 484	if (md->enabled)485		mipid_esd_stop_check(md);486}487 488static const struct lcd_panel mipid_panel = {489	.config		= OMAP_LCDC_PANEL_TFT,490 491	.bpp		= 16,492	.x_res		= 800,493	.y_res		= 480,494	.pixel_clock	= 21940,495	.hsw		= 50,496	.hfp		= 20,497	.hbp		= 15,498	.vsw		= 2,499	.vfp		= 1,500	.vbp		= 3,501 502	.init			= mipid_init,503	.cleanup		= mipid_cleanup,504	.enable			= mipid_enable,505	.disable		= mipid_disable,506	.get_caps		= mipid_get_caps,507	.set_bklight_level	= mipid_set_bklight_level,508	.get_bklight_level	= mipid_get_bklight_level,509	.get_bklight_max	= mipid_get_bklight_max,510	.run_test		= mipid_run_test,511};512 513static int mipid_detect(struct mipid_device *md)514{515	struct mipid_platform_data *pdata;516	u8 display_id[3];517 518	pdata = md->spi->dev.platform_data;519	if (pdata == NULL) {520		dev_err(&md->spi->dev, "missing platform data\n");521		return -ENOENT;522	}523 524	mipid_read(md, MIPID_CMD_READ_DISP_ID, display_id, 3);525	dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",526		display_id[0], display_id[1], display_id[2]);527 528	switch (display_id[0]) {529	case 0x45:530		md->panel.name = "lph8923";531		break;532	case 0x83:533		md->panel.name = "ls041y3";534		md->esd_check = ls041y3_esd_check;535		break;536	default:537		md->panel.name = "unknown";538		dev_err(&md->spi->dev, "invalid display ID\n");539		return -ENODEV;540	}541 542	md->revision = display_id[1];543	md->panel.data_lines = pdata->data_lines;544	pr_info("omapfb: %s rev %02x LCD detected, %d data lines\n",545			md->panel.name, md->revision, md->panel.data_lines);546 547	return 0;548}549 550static int mipid_spi_probe(struct spi_device *spi)551{552	struct mipid_device *md;553	int r;554 555	md = kzalloc(sizeof(*md), GFP_KERNEL);556	if (md == NULL) {557		dev_err(&spi->dev, "out of memory\n");558		return -ENOMEM;559	}560 561	/* This will de-assert RESET if active */562	md->reset = gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);563	if (IS_ERR(md->reset))564		return dev_err_probe(&spi->dev, PTR_ERR(md->reset),565				     "no reset GPIO line\n");566 567	spi->mode = SPI_MODE_0;568	md->spi = spi;569	dev_set_drvdata(&spi->dev, md);570	md->panel = mipid_panel;571 572	r = mipid_detect(md);573	if (r < 0)574		goto free_md;575 576	omapfb_register_panel(&md->panel);577 578	return 0;579 580free_md:581	kfree(md);582	return r;583}584 585static void mipid_spi_remove(struct spi_device *spi)586{587	struct mipid_device *md = dev_get_drvdata(&spi->dev);588 589	/* Asserts RESET */590	gpiod_set_value(md->reset, 1);591	mipid_disable(&md->panel);592	kfree(md);593}594 595static struct spi_driver mipid_spi_driver = {596	.driver = {597		.name	= MIPID_MODULE_NAME,598	},599	.probe	= mipid_spi_probe,600	.remove	= mipid_spi_remove,601};602 603module_spi_driver(mipid_spi_driver);604 605MODULE_DESCRIPTION("MIPI display driver");606MODULE_LICENSE("GPL");607