brintos

brintos / linux-shallow public Read only

0
0
Text · 26.3 KiB · 4a0df64 Raw
1290 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Generic DSI Command Mode panel driver4 *5 * Copyright (C) 2013 Texas Instruments6 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>7 */8 9/* #define DEBUG */10 11#include <linux/backlight.h>12#include <linux/delay.h>13#include <linux/err.h>14#include <linux/fb.h>15#include <linux/gpio/consumer.h>16#include <linux/interrupt.h>17#include <linux/jiffies.h>18#include <linux/mod_devicetable.h>19#include <linux/module.h>20#include <linux/platform_device.h>21#include <linux/sched/signal.h>22#include <linux/slab.h>23#include <linux/workqueue.h>24 25#include <video/omapfb_dss.h>26#include <video/mipi_display.h>27 28/* DSI Virtual channel. Hardcoded for now. */29#define TCH 030 31#define DCS_READ_NUM_ERRORS	0x0532#define DCS_BRIGHTNESS		0x5133#define DCS_CTRL_DISPLAY	0x5334#define DCS_GET_ID1		0xda35#define DCS_GET_ID2		0xdb36#define DCS_GET_ID3		0xdc37 38struct panel_drv_data {39	struct omap_dss_device dssdev;40	struct omap_dss_device *in;41 42	struct omap_video_timings timings;43 44	struct platform_device *pdev;45 46	struct mutex lock;47 48	struct backlight_device *bldev;49 50	unsigned long	hw_guard_end;	/* next value of jiffies when we can51					 * issue the next sleep in/out command52					 */53	unsigned long	hw_guard_wait;	/* max guard time in jiffies */54 55	/* panel HW configuration from DT or platform data */56	struct gpio_desc *reset_gpio;57	struct gpio_desc *ext_te_gpio;58 59	bool use_dsi_backlight;60 61	struct omap_dsi_pin_config pin_config;62 63	/* runtime variables */64	bool enabled;65 66	bool te_enabled;67 68	atomic_t do_update;69	int channel;70 71	struct delayed_work te_timeout_work;72 73	bool intro_printed;74 75	bool ulps_enabled;76	unsigned ulps_timeout;77	struct delayed_work ulps_work;78};79 80#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)81 82static irqreturn_t dsicm_te_isr(int irq, void *data);83static void dsicm_te_timeout_work_callback(struct work_struct *work);84static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable);85 86static int dsicm_panel_reset(struct panel_drv_data *ddata);87 88static void dsicm_ulps_work(struct work_struct *work);89 90static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)91{92	ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);93	ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;94}95 96static void hw_guard_wait(struct panel_drv_data *ddata)97{98	unsigned long wait = ddata->hw_guard_end - jiffies;99 100	if ((long)wait > 0 && time_before_eq(wait, ddata->hw_guard_wait)) {101		set_current_state(TASK_UNINTERRUPTIBLE);102		schedule_timeout(wait);103	}104}105 106static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)107{108	struct omap_dss_device *in = ddata->in;109	int r;110	u8 buf[1];111 112	r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd, buf, 1);113 114	if (r < 0)115		return r;116 117	*data = buf[0];118 119	return 0;120}121 122static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd)123{124	struct omap_dss_device *in = ddata->in;125	return in->ops.dsi->dcs_write(in, ddata->channel, &dcs_cmd, 1);126}127 128static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)129{130	struct omap_dss_device *in = ddata->in;131	u8 buf[2] = { dcs_cmd, param };132 133	return in->ops.dsi->dcs_write(in, ddata->channel, buf, 2);134}135 136static int dsicm_sleep_in(struct panel_drv_data *ddata)137 138{139	struct omap_dss_device *in = ddata->in;140	u8 cmd;141	int r;142 143	hw_guard_wait(ddata);144 145	cmd = MIPI_DCS_ENTER_SLEEP_MODE;146	r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, &cmd, 1);147	if (r)148		return r;149 150	hw_guard_start(ddata, 120);151 152	usleep_range(5000, 10000);153 154	return 0;155}156 157static int dsicm_sleep_out(struct panel_drv_data *ddata)158{159	int r;160 161	hw_guard_wait(ddata);162 163	r = dsicm_dcs_write_0(ddata, MIPI_DCS_EXIT_SLEEP_MODE);164	if (r)165		return r;166 167	hw_guard_start(ddata, 120);168 169	usleep_range(5000, 10000);170 171	return 0;172}173 174static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)175{176	int r;177 178	r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, id1);179	if (r)180		return r;181	r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, id2);182	if (r)183		return r;184	r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, id3);185	if (r)186		return r;187 188	return 0;189}190 191static int dsicm_set_update_window(struct panel_drv_data *ddata,192		u16 x, u16 y, u16 w, u16 h)193{194	struct omap_dss_device *in = ddata->in;195	int r;196	u16 x1 = x;197	u16 x2 = x + w - 1;198	u16 y1 = y;199	u16 y2 = y + h - 1;200 201	u8 buf[5];202	buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS;203	buf[1] = (x1 >> 8) & 0xff;204	buf[2] = (x1 >> 0) & 0xff;205	buf[3] = (x2 >> 8) & 0xff;206	buf[4] = (x2 >> 0) & 0xff;207 208	r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));209	if (r)210		return r;211 212	buf[0] = MIPI_DCS_SET_PAGE_ADDRESS;213	buf[1] = (y1 >> 8) & 0xff;214	buf[2] = (y1 >> 0) & 0xff;215	buf[3] = (y2 >> 8) & 0xff;216	buf[4] = (y2 >> 0) & 0xff;217 218	r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));219	if (r)220		return r;221 222	in->ops.dsi->bta_sync(in, ddata->channel);223 224	return r;225}226 227static void dsicm_queue_ulps_work(struct panel_drv_data *ddata)228{229	if (ddata->ulps_timeout > 0)230		schedule_delayed_work(&ddata->ulps_work,231				msecs_to_jiffies(ddata->ulps_timeout));232}233 234static void dsicm_cancel_ulps_work(struct panel_drv_data *ddata)235{236	cancel_delayed_work(&ddata->ulps_work);237}238 239static int dsicm_enter_ulps(struct panel_drv_data *ddata)240{241	struct omap_dss_device *in = ddata->in;242	int r;243 244	if (ddata->ulps_enabled)245		return 0;246 247	dsicm_cancel_ulps_work(ddata);248 249	r = _dsicm_enable_te(ddata, false);250	if (r)251		goto err;252 253	if (ddata->ext_te_gpio)254		disable_irq(gpiod_to_irq(ddata->ext_te_gpio));255 256	in->ops.dsi->disable(in, false, true);257 258	ddata->ulps_enabled = true;259 260	return 0;261 262err:263	dev_err(&ddata->pdev->dev, "enter ULPS failed");264	dsicm_panel_reset(ddata);265 266	ddata->ulps_enabled = false;267 268	dsicm_queue_ulps_work(ddata);269 270	return r;271}272 273static int dsicm_exit_ulps(struct panel_drv_data *ddata)274{275	struct omap_dss_device *in = ddata->in;276	int r;277 278	if (!ddata->ulps_enabled)279		return 0;280 281	r = in->ops.dsi->enable(in);282	if (r) {283		dev_err(&ddata->pdev->dev, "failed to enable DSI\n");284		goto err1;285	}286 287	in->ops.dsi->enable_hs(in, ddata->channel, true);288 289	r = _dsicm_enable_te(ddata, true);290	if (r) {291		dev_err(&ddata->pdev->dev, "failed to re-enable TE");292		goto err2;293	}294 295	if (ddata->ext_te_gpio)296		enable_irq(gpiod_to_irq(ddata->ext_te_gpio));297 298	dsicm_queue_ulps_work(ddata);299 300	ddata->ulps_enabled = false;301 302	return 0;303 304err2:305	dev_err(&ddata->pdev->dev, "failed to exit ULPS");306 307	r = dsicm_panel_reset(ddata);308	if (!r) {309		if (ddata->ext_te_gpio)310			enable_irq(gpiod_to_irq(ddata->ext_te_gpio));311		ddata->ulps_enabled = false;312	}313err1:314	dsicm_queue_ulps_work(ddata);315 316	return r;317}318 319static int dsicm_wake_up(struct panel_drv_data *ddata)320{321	if (ddata->ulps_enabled)322		return dsicm_exit_ulps(ddata);323 324	dsicm_cancel_ulps_work(ddata);325	dsicm_queue_ulps_work(ddata);326	return 0;327}328 329static int dsicm_bl_update_status(struct backlight_device *dev)330{331	struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);332	struct omap_dss_device *in = ddata->in;333	int r;334	int level = backlight_get_brightness(dev);335 336	dev_dbg(&ddata->pdev->dev, "update brightness to %d\n", level);337 338	mutex_lock(&ddata->lock);339 340	if (ddata->enabled) {341		in->ops.dsi->bus_lock(in);342 343		r = dsicm_wake_up(ddata);344		if (!r)345			r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level);346 347		in->ops.dsi->bus_unlock(in);348	} else {349		r = 0;350	}351 352	mutex_unlock(&ddata->lock);353 354	return r;355}356 357static int dsicm_bl_get_intensity(struct backlight_device *dev)358{359	return backlight_get_brightness(dev);360}361 362static const struct backlight_ops dsicm_bl_ops = {363	.get_brightness = dsicm_bl_get_intensity,364	.update_status  = dsicm_bl_update_status,365};366 367static void dsicm_get_resolution(struct omap_dss_device *dssdev,368		u16 *xres, u16 *yres)369{370	*xres = dssdev->panel.timings.x_res;371	*yres = dssdev->panel.timings.y_res;372}373 374static ssize_t dsicm_num_errors_show(struct device *dev,375		struct device_attribute *attr, char *buf)376{377	struct panel_drv_data *ddata = dev_get_drvdata(dev);378	struct omap_dss_device *in = ddata->in;379	u8 errors = 0;380	int r;381 382	mutex_lock(&ddata->lock);383 384	if (ddata->enabled) {385		in->ops.dsi->bus_lock(in);386 387		r = dsicm_wake_up(ddata);388		if (!r)389			r = dsicm_dcs_read_1(ddata, DCS_READ_NUM_ERRORS,390					&errors);391 392		in->ops.dsi->bus_unlock(in);393	} else {394		r = -ENODEV;395	}396 397	mutex_unlock(&ddata->lock);398 399	if (r)400		return r;401 402	return sysfs_emit(buf, "%d\n", errors);403}404 405static ssize_t dsicm_hw_revision_show(struct device *dev,406		struct device_attribute *attr, char *buf)407{408	struct panel_drv_data *ddata = dev_get_drvdata(dev);409	struct omap_dss_device *in = ddata->in;410	u8 id1, id2, id3;411	int r;412 413	mutex_lock(&ddata->lock);414 415	if (ddata->enabled) {416		in->ops.dsi->bus_lock(in);417 418		r = dsicm_wake_up(ddata);419		if (!r)420			r = dsicm_get_id(ddata, &id1, &id2, &id3);421 422		in->ops.dsi->bus_unlock(in);423	} else {424		r = -ENODEV;425	}426 427	mutex_unlock(&ddata->lock);428 429	if (r)430		return r;431 432	return sysfs_emit(buf, "%02x.%02x.%02x\n", id1, id2, id3);433}434 435static ssize_t dsicm_store_ulps(struct device *dev,436		struct device_attribute *attr,437		const char *buf, size_t count)438{439	struct panel_drv_data *ddata = dev_get_drvdata(dev);440	struct omap_dss_device *in = ddata->in;441	unsigned long t;442	int r;443 444	r = kstrtoul(buf, 0, &t);445	if (r)446		return r;447 448	mutex_lock(&ddata->lock);449 450	if (ddata->enabled) {451		in->ops.dsi->bus_lock(in);452 453		if (t)454			r = dsicm_enter_ulps(ddata);455		else456			r = dsicm_wake_up(ddata);457 458		in->ops.dsi->bus_unlock(in);459	}460 461	mutex_unlock(&ddata->lock);462 463	if (r)464		return r;465 466	return count;467}468 469static ssize_t dsicm_show_ulps(struct device *dev,470		struct device_attribute *attr,471		char *buf)472{473	struct panel_drv_data *ddata = dev_get_drvdata(dev);474	unsigned t;475 476	mutex_lock(&ddata->lock);477	t = ddata->ulps_enabled;478	mutex_unlock(&ddata->lock);479 480	return sysfs_emit(buf, "%u\n", t);481}482 483static ssize_t dsicm_store_ulps_timeout(struct device *dev,484		struct device_attribute *attr,485		const char *buf, size_t count)486{487	struct panel_drv_data *ddata = dev_get_drvdata(dev);488	struct omap_dss_device *in = ddata->in;489	unsigned long t;490	int r;491 492	r = kstrtoul(buf, 0, &t);493	if (r)494		return r;495 496	mutex_lock(&ddata->lock);497	ddata->ulps_timeout = t;498 499	if (ddata->enabled) {500		/* dsicm_wake_up will restart the timer */501		in->ops.dsi->bus_lock(in);502		r = dsicm_wake_up(ddata);503		in->ops.dsi->bus_unlock(in);504	}505 506	mutex_unlock(&ddata->lock);507 508	if (r)509		return r;510 511	return count;512}513 514static ssize_t dsicm_show_ulps_timeout(struct device *dev,515		struct device_attribute *attr,516		char *buf)517{518	struct panel_drv_data *ddata = dev_get_drvdata(dev);519	unsigned t;520 521	mutex_lock(&ddata->lock);522	t = ddata->ulps_timeout;523	mutex_unlock(&ddata->lock);524 525	return sysfs_emit(buf, "%u\n", t);526}527 528static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL);529static DEVICE_ATTR(hw_revision, S_IRUGO, dsicm_hw_revision_show, NULL);530static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,531		dsicm_show_ulps, dsicm_store_ulps);532static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,533		dsicm_show_ulps_timeout, dsicm_store_ulps_timeout);534 535static struct attribute *dsicm_attrs[] = {536	&dev_attr_num_dsi_errors.attr,537	&dev_attr_hw_revision.attr,538	&dev_attr_ulps.attr,539	&dev_attr_ulps_timeout.attr,540	NULL,541};542 543static const struct attribute_group dsicm_attr_group = {544	.attrs = dsicm_attrs,545};546 547static void dsicm_hw_reset(struct panel_drv_data *ddata)548{549	/*550	 * Note that we appear to activate the reset line here. However551	 * existing DTSes specified incorrect polarity for it (active high),552	 * so in fact this deasserts the reset line.553	 */554	gpiod_set_value_cansleep(ddata->reset_gpio, 1);555	udelay(10);556	/* reset the panel */557	gpiod_set_value_cansleep(ddata->reset_gpio, 0);558	/* keep reset asserted */559	udelay(10);560	/* release reset line */561	gpiod_set_value_cansleep(ddata->reset_gpio, 1);562	/* wait after releasing reset */563	usleep_range(5000, 10000);564}565 566static int dsicm_power_on(struct panel_drv_data *ddata)567{568	struct omap_dss_device *in = ddata->in;569	u8 id1, id2, id3;570	int r;571	struct omap_dss_dsi_config dsi_config = {572		.mode = OMAP_DSS_DSI_CMD_MODE,573		.pixel_format = OMAP_DSS_DSI_FMT_RGB888,574		.timings = &ddata->timings,575		.hs_clk_min = 150000000,576		.hs_clk_max = 300000000,577		.lp_clk_min = 7000000,578		.lp_clk_max = 10000000,579	};580 581	if (ddata->pin_config.num_pins > 0) {582		r = in->ops.dsi->configure_pins(in, &ddata->pin_config);583		if (r) {584			dev_err(&ddata->pdev->dev,585				"failed to configure DSI pins\n");586			goto err0;587		}588	}589 590	r = in->ops.dsi->set_config(in, &dsi_config);591	if (r) {592		dev_err(&ddata->pdev->dev, "failed to configure DSI\n");593		goto err0;594	}595 596	r = in->ops.dsi->enable(in);597	if (r) {598		dev_err(&ddata->pdev->dev, "failed to enable DSI\n");599		goto err0;600	}601 602	dsicm_hw_reset(ddata);603 604	in->ops.dsi->enable_hs(in, ddata->channel, false);605 606	r = dsicm_sleep_out(ddata);607	if (r)608		goto err;609 610	r = dsicm_get_id(ddata, &id1, &id2, &id3);611	if (r)612		goto err;613 614	r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, 0xff);615	if (r)616		goto err;617 618	r = dsicm_dcs_write_1(ddata, DCS_CTRL_DISPLAY,619			(1<<2) | (1<<5));	/* BL | BCTRL */620	if (r)621		goto err;622 623	r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_PIXEL_FORMAT,624		MIPI_DCS_PIXEL_FMT_24BIT);625	if (r)626		goto err;627 628	r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_ON);629	if (r)630		goto err;631 632	r = _dsicm_enable_te(ddata, ddata->te_enabled);633	if (r)634		goto err;635 636	r = in->ops.dsi->enable_video_output(in, ddata->channel);637	if (r)638		goto err;639 640	ddata->enabled = 1;641 642	if (!ddata->intro_printed) {643		dev_info(&ddata->pdev->dev, "panel revision %02x.%02x.%02x\n",644			id1, id2, id3);645		ddata->intro_printed = true;646	}647 648	in->ops.dsi->enable_hs(in, ddata->channel, true);649 650	return 0;651err:652	dev_err(&ddata->pdev->dev, "error while enabling panel, issuing HW reset\n");653 654	dsicm_hw_reset(ddata);655 656	in->ops.dsi->disable(in, true, false);657err0:658	return r;659}660 661static void dsicm_power_off(struct panel_drv_data *ddata)662{663	struct omap_dss_device *in = ddata->in;664	int r;665 666	in->ops.dsi->disable_video_output(in, ddata->channel);667 668	r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_OFF);669	if (!r)670		r = dsicm_sleep_in(ddata);671 672	if (r) {673		dev_err(&ddata->pdev->dev,674				"error disabling panel, issuing HW reset\n");675		dsicm_hw_reset(ddata);676	}677 678	in->ops.dsi->disable(in, true, false);679 680	ddata->enabled = 0;681}682 683static int dsicm_panel_reset(struct panel_drv_data *ddata)684{685	dev_err(&ddata->pdev->dev, "performing LCD reset\n");686 687	dsicm_power_off(ddata);688	dsicm_hw_reset(ddata);689	return dsicm_power_on(ddata);690}691 692static int dsicm_connect(struct omap_dss_device *dssdev)693{694	struct panel_drv_data *ddata = to_panel_data(dssdev);695	struct omap_dss_device *in = ddata->in;696	struct device *dev = &ddata->pdev->dev;697	int r;698 699	if (omapdss_device_is_connected(dssdev))700		return 0;701 702	r = in->ops.dsi->connect(in, dssdev);703	if (r) {704		dev_err(dev, "Failed to connect to video source\n");705		return r;706	}707 708	r = in->ops.dsi->request_vc(ddata->in, &ddata->channel);709	if (r) {710		dev_err(dev, "failed to get virtual channel\n");711		goto err_req_vc;712	}713 714	r = in->ops.dsi->set_vc_id(ddata->in, ddata->channel, TCH);715	if (r) {716		dev_err(dev, "failed to set VC_ID\n");717		goto err_vc_id;718	}719 720	return 0;721 722err_vc_id:723	in->ops.dsi->release_vc(ddata->in, ddata->channel);724err_req_vc:725	in->ops.dsi->disconnect(in, dssdev);726	return r;727}728 729static void dsicm_disconnect(struct omap_dss_device *dssdev)730{731	struct panel_drv_data *ddata = to_panel_data(dssdev);732	struct omap_dss_device *in = ddata->in;733 734	if (!omapdss_device_is_connected(dssdev))735		return;736 737	in->ops.dsi->release_vc(in, ddata->channel);738	in->ops.dsi->disconnect(in, dssdev);739}740 741static int dsicm_enable(struct omap_dss_device *dssdev)742{743	struct panel_drv_data *ddata = to_panel_data(dssdev);744	struct omap_dss_device *in = ddata->in;745	int r;746 747	dev_dbg(&ddata->pdev->dev, "enable\n");748 749	mutex_lock(&ddata->lock);750 751	if (!omapdss_device_is_connected(dssdev)) {752		r = -ENODEV;753		goto err;754	}755 756	if (omapdss_device_is_enabled(dssdev)) {757		r = 0;758		goto err;759	}760 761	in->ops.dsi->bus_lock(in);762 763	r = dsicm_power_on(ddata);764 765	in->ops.dsi->bus_unlock(in);766 767	if (r)768		goto err;769 770	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;771 772	mutex_unlock(&ddata->lock);773 774	return 0;775err:776	dev_dbg(&ddata->pdev->dev, "enable failed\n");777	mutex_unlock(&ddata->lock);778	return r;779}780 781static void dsicm_disable(struct omap_dss_device *dssdev)782{783	struct panel_drv_data *ddata = to_panel_data(dssdev);784	struct omap_dss_device *in = ddata->in;785	int r;786 787	dev_dbg(&ddata->pdev->dev, "disable\n");788 789	mutex_lock(&ddata->lock);790 791	dsicm_cancel_ulps_work(ddata);792 793	in->ops.dsi->bus_lock(in);794 795	if (omapdss_device_is_enabled(dssdev)) {796		r = dsicm_wake_up(ddata);797		if (!r)798			dsicm_power_off(ddata);799	}800 801	in->ops.dsi->bus_unlock(in);802 803	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;804 805	mutex_unlock(&ddata->lock);806}807 808static void dsicm_framedone_cb(int err, void *data)809{810	struct panel_drv_data *ddata = data;811	struct omap_dss_device *in = ddata->in;812 813	dev_dbg(&ddata->pdev->dev, "framedone, err %d\n", err);814	in->ops.dsi->bus_unlock(ddata->in);815}816 817static irqreturn_t dsicm_te_isr(int irq, void *data)818{819	struct panel_drv_data *ddata = data;820	struct omap_dss_device *in = ddata->in;821	int old;822	int r;823 824	old = atomic_cmpxchg(&ddata->do_update, 1, 0);825 826	if (old) {827		cancel_delayed_work(&ddata->te_timeout_work);828 829		r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,830				ddata);831		if (r)832			goto err;833	}834 835	return IRQ_HANDLED;836err:837	dev_err(&ddata->pdev->dev, "start update failed\n");838	in->ops.dsi->bus_unlock(in);839	return IRQ_HANDLED;840}841 842static void dsicm_te_timeout_work_callback(struct work_struct *work)843{844	struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,845					te_timeout_work.work);846	struct omap_dss_device *in = ddata->in;847 848	dev_err(&ddata->pdev->dev, "TE not received for 250ms!\n");849 850	atomic_set(&ddata->do_update, 0);851	in->ops.dsi->bus_unlock(in);852}853 854static int dsicm_update(struct omap_dss_device *dssdev,855				    u16 x, u16 y, u16 w, u16 h)856{857	struct panel_drv_data *ddata = to_panel_data(dssdev);858	struct omap_dss_device *in = ddata->in;859	int r;860 861	dev_dbg(&ddata->pdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);862 863	mutex_lock(&ddata->lock);864	in->ops.dsi->bus_lock(in);865 866	r = dsicm_wake_up(ddata);867	if (r)868		goto err;869 870	if (!ddata->enabled) {871		r = 0;872		goto err;873	}874 875	/* XXX no need to send this every frame, but dsi break if not done */876	r = dsicm_set_update_window(ddata, 0, 0,877			dssdev->panel.timings.x_res,878			dssdev->panel.timings.y_res);879	if (r)880		goto err;881 882	if (ddata->te_enabled && ddata->ext_te_gpio) {883		schedule_delayed_work(&ddata->te_timeout_work,884				msecs_to_jiffies(250));885		atomic_set(&ddata->do_update, 1);886	} else {887		r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,888				ddata);889		if (r)890			goto err;891	}892 893	/* note: no bus_unlock here. unlock is in framedone_cb */894	mutex_unlock(&ddata->lock);895	return 0;896err:897	in->ops.dsi->bus_unlock(in);898	mutex_unlock(&ddata->lock);899	return r;900}901 902static int dsicm_sync(struct omap_dss_device *dssdev)903{904	struct panel_drv_data *ddata = to_panel_data(dssdev);905	struct omap_dss_device *in = ddata->in;906 907	dev_dbg(&ddata->pdev->dev, "sync\n");908 909	mutex_lock(&ddata->lock);910	in->ops.dsi->bus_lock(in);911	in->ops.dsi->bus_unlock(in);912	mutex_unlock(&ddata->lock);913 914	dev_dbg(&ddata->pdev->dev, "sync done\n");915 916	return 0;917}918 919static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)920{921	struct omap_dss_device *in = ddata->in;922	int r;923 924	if (enable)925		r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_TEAR_ON, 0);926	else927		r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_TEAR_OFF);928 929	if (!ddata->ext_te_gpio)930		in->ops.dsi->enable_te(in, enable);931 932	/* possible panel bug */933	msleep(100);934 935	return r;936}937 938static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)939{940	struct panel_drv_data *ddata = to_panel_data(dssdev);941	struct omap_dss_device *in = ddata->in;942	int r;943 944	mutex_lock(&ddata->lock);945 946	if (ddata->te_enabled == enable)947		goto end;948 949	in->ops.dsi->bus_lock(in);950 951	if (ddata->enabled) {952		r = dsicm_wake_up(ddata);953		if (r)954			goto err;955 956		r = _dsicm_enable_te(ddata, enable);957		if (r)958			goto err;959	}960 961	ddata->te_enabled = enable;962 963	in->ops.dsi->bus_unlock(in);964end:965	mutex_unlock(&ddata->lock);966 967	return 0;968err:969	in->ops.dsi->bus_unlock(in);970	mutex_unlock(&ddata->lock);971 972	return r;973}974 975static int dsicm_get_te(struct omap_dss_device *dssdev)976{977	struct panel_drv_data *ddata = to_panel_data(dssdev);978	int r;979 980	mutex_lock(&ddata->lock);981	r = ddata->te_enabled;982	mutex_unlock(&ddata->lock);983 984	return r;985}986 987static int dsicm_memory_read(struct omap_dss_device *dssdev,988		void *buf, size_t size,989		u16 x, u16 y, u16 w, u16 h)990{991	struct panel_drv_data *ddata = to_panel_data(dssdev);992	struct omap_dss_device *in = ddata->in;993	int r;994	int first = 1;995	int plen;996	unsigned buf_used = 0;997 998	if (size < w * h * 3)999		return -ENOMEM;1000 1001	mutex_lock(&ddata->lock);1002 1003	if (!ddata->enabled) {1004		r = -ENODEV;1005		goto err1;1006	}1007 1008	size = min(w * h * 3,1009			dssdev->panel.timings.x_res *1010			dssdev->panel.timings.y_res * 3);1011 1012	in->ops.dsi->bus_lock(in);1013 1014	r = dsicm_wake_up(ddata);1015	if (r)1016		goto err2;1017 1018	/* plen 1 or 2 goes into short packet. until checksum error is fixed,1019	 * use short packets. plen 32 works, but bigger packets seem to cause1020	 * an error. */1021	if (size % 2)1022		plen = 1;1023	else1024		plen = 2;1025 1026	dsicm_set_update_window(ddata, x, y, w, h);1027 1028	r = in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, plen);1029	if (r)1030		goto err2;1031 1032	while (buf_used < size) {1033		u8 dcs_cmd = first ? 0x2e : 0x3e;1034		first = 0;1035 1036		r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd,1037				buf + buf_used, size - buf_used);1038 1039		if (r < 0) {1040			dev_err(dssdev->dev, "read error\n");1041			goto err3;1042		}1043 1044		buf_used += r;1045 1046		if (r < plen) {1047			dev_err(&ddata->pdev->dev, "short read\n");1048			break;1049		}1050 1051		if (signal_pending(current)) {1052			dev_err(&ddata->pdev->dev, "signal pending, "1053					"aborting memory read\n");1054			r = -ERESTARTSYS;1055			goto err3;1056		}1057	}1058 1059	r = buf_used;1060 1061err3:1062	in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, 1);1063err2:1064	in->ops.dsi->bus_unlock(in);1065err1:1066	mutex_unlock(&ddata->lock);1067	return r;1068}1069 1070static void dsicm_ulps_work(struct work_struct *work)1071{1072	struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,1073			ulps_work.work);1074	struct omap_dss_device *dssdev = &ddata->dssdev;1075	struct omap_dss_device *in = ddata->in;1076 1077	mutex_lock(&ddata->lock);1078 1079	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !ddata->enabled) {1080		mutex_unlock(&ddata->lock);1081		return;1082	}1083 1084	in->ops.dsi->bus_lock(in);1085 1086	dsicm_enter_ulps(ddata);1087 1088	in->ops.dsi->bus_unlock(in);1089	mutex_unlock(&ddata->lock);1090}1091 1092static struct omap_dss_driver dsicm_ops = {1093	.connect	= dsicm_connect,1094	.disconnect	= dsicm_disconnect,1095 1096	.enable		= dsicm_enable,1097	.disable	= dsicm_disable,1098 1099	.update		= dsicm_update,1100	.sync		= dsicm_sync,1101 1102	.get_resolution	= dsicm_get_resolution,1103	.get_recommended_bpp = omapdss_default_get_recommended_bpp,1104 1105	.enable_te	= dsicm_enable_te,1106	.get_te		= dsicm_get_te,1107 1108	.memory_read	= dsicm_memory_read,1109};1110 1111static int dsicm_probe(struct platform_device *pdev)1112{1113	struct backlight_properties props;1114	struct panel_drv_data *ddata;1115	struct backlight_device *bldev = NULL;1116	struct device *dev = &pdev->dev;1117	struct omap_dss_device *dssdev;1118	int r;1119 1120	dev_dbg(dev, "probe\n");1121 1122	if (!pdev->dev.of_node)1123		return -ENODEV;1124 1125	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);1126	if (!ddata)1127		return -ENOMEM;1128 1129	platform_set_drvdata(pdev, ddata);1130	ddata->pdev = pdev;1131 1132	ddata->in = omapdss_of_find_source_for_first_ep(pdev->dev.of_node);1133	r = PTR_ERR_OR_ZERO(ddata->in);1134	if (r) {1135		dev_err(&pdev->dev, "failed to find video source: %d\n", r);1136		return r;1137	}1138 1139	ddata->timings.x_res = 864;1140	ddata->timings.y_res = 480;1141	ddata->timings.pixelclock = 864 * 480 * 60;1142 1143	dssdev = &ddata->dssdev;1144	dssdev->dev = dev;1145	dssdev->driver = &dsicm_ops;1146	dssdev->panel.timings = ddata->timings;1147	dssdev->type = OMAP_DISPLAY_TYPE_DSI;1148	dssdev->owner = THIS_MODULE;1149 1150	dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;1151	dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |1152		OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;1153 1154	r = omapdss_register_display(dssdev);1155	if (r) {1156		dev_err(dev, "Failed to register panel\n");1157		goto err_reg;1158	}1159 1160	mutex_init(&ddata->lock);1161 1162	atomic_set(&ddata->do_update, 0);1163 1164	ddata->reset_gpio = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);1165	r = PTR_ERR_OR_ZERO(ddata->reset_gpio);1166	if (r) {1167		dev_err(&pdev->dev, "Failed to request reset gpio: %d\n", r);1168		return r;1169	}1170 1171	gpiod_set_consumer_name(ddata->reset_gpio, "taal rst");1172 1173	ddata->ext_te_gpio = devm_gpiod_get_optional(&pdev->dev, "te",1174						     GPIOD_IN);1175	r = PTR_ERR_OR_ZERO(ddata->ext_te_gpio);1176	if (r) {1177		dev_err(&pdev->dev, "Failed to request TE gpio: %d\n", r);1178		return r;1179	}1180 1181	if (ddata->ext_te_gpio) {1182		gpiod_set_consumer_name(ddata->ext_te_gpio, "taal irq");1183 1184		r = devm_request_irq(dev, gpiod_to_irq(ddata->ext_te_gpio),1185				dsicm_te_isr,1186				IRQF_TRIGGER_RISING,1187				"taal vsync", ddata);1188 1189		if (r) {1190			dev_err(dev, "IRQ request failed\n");1191			return r;1192		}1193 1194		INIT_DEFERRABLE_WORK(&ddata->te_timeout_work,1195					dsicm_te_timeout_work_callback);1196 1197		dev_dbg(dev, "Using GPIO TE\n");1198	}1199 1200	INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work);1201 1202	dsicm_hw_reset(ddata);1203 1204	if (ddata->use_dsi_backlight) {1205		memset(&props, 0, sizeof(struct backlight_properties));1206		props.max_brightness = 255;1207 1208		props.type = BACKLIGHT_RAW;1209		bldev = backlight_device_register(dev_name(dev),1210				dev, ddata, &dsicm_bl_ops, &props);1211		if (IS_ERR(bldev)) {1212			r = PTR_ERR(bldev);1213			goto err_reg;1214		}1215 1216		ddata->bldev = bldev;1217 1218		bldev->props.power = FB_BLANK_UNBLANK;1219		bldev->props.brightness = 255;1220 1221		dsicm_bl_update_status(bldev);1222	}1223 1224	r = sysfs_create_group(&dev->kobj, &dsicm_attr_group);1225	if (r) {1226		dev_err(dev, "failed to create sysfs files\n");1227		goto err_sysfs_create;1228	}1229 1230	return 0;1231 1232err_sysfs_create:1233	if (bldev != NULL)1234		backlight_device_unregister(bldev);1235err_reg:1236	return r;1237}1238 1239static void dsicm_remove(struct platform_device *pdev)1240{1241	struct panel_drv_data *ddata = platform_get_drvdata(pdev);1242	struct omap_dss_device *dssdev = &ddata->dssdev;1243	struct backlight_device *bldev;1244 1245	dev_dbg(&pdev->dev, "remove\n");1246 1247	omapdss_unregister_display(dssdev);1248 1249	dsicm_disable(dssdev);1250	dsicm_disconnect(dssdev);1251 1252	sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group);1253 1254	bldev = ddata->bldev;1255	if (bldev != NULL) {1256		bldev->props.power = FB_BLANK_POWERDOWN;1257		dsicm_bl_update_status(bldev);1258		backlight_device_unregister(bldev);1259	}1260 1261	omap_dss_put_device(ddata->in);1262 1263	dsicm_cancel_ulps_work(ddata);1264 1265	/* reset, to be sure that the panel is in a valid state */1266	dsicm_hw_reset(ddata);1267}1268 1269static const struct of_device_id dsicm_of_match[] = {1270	{ .compatible = "omapdss,panel-dsi-cm", },1271	{},1272};1273 1274MODULE_DEVICE_TABLE(of, dsicm_of_match);1275 1276static struct platform_driver dsicm_driver = {1277	.probe = dsicm_probe,1278	.remove = dsicm_remove,1279	.driver = {1280		.name = "panel-dsi-cm",1281		.of_match_table = dsicm_of_match,1282	},1283};1284 1285module_platform_driver(dsicm_driver);1286 1287MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");1288MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver");1289MODULE_LICENSE("GPL");1290