4 * Driver for rockchip gm7122 tv encoder control
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
14 #include <linux/module.h>
15 #include <linux/device.h>
16 #include <linux/delay.h>
18 #include <linux/rk_fb.h>
19 #include <linux/display-sys.h>
20 #include <linux/rockchip/grf.h>
21 #include <linux/rockchip/iomap.h>
22 #include "gm7122_tve.h"
23 #include <linux/init.h>
24 #include <linux/i2c.h>
25 #include <linux/err.h>
26 #include <linux/clk.h>
27 #include <linux/gpio.h>
28 #include <linux/slab.h>
29 #include <linux/mfd/core.h>
31 #include <linux/of_gpio.h>
32 #include <linux/regulator/consumer.h>
33 #include <linux/mfd/syscon.h>
35 static const struct fb_videomode gm7122_cvbs_mode[] = {
36 /*name refresh xres yres pixclock h_bp h_fp v_bp v_fp h_pw v_pw polariry PorI flag */
37 {"NTSC", 60, 720, 480, 27000000, 57, 19, 15, 4, 62, 3, 0, FB_VMODE_INTERLACED, 0},
38 {"PAL", 50, 720, 576, 27000000, 62, 14, 17, 2, 68, 5, 0, FB_VMODE_INTERLACED, 0},
41 static struct gm7122_tve *gm7122_tve;
43 static int cvbsformat;
45 #define tve_writel(offset, v) gm7122_i2c_send(offset, v)
46 /*#define tve_readl(offset, *v) gm7122_i2c_recv(offset, v)*/
49 #define TVEDBG(format, ...) \
50 dev_info(gm7122_tve->dev,\
51 "GM7122 TVE: " format "\n", ## __VA_ARGS__)
53 #define TVEDBG(format, ...)
56 int gm7122_i2c_send(const u8 reg, const u8 value)
63 ret = i2c_master_send(gm7122_tve->client, buf, 2);
65 TVEDBG("gm7122 control i2c write err,ret =%d\n", ret);
71 int gm7122_i2c_recv(const u8 reg, char *value)
75 ret = i2c_master_send(gm7122_tve->client, ®, 1);
76 i2c_master_recv(gm7122_tve->client, value, 1);
77 pr_info("%s reg = 0x%x , value = 0x%c\n", __func__, reg, *value);
78 return (ret == 2) ? 0 : -1;
82 static void tve_set_mode(int mode)
84 TVEDBG("%s mode %d\n", __func__, mode);
88 if (mode == TVOUT_CVBS_NTSC) {
89 tve_writel(BURST_START, V_D0_BS0(1) | V_D0_BS5(1));
90 tve_writel(BURST_END, V_D0_BE0(1) | V_D0_BE2(1) |
91 V_D0_BE3(1) | V_D0_BE4(1));
92 tve_writel(INPUT_PORT_CTL, V_SYMP(1) | V_UV2C(1) | V_Y2C(1));
93 tve_writel(COLOR_DIFF_CTL, 0x00);
94 tve_writel(U_GAIN_CTL, V_GAINU0(1) | V_GAINU2(1) |
95 V_GAINU3(3) | V_GAINU5(1) | V_GAINU6(1));
96 tve_writel(V_GAIN_CTL, V_GAINV0(1) | V_GAINV1(1) |
97 V_GAINV2(1) | V_GAINV3(1) | V_GAINV4(1) |
99 tve_writel(UMSB_BLACK_GAIN, V_BLACK1(1) | V_BLACK2(1) |
101 tve_writel(VMSB_BLNNL_GAIN, V_BLNNL2(1) | V_BLNNL3(1) |
103 tve_writel(STANDARD_CTL, V_PAL(0) | V_BIT0(1));
104 tve_writel(RTCEN_BURST_CTL, V_BSTA0(1) | V_BSTA1(1)|
105 V_BSTA3(1) | V_BSTA4(1) | V_BSTA5(1));
106 tve_writel(SUBCARRIER0, V_FSC00(1) | V_FSC01(1)|
107 V_FSC02(1) | V_FSC03(1) | V_FSC04(1));
108 tve_writel(SUBCARRIER1, V_FSC10(1) | V_FSC11(1)|
109 V_FSC12(1) | V_FSC13(1) | V_FSC14(1));
110 tve_writel(SUBCARRIER2, V_FSC20(1) | V_FSC21(1) |
111 V_FSC22(1) | V_FSC23(1));
112 tve_writel(SUBCARRIER3, V_FSC29(1) | V_FSC24(1));
113 tve_writel(RCV_PORT_CTL, 0x00);
114 tve_writel(TRIG0_CTL, V_HTRIG0(1) | V_HTRIG2(1) | V_HTRIG4(1) |
115 V_HTRIG5(1) | V_HTRIG6(1) | V_HTRIG7(1));
116 tve_writel(TRIG1_CTL, V_VTRIG0(1) | V_VTRIG4(1) | V_HTRIG8(1) |
118 } else if (mode == TVOUT_CVBS_PAL) {
119 tve_writel(BURST_START, V_D0_BS0(1) | V_D0_BS5(1));
120 tve_writel(BURST_END, V_D0_BE0(1) | V_D0_BE2(1) |
121 V_D0_BE3(1) | V_D0_BE4(1));
122 tve_writel(INPUT_PORT_CTL, V_SYMP(1) | V_UV2C(1) | V_Y2C(1));
123 /*tve_writel(INPUT_PORT_CTL, 0x93);*//*color bar for debug*/
124 tve_writel(COLOR_DIFF_CTL, V_CHPS0(1));
125 tve_writel(U_GAIN_CTL, V_GAINU1(1) | V_GAINU3(1) |
126 V_GAINU5(1) | V_GAINU6(1));
127 tve_writel(V_GAIN_CTL, V_GAINV0(1) | V_GAINV1(1) |
128 V_GAINV2(1) | V_GAINV3(1) | V_GAINV4(1) |
130 tve_writel(UMSB_BLACK_GAIN, V_BLACK1(1) | V_BLACK4(1));
131 tve_writel(VMSB_BLNNL_GAIN, V_BLNNL0(1) | V_BLNNL1(1) |
132 V_BLNNL2(1) | V_BLNNL3(1) | V_BLNNL4(1));
133 tve_writel(STANDARD_CTL, V_PAL(1) | V_SCBW(1));
134 tve_writel(RTCEN_BURST_CTL, V_BSTA0(1) | V_BSTA1(1)|
135 V_BSTA3(1) | V_BSTA4(1) | V_BSTA5(1));
136 tve_writel(SUBCARRIER0, V_FSC00(1) | V_FSC01(1)|
137 V_FSC03(1) | V_FSC06(1) | V_FSC07(1));
138 tve_writel(SUBCARRIER1, V_FSC15(1) | V_FSC11(1)|
140 tve_writel(SUBCARRIER2, V_FSC19(1) | V_FSC16(1));
141 tve_writel(SUBCARRIER3, V_FSC29(1) | V_FSC27(1) | V_FSC25(1));
142 tve_writel(RCV_PORT_CTL, 0x00);
143 tve_writel(TRIG0_CTL, V_HTRIG0(1) | V_HTRIG2(1) | V_HTRIG4(1) |
144 V_HTRIG5(1) | V_HTRIG6(1) | V_HTRIG7(1));
145 tve_writel(TRIG1_CTL, V_VTRIG0(1) | V_VTRIG4(1) | V_HTRIG8(1) |
150 static int tve_switch_fb(const struct fb_videomode *modedb, int enable)
152 struct rk_screen *screen = &gm7122_tve->screen;
157 memset(screen, 0, sizeof(struct rk_screen));
158 /* screen type & face */
159 /*screen->type = SCREEN_TVOUT;*/
160 screen->type = SCREEN_RGB;
161 screen->face = OUT_CCIR656;
162 screen->color_mode = COLOR_YCBCR;
163 screen->mode = *modedb;
164 /*screen->mode.vmode = 0;*/
167 if (FB_SYNC_HOR_HIGH_ACT & modedb->sync)
168 screen->pin_hsync = 1;
170 screen->pin_hsync = 0;
171 if (FB_SYNC_VERT_HIGH_ACT & modedb->sync)
172 screen->pin_vsync = 1;
174 screen->pin_vsync = 0;
176 screen->pin_dclk = 1;
177 /*screen->pixelrepeat = 1;*/
183 screen->swap_delta = 0;
184 screen->swap_dumy = 0;
185 screen->overscan.left = 100;
186 screen->overscan.top = 100;
187 screen->overscan.right = 100;
188 screen->overscan.bottom = 100;
189 /* Operation function*/
191 screen->standby = NULL;
192 rk_fb_switch_screen(screen, enable, gm7122_tve->lcdcid);
194 if (screen->mode.yres == 480)
195 tve_set_mode(TVOUT_CVBS_NTSC);
197 tve_set_mode(TVOUT_CVBS_PAL);
202 static int cvbs_set_enable(struct rk_display_device *device, int enable)
204 if (gm7122_tve->enable != enable) {
205 gm7122_tve->enable = enable;
206 if (gm7122_tve->suspend)
210 /*tve_enable(false);*/
212 tve_switch_fb(gm7122_tve->mode, 0);
213 } else if (enable == 1) {
214 tve_switch_fb(gm7122_tve->mode, 1);
215 /*tve_enable(true);*/
221 static int cvbs_get_enable(struct rk_display_device *device)
223 TVEDBG("%s enable %d\n", __func__, gm7122_tve->enable);
224 return gm7122_tve->enable;
227 static int cvbs_get_status(struct rk_display_device *device)
233 cvbs_get_modelist(struct rk_display_device *device, struct list_head **modelist)
235 *modelist = &(gm7122_tve->modelist);
240 cvbs_set_mode(struct rk_display_device *device, struct fb_videomode *mode)
244 for (i = 0; i < ARRAY_SIZE(gm7122_cvbs_mode); i++) {
245 if (fb_mode_is_equal(&gm7122_cvbs_mode[i], mode)) {
246 if (gm7122_tve->mode != &gm7122_cvbs_mode[i]) {
248 (struct fb_videomode *)&gm7122_cvbs_mode[i];
249 if (gm7122_tve->enable &&
250 !gm7122_tve->suspend) {
251 /*tve_enable(false);*/
252 if (!fb_mode_is_equal(gm7122_tve->mode,
255 gm7122_tve->io_sleep.gpio,
256 gm7122_tve->io_sleep.active);
259 gm7122_tve->io_sleep.gpio,
260 !(gm7122_tve->io_sleep.active));
262 tve_switch_fb(gm7122_tve->mode, 1);
264 /*tve_enable(true);*/
269 TVEDBG("%s\n", __func__);
274 cvbs_get_mode(struct rk_display_device *device, struct fb_videomode *mode)
276 *mode = *(gm7122_tve->mode);
281 tve_fb_event_notify(struct notifier_block *self,
282 unsigned long action, void *data)
284 struct fb_event *event = data;
285 int blank_mode = *((int *)event->data);
287 if (action == FB_EARLY_EVENT_BLANK) {
288 switch (blank_mode) {
289 case FB_BLANK_UNBLANK:
292 TVEDBG("suspend tve\n");
293 if (!gm7122_tve->suspend) {
294 gm7122_tve->suspend = 1;
295 if (gm7122_tve->enable) {
296 tve_switch_fb(gm7122_tve->mode, 0);
297 /*tve_enable(false);*/
302 } else if (action == FB_EVENT_BLANK) {
303 switch (blank_mode) {
304 case FB_BLANK_UNBLANK:
305 TVEDBG("resume tve\n");
306 if (gm7122_tve->suspend) {
307 gm7122_tve->suspend = 0;
308 if (gm7122_tve->enable) {
309 tve_switch_fb(gm7122_tve->mode, 1);
310 /*tve_enable(true);*/
321 static struct notifier_block tve_fb_notifier = {
322 .notifier_call = tve_fb_event_notify,
325 static struct rk_display_ops cvbs_display_ops = {
326 .setenable = cvbs_set_enable,
327 .getenable = cvbs_get_enable,
328 .getstatus = cvbs_get_status,
329 .getmodelist = cvbs_get_modelist,
330 .setmode = cvbs_set_mode,
331 .getmode = cvbs_get_mode,
335 display_cvbs_probe(struct rk_display_device *device, void *devdata)
337 device->owner = THIS_MODULE;
338 strcpy(device->type, "TV");
339 device->name = "cvbs";
340 device->priority = DISPLAY_PRIORITY_TV;
341 device->property = 0;/*just for test*/
342 device->priv_data = devdata;
343 device->ops = &cvbs_display_ops;
347 static struct rk_display_driver display_cvbs = {
348 .probe = display_cvbs_probe,
351 #if defined(CONFIG_OF)
352 static const struct i2c_device_id gm7122_tve_dt_ids[] = {
358 static int __init bootloader_tve_setup(char *str)
361 pr_info("cvbs init tve.format is %s\n", str);
362 if (kstrtoint(str, 0, &cvbsformat) < 0)
368 early_param("tve.format", bootloader_tve_setup);
371 static int gm7122_tve_probe(struct i2c_client *client,
372 const struct i2c_device_id *id)
375 struct device_node *gm7122_np;
376 enum of_gpio_flags flags;
379 gm7122_tve = kmalloc(sizeof(*gm7122_tve), GFP_KERNEL);
381 dev_err(&client->dev, "gm7122 tv encoder device kmalloc fail!\n");
384 memset(gm7122_tve, 0, sizeof(*gm7122_tve));
385 gm7122_tve->client = client;
386 gm7122_tve->dev = &client->dev;
387 gm7122_np = gm7122_tve->dev->of_node;
388 of_property_read_u32(gm7122_np, "rockchip,source", &(ret));
389 gm7122_tve->lcdcid = ret;
390 of_property_read_u32(gm7122_np, "rockchip,prop", &(ret));
391 gm7122_tve->property = ret;
392 /********Get reset pin***********/
393 gm7122_tve->io_reset.gpio = of_get_named_gpio_flags(gm7122_np, "gpio-reset",
395 if (!gpio_is_valid(gm7122_tve->io_reset.gpio)) {
396 TVEDBG("invalid gm7122_tve->io_reset.gpio: %d\n",
397 gm7122_tve->io_reset.gpio);
400 ret = gpio_request(gm7122_tve->io_reset.gpio, "gm7122-reset-io");
402 TVEDBG("gpio_request gm7122_tve->io_reset.gpio invalid: %d\n",
403 gm7122_tve->io_reset.gpio);
406 gm7122_tve->io_reset.active = (flags & OF_GPIO_ACTIVE_LOW);
407 gpio_direction_output(gm7122_tve->io_reset.gpio,
408 !(gm7122_tve->io_reset.active));
409 gpio_set_value(gm7122_tve->io_reset.gpio,
410 !(gm7122_tve->io_reset.active));
411 /********Reset pin end***********/
412 /********Get sleep pin***********/
413 gm7122_tve->io_sleep.gpio = of_get_named_gpio_flags(gm7122_np, "gpio-sleep", 0, &flags);
414 if (!gpio_is_valid(gm7122_tve->io_sleep.gpio)) {
415 TVEDBG("invalid gm7122_tve->io_reset.gpio: %d\n",
416 gm7122_tve->io_sleep.gpio);
418 ret = gpio_request(gm7122_tve->io_sleep.gpio, "gm7122-sleep-io");
420 TVEDBG("gpio_request gm7122_tve->io_reset.gpio invalid: %d\n",
421 gm7122_tve->io_sleep.gpio);
424 gm7122_tve->io_sleep.active = !(flags & OF_GPIO_ACTIVE_LOW);
425 gpio_direction_output(gm7122_tve->io_sleep.gpio,
426 !(gm7122_tve->io_sleep.active));
427 gpio_set_value(gm7122_tve->io_sleep.gpio,
428 !(gm7122_tve->io_sleep.active));
429 /********Sleep pin end***********/
430 INIT_LIST_HEAD(&(gm7122_tve->modelist));
431 for (i = 0; i < ARRAY_SIZE(gm7122_cvbs_mode); i++)
432 fb_add_videomode(&gm7122_cvbs_mode[i], &(gm7122_tve->modelist));
433 if (cvbsformat >= 0) {
435 (struct fb_videomode *)&gm7122_cvbs_mode[cvbsformat];
436 /*gm7122_tve->enable = 1;
437 tve_switch_fb(gm7122_tve->mode, 1);*/
439 gm7122_tve->mode = (struct fb_videomode *)&gm7122_cvbs_mode[1];
442 rk_display_device_register(&display_cvbs,
443 gm7122_tve->dev, NULL);
444 rk_display_device_enable(gm7122_tve->ddev);
445 fb_register_client(&tve_fb_notifier);
447 pr_info("%s tv encoder probe ok!\n", __func__);
455 /*static void gm7122_tve_shutdown(struct platform_device *pdev)
458 static int gm7122_tve_remove(struct i2c_client *client)
463 MODULE_DEVICE_TABLE(i2c, gm7122_tve_dt_ids);
465 static struct i2c_driver gm7122_tve_driver = {
466 .probe = gm7122_tve_probe,
467 .remove = gm7122_tve_remove,
469 .name = "gm7122_tve",
470 .owner = THIS_MODULE,
472 /*.shutdown = gm7122_tve_shutdown,*/
473 .id_table = gm7122_tve_dt_ids,
476 static int __init gm7122_tve_init(void)
478 return i2c_add_driver(&gm7122_tve_driver);
481 static void __exit gm7122_tve_exit(void)
483 i2c_del_driver(&gm7122_tve_driver);
486 module_init(gm7122_tve_init);
487 module_exit(gm7122_tve_exit);
490 MODULE_DESCRIPTION("ROCKCHIP GM7122 TV Encoder ");
491 MODULE_AUTHOR("Rock-chips, <www.rock-chips.com>");
492 MODULE_LICENSE("GPL");