xref: /linux-6.15/drivers/gpu/drm/tiny/sharp-memory.c (revision cb2e1c21)
1b8f9f217SAlex Lanzano // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2b8f9f217SAlex Lanzano 
3*b86711c6SThomas Zimmermann #include <drm/clients/drm_client_setup.h>
4b8f9f217SAlex Lanzano #include <drm/drm_atomic.h>
5b8f9f217SAlex Lanzano #include <drm/drm_atomic_helper.h>
6b8f9f217SAlex Lanzano #include <drm/drm_connector.h>
7b8f9f217SAlex Lanzano #include <drm/drm_damage_helper.h>
8b8f9f217SAlex Lanzano #include <drm/drm_drv.h>
9b8f9f217SAlex Lanzano #include <drm/drm_fb_dma_helper.h>
10b8f9f217SAlex Lanzano #include <drm/drm_fbdev_dma.h>
11b8f9f217SAlex Lanzano #include <drm/drm_format_helper.h>
12b8f9f217SAlex Lanzano #include <drm/drm_framebuffer.h>
13b8f9f217SAlex Lanzano #include <drm/drm_gem_atomic_helper.h>
14b8f9f217SAlex Lanzano #include <drm/drm_gem_dma_helper.h>
15b8f9f217SAlex Lanzano #include <drm/drm_gem_framebuffer_helper.h>
16b8f9f217SAlex Lanzano #include <drm/drm_managed.h>
17b8f9f217SAlex Lanzano #include <drm/drm_modes.h>
18b8f9f217SAlex Lanzano #include <drm/drm_probe_helper.h>
19b8f9f217SAlex Lanzano #include <drm/drm_rect.h>
20b8f9f217SAlex Lanzano #include <linux/bitrev.h>
21b8f9f217SAlex Lanzano #include <linux/delay.h>
22b8f9f217SAlex Lanzano #include <linux/gpio/consumer.h>
23b8f9f217SAlex Lanzano #include <linux/kthread.h>
24b8f9f217SAlex Lanzano #include <linux/mod_devicetable.h>
25b8f9f217SAlex Lanzano #include <linux/module.h>
26b8f9f217SAlex Lanzano #include <linux/mutex.h>
27b8f9f217SAlex Lanzano #include <linux/pwm.h>
28b8f9f217SAlex Lanzano #include <linux/spi/spi.h>
29b8f9f217SAlex Lanzano 
30b8f9f217SAlex Lanzano #define SHARP_MODE_PERIOD 8
31b8f9f217SAlex Lanzano #define SHARP_ADDR_PERIOD 8
32b8f9f217SAlex Lanzano #define SHARP_DUMMY_PERIOD 8
33b8f9f217SAlex Lanzano 
34b8f9f217SAlex Lanzano #define SHARP_MEMORY_DISPLAY_MAINTAIN_MODE 0
35b8f9f217SAlex Lanzano #define SHARP_MEMORY_DISPLAY_UPDATE_MODE 1
36b8f9f217SAlex Lanzano #define SHARP_MEMORY_DISPLAY_CLEAR_MODE 4
37b8f9f217SAlex Lanzano 
38b8f9f217SAlex Lanzano enum sharp_memory_model {
39b8f9f217SAlex Lanzano 	LS010B7DH04,
40b8f9f217SAlex Lanzano 	LS011B7DH03,
41b8f9f217SAlex Lanzano 	LS012B7DD01,
42b8f9f217SAlex Lanzano 	LS013B7DH03,
43b8f9f217SAlex Lanzano 	LS013B7DH05,
44b8f9f217SAlex Lanzano 	LS018B7DH02,
45b8f9f217SAlex Lanzano 	LS027B7DH01,
46b8f9f217SAlex Lanzano 	LS027B7DH01A,
47b8f9f217SAlex Lanzano 	LS032B7DD02,
48b8f9f217SAlex Lanzano 	LS044Q7DH01,
49b8f9f217SAlex Lanzano };
50b8f9f217SAlex Lanzano 
51b8f9f217SAlex Lanzano enum sharp_memory_vcom_mode {
52b8f9f217SAlex Lanzano 	SHARP_MEMORY_SOFTWARE_VCOM,
53b8f9f217SAlex Lanzano 	SHARP_MEMORY_EXTERNAL_VCOM,
54b8f9f217SAlex Lanzano 	SHARP_MEMORY_PWM_VCOM
55b8f9f217SAlex Lanzano };
56b8f9f217SAlex Lanzano 
57b8f9f217SAlex Lanzano struct sharp_memory_device {
58b8f9f217SAlex Lanzano 	struct drm_device drm;
59b8f9f217SAlex Lanzano 	struct spi_device *spi;
60b8f9f217SAlex Lanzano 
61b8f9f217SAlex Lanzano 	const struct drm_display_mode *mode;
62b8f9f217SAlex Lanzano 
63b8f9f217SAlex Lanzano 	struct drm_crtc crtc;
64b8f9f217SAlex Lanzano 	struct drm_plane plane;
65b8f9f217SAlex Lanzano 	struct drm_encoder encoder;
66b8f9f217SAlex Lanzano 	struct drm_connector connector;
67b8f9f217SAlex Lanzano 
68b8f9f217SAlex Lanzano 	struct gpio_desc *enable_gpio;
69b8f9f217SAlex Lanzano 
70b8f9f217SAlex Lanzano 	struct task_struct *sw_vcom_signal;
71b8f9f217SAlex Lanzano 	struct pwm_device *pwm_vcom_signal;
72b8f9f217SAlex Lanzano 
73b8f9f217SAlex Lanzano 	enum sharp_memory_vcom_mode vcom_mode;
74b8f9f217SAlex Lanzano 	u8 vcom;
75b8f9f217SAlex Lanzano 
76b8f9f217SAlex Lanzano 	u32 pitch;
77b8f9f217SAlex Lanzano 	u32 tx_buffer_size;
78b8f9f217SAlex Lanzano 	u8 *tx_buffer;
79b8f9f217SAlex Lanzano 
80b8f9f217SAlex Lanzano 	/* When vcom_mode == "software" a kthread is used to periodically send a
81b8f9f217SAlex Lanzano 	 * 'maintain display' message over spi. This mutex ensures tx_buffer access
82b8f9f217SAlex Lanzano 	 * and spi bus usage is synchronized in this case.
83b8f9f217SAlex Lanzano 	 */
84b8f9f217SAlex Lanzano 	struct mutex tx_mutex;
85b8f9f217SAlex Lanzano };
86b8f9f217SAlex Lanzano 
sharp_memory_spi_write(struct spi_device * spi,void * buf,size_t len)87b8f9f217SAlex Lanzano static inline int sharp_memory_spi_write(struct spi_device *spi, void *buf, size_t len)
88b8f9f217SAlex Lanzano {
89b8f9f217SAlex Lanzano 	/* Reverse the bit order */
90b8f9f217SAlex Lanzano 	for (u8 *b = buf; b < ((u8 *)buf) + len; ++b)
91b8f9f217SAlex Lanzano 		*b = bitrev8(*b);
92b8f9f217SAlex Lanzano 
93b8f9f217SAlex Lanzano 	return spi_write(spi, buf, len);
94b8f9f217SAlex Lanzano }
95b8f9f217SAlex Lanzano 
drm_to_sharp_memory_device(struct drm_device * drm)96b8f9f217SAlex Lanzano static inline struct sharp_memory_device *drm_to_sharp_memory_device(struct drm_device *drm)
97b8f9f217SAlex Lanzano {
98b8f9f217SAlex Lanzano 	return container_of(drm, struct sharp_memory_device, drm);
99b8f9f217SAlex Lanzano }
100b8f9f217SAlex Lanzano 
101b8f9f217SAlex Lanzano DEFINE_DRM_GEM_DMA_FOPS(sharp_memory_fops);
102b8f9f217SAlex Lanzano 
103b8f9f217SAlex Lanzano static const struct drm_driver sharp_memory_drm_driver = {
104b8f9f217SAlex Lanzano 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
105b8f9f217SAlex Lanzano 	.fops			= &sharp_memory_fops,
106b8f9f217SAlex Lanzano 	DRM_GEM_DMA_DRIVER_OPS_VMAP,
107b8f9f217SAlex Lanzano 	DRM_FBDEV_DMA_DRIVER_OPS,
108b8f9f217SAlex Lanzano 	.name			= "sharp_memory_display",
109b8f9f217SAlex Lanzano 	.desc			= "Sharp Display Memory LCD",
110b8f9f217SAlex Lanzano 	.major			= 1,
111b8f9f217SAlex Lanzano 	.minor			= 0,
112b8f9f217SAlex Lanzano };
113b8f9f217SAlex Lanzano 
sharp_memory_set_tx_buffer_mode(u8 * buffer,u8 mode,u8 vcom)114b8f9f217SAlex Lanzano static inline void sharp_memory_set_tx_buffer_mode(u8 *buffer, u8 mode, u8 vcom)
115b8f9f217SAlex Lanzano {
116b8f9f217SAlex Lanzano 	*buffer = mode | (vcom << 1);
117b8f9f217SAlex Lanzano }
118b8f9f217SAlex Lanzano 
sharp_memory_set_tx_buffer_addresses(u8 * buffer,struct drm_rect clip,u32 pitch)119b8f9f217SAlex Lanzano static inline void sharp_memory_set_tx_buffer_addresses(u8 *buffer,
120b8f9f217SAlex Lanzano 							struct drm_rect clip,
121b8f9f217SAlex Lanzano 							u32 pitch)
122b8f9f217SAlex Lanzano {
123b8f9f217SAlex Lanzano 	for (u32 line = 0; line < clip.y2; ++line)
124b8f9f217SAlex Lanzano 		buffer[line * pitch] = line + 1;
125b8f9f217SAlex Lanzano }
126b8f9f217SAlex Lanzano 
sharp_memory_set_tx_buffer_data(u8 * buffer,struct drm_framebuffer * fb,struct drm_rect clip,u32 pitch,struct drm_format_conv_state * fmtcnv_state)127b8f9f217SAlex Lanzano static void sharp_memory_set_tx_buffer_data(u8 *buffer,
128b8f9f217SAlex Lanzano 					    struct drm_framebuffer *fb,
129b8f9f217SAlex Lanzano 					    struct drm_rect clip,
130b8f9f217SAlex Lanzano 					    u32 pitch,
131b8f9f217SAlex Lanzano 					    struct drm_format_conv_state *fmtcnv_state)
132b8f9f217SAlex Lanzano {
133b8f9f217SAlex Lanzano 	int ret;
134b8f9f217SAlex Lanzano 	struct iosys_map dst, vmap;
135b8f9f217SAlex Lanzano 	struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
136b8f9f217SAlex Lanzano 
137b8f9f217SAlex Lanzano 	ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
138b8f9f217SAlex Lanzano 	if (ret)
139b8f9f217SAlex Lanzano 		return;
140b8f9f217SAlex Lanzano 
141b8f9f217SAlex Lanzano 	iosys_map_set_vaddr(&dst, buffer);
142b8f9f217SAlex Lanzano 	iosys_map_set_vaddr(&vmap, dma_obj->vaddr);
143b8f9f217SAlex Lanzano 
144b8f9f217SAlex Lanzano 	drm_fb_xrgb8888_to_mono(&dst, &pitch, &vmap, fb, &clip, fmtcnv_state);
145b8f9f217SAlex Lanzano 
146b8f9f217SAlex Lanzano 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
147b8f9f217SAlex Lanzano }
148b8f9f217SAlex Lanzano 
sharp_memory_update_display(struct sharp_memory_device * smd,struct drm_framebuffer * fb,struct drm_rect clip,struct drm_format_conv_state * fmtcnv_state)149b8f9f217SAlex Lanzano static int sharp_memory_update_display(struct sharp_memory_device *smd,
150b8f9f217SAlex Lanzano 				       struct drm_framebuffer *fb,
151b8f9f217SAlex Lanzano 				       struct drm_rect clip,
152b8f9f217SAlex Lanzano 				       struct drm_format_conv_state *fmtcnv_state)
153b8f9f217SAlex Lanzano {
154b8f9f217SAlex Lanzano 	int ret;
155b8f9f217SAlex Lanzano 	u32 pitch = smd->pitch;
156b8f9f217SAlex Lanzano 	u8 vcom = smd->vcom;
157b8f9f217SAlex Lanzano 	u8 *tx_buffer = smd->tx_buffer;
158b8f9f217SAlex Lanzano 	u32 tx_buffer_size = smd->tx_buffer_size;
159b8f9f217SAlex Lanzano 
160b8f9f217SAlex Lanzano 	mutex_lock(&smd->tx_mutex);
161b8f9f217SAlex Lanzano 
162b8f9f217SAlex Lanzano 	/* Populate the transmit buffer with frame data */
163b8f9f217SAlex Lanzano 	sharp_memory_set_tx_buffer_mode(&tx_buffer[0],
164b8f9f217SAlex Lanzano 					SHARP_MEMORY_DISPLAY_UPDATE_MODE, vcom);
165b8f9f217SAlex Lanzano 	sharp_memory_set_tx_buffer_addresses(&tx_buffer[1], clip, pitch);
166b8f9f217SAlex Lanzano 	sharp_memory_set_tx_buffer_data(&tx_buffer[2], fb, clip, pitch, fmtcnv_state);
167b8f9f217SAlex Lanzano 
168b8f9f217SAlex Lanzano 	ret = sharp_memory_spi_write(smd->spi, tx_buffer, tx_buffer_size);
169b8f9f217SAlex Lanzano 
170b8f9f217SAlex Lanzano 	mutex_unlock(&smd->tx_mutex);
171b8f9f217SAlex Lanzano 
172b8f9f217SAlex Lanzano 	return ret;
173b8f9f217SAlex Lanzano }
174b8f9f217SAlex Lanzano 
sharp_memory_maintain_display(struct sharp_memory_device * smd)175b8f9f217SAlex Lanzano static int sharp_memory_maintain_display(struct sharp_memory_device *smd)
176b8f9f217SAlex Lanzano {
177b8f9f217SAlex Lanzano 	int ret;
178b8f9f217SAlex Lanzano 	u8 vcom = smd->vcom;
179b8f9f217SAlex Lanzano 	u8 *tx_buffer = smd->tx_buffer;
180b8f9f217SAlex Lanzano 
181b8f9f217SAlex Lanzano 	mutex_lock(&smd->tx_mutex);
182b8f9f217SAlex Lanzano 
183b8f9f217SAlex Lanzano 	sharp_memory_set_tx_buffer_mode(&tx_buffer[0], SHARP_MEMORY_DISPLAY_MAINTAIN_MODE, vcom);
184b8f9f217SAlex Lanzano 	tx_buffer[1] = 0; /* Write dummy data */
185b8f9f217SAlex Lanzano 	ret = sharp_memory_spi_write(smd->spi, tx_buffer, 2);
186b8f9f217SAlex Lanzano 
187b8f9f217SAlex Lanzano 	mutex_unlock(&smd->tx_mutex);
188b8f9f217SAlex Lanzano 
189b8f9f217SAlex Lanzano 	return ret;
190b8f9f217SAlex Lanzano }
191b8f9f217SAlex Lanzano 
sharp_memory_clear_display(struct sharp_memory_device * smd)192b8f9f217SAlex Lanzano static int sharp_memory_clear_display(struct sharp_memory_device *smd)
193b8f9f217SAlex Lanzano {
194b8f9f217SAlex Lanzano 	int ret;
195b8f9f217SAlex Lanzano 	u8 vcom = smd->vcom;
196b8f9f217SAlex Lanzano 	u8 *tx_buffer = smd->tx_buffer;
197b8f9f217SAlex Lanzano 
198b8f9f217SAlex Lanzano 	mutex_lock(&smd->tx_mutex);
199b8f9f217SAlex Lanzano 
200b8f9f217SAlex Lanzano 	sharp_memory_set_tx_buffer_mode(&tx_buffer[0], SHARP_MEMORY_DISPLAY_CLEAR_MODE, vcom);
201b8f9f217SAlex Lanzano 	tx_buffer[1] = 0; /* write dummy data */
202b8f9f217SAlex Lanzano 	ret = sharp_memory_spi_write(smd->spi, tx_buffer, 2);
203b8f9f217SAlex Lanzano 
204b8f9f217SAlex Lanzano 	mutex_unlock(&smd->tx_mutex);
205b8f9f217SAlex Lanzano 
206b8f9f217SAlex Lanzano 	return ret;
207b8f9f217SAlex Lanzano }
208b8f9f217SAlex Lanzano 
sharp_memory_fb_dirty(struct drm_framebuffer * fb,struct drm_rect * rect,struct drm_format_conv_state * fmtconv_state)209b8f9f217SAlex Lanzano static void sharp_memory_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect,
210b8f9f217SAlex Lanzano 				  struct drm_format_conv_state *fmtconv_state)
211b8f9f217SAlex Lanzano {
212b8f9f217SAlex Lanzano 	struct drm_rect clip;
213b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd = drm_to_sharp_memory_device(fb->dev);
214b8f9f217SAlex Lanzano 
215b8f9f217SAlex Lanzano 	/* Always update a full line regardless of what is dirty */
216b8f9f217SAlex Lanzano 	clip.x1 = 0;
217b8f9f217SAlex Lanzano 	clip.x2 = fb->width;
218b8f9f217SAlex Lanzano 	clip.y1 = rect->y1;
219b8f9f217SAlex Lanzano 	clip.y2 = rect->y2;
220b8f9f217SAlex Lanzano 
221b8f9f217SAlex Lanzano 	sharp_memory_update_display(smd, fb, clip, fmtconv_state);
222b8f9f217SAlex Lanzano }
223b8f9f217SAlex Lanzano 
sharp_memory_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)224b8f9f217SAlex Lanzano static int sharp_memory_plane_atomic_check(struct drm_plane *plane,
225b8f9f217SAlex Lanzano 					   struct drm_atomic_state *state)
226b8f9f217SAlex Lanzano {
227b8f9f217SAlex Lanzano 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
228b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd;
229b8f9f217SAlex Lanzano 	struct drm_crtc_state *crtc_state;
230b8f9f217SAlex Lanzano 
231b8f9f217SAlex Lanzano 	smd = container_of(plane, struct sharp_memory_device, plane);
232b8f9f217SAlex Lanzano 	crtc_state = drm_atomic_get_new_crtc_state(state, &smd->crtc);
233b8f9f217SAlex Lanzano 
234b8f9f217SAlex Lanzano 	return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
235b8f9f217SAlex Lanzano 						   DRM_PLANE_NO_SCALING,
236b8f9f217SAlex Lanzano 						   DRM_PLANE_NO_SCALING,
237b8f9f217SAlex Lanzano 						   false, false);
238b8f9f217SAlex Lanzano }
239b8f9f217SAlex Lanzano 
sharp_memory_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)240b8f9f217SAlex Lanzano static void sharp_memory_plane_atomic_update(struct drm_plane *plane,
241b8f9f217SAlex Lanzano 					     struct drm_atomic_state *state)
242b8f9f217SAlex Lanzano {
243b8f9f217SAlex Lanzano 	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
244b8f9f217SAlex Lanzano 	struct drm_plane_state *plane_state = plane->state;
245b8f9f217SAlex Lanzano 	struct drm_format_conv_state fmtcnv_state = DRM_FORMAT_CONV_STATE_INIT;
246b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd;
247b8f9f217SAlex Lanzano 	struct drm_rect rect;
248b8f9f217SAlex Lanzano 
249b8f9f217SAlex Lanzano 	smd = container_of(plane, struct sharp_memory_device, plane);
250b8f9f217SAlex Lanzano 	if (!smd->crtc.state->active)
251b8f9f217SAlex Lanzano 		return;
252b8f9f217SAlex Lanzano 
253b8f9f217SAlex Lanzano 	if (drm_atomic_helper_damage_merged(old_state, plane_state, &rect))
254b8f9f217SAlex Lanzano 		sharp_memory_fb_dirty(plane_state->fb, &rect, &fmtcnv_state);
255b8f9f217SAlex Lanzano 
256b8f9f217SAlex Lanzano 	drm_format_conv_state_release(&fmtcnv_state);
257b8f9f217SAlex Lanzano }
258b8f9f217SAlex Lanzano 
259b8f9f217SAlex Lanzano static const struct drm_plane_helper_funcs sharp_memory_plane_helper_funcs = {
260b8f9f217SAlex Lanzano 	.prepare_fb = drm_gem_plane_helper_prepare_fb,
261b8f9f217SAlex Lanzano 	.atomic_check = sharp_memory_plane_atomic_check,
262b8f9f217SAlex Lanzano 	.atomic_update = sharp_memory_plane_atomic_update,
263b8f9f217SAlex Lanzano };
264b8f9f217SAlex Lanzano 
sharp_memory_format_mod_supported(struct drm_plane * plane,u32 format,u64 modifier)265b8f9f217SAlex Lanzano static bool sharp_memory_format_mod_supported(struct drm_plane *plane,
266b8f9f217SAlex Lanzano 					      u32 format,
267b8f9f217SAlex Lanzano 					      u64 modifier)
268b8f9f217SAlex Lanzano {
269b8f9f217SAlex Lanzano 	return modifier == DRM_FORMAT_MOD_LINEAR;
270b8f9f217SAlex Lanzano }
271b8f9f217SAlex Lanzano 
272b8f9f217SAlex Lanzano static const struct drm_plane_funcs sharp_memory_plane_funcs = {
273b8f9f217SAlex Lanzano 	.update_plane = drm_atomic_helper_update_plane,
274b8f9f217SAlex Lanzano 	.disable_plane = drm_atomic_helper_disable_plane,
275b8f9f217SAlex Lanzano 	.destroy = drm_plane_cleanup,
276b8f9f217SAlex Lanzano 	.reset = drm_atomic_helper_plane_reset,
277b8f9f217SAlex Lanzano 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
278b8f9f217SAlex Lanzano 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
279b8f9f217SAlex Lanzano 	.format_mod_supported = sharp_memory_format_mod_supported,
280b8f9f217SAlex Lanzano };
281b8f9f217SAlex Lanzano 
sharp_memory_crtc_mode_valid(struct drm_crtc * crtc,const struct drm_display_mode * mode)282b8f9f217SAlex Lanzano static enum drm_mode_status sharp_memory_crtc_mode_valid(struct drm_crtc *crtc,
283b8f9f217SAlex Lanzano 							 const struct drm_display_mode *mode)
284b8f9f217SAlex Lanzano {
285b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd = drm_to_sharp_memory_device(crtc->dev);
286b8f9f217SAlex Lanzano 
287b8f9f217SAlex Lanzano 	return drm_crtc_helper_mode_valid_fixed(crtc, mode, smd->mode);
288b8f9f217SAlex Lanzano }
289b8f9f217SAlex Lanzano 
sharp_memory_crtc_check(struct drm_crtc * crtc,struct drm_atomic_state * state)290b8f9f217SAlex Lanzano static int sharp_memory_crtc_check(struct drm_crtc *crtc,
291b8f9f217SAlex Lanzano 				   struct drm_atomic_state *state)
292b8f9f217SAlex Lanzano {
293b8f9f217SAlex Lanzano 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
294b8f9f217SAlex Lanzano 	int ret;
295b8f9f217SAlex Lanzano 
296b8f9f217SAlex Lanzano 	if (!crtc_state->enable)
297b8f9f217SAlex Lanzano 		goto out;
298b8f9f217SAlex Lanzano 
299b8f9f217SAlex Lanzano 	ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
300b8f9f217SAlex Lanzano 	if (ret)
301b8f9f217SAlex Lanzano 		return ret;
302b8f9f217SAlex Lanzano 
303b8f9f217SAlex Lanzano out:
304b8f9f217SAlex Lanzano 	return drm_atomic_add_affected_planes(state, crtc);
305b8f9f217SAlex Lanzano }
306b8f9f217SAlex Lanzano 
sharp_memory_sw_vcom_signal_thread(void * data)307b8f9f217SAlex Lanzano static int sharp_memory_sw_vcom_signal_thread(void *data)
308b8f9f217SAlex Lanzano {
309b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd = data;
310b8f9f217SAlex Lanzano 
311b8f9f217SAlex Lanzano 	while (!kthread_should_stop()) {
312b8f9f217SAlex Lanzano 		smd->vcom ^= 1; /* Toggle vcom */
313b8f9f217SAlex Lanzano 		sharp_memory_maintain_display(smd);
314b8f9f217SAlex Lanzano 		msleep(1000);
315b8f9f217SAlex Lanzano 	}
316b8f9f217SAlex Lanzano 
317b8f9f217SAlex Lanzano 	return 0;
318b8f9f217SAlex Lanzano }
319b8f9f217SAlex Lanzano 
sharp_memory_crtc_enable(struct drm_crtc * crtc,struct drm_atomic_state * state)320b8f9f217SAlex Lanzano static void sharp_memory_crtc_enable(struct drm_crtc *crtc,
321b8f9f217SAlex Lanzano 				     struct drm_atomic_state *state)
322b8f9f217SAlex Lanzano {
323b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd = drm_to_sharp_memory_device(crtc->dev);
324b8f9f217SAlex Lanzano 
325b8f9f217SAlex Lanzano 	sharp_memory_clear_display(smd);
326b8f9f217SAlex Lanzano 
327b8f9f217SAlex Lanzano 	if (smd->enable_gpio)
328b8f9f217SAlex Lanzano 		gpiod_set_value(smd->enable_gpio, 1);
329b8f9f217SAlex Lanzano }
330b8f9f217SAlex Lanzano 
sharp_memory_crtc_disable(struct drm_crtc * crtc,struct drm_atomic_state * state)331b8f9f217SAlex Lanzano static void sharp_memory_crtc_disable(struct drm_crtc *crtc,
332b8f9f217SAlex Lanzano 				      struct drm_atomic_state *state)
333b8f9f217SAlex Lanzano {
334b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd = drm_to_sharp_memory_device(crtc->dev);
335b8f9f217SAlex Lanzano 
336b8f9f217SAlex Lanzano 	sharp_memory_clear_display(smd);
337b8f9f217SAlex Lanzano 
338b8f9f217SAlex Lanzano 	if (smd->enable_gpio)
339b8f9f217SAlex Lanzano 		gpiod_set_value(smd->enable_gpio, 0);
340b8f9f217SAlex Lanzano }
341b8f9f217SAlex Lanzano 
342b8f9f217SAlex Lanzano static const struct drm_crtc_helper_funcs sharp_memory_crtc_helper_funcs = {
343b8f9f217SAlex Lanzano 	.mode_valid = sharp_memory_crtc_mode_valid,
344b8f9f217SAlex Lanzano 	.atomic_check = sharp_memory_crtc_check,
345b8f9f217SAlex Lanzano 	.atomic_enable = sharp_memory_crtc_enable,
346b8f9f217SAlex Lanzano 	.atomic_disable = sharp_memory_crtc_disable,
347b8f9f217SAlex Lanzano };
348b8f9f217SAlex Lanzano 
349b8f9f217SAlex Lanzano static const struct drm_crtc_funcs sharp_memory_crtc_funcs = {
350b8f9f217SAlex Lanzano 	.reset = drm_atomic_helper_crtc_reset,
351b8f9f217SAlex Lanzano 	.destroy = drm_crtc_cleanup,
352b8f9f217SAlex Lanzano 	.set_config = drm_atomic_helper_set_config,
353b8f9f217SAlex Lanzano 	.page_flip = drm_atomic_helper_page_flip,
354b8f9f217SAlex Lanzano 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
355b8f9f217SAlex Lanzano 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
356b8f9f217SAlex Lanzano };
357b8f9f217SAlex Lanzano 
358b8f9f217SAlex Lanzano static const struct drm_encoder_funcs sharp_memory_encoder_funcs = {
359b8f9f217SAlex Lanzano 	.destroy = drm_encoder_cleanup,
360b8f9f217SAlex Lanzano };
361b8f9f217SAlex Lanzano 
sharp_memory_connector_get_modes(struct drm_connector * connector)362b8f9f217SAlex Lanzano static int sharp_memory_connector_get_modes(struct drm_connector *connector)
363b8f9f217SAlex Lanzano {
364b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd = drm_to_sharp_memory_device(connector->dev);
365b8f9f217SAlex Lanzano 
366b8f9f217SAlex Lanzano 	return drm_connector_helper_get_modes_fixed(connector, smd->mode);
367b8f9f217SAlex Lanzano }
368b8f9f217SAlex Lanzano 
369b8f9f217SAlex Lanzano static const struct drm_connector_helper_funcs sharp_memory_connector_hfuncs = {
370b8f9f217SAlex Lanzano 	.get_modes = sharp_memory_connector_get_modes,
371b8f9f217SAlex Lanzano };
372b8f9f217SAlex Lanzano 
373b8f9f217SAlex Lanzano static const struct drm_connector_funcs sharp_memory_connector_funcs = {
374b8f9f217SAlex Lanzano 	.reset = drm_atomic_helper_connector_reset,
375b8f9f217SAlex Lanzano 	.fill_modes = drm_helper_probe_single_connector_modes,
376b8f9f217SAlex Lanzano 	.destroy = drm_connector_cleanup,
377b8f9f217SAlex Lanzano 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
378b8f9f217SAlex Lanzano 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
379b8f9f217SAlex Lanzano 
380b8f9f217SAlex Lanzano };
381b8f9f217SAlex Lanzano 
382b8f9f217SAlex Lanzano static const struct drm_mode_config_funcs sharp_memory_mode_config_funcs = {
383b8f9f217SAlex Lanzano 	.fb_create = drm_gem_fb_create_with_dirty,
384b8f9f217SAlex Lanzano 	.atomic_check = drm_atomic_helper_check,
385b8f9f217SAlex Lanzano 	.atomic_commit = drm_atomic_helper_commit,
386b8f9f217SAlex Lanzano };
387b8f9f217SAlex Lanzano 
388b8f9f217SAlex Lanzano static const struct drm_display_mode sharp_memory_ls010b7dh04_mode = {
389b8f9f217SAlex Lanzano 	DRM_SIMPLE_MODE(128, 128, 18, 18),
390b8f9f217SAlex Lanzano };
391b8f9f217SAlex Lanzano 
392b8f9f217SAlex Lanzano static const struct drm_display_mode sharp_memory_ls011b7dh03_mode = {
393b8f9f217SAlex Lanzano 	DRM_SIMPLE_MODE(160, 68, 25, 10),
394b8f9f217SAlex Lanzano };
395b8f9f217SAlex Lanzano 
396b8f9f217SAlex Lanzano static const struct drm_display_mode sharp_memory_ls012b7dd01_mode = {
397b8f9f217SAlex Lanzano 	DRM_SIMPLE_MODE(184, 38, 29, 6),
398b8f9f217SAlex Lanzano };
399b8f9f217SAlex Lanzano 
400b8f9f217SAlex Lanzano static const struct drm_display_mode sharp_memory_ls013b7dh03_mode = {
401b8f9f217SAlex Lanzano 	DRM_SIMPLE_MODE(128, 128, 23, 23),
402b8f9f217SAlex Lanzano };
403b8f9f217SAlex Lanzano 
404b8f9f217SAlex Lanzano static const struct drm_display_mode sharp_memory_ls013b7dh05_mode = {
405b8f9f217SAlex Lanzano 	DRM_SIMPLE_MODE(144, 168, 20, 24),
406b8f9f217SAlex Lanzano };
407b8f9f217SAlex Lanzano 
408b8f9f217SAlex Lanzano static const struct drm_display_mode sharp_memory_ls018b7dh02_mode = {
409b8f9f217SAlex Lanzano 	DRM_SIMPLE_MODE(230, 303, 27, 36),
410b8f9f217SAlex Lanzano };
411b8f9f217SAlex Lanzano 
412b8f9f217SAlex Lanzano static const struct drm_display_mode sharp_memory_ls027b7dh01_mode = {
413b8f9f217SAlex Lanzano 	DRM_SIMPLE_MODE(400, 240, 58, 35),
414b8f9f217SAlex Lanzano };
415b8f9f217SAlex Lanzano 
416b8f9f217SAlex Lanzano static const struct drm_display_mode sharp_memory_ls032b7dd02_mode = {
417b8f9f217SAlex Lanzano 	DRM_SIMPLE_MODE(336, 536, 42, 68),
418b8f9f217SAlex Lanzano };
419b8f9f217SAlex Lanzano 
420b8f9f217SAlex Lanzano static const struct drm_display_mode sharp_memory_ls044q7dh01_mode = {
421b8f9f217SAlex Lanzano 	DRM_SIMPLE_MODE(320, 240, 89, 67),
422b8f9f217SAlex Lanzano };
423b8f9f217SAlex Lanzano 
424b8f9f217SAlex Lanzano static const struct spi_device_id sharp_memory_ids[] = {
425b8f9f217SAlex Lanzano 	{"ls010b7dh04", (kernel_ulong_t)&sharp_memory_ls010b7dh04_mode},
426b8f9f217SAlex Lanzano 	{"ls011b7dh03", (kernel_ulong_t)&sharp_memory_ls011b7dh03_mode},
427b8f9f217SAlex Lanzano 	{"ls012b7dd01", (kernel_ulong_t)&sharp_memory_ls012b7dd01_mode},
428b8f9f217SAlex Lanzano 	{"ls013b7dh03", (kernel_ulong_t)&sharp_memory_ls013b7dh03_mode},
429b8f9f217SAlex Lanzano 	{"ls013b7dh05", (kernel_ulong_t)&sharp_memory_ls013b7dh05_mode},
430b8f9f217SAlex Lanzano 	{"ls018b7dh02", (kernel_ulong_t)&sharp_memory_ls018b7dh02_mode},
431b8f9f217SAlex Lanzano 	{"ls027b7dh01", (kernel_ulong_t)&sharp_memory_ls027b7dh01_mode},
432b8f9f217SAlex Lanzano 	{"ls027b7dh01a", (kernel_ulong_t)&sharp_memory_ls027b7dh01_mode},
433b8f9f217SAlex Lanzano 	{"ls032b7dd02", (kernel_ulong_t)&sharp_memory_ls032b7dd02_mode},
434b8f9f217SAlex Lanzano 	{"ls044q7dh01", (kernel_ulong_t)&sharp_memory_ls044q7dh01_mode},
435b8f9f217SAlex Lanzano 	{},
436b8f9f217SAlex Lanzano };
437b8f9f217SAlex Lanzano MODULE_DEVICE_TABLE(spi, sharp_memory_ids);
438b8f9f217SAlex Lanzano 
439b8f9f217SAlex Lanzano static const struct of_device_id sharp_memory_of_match[] = {
440b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls010b7dh04", &sharp_memory_ls010b7dh04_mode},
441b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls011b7dh03", &sharp_memory_ls011b7dh03_mode},
442b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls012b7dd01", &sharp_memory_ls012b7dd01_mode},
443b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls013b7dh03", &sharp_memory_ls013b7dh03_mode},
444b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls013b7dh05", &sharp_memory_ls013b7dh05_mode},
445b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls018b7dh02", &sharp_memory_ls018b7dh02_mode},
446b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls027b7dh01", &sharp_memory_ls027b7dh01_mode},
447b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls027b7dh01a", &sharp_memory_ls027b7dh01_mode},
448b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls032b7dd02", &sharp_memory_ls032b7dd02_mode},
449b8f9f217SAlex Lanzano 	{.compatible = "sharp,ls044q7dh01", &sharp_memory_ls044q7dh01_mode},
450b8f9f217SAlex Lanzano 	{},
451b8f9f217SAlex Lanzano };
452b8f9f217SAlex Lanzano MODULE_DEVICE_TABLE(of, sharp_memory_of_match);
453b8f9f217SAlex Lanzano 
454b8f9f217SAlex Lanzano static const u32 sharp_memory_formats[] = {
455b8f9f217SAlex Lanzano 	DRM_FORMAT_XRGB8888,
456b8f9f217SAlex Lanzano };
457b8f9f217SAlex Lanzano 
sharp_memory_pipe_init(struct drm_device * dev,struct sharp_memory_device * smd,const u32 * formats,unsigned int format_count,const u64 * format_modifiers)458b8f9f217SAlex Lanzano static int sharp_memory_pipe_init(struct drm_device *dev,
459b8f9f217SAlex Lanzano 				  struct sharp_memory_device *smd,
460b8f9f217SAlex Lanzano 				  const u32 *formats, unsigned int format_count,
461b8f9f217SAlex Lanzano 				  const u64 *format_modifiers)
462b8f9f217SAlex Lanzano {
463b8f9f217SAlex Lanzano 	int ret;
464b8f9f217SAlex Lanzano 	struct drm_encoder *encoder = &smd->encoder;
465b8f9f217SAlex Lanzano 	struct drm_plane *plane = &smd->plane;
466b8f9f217SAlex Lanzano 	struct drm_crtc *crtc = &smd->crtc;
467b8f9f217SAlex Lanzano 	struct drm_connector *connector = &smd->connector;
468b8f9f217SAlex Lanzano 
469b8f9f217SAlex Lanzano 	drm_plane_helper_add(plane, &sharp_memory_plane_helper_funcs);
470b8f9f217SAlex Lanzano 	ret = drm_universal_plane_init(dev, plane, 0,
471b8f9f217SAlex Lanzano 				       &sharp_memory_plane_funcs,
472b8f9f217SAlex Lanzano 				       formats, format_count,
473b8f9f217SAlex Lanzano 				       format_modifiers,
474b8f9f217SAlex Lanzano 				       DRM_PLANE_TYPE_PRIMARY, NULL);
475b8f9f217SAlex Lanzano 	if (ret)
476b8f9f217SAlex Lanzano 		return ret;
477b8f9f217SAlex Lanzano 
478b8f9f217SAlex Lanzano 	drm_crtc_helper_add(crtc, &sharp_memory_crtc_helper_funcs);
479b8f9f217SAlex Lanzano 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
480b8f9f217SAlex Lanzano 					&sharp_memory_crtc_funcs, NULL);
481b8f9f217SAlex Lanzano 	if (ret)
482b8f9f217SAlex Lanzano 		return ret;
483b8f9f217SAlex Lanzano 
484b8f9f217SAlex Lanzano 	encoder->possible_crtcs = drm_crtc_mask(crtc);
485b8f9f217SAlex Lanzano 	ret = drm_encoder_init(dev, encoder, &sharp_memory_encoder_funcs,
486b8f9f217SAlex Lanzano 			       DRM_MODE_ENCODER_NONE, NULL);
487b8f9f217SAlex Lanzano 	if (ret)
488b8f9f217SAlex Lanzano 		return ret;
489b8f9f217SAlex Lanzano 
490b8f9f217SAlex Lanzano 	ret = drm_connector_init(&smd->drm, &smd->connector,
491b8f9f217SAlex Lanzano 				 &sharp_memory_connector_funcs,
492b8f9f217SAlex Lanzano 				 DRM_MODE_CONNECTOR_SPI);
493b8f9f217SAlex Lanzano 	if (ret)
494b8f9f217SAlex Lanzano 		return ret;
495b8f9f217SAlex Lanzano 
496b8f9f217SAlex Lanzano 	drm_connector_helper_add(&smd->connector,
497b8f9f217SAlex Lanzano 				 &sharp_memory_connector_hfuncs);
498b8f9f217SAlex Lanzano 
499b8f9f217SAlex Lanzano 	return drm_connector_attach_encoder(connector, encoder);
500b8f9f217SAlex Lanzano }
501b8f9f217SAlex Lanzano 
sharp_memory_init_pwm_vcom_signal(struct sharp_memory_device * smd)502b8f9f217SAlex Lanzano static int sharp_memory_init_pwm_vcom_signal(struct sharp_memory_device *smd)
503b8f9f217SAlex Lanzano {
504b8f9f217SAlex Lanzano 	int ret;
505b8f9f217SAlex Lanzano 	struct device *dev = &smd->spi->dev;
506b8f9f217SAlex Lanzano 	struct pwm_state pwm_state;
507b8f9f217SAlex Lanzano 
508b8f9f217SAlex Lanzano 	smd->pwm_vcom_signal = devm_pwm_get(dev, NULL);
509b8f9f217SAlex Lanzano 	if (IS_ERR(smd->pwm_vcom_signal))
510b8f9f217SAlex Lanzano 		return dev_err_probe(dev, PTR_ERR(smd->pwm_vcom_signal),
511b8f9f217SAlex Lanzano 				     "Could not get pwm device\n");
512b8f9f217SAlex Lanzano 
513b8f9f217SAlex Lanzano 	pwm_init_state(smd->pwm_vcom_signal, &pwm_state);
514b8f9f217SAlex Lanzano 	pwm_set_relative_duty_cycle(&pwm_state, 1, 10);
515b8f9f217SAlex Lanzano 	pwm_state.enabled = true;
516b8f9f217SAlex Lanzano 	ret = pwm_apply_might_sleep(smd->pwm_vcom_signal, &pwm_state);
517b8f9f217SAlex Lanzano 	if (ret)
518b8f9f217SAlex Lanzano 		return dev_err_probe(dev, -EINVAL, "Could not apply pwm state\n");
519b8f9f217SAlex Lanzano 
520b8f9f217SAlex Lanzano 	return 0;
521b8f9f217SAlex Lanzano }
522b8f9f217SAlex Lanzano 
sharp_memory_probe(struct spi_device * spi)523b8f9f217SAlex Lanzano static int sharp_memory_probe(struct spi_device *spi)
524b8f9f217SAlex Lanzano {
525b8f9f217SAlex Lanzano 	int ret;
526b8f9f217SAlex Lanzano 	struct device *dev;
527b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd;
528b8f9f217SAlex Lanzano 	struct drm_device *drm;
529b8f9f217SAlex Lanzano 	const char *vcom_mode_str;
530b8f9f217SAlex Lanzano 
531b8f9f217SAlex Lanzano 	dev = &spi->dev;
532b8f9f217SAlex Lanzano 
533b8f9f217SAlex Lanzano 	ret = spi_setup(spi);
534b8f9f217SAlex Lanzano 	if (ret < 0)
535b8f9f217SAlex Lanzano 		return dev_err_probe(dev, ret, "Failed to setup spi device\n");
536b8f9f217SAlex Lanzano 
537b8f9f217SAlex Lanzano 	if (!dev->coherent_dma_mask) {
538b8f9f217SAlex Lanzano 		ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
539b8f9f217SAlex Lanzano 		if (ret)
540b8f9f217SAlex Lanzano 			return dev_err_probe(dev, ret, "Failed to set dma mask\n");
541b8f9f217SAlex Lanzano 	}
542b8f9f217SAlex Lanzano 
543b8f9f217SAlex Lanzano 	smd = devm_drm_dev_alloc(dev, &sharp_memory_drm_driver,
544b8f9f217SAlex Lanzano 				 struct sharp_memory_device, drm);
545b8f9f217SAlex Lanzano 	if (!smd)
546b8f9f217SAlex Lanzano 		return -ENOMEM;
547b8f9f217SAlex Lanzano 
548b8f9f217SAlex Lanzano 	spi_set_drvdata(spi, smd);
549b8f9f217SAlex Lanzano 
550b8f9f217SAlex Lanzano 	smd->spi = spi;
551b8f9f217SAlex Lanzano 	drm = &smd->drm;
552b8f9f217SAlex Lanzano 	ret = drmm_mode_config_init(drm);
553b8f9f217SAlex Lanzano 	if (ret)
554b8f9f217SAlex Lanzano 		return dev_err_probe(dev, ret, "Failed to initialize drm config\n");
555b8f9f217SAlex Lanzano 
556b8f9f217SAlex Lanzano 	smd->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
557b8f9f217SAlex Lanzano 	if (!smd->enable_gpio)
558b8f9f217SAlex Lanzano 		dev_warn(dev, "Enable gpio not defined\n");
559b8f9f217SAlex Lanzano 
560b8f9f217SAlex Lanzano 	drm->mode_config.funcs = &sharp_memory_mode_config_funcs;
561b8f9f217SAlex Lanzano 	smd->mode = spi_get_device_match_data(spi);
562b8f9f217SAlex Lanzano 
563b8f9f217SAlex Lanzano 	smd->pitch = (SHARP_ADDR_PERIOD + smd->mode->hdisplay + SHARP_DUMMY_PERIOD) / 8;
564b8f9f217SAlex Lanzano 	smd->tx_buffer_size = (SHARP_MODE_PERIOD +
565b8f9f217SAlex Lanzano 			       (SHARP_ADDR_PERIOD + (smd->mode->hdisplay) + SHARP_DUMMY_PERIOD) *
566b8f9f217SAlex Lanzano 			       smd->mode->vdisplay) / 8;
567b8f9f217SAlex Lanzano 
568b8f9f217SAlex Lanzano 	smd->tx_buffer = devm_kzalloc(dev, smd->tx_buffer_size, GFP_KERNEL);
569b8f9f217SAlex Lanzano 	if (!smd->tx_buffer)
570b8f9f217SAlex Lanzano 		return -ENOMEM;
571b8f9f217SAlex Lanzano 
572b8f9f217SAlex Lanzano 	mutex_init(&smd->tx_mutex);
573b8f9f217SAlex Lanzano 
574b8f9f217SAlex Lanzano 	/*
575b8f9f217SAlex Lanzano 	 * VCOM is a signal that prevents DC bias from being built up in
576b8f9f217SAlex Lanzano 	 * the panel resulting in pixels being forever stuck in one state.
577b8f9f217SAlex Lanzano 	 *
578b8f9f217SAlex Lanzano 	 * This driver supports three different methods to generate this
579b8f9f217SAlex Lanzano 	 * signal depending on EXTMODE pin:
580b8f9f217SAlex Lanzano 	 *
581b8f9f217SAlex Lanzano 	 * software (EXTMODE = L) - This mode uses a kthread to
582b8f9f217SAlex Lanzano 	 * periodically send a "maintain display" message to the display,
583b8f9f217SAlex Lanzano 	 * toggling the vcom bit on and off with each message
584b8f9f217SAlex Lanzano 	 *
585b8f9f217SAlex Lanzano 	 * external (EXTMODE = H) - This mode relies on an external
586b8f9f217SAlex Lanzano 	 * clock to generate the signal on the EXTCOMM pin
587b8f9f217SAlex Lanzano 	 *
588b8f9f217SAlex Lanzano 	 * pwm (EXTMODE = H) - This mode uses a pwm device to generate
589b8f9f217SAlex Lanzano 	 * the signal on the EXTCOMM pin
590b8f9f217SAlex Lanzano 	 *
591b8f9f217SAlex Lanzano 	 */
592b8f9f217SAlex Lanzano 	if (device_property_read_string(dev, "sharp,vcom-mode", &vcom_mode_str))
593b8f9f217SAlex Lanzano 		return dev_err_probe(dev, -EINVAL,
594b8f9f217SAlex Lanzano 				     "Unable to find sharp,vcom-mode node in device tree\n");
595b8f9f217SAlex Lanzano 
596b8f9f217SAlex Lanzano 	if (!strcmp("software", vcom_mode_str)) {
597b8f9f217SAlex Lanzano 		smd->vcom_mode = SHARP_MEMORY_SOFTWARE_VCOM;
598b8f9f217SAlex Lanzano 		smd->sw_vcom_signal = kthread_run(sharp_memory_sw_vcom_signal_thread,
599b8f9f217SAlex Lanzano 						  smd, "sw_vcom_signal");
600b8f9f217SAlex Lanzano 
601b8f9f217SAlex Lanzano 	} else if (!strcmp("external", vcom_mode_str)) {
602b8f9f217SAlex Lanzano 		smd->vcom_mode = SHARP_MEMORY_EXTERNAL_VCOM;
603b8f9f217SAlex Lanzano 
604b8f9f217SAlex Lanzano 	} else if (!strcmp("pwm", vcom_mode_str)) {
605b8f9f217SAlex Lanzano 		smd->vcom_mode = SHARP_MEMORY_PWM_VCOM;
606b8f9f217SAlex Lanzano 		ret = sharp_memory_init_pwm_vcom_signal(smd);
607b8f9f217SAlex Lanzano 		if (ret)
608b8f9f217SAlex Lanzano 			return ret;
609b8f9f217SAlex Lanzano 	} else {
610b8f9f217SAlex Lanzano 		return dev_err_probe(dev, -EINVAL, "Invalid value set for vcom-mode\n");
611b8f9f217SAlex Lanzano 	}
612b8f9f217SAlex Lanzano 
613b8f9f217SAlex Lanzano 	drm->mode_config.min_width = smd->mode->hdisplay;
614b8f9f217SAlex Lanzano 	drm->mode_config.max_width = smd->mode->hdisplay;
615b8f9f217SAlex Lanzano 	drm->mode_config.min_height = smd->mode->vdisplay;
616b8f9f217SAlex Lanzano 	drm->mode_config.max_height = smd->mode->vdisplay;
617b8f9f217SAlex Lanzano 
618b8f9f217SAlex Lanzano 	ret = sharp_memory_pipe_init(drm, smd, sharp_memory_formats,
619b8f9f217SAlex Lanzano 				     ARRAY_SIZE(sharp_memory_formats),
620b8f9f217SAlex Lanzano 				     NULL);
621b8f9f217SAlex Lanzano 	if (ret)
622b8f9f217SAlex Lanzano 		return dev_err_probe(dev, ret, "Failed to initialize display pipeline.\n");
623b8f9f217SAlex Lanzano 
624b8f9f217SAlex Lanzano 	drm_plane_enable_fb_damage_clips(&smd->plane);
625b8f9f217SAlex Lanzano 	drm_mode_config_reset(drm);
626b8f9f217SAlex Lanzano 
627b8f9f217SAlex Lanzano 	ret = drm_dev_register(drm, 0);
628b8f9f217SAlex Lanzano 	if (ret)
629b8f9f217SAlex Lanzano 		return dev_err_probe(dev, ret, "Failed to register drm device.\n");
630b8f9f217SAlex Lanzano 
631b8f9f217SAlex Lanzano 	drm_client_setup(drm, NULL);
632b8f9f217SAlex Lanzano 
633b8f9f217SAlex Lanzano 	return 0;
634b8f9f217SAlex Lanzano }
635b8f9f217SAlex Lanzano 
sharp_memory_remove(struct spi_device * spi)636b8f9f217SAlex Lanzano static void sharp_memory_remove(struct spi_device *spi)
637b8f9f217SAlex Lanzano {
638b8f9f217SAlex Lanzano 	struct sharp_memory_device *smd = spi_get_drvdata(spi);
639b8f9f217SAlex Lanzano 
640b8f9f217SAlex Lanzano 	drm_dev_unplug(&smd->drm);
641b8f9f217SAlex Lanzano 	drm_atomic_helper_shutdown(&smd->drm);
642b8f9f217SAlex Lanzano 
643b8f9f217SAlex Lanzano 	switch (smd->vcom_mode) {
644b8f9f217SAlex Lanzano 	case SHARP_MEMORY_SOFTWARE_VCOM:
645b8f9f217SAlex Lanzano 		kthread_stop(smd->sw_vcom_signal);
646b8f9f217SAlex Lanzano 		break;
647b8f9f217SAlex Lanzano 
648b8f9f217SAlex Lanzano 	case SHARP_MEMORY_EXTERNAL_VCOM:
649b8f9f217SAlex Lanzano 		break;
650b8f9f217SAlex Lanzano 
651b8f9f217SAlex Lanzano 	case SHARP_MEMORY_PWM_VCOM:
652b8f9f217SAlex Lanzano 		pwm_disable(smd->pwm_vcom_signal);
653b8f9f217SAlex Lanzano 		break;
654b8f9f217SAlex Lanzano 	}
655b8f9f217SAlex Lanzano }
656b8f9f217SAlex Lanzano 
657b8f9f217SAlex Lanzano static struct spi_driver sharp_memory_spi_driver = {
658b8f9f217SAlex Lanzano 	.driver = {
659b8f9f217SAlex Lanzano 		.name = "sharp_memory",
660b8f9f217SAlex Lanzano 		.of_match_table = sharp_memory_of_match,
661b8f9f217SAlex Lanzano 	},
662b8f9f217SAlex Lanzano 	.probe = sharp_memory_probe,
663b8f9f217SAlex Lanzano 	.remove = sharp_memory_remove,
664b8f9f217SAlex Lanzano 	.id_table = sharp_memory_ids,
665b8f9f217SAlex Lanzano };
666b8f9f217SAlex Lanzano module_spi_driver(sharp_memory_spi_driver);
667b8f9f217SAlex Lanzano 
668b8f9f217SAlex Lanzano MODULE_AUTHOR("Alex Lanzano <[email protected]>");
669b8f9f217SAlex Lanzano MODULE_DESCRIPTION("SPI Protocol driver for the sharp_memory display");
670b8f9f217SAlex Lanzano MODULE_LICENSE("GPL");
671