Guest User

Untitled

a guest
May 21st, 2018
210
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.80 KB | None | 0 0
  1. /*
  2. * arch/arm/mach-lf1000/screen.c
  3. *
  4. * Copyright 2010 LeapFrog Enterprises Inc.
  5. *
  6. * Andrey Yurovsky <ayurovsky@leapfrog.com>
  7. *
  8. * Display Controller (DPC) support. We also describe platform screen modules
  9. * and provide information on the system's screen.
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation.
  14. */
  15.  
  16. #include <linux/module.h>
  17. #include <linux/ioport.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/sysfs.h>
  20. #include <asm/uaccess.h>
  21. #include <asm/io.h>
  22. #include <asm/delay.h>
  23.  
  24. #include <mach/platform.h>
  25. #include <mach/screen.h>
  26. #include <mach/gpio.h>
  27.  
  28. #define RESSIZE(res) (((res)->end - (res)->start)+1)
  29.  
  30. #define SCREEN_RES_640x480 1
  31. #define SCREEN_RES_800x600 2
  32. #define SCREEN_RES_1024x768 3
  33. #define SCREEN_RES_1152x864 4
  34. #define SCREEN_RES_1280x1024 5
  35.  
  36. #define SCREEN_RES SCREEN_RES_1024x768
  37. //#define SCREEN_RES SCREEN_RES_800x600
  38.  
  39.  
  40. #if SCREEN_RES == SCREEN_RES_800x600
  41. static struct lf1000_screen_info emerald_screen = {
  42. .xres = 800,
  43. .yres = 600,
  44. .clk_hz = 40000000,
  45.  
  46. .hsw = 128,
  47. .hfp = 40,
  48. .hbp = 88,
  49.  
  50. .vsw = 4,
  51. .vfp = 1,
  52. .vbp = 23,
  53. };
  54. #endif
  55.  
  56. #if SCREEN_RES == SCREEN_RES_1024x768
  57. static struct lf1000_screen_info emerald_screen = {
  58. .xres = 1024,
  59. .yres = 768,
  60. .clk_hz = 65000000,
  61.  
  62. .hsw = 136,
  63. .hfp = 24,
  64. .hbp = 160,
  65.  
  66. .vsw = 6,
  67. .vfp = 3,
  68. .vbp = 29,
  69. };
  70. #endif
  71.  
  72. #if SCREEN_RES == SCREEN_RES_1280x1024
  73. static struct lf1000_screen_info emerald_screen = {
  74. .xres = 1280,
  75. .yres = 1024,
  76. .clk_hz = 108000000,
  77.  
  78. .hsw = 112,
  79. .hfp = 48,
  80. .hbp = 248,
  81.  
  82. .vsw = 3,
  83. .vfp = 1,
  84. .vbp = 38,
  85. };
  86. #endif
  87.  
  88. static struct {
  89. void __iomem *mem;
  90. int div;
  91. struct lf1000_screen_info *screen;
  92. unsigned tvout : 1;
  93. } dpc;
  94.  
  95. struct lf1000_screen_info *lf1000_get_screen_info(void)
  96. {
  97. return &emerald_screen;
  98. }
  99. EXPORT_SYMBOL_GPL(lf1000_get_screen_info);
  100.  
  101. /* DPC Hardware */
  102.  
  103. static char pvd_pins[] = {
  104. GPIO_PIN0, GPIO_PIN1, GPIO_PIN2, GPIO_PIN3, GPIO_PIN4, GPIO_PIN5,
  105. GPIO_PIN6, GPIO_PIN7, GPIO_PIN16, GPIO_PIN17, GPIO_PIN18, GPIO_PIN19,
  106. GPIO_PIN20, GPIO_PIN21, GPIO_PIN22, GPIO_PIN23, GPIO_PIN24,
  107. GPIO_PIN25, GPIO_PIN26, GPIO_PIN27, GPIO_PIN28, GPIO_PIN29, GPIO_PIN30,
  108. GPIO_PIN31
  109. };
  110.  
  111. static char pvd_ports[] = {
  112. GPIO_PORT_A, GPIO_PORT_A, GPIO_PORT_A, GPIO_PORT_A, GPIO_PORT_A,
  113. GPIO_PORT_A, GPIO_PORT_A, GPIO_PORT_A, GPIO_PORT_B, GPIO_PORT_B,
  114. GPIO_PORT_B, GPIO_PORT_B, GPIO_PORT_B, GPIO_PORT_B, GPIO_PORT_B,
  115. GPIO_PORT_B, GPIO_PORT_B, GPIO_PORT_B, GPIO_PORT_B, GPIO_PORT_B,
  116. GPIO_PORT_B, GPIO_PORT_B, GPIO_PORT_B, GPIO_PORT_B,
  117. };
  118.  
  119. #define DPCHTOTAL 0x07C
  120. #define DPCHSWIDTH 0x07E
  121. #define DPCHASTART 0x080
  122. #define DPCHAEND 0x082
  123. #define DPCVTOTAL 0x084
  124. #define DPCVSWIDTH 0x086
  125. #define DPCVASTART 0x088
  126. #define DPCVAEND 0x08A
  127. #define DPCCTRL0 0x08C
  128. #define DPCCTRL1 0x08E
  129. #define DPCEVTOTAL 0x090
  130. #define DPCEVSWIDTH 0x092
  131. #define DPCEVASTART 0x094
  132. #define DPCEVAEND 0x096
  133. #define DPCCTRL2 0x098
  134. #define DPCVSEOFFSET 0x09A
  135. #define DPCVSSOFFSET 0x09C
  136. #define DPCEVSEOFFSET 0x09E
  137. #define DPCEVSSOFFSET 0x0A0
  138. #define DPCDELAY0 0x0A2
  139. #define DPCCLKENB 0x1C0
  140. #define DPCCLKGEN0 0x1C4
  141. #define DPCCLKGEN1 0x1C8
  142.  
  143. #define VENCCTRLA 0x002
  144. #define VENCCTRLB 0x004
  145. #define VENCSCH 0x008
  146. #define VENCHUE 0x00A
  147. #define VENCSAT 0x00C
  148. #define VENCCRT 0x00E
  149. #define VENCBRT 0x010
  150. #define VENCFSCADJH 0x012
  151. #define VENCFSCADJL 0x014
  152. #define VENCDACSEL 0x020
  153. #define VENCICNTL 0x040
  154. #define VENCHSVS0 0x048
  155. #define VENCHSOS 0x04A
  156. #define VENCHSOE 0x04C
  157. #define VENCVSOS 0x04E
  158. #define VENCVSOE 0x050
  159. #define DPUPSCALECON0 0x0A4
  160. #define DPUPSCALECON1 0x0A6
  161. #define DPUPSCALECON2 0x0A8
  162.  
  163. /* DPC CLOCK GENERATION CONTROL 0 REGISTER (DPCCLKGEN0) */
  164. #define OUTCLKENB 15
  165. #define OUTCLKDELAY0 12
  166. #define CLKDIV0 4
  167. #define CLKSRCSEL0 1
  168. #define OUTCLKINV0 0
  169.  
  170. /* DPC CLOCK GENERATION CONTROL 1 REGISTER (DPCCLKGEN1) */
  171. #define OUTCLKDELAY1 12
  172. #define CLKDIV1 4
  173. #define CLKSRCSEL1 1
  174. #define OUTCLKINV1 0
  175.  
  176. static void lf1000_dpc_clear_int(void)
  177. {
  178. u16 reg = readw(dpc.mem + DPCCTRL0);
  179. writew(reg & ~(1<<10), dpc.mem + DPCCTRL0);
  180. }
  181.  
  182. static void lf1000_dpc_set_enable(u8 index, bool en)
  183. {
  184. void __iomem *mem = index ? dpc.mem + 0x400 : dpc.mem;
  185. u16 reg = readw(mem + DPCCTRL0) & ~(1<<15);
  186.  
  187. if (en)
  188. reg |= (1<<15);
  189. writew(reg, mem + DPCCTRL0);
  190. }
  191.  
  192. static void lf1000_dpc_set_clock_enable(u8 index, bool en)
  193. {
  194. u32 reg = readl(dpc.mem + DPCCLKENB) & ~(1<<2);
  195. void __iomem *mem = index ? dpc.mem + 0x400 : dpc.mem;
  196.  
  197. if (en)
  198. reg |= (1<<2);
  199. writel(reg, mem + DPCCLKENB);
  200. }
  201.  
  202. static void lf1000_dpc_configure(void)
  203. {
  204. u32 reg32;
  205. u16 reg16;
  206. int i;
  207. unsigned int div;
  208. struct lf1000_screen_info *screen = dpc.screen;
  209.  
  210. for (i = 0; i < ARRAY_SIZE(pvd_pins); i++)
  211. gpio_configure_pin(pvd_ports[i], pvd_pins[i], GPIO_ALT1,
  212. 1, 0, 0);
  213.  
  214. /* set PCLK mode to "only when CPU accesses" */
  215. reg32 = readl(dpc.mem + DPCCLKENB) & ~(1<<3);
  216. writel(reg32, dpc.mem + DPCCLKENB);
  217.  
  218. /* configure Clock 0 */
  219. div = dpc.div > 0 ? dpc.div - 1 : dpc.div;
  220. div &= 0x3F;
  221. reg32 = readl(dpc.mem + DPCCLKGEN0);
  222. reg32 &= ~((7<<CLKSRCSEL0)|(0x3F<<CLKDIV0)|(3<<OUTCLKDELAY0));
  223. reg32 |= (0<<CLKSRCSEL0); /* clock source: PLL0 */
  224. reg32 |= (div<<CLKDIV0); /* clock divider */
  225. reg32 |= (1<<OUTCLKINV0); /* inverted */
  226. writel(reg32, dpc.mem + DPCCLKGEN0);
  227.  
  228. /* configure Clock 1 to derive from Clock 0, no divider */
  229. reg32 = readl(dpc.mem + DPCCLKGEN1);
  230. reg32 &= ~((7<<CLKSRCSEL1)|(0x3F<<CLKDIV1)|(3<<OUTCLKDELAY1));
  231. reg32 |= (7<<CLKSRCSEL1); /* clock source: DPC Clock 0 */
  232. reg32 |= (1<<OUTCLKINV1); /* inverted */
  233. writel(reg32, dpc.mem + DPCCLKGEN1);
  234.  
  235. lf1000_dpc_set_clock_enable(0, 1);
  236.  
  237. /* set Control Register 0 flags */
  238. reg16 = readw(dpc.mem + DPCCTRL0) & ~(1<<10);
  239. reg16 &= ~(0x304); /* turn off: embedded sync, inverted, interlace */
  240. reg16 |= (1<<12); /* enable RGB mode */
  241. writew(reg16, dpc.mem + DPCCTRL0);
  242.  
  243. /* set Control Register 1 flags (vid order: CbYCrY, don't swap RGB,
  244. * no dithering), RGB888 format */
  245. reg16 = readw(dpc.mem + DPCCTRL1) & ~(0xAFFF);
  246. writew(reg16 | (3<<8), dpc.mem + DPCCTRL1);
  247.  
  248. /* set Control Register 2 flags (pad Vclk set to nVCLK2) */
  249. reg16 = readw(dpc.mem + DPCCTRL2);
  250. writew(reg16 | (3<<3), dpc.mem + DPCCTRL2);
  251. /* set up horizonal sync */
  252. writew(screen->xres - 1 + screen->hbp + screen->hfp + screen->hsw,
  253. dpc.mem + DPCHTOTAL);
  254. writew(screen->hsw - 1, dpc.mem + DPCHSWIDTH);
  255. writew(screen->hsw + screen->hbp - 1, dpc.mem + DPCHASTART);
  256. writew(screen->hsw + screen->hbp + screen->xres - 1,
  257. dpc.mem + DPCHAEND);
  258. lf1000_dpc_clear_int();
  259.  
  260. /* set up vertical sync */
  261. writew(screen->yres - 1 + screen->vbp + screen->vfp + screen->vsw,
  262. dpc.mem + DPCVTOTAL);
  263. writew(screen->vsw - 1, dpc.mem + DPCVSWIDTH);
  264. writew(screen->vsw + screen->vbp - 1, dpc.mem + DPCVASTART);
  265. writew(screen->vsw + screen->vbp + screen->yres - 1,
  266. dpc.mem + DPCVAEND);
  267. writew(3, dpc.mem + DPCEVTOTAL);
  268. writew(0, dpc.mem + DPCEVSWIDTH);
  269. writew(1, dpc.mem + DPCEVASTART);
  270. writew(2, dpc.mem + DPCEVAEND);
  271. lf1000_dpc_clear_int();
  272.  
  273. /* delays */
  274. writew((7<<8)|(7<<4)|(7<<0), dpc.mem + DPCDELAY0);
  275. lf1000_dpc_clear_int();
  276.  
  277. /* vsync offset */
  278. writew(1, dpc.mem + DPCVSEOFFSET);
  279. writew(1, dpc.mem + DPCVSSOFFSET);
  280. writew(1, dpc.mem + DPCEVSEOFFSET);
  281. writew(1, dpc.mem + DPCEVSSOFFSET);
  282.  
  283. lf1000_dpc_set_enable(0, 1);
  284. }
  285.  
  286. static void lf1000_dpc_set_encoder_powerdown(bool en)
  287. {
  288. u16 reg;
  289. void __iomem *mem = dpc.mem + 0x400; /* second DPC register set */
  290.  
  291. /* power-down mode */
  292. reg = readw(mem + VENCCTRLA) & ~(1<<7);
  293. if (en)
  294. reg |= (1<<7);
  295. writew(reg, mem + VENCCTRLA);
  296.  
  297. /* DAC output */
  298. writew(en, mem + VENCDACSEL);
  299. }
  300.  
  301. static void lf1000_dpc_set_dac_enable(bool en)
  302. {
  303. u16 reg;
  304. void __iomem *mem = dpc.mem + 0x400; /* second DPC register set */
  305.  
  306. reg = readw(mem + DPCCTRL0) & ~(1<<10);
  307. if (en)
  308. reg |= (1<<13);
  309. else
  310. reg &= ~(1<<13);
  311. reg |= (1<<14); /* ENCENB */
  312. writew(reg, mem + DPCCTRL0);
  313.  
  314. if (en)
  315. writew(7, mem + VENCICNTL); /* encoder timing config */
  316. }
  317.  
  318. static inline void lf1000_dpc_reset_encoder(void)
  319. {
  320. lf1000_dpc_set_dac_enable(1);
  321. udelay(100);
  322. lf1000_dpc_set_clock_enable(1, 1);
  323. udelay(100);
  324. lf1000_dpc_set_dac_enable(0);
  325. udelay(100);
  326. lf1000_dpc_set_clock_enable(1, 0);
  327. udelay(100);
  328. lf1000_dpc_set_clock_enable(1, 1);
  329. }
  330.  
  331. static void lf1000_dpc_enable_tvout(void)
  332. {
  333. u32 reg32;
  334. u16 reg16;
  335. struct lf1000_screen_info *screen = dpc.screen;
  336. void __iomem *mem = dpc.mem + 0x400; /* second DPC register set */
  337.  
  338. /* set PCLK mode to "only when CPU accesses" */
  339. reg32 = readl(mem + DPCCLKENB) & ~(1<<3);
  340. writel(reg32, mem + DPCCLKENB);
  341.  
  342. /* configure Clock 0 */
  343. reg32 = readl(mem + DPCCLKGEN0);
  344. reg32 &= ~((7<<CLKSRCSEL0)|(0x3F<<CLKDIV0)|(3<<OUTCLKDELAY0));
  345. reg32 |= (5<<CLKSRCSEL0); /* clock source: XTI */
  346. writel(reg32, mem + DPCCLKGEN0);
  347.  
  348. /* configure Clock 1 to derive from Clock 0 */
  349. reg32 = readl(mem + DPCCLKGEN1);
  350. reg32 &= ~((7<<CLKSRCSEL1)|(0x3F<<CLKDIV1)|(3<<OUTCLKDELAY1));
  351. reg32 |= (7<<CLKSRCSEL1); /* clock source: DPC Clock 0 */
  352. reg32 |= (1<<4); /* divide by 2 */
  353. writel(reg32, mem + DPCCLKGEN1);
  354.  
  355. /* set Control Register 0 flags */
  356. reg16 = readw(mem + DPCCTRL0) & ~(1<<10);
  357. reg16 &= ~(0x304); /* turn off: embedded sync, inverted */
  358. reg16 |= (1<<9); /* enable interlacing */
  359. reg16 &= ~(1<<12); /* disable RGB mode */
  360. writew(reg16, mem + DPCCTRL0);
  361.  
  362. /* set Control Register 1 flags (vid order: CbYCrY, don't swap RGB,
  363. * no dithering), CCIR601B format */
  364. reg16 = readw(mem + DPCCTRL1) & ~(0xAFFF);
  365. writew(reg16 | (13<<8), mem + DPCCTRL1);
  366.  
  367. /* set Control Register 2 flags (pad Vclk set to nVCLK2) */
  368. reg16 = readw(mem + DPCCTRL2);
  369. writew(reg16 | (3<<3), mem + DPCCTRL2);
  370. /* set up horizonal sync: 720 */
  371. writew(720 - 1 + 81 + 24 + 33, mem + DPCHTOTAL);
  372. writew(33 - 1, mem + DPCHSWIDTH);
  373. writew(33 + 81 - 1, mem + DPCHASTART);
  374. writew(33 + 81 + 720 - 1, mem + DPCHAEND);
  375. lf1000_dpc_clear_int();
  376.  
  377. /* set up vertical sync: 240 */
  378. writew(240 - 1 + 16 + 3 + 2, mem + DPCVTOTAL);
  379. writew(3 - 1, mem + DPCVSWIDTH);
  380. writew(3 + 16 - 1, mem + DPCVASTART);
  381. writew(3 + 16 + 240 - 1, mem + DPCVAEND);
  382. writew(240 - 1 + 3 + 4 + 16, mem + DPCEVTOTAL);
  383. writew(240 - 1, mem + DPCEVSWIDTH);
  384. writew(240 - 1 + 16, mem + DPCEVASTART);
  385. writew(240 - 1 + 16 + 3, mem + DPCEVAEND);
  386. lf1000_dpc_clear_int();
  387.  
  388. /* delays */
  389. writew((4<<8)|(4<<4)|(4<<0), mem + DPCDELAY0);
  390. lf1000_dpc_clear_int();
  391.  
  392. /* vsync offset */
  393. writew(0, mem + DPCVSEOFFSET);
  394. writew(0, mem + DPCVSSOFFSET);
  395. writew(0, mem + DPCEVSEOFFSET);
  396. writew(0, mem + DPCEVSSOFFSET);
  397.  
  398. lf1000_dpc_reset_encoder();
  399. lf1000_dpc_set_dac_enable(1);
  400. lf1000_dpc_set_encoder_powerdown(1);
  401.  
  402. /* NTSC mode with pedestal */
  403. reg16 = readw(mem + VENCCTRLA) & ~((1<<5)|(1<<4));
  404. writew(reg16 | (1<<6)|(1<<4), mem + VENCCTRLA);
  405.  
  406. /* color burst frequency adjust */
  407. writew(0, mem + VENCFSCADJH);
  408. writew(0, mem + VENCFSCADJL);
  409.  
  410. /* luma/chroma bandwidth */
  411. writew(0, mem + VENCCTRLB);
  412.  
  413. /* color phase, hue, saturation, contrast, brightness */
  414. writew(0, mem + VENCSCH);
  415. writew(0, mem + VENCHUE);
  416. writew(0, mem + VENCSAT);
  417. writew(0, mem + VENCCRT);
  418. writew(0, mem + VENCBRT);
  419.  
  420. /* set encoder timings */
  421. writew(((1716-1)>>8) & 0x7, mem + VENCHSVS0);
  422. writew(64-1, mem + VENCHSOS);
  423. writew(1716-1, mem + VENCHSOE);
  424. writew(0, mem + VENCVSOS);
  425. writew(3, mem + VENCVSOE);
  426.  
  427. /* set horizonal upscaler: screen resoltuion to 720 */
  428. writew(screen->xres - 1, mem + DPUPSCALECON2);
  429. reg16 = ((screen->xres - 1)*(1<<11))/(720-1);
  430. writew(reg16>>8, mem + DPUPSCALECON1);
  431. writew(reg16 & 0xFF, mem + DPUPSCALECON0);
  432.  
  433. lf1000_dpc_set_encoder_powerdown(0);
  434. lf1000_dpc_set_enable(1, 1);
  435. lf1000_dpc_set_clock_enable(1, 1);
  436. }
  437.  
  438. static void lf1000_dpc_disable_tvout(void)
  439. {
  440. lf1000_dpc_set_dac_enable(0);
  441. lf1000_dpc_set_encoder_powerdown(1);
  442. lf1000_dpc_set_clock_enable(1, 0);
  443. lf1000_dpc_set_enable(1, 0);
  444. }
  445.  
  446. /* sysfs interface */
  447.  
  448. static ssize_t show_tvout(struct device *dev, struct device_attribute *attr,
  449. char *buf)
  450. {
  451. return sprintf(buf, "%d", dpc.tvout);
  452. }
  453.  
  454. static ssize_t set_tvout(struct device *dev, struct device_attribute *attr,
  455. const char *buf, size_t count)
  456. {
  457. int val;
  458.  
  459. if ((sscanf(buf, "%i", &val) != 1) || (val != 0 && val != 1))
  460. return -EINVAL;
  461.  
  462. if (val)
  463. lf1000_dpc_enable_tvout();
  464. else
  465. lf1000_dpc_disable_tvout();
  466. dpc.tvout = val;
  467.  
  468. return count;
  469. }
  470.  
  471. static DEVICE_ATTR(tvout, S_IRUGO | S_IWUGO, show_tvout, set_tvout);
  472.  
  473. static struct attribute *dpc_attributes[] = {
  474. &dev_attr_tvout.attr,
  475. NULL
  476. };
  477.  
  478. static struct attribute_group dpc_attr_group = {
  479. .attrs = dpc_attributes,
  480. };
  481.  
  482. static int lf1000_dpc_probe(struct platform_device *pdev)
  483. {
  484. struct resource *res;
  485. struct lf1000_screen_info *screen = lf1000_get_screen_info();
  486.  
  487. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  488. if (!res) {
  489. dev_err(&pdev->dev, "failed to get resource\n");
  490. return -ENXIO;
  491. }
  492.  
  493. dpc.div = lf1000_CalcDivider(get_pll_freq(PLL0), screen->clk_hz);
  494. if (dpc.div < 0) {
  495. dev_err(&pdev->dev, "failed to get clock divider\n");
  496. return -EFAULT;
  497. }
  498.  
  499. if (!request_mem_region(res->start, RESSIZE(res), "lf1000-dpc")) {
  500. dev_err(&pdev->dev, "failed to get memory region\n");
  501. return -EBUSY;
  502. }
  503.  
  504. dpc.mem = ioremap_nocache(res->start, RESSIZE(res));
  505. if (!dpc.mem) {
  506. dev_err(&pdev->dev, "failed to ioremap\n");
  507. release_mem_region(res->start, RESSIZE(res));
  508. return -ENOMEM;
  509. }
  510.  
  511. dev_info(&pdev->dev, "screen: %dx%d\n", screen->xres, screen->yres);
  512.  
  513. dpc.screen = screen;
  514.  
  515. lf1000_dpc_configure();
  516.  
  517. dpc.tvout = gpio_have_tvout();
  518. if (dpc.tvout)
  519. lf1000_dpc_enable_tvout();
  520. else
  521. lf1000_dpc_disable_tvout();
  522.  
  523. sysfs_create_group(&pdev->dev.kobj, &dpc_attr_group);
  524.  
  525. return 0;
  526. }
  527.  
  528. static int lf1000_dpc_remove(struct platform_device *pdev)
  529. {
  530. struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  531.  
  532. sysfs_remove_group(&pdev->dev.kobj, &dpc_attr_group);
  533.  
  534. iounmap(dpc.mem);
  535. if (res)
  536. release_mem_region(res->start, RESSIZE(res));
  537.  
  538. memset(&dpc, sizeof(dpc), 0);
  539.  
  540. return 0;
  541. }
  542.  
  543. static struct platform_driver lf1000_dpc_driver = {
  544. .probe = lf1000_dpc_probe,
  545. .remove = lf1000_dpc_remove,
  546. .driver = {
  547. .name = "lf1000-dpc",
  548. .owner = THIS_MODULE,
  549. },
  550. };
  551.  
  552. int __init lf1000_dpc_init(void)
  553. {
  554. return platform_driver_register(&lf1000_dpc_driver);
  555. }
  556.  
  557. static void __exit lf1000_dpc_cleanup(void)
  558. {
  559. platform_driver_unregister(&lf1000_dpc_driver);
  560. }
  561.  
  562. module_init(lf1000_dpc_init);
  563. module_exit(lf1000_dpc_cleanup);
  564. MODULE_DESCRIPTION("LF1000 Display Controller Driver");
  565. MODULE_AUTHOR("Andrey Yurovsky");
  566. MODULE_LICENSE("GPL");
  567. MODULE_ALIAS("platform:lf1000-dpc");
Add Comment
Please, Sign In to add comment