Subversion Repositories Kolibri OS

Rev

Rev 5060 | Rev 6084 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *
  3.  * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter
  4.  *
  5.  * All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the
  9.  * "Software"), to deal in the Software without restriction, including
  10.  * without limitation the rights to use, copy, modify, merge, publish,
  11.  * distribute, sub license, and/or sell copies of the Software, and to
  12.  * permit persons to whom the Software is furnished to do so, subject to
  13.  * the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice (including the
  16.  * next paragraph) shall be included in all copies or substantial portions
  17.  * of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  23.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  *
  27.  */
  28.  
  29. #include "dvo.h"
  30. #include "i915_reg.h"
  31. #include "i915_drv.h"
  32.  
  33. #define NS2501_VID 0x1305
  34. #define NS2501_DID 0x6726
  35.  
  36. #define NS2501_VID_LO 0x00
  37. #define NS2501_VID_HI 0x01
  38. #define NS2501_DID_LO 0x02
  39. #define NS2501_DID_HI 0x03
  40. #define NS2501_REV 0x04
  41. #define NS2501_RSVD 0x05
  42. #define NS2501_FREQ_LO 0x06
  43. #define NS2501_FREQ_HI 0x07
  44.  
  45. #define NS2501_REG8 0x08
  46. #define NS2501_8_VEN (1<<5)
  47. #define NS2501_8_HEN (1<<4)
  48. #define NS2501_8_DSEL (1<<3)
  49. #define NS2501_8_BPAS (1<<2)
  50. #define NS2501_8_RSVD (1<<1)
  51. #define NS2501_8_PD (1<<0)
  52.  
  53. #define NS2501_REG9 0x09
  54. #define NS2501_9_VLOW (1<<7)
  55. #define NS2501_9_MSEL_MASK (0x7<<4)
  56. #define NS2501_9_TSEL (1<<3)
  57. #define NS2501_9_RSEN (1<<2)
  58. #define NS2501_9_RSVD (1<<1)
  59. #define NS2501_9_MDI (1<<0)
  60.  
  61. #define NS2501_REGC 0x0c
  62.  
  63. enum {
  64.         MODE_640x480,
  65.         MODE_800x600,
  66.         MODE_1024x768,
  67. };
  68.  
  69. struct ns2501_reg {
  70.          uint8_t offset;
  71.          uint8_t value;
  72. };
  73.  
  74. /*
  75.  * Magic values based on what the BIOS on
  76.  * Fujitsu-Siemens Lifebook S6010 programs (1024x768 panel).
  77.  */
  78. static const struct ns2501_reg regs_1024x768[][86] = {
  79.         [MODE_640x480] = {
  80.                 [0] = { .offset = 0x0a, .value = 0x81, },
  81.                 [1] = { .offset = 0x18, .value = 0x07, },
  82.                 [2] = { .offset = 0x19, .value = 0x00, },
  83.                 [3] = { .offset = 0x1a, .value = 0x00, },
  84.                 [4] = { .offset = 0x1b, .value = 0x11, },
  85.                 [5] = { .offset = 0x1c, .value = 0x54, },
  86.                 [6] = { .offset = 0x1d, .value = 0x03, },
  87.                 [7] = { .offset = 0x1e, .value = 0x02, },
  88.                 [8] = { .offset = 0xf3, .value = 0x90, },
  89.                 [9] = { .offset = 0xf9, .value = 0x00, },
  90.                 [10] = { .offset = 0xc1, .value = 0x90, },
  91.                 [11] = { .offset = 0xc2, .value = 0x00, },
  92.                 [12] = { .offset = 0xc3, .value = 0x0f, },
  93.                 [13] = { .offset = 0xc4, .value = 0x03, },
  94.                 [14] = { .offset = 0xc5, .value = 0x16, },
  95.                 [15] = { .offset = 0xc6, .value = 0x00, },
  96.                 [16] = { .offset = 0xc7, .value = 0x02, },
  97.                 [17] = { .offset = 0xc8, .value = 0x02, },
  98.                 [18] = { .offset = 0xf4, .value = 0x00, },
  99.                 [19] = { .offset = 0x80, .value = 0xff, },
  100.                 [20] = { .offset = 0x81, .value = 0x07, },
  101.                 [21] = { .offset = 0x82, .value = 0x3d, },
  102.                 [22] = { .offset = 0x83, .value = 0x05, },
  103.                 [23] = { .offset = 0x94, .value = 0x00, },
  104.                 [24] = { .offset = 0x95, .value = 0x00, },
  105.                 [25] = { .offset = 0x96, .value = 0x05, },
  106.                 [26] = { .offset = 0x97, .value = 0x00, },
  107.                 [27] = { .offset = 0x9a, .value = 0x88, },
  108.                 [28] = { .offset = 0x9b, .value = 0x00, },
  109.                 [29] = { .offset = 0x98, .value = 0x00, },
  110.                 [30] = { .offset = 0x99, .value = 0x00, },
  111.                 [31] = { .offset = 0xf7, .value = 0x88, },
  112.                 [32] = { .offset = 0xf8, .value = 0x0a, },
  113.                 [33] = { .offset = 0x9c, .value = 0x24, },
  114.                 [34] = { .offset = 0x9d, .value = 0x00, },
  115.                 [35] = { .offset = 0x9e, .value = 0x25, },
  116.                 [36] = { .offset = 0x9f, .value = 0x03, },
  117.                 [37] = { .offset = 0xa0, .value = 0x28, },
  118.                 [38] = { .offset = 0xa1, .value = 0x01, },
  119.                 [39] = { .offset = 0xa2, .value = 0x28, },
  120.                 [40] = { .offset = 0xa3, .value = 0x05, },
  121.                 [41] = { .offset = 0xb6, .value = 0x09, },
  122.                 [42] = { .offset = 0xb8, .value = 0x00, },
  123.                 [43] = { .offset = 0xb9, .value = 0xa0, },
  124.                 [44] = { .offset = 0xba, .value = 0x00, },
  125.                 [45] = { .offset = 0xbb, .value = 0x20, },
  126.                 [46] = { .offset = 0x10, .value = 0x00, },
  127.                 [47] = { .offset = 0x11, .value = 0xa0, },
  128.                 [48] = { .offset = 0x12, .value = 0x02, },
  129.                 [49] = { .offset = 0x20, .value = 0x00, },
  130.                 [50] = { .offset = 0x22, .value = 0x00, },
  131.                 [51] = { .offset = 0x23, .value = 0x00, },
  132.                 [52] = { .offset = 0x24, .value = 0x00, },
  133.                 [53] = { .offset = 0x25, .value = 0x00, },
  134.                 [54] = { .offset = 0x8c, .value = 0x10, },
  135.                 [55] = { .offset = 0x8d, .value = 0x02, },
  136.                 [56] = { .offset = 0x8e, .value = 0x10, },
  137.                 [57] = { .offset = 0x8f, .value = 0x00, },
  138.                 [58] = { .offset = 0x90, .value = 0xff, },
  139.                 [59] = { .offset = 0x91, .value = 0x07, },
  140.                 [60] = { .offset = 0x92, .value = 0xa0, },
  141.                 [61] = { .offset = 0x93, .value = 0x02, },
  142.                 [62] = { .offset = 0xa5, .value = 0x00, },
  143.                 [63] = { .offset = 0xa6, .value = 0x00, },
  144.                 [64] = { .offset = 0xa7, .value = 0x00, },
  145.                 [65] = { .offset = 0xa8, .value = 0x00, },
  146.                 [66] = { .offset = 0xa9, .value = 0x04, },
  147.                 [67] = { .offset = 0xaa, .value = 0x70, },
  148.                 [68] = { .offset = 0xab, .value = 0x4f, },
  149.                 [69] = { .offset = 0xac, .value = 0x00, },
  150.                 [70] = { .offset = 0xa4, .value = 0x84, },
  151.                 [71] = { .offset = 0x7e, .value = 0x18, },
  152.                 [72] = { .offset = 0x84, .value = 0x00, },
  153.                 [73] = { .offset = 0x85, .value = 0x00, },
  154.                 [74] = { .offset = 0x86, .value = 0x00, },
  155.                 [75] = { .offset = 0x87, .value = 0x00, },
  156.                 [76] = { .offset = 0x88, .value = 0x00, },
  157.                 [77] = { .offset = 0x89, .value = 0x00, },
  158.                 [78] = { .offset = 0x8a, .value = 0x00, },
  159.                 [79] = { .offset = 0x8b, .value = 0x00, },
  160.                 [80] = { .offset = 0x26, .value = 0x00, },
  161.                 [81] = { .offset = 0x27, .value = 0x00, },
  162.                 [82] = { .offset = 0xad, .value = 0x00, },
  163.                 [83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */
  164.                 [84] = { .offset = 0x41, .value = 0x00, },
  165.                 [85] = { .offset = 0xc0, .value = 0x05, },
  166.         },
  167.         [MODE_800x600] = {
  168.                 [0] = { .offset = 0x0a, .value = 0x81, },
  169.                 [1] = { .offset = 0x18, .value = 0x07, },
  170.                 [2] = { .offset = 0x19, .value = 0x00, },
  171.                 [3] = { .offset = 0x1a, .value = 0x00, },
  172.                 [4] = { .offset = 0x1b, .value = 0x19, },
  173.                 [5] = { .offset = 0x1c, .value = 0x64, },
  174.                 [6] = { .offset = 0x1d, .value = 0x02, },
  175.                 [7] = { .offset = 0x1e, .value = 0x02, },
  176.                 [8] = { .offset = 0xf3, .value = 0x90, },
  177.                 [9] = { .offset = 0xf9, .value = 0x00, },
  178.                 [10] = { .offset = 0xc1, .value = 0xd7, },
  179.                 [11] = { .offset = 0xc2, .value = 0x00, },
  180.                 [12] = { .offset = 0xc3, .value = 0xf8, },
  181.                 [13] = { .offset = 0xc4, .value = 0x03, },
  182.                 [14] = { .offset = 0xc5, .value = 0x1a, },
  183.                 [15] = { .offset = 0xc6, .value = 0x00, },
  184.                 [16] = { .offset = 0xc7, .value = 0x73, },
  185.                 [17] = { .offset = 0xc8, .value = 0x02, },
  186.                 [18] = { .offset = 0xf4, .value = 0x00, },
  187.                 [19] = { .offset = 0x80, .value = 0x27, },
  188.                 [20] = { .offset = 0x81, .value = 0x03, },
  189.                 [21] = { .offset = 0x82, .value = 0x41, },
  190.                 [22] = { .offset = 0x83, .value = 0x05, },
  191.                 [23] = { .offset = 0x94, .value = 0x00, },
  192.                 [24] = { .offset = 0x95, .value = 0x00, },
  193.                 [25] = { .offset = 0x96, .value = 0x05, },
  194.                 [26] = { .offset = 0x97, .value = 0x00, },
  195.                 [27] = { .offset = 0x9a, .value = 0x88, },
  196.                 [28] = { .offset = 0x9b, .value = 0x00, },
  197.                 [29] = { .offset = 0x98, .value = 0x00, },
  198.                 [30] = { .offset = 0x99, .value = 0x00, },
  199.                 [31] = { .offset = 0xf7, .value = 0x88, },
  200.                 [32] = { .offset = 0xf8, .value = 0x06, },
  201.                 [33] = { .offset = 0x9c, .value = 0x23, },
  202.                 [34] = { .offset = 0x9d, .value = 0x00, },
  203.                 [35] = { .offset = 0x9e, .value = 0x25, },
  204.                 [36] = { .offset = 0x9f, .value = 0x03, },
  205.                 [37] = { .offset = 0xa0, .value = 0x28, },
  206.                 [38] = { .offset = 0xa1, .value = 0x01, },
  207.                 [39] = { .offset = 0xa2, .value = 0x28, },
  208.                 [40] = { .offset = 0xa3, .value = 0x05, },
  209.                 [41] = { .offset = 0xb6, .value = 0x09, },
  210.                 [42] = { .offset = 0xb8, .value = 0x30, },
  211.                 [43] = { .offset = 0xb9, .value = 0xc8, },
  212.                 [44] = { .offset = 0xba, .value = 0x00, },
  213.                 [45] = { .offset = 0xbb, .value = 0x20, },
  214.                 [46] = { .offset = 0x10, .value = 0x20, },
  215.                 [47] = { .offset = 0x11, .value = 0xc8, },
  216.                 [48] = { .offset = 0x12, .value = 0x02, },
  217.                 [49] = { .offset = 0x20, .value = 0x00, },
  218.                 [50] = { .offset = 0x22, .value = 0x00, },
  219.                 [51] = { .offset = 0x23, .value = 0x00, },
  220.                 [52] = { .offset = 0x24, .value = 0x00, },
  221.                 [53] = { .offset = 0x25, .value = 0x00, },
  222.                 [54] = { .offset = 0x8c, .value = 0x10, },
  223.                 [55] = { .offset = 0x8d, .value = 0x02, },
  224.                 [56] = { .offset = 0x8e, .value = 0x04, },
  225.                 [57] = { .offset = 0x8f, .value = 0x00, },
  226.                 [58] = { .offset = 0x90, .value = 0xff, },
  227.                 [59] = { .offset = 0x91, .value = 0x07, },
  228.                 [60] = { .offset = 0x92, .value = 0xa0, },
  229.                 [61] = { .offset = 0x93, .value = 0x02, },
  230.                 [62] = { .offset = 0xa5, .value = 0x00, },
  231.                 [63] = { .offset = 0xa6, .value = 0x00, },
  232.                 [64] = { .offset = 0xa7, .value = 0x00, },
  233.                 [65] = { .offset = 0xa8, .value = 0x00, },
  234.                 [66] = { .offset = 0xa9, .value = 0x83, },
  235.                 [67] = { .offset = 0xaa, .value = 0x40, },
  236.                 [68] = { .offset = 0xab, .value = 0x32, },
  237.                 [69] = { .offset = 0xac, .value = 0x00, },
  238.                 [70] = { .offset = 0xa4, .value = 0x80, },
  239.                 [71] = { .offset = 0x7e, .value = 0x18, },
  240.                 [72] = { .offset = 0x84, .value = 0x00, },
  241.                 [73] = { .offset = 0x85, .value = 0x00, },
  242.                 [74] = { .offset = 0x86, .value = 0x00, },
  243.                 [75] = { .offset = 0x87, .value = 0x00, },
  244.                 [76] = { .offset = 0x88, .value = 0x00, },
  245.                 [77] = { .offset = 0x89, .value = 0x00, },
  246.                 [78] = { .offset = 0x8a, .value = 0x00, },
  247.                 [79] = { .offset = 0x8b, .value = 0x00, },
  248.                 [80] = { .offset = 0x26, .value = 0x00, },
  249.                 [81] = { .offset = 0x27, .value = 0x00, },
  250.                 [82] = { .offset = 0xad, .value = 0x00, },
  251.                 [83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */
  252.                 [84] = { .offset = 0x41, .value = 0x00, },
  253.                 [85] = { .offset = 0xc0, .value = 0x07, },
  254.         },
  255.         [MODE_1024x768] = {
  256.                 [0] = { .offset = 0x0a, .value = 0x81, },
  257.                 [1] = { .offset = 0x18, .value = 0x07, },
  258.                 [2] = { .offset = 0x19, .value = 0x00, },
  259.                 [3] = { .offset = 0x1a, .value = 0x00, },
  260.                 [4] = { .offset = 0x1b, .value = 0x11, },
  261.                 [5] = { .offset = 0x1c, .value = 0x54, },
  262.                 [6] = { .offset = 0x1d, .value = 0x03, },
  263.                 [7] = { .offset = 0x1e, .value = 0x02, },
  264.                 [8] = { .offset = 0xf3, .value = 0x90, },
  265.                 [9] = { .offset = 0xf9, .value = 0x00, },
  266.                 [10] = { .offset = 0xc1, .value = 0x90, },
  267.                 [11] = { .offset = 0xc2, .value = 0x00, },
  268.                 [12] = { .offset = 0xc3, .value = 0x0f, },
  269.                 [13] = { .offset = 0xc4, .value = 0x03, },
  270.                 [14] = { .offset = 0xc5, .value = 0x16, },
  271.                 [15] = { .offset = 0xc6, .value = 0x00, },
  272.                 [16] = { .offset = 0xc7, .value = 0x02, },
  273.                 [17] = { .offset = 0xc8, .value = 0x02, },
  274.                 [18] = { .offset = 0xf4, .value = 0x00, },
  275.                 [19] = { .offset = 0x80, .value = 0xff, },
  276.                 [20] = { .offset = 0x81, .value = 0x07, },
  277.                 [21] = { .offset = 0x82, .value = 0x3d, },
  278.                 [22] = { .offset = 0x83, .value = 0x05, },
  279.                 [23] = { .offset = 0x94, .value = 0x00, },
  280.                 [24] = { .offset = 0x95, .value = 0x00, },
  281.                 [25] = { .offset = 0x96, .value = 0x05, },
  282.                 [26] = { .offset = 0x97, .value = 0x00, },
  283.                 [27] = { .offset = 0x9a, .value = 0x88, },
  284.                 [28] = { .offset = 0x9b, .value = 0x00, },
  285.                 [29] = { .offset = 0x98, .value = 0x00, },
  286.                 [30] = { .offset = 0x99, .value = 0x00, },
  287.                 [31] = { .offset = 0xf7, .value = 0x88, },
  288.                 [32] = { .offset = 0xf8, .value = 0x0a, },
  289.                 [33] = { .offset = 0x9c, .value = 0x24, },
  290.                 [34] = { .offset = 0x9d, .value = 0x00, },
  291.                 [35] = { .offset = 0x9e, .value = 0x25, },
  292.                 [36] = { .offset = 0x9f, .value = 0x03, },
  293.                 [37] = { .offset = 0xa0, .value = 0x28, },
  294.                 [38] = { .offset = 0xa1, .value = 0x01, },
  295.                 [39] = { .offset = 0xa2, .value = 0x28, },
  296.                 [40] = { .offset = 0xa3, .value = 0x05, },
  297.                 [41] = { .offset = 0xb6, .value = 0x09, },
  298.                 [42] = { .offset = 0xb8, .value = 0x00, },
  299.                 [43] = { .offset = 0xb9, .value = 0xa0, },
  300.                 [44] = { .offset = 0xba, .value = 0x00, },
  301.                 [45] = { .offset = 0xbb, .value = 0x20, },
  302.                 [46] = { .offset = 0x10, .value = 0x00, },
  303.                 [47] = { .offset = 0x11, .value = 0xa0, },
  304.                 [48] = { .offset = 0x12, .value = 0x02, },
  305.                 [49] = { .offset = 0x20, .value = 0x00, },
  306.                 [50] = { .offset = 0x22, .value = 0x00, },
  307.                 [51] = { .offset = 0x23, .value = 0x00, },
  308.                 [52] = { .offset = 0x24, .value = 0x00, },
  309.                 [53] = { .offset = 0x25, .value = 0x00, },
  310.                 [54] = { .offset = 0x8c, .value = 0x10, },
  311.                 [55] = { .offset = 0x8d, .value = 0x02, },
  312.                 [56] = { .offset = 0x8e, .value = 0x10, },
  313.                 [57] = { .offset = 0x8f, .value = 0x00, },
  314.                 [58] = { .offset = 0x90, .value = 0xff, },
  315.                 [59] = { .offset = 0x91, .value = 0x07, },
  316.                 [60] = { .offset = 0x92, .value = 0xa0, },
  317.                 [61] = { .offset = 0x93, .value = 0x02, },
  318.                 [62] = { .offset = 0xa5, .value = 0x00, },
  319.                 [63] = { .offset = 0xa6, .value = 0x00, },
  320.                 [64] = { .offset = 0xa7, .value = 0x00, },
  321.                 [65] = { .offset = 0xa8, .value = 0x00, },
  322.                 [66] = { .offset = 0xa9, .value = 0x04, },
  323.                 [67] = { .offset = 0xaa, .value = 0x70, },
  324.                 [68] = { .offset = 0xab, .value = 0x4f, },
  325.                 [69] = { .offset = 0xac, .value = 0x00, },
  326.                 [70] = { .offset = 0xa4, .value = 0x84, },
  327.                 [71] = { .offset = 0x7e, .value = 0x18, },
  328.                 [72] = { .offset = 0x84, .value = 0x00, },
  329.                 [73] = { .offset = 0x85, .value = 0x00, },
  330.                 [74] = { .offset = 0x86, .value = 0x00, },
  331.                 [75] = { .offset = 0x87, .value = 0x00, },
  332.                 [76] = { .offset = 0x88, .value = 0x00, },
  333.                 [77] = { .offset = 0x89, .value = 0x00, },
  334.                 [78] = { .offset = 0x8a, .value = 0x00, },
  335.                 [79] = { .offset = 0x8b, .value = 0x00, },
  336.                 [80] = { .offset = 0x26, .value = 0x00, },
  337.                 [81] = { .offset = 0x27, .value = 0x00, },
  338.                 [82] = { .offset = 0xad, .value = 0x00, },
  339.                 [83] = { .offset = 0x08, .value = 0x34, }, /* 0x35 */
  340.                 [84] = { .offset = 0x41, .value = 0x00, },
  341.                 [85] = { .offset = 0xc0, .value = 0x01, },
  342.         },
  343. };
  344.  
  345. static const struct ns2501_reg regs_init[] = {
  346.         [0] = { .offset = 0x35, .value = 0xff, },
  347.         [1] = { .offset = 0x34, .value = 0x00, },
  348.         [2] = { .offset = 0x08, .value = 0x30, },
  349. };
  350.  
  351. struct ns2501_priv {
  352.         bool quiet;
  353.         const struct ns2501_reg *regs;
  354. };
  355.  
  356. #define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
  357.  
  358. /*
  359.  * For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens
  360.  * laptops does not react on the i2c bus unless
  361.  * both the PLL is running and the display is configured in its native
  362.  * resolution.
  363.  * This function forces the DVO on, and stores the registers it touches.
  364.  * Afterwards, registers are restored to regular values.
  365.  *
  366.  * This is pretty much a hack, though it works.
  367.  * Without that, ns2501_readb and ns2501_writeb fail
  368.  * when switching the resolution.
  369.  */
  370.  
  371. /*
  372. ** Read a register from the ns2501.
  373. ** Returns true if successful, false otherwise.
  374. ** If it returns false, it might be wise to enable the
  375. ** DVO with the above function.
  376. */
  377. static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch)
  378. {
  379.         struct ns2501_priv *ns = dvo->dev_priv;
  380.         struct i2c_adapter *adapter = dvo->i2c_bus;
  381.         u8 out_buf[2];
  382.         u8 in_buf[2];
  383.  
  384.         struct i2c_msg msgs[] = {
  385.                 {
  386.                  .addr = dvo->slave_addr,
  387.                  .flags = 0,
  388.                  .len = 1,
  389.                  .buf = out_buf,
  390.                  },
  391.                 {
  392.                  .addr = dvo->slave_addr,
  393.                  .flags = I2C_M_RD,
  394.                  .len = 1,
  395.                  .buf = in_buf,
  396.                  }
  397.         };
  398.  
  399.         out_buf[0] = addr;
  400.         out_buf[1] = 0;
  401.  
  402.         if (i2c_transfer(adapter, msgs, 2) == 2) {
  403.                 *ch = in_buf[0];
  404.                 return true;
  405.         }
  406.  
  407.         if (!ns->quiet) {
  408.                 DRM_DEBUG_KMS
  409.                     ("Unable to read register 0x%02x from %s:0x%02x.\n", addr,
  410.                      adapter->name, dvo->slave_addr);
  411.         }
  412.  
  413.         return false;
  414. }
  415.  
  416. /*
  417. ** Write a register to the ns2501.
  418. ** Returns true if successful, false otherwise.
  419. ** If it returns false, it might be wise to enable the
  420. ** DVO with the above function.
  421. */
  422. static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
  423. {
  424.         struct ns2501_priv *ns = dvo->dev_priv;
  425.         struct i2c_adapter *adapter = dvo->i2c_bus;
  426.         uint8_t out_buf[2];
  427.  
  428.         struct i2c_msg msg = {
  429.                 .addr = dvo->slave_addr,
  430.                 .flags = 0,
  431.                 .len = 2,
  432.                 .buf = out_buf,
  433.         };
  434.  
  435.         out_buf[0] = addr;
  436.         out_buf[1] = ch;
  437.  
  438.         if (i2c_transfer(adapter, &msg, 1) == 1) {
  439.                 return true;
  440.         }
  441.  
  442.         if (!ns->quiet) {
  443.                 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n",
  444.                               addr, adapter->name, dvo->slave_addr);
  445.         }
  446.  
  447.         return false;
  448. }
  449.  
  450. /* National Semiconductor 2501 driver for chip on i2c bus
  451.  * scan for the chip on the bus.
  452.  * Hope the VBIOS initialized the PLL correctly so we can
  453.  * talk to it. If not, it will not be seen and not detected.
  454.  * Bummer!
  455.  */
  456. static bool ns2501_init(struct intel_dvo_device *dvo,
  457.                         struct i2c_adapter *adapter)
  458. {
  459.         /* this will detect the NS2501 chip on the specified i2c bus */
  460.         struct ns2501_priv *ns;
  461.         unsigned char ch;
  462.  
  463.         ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL);
  464.         if (ns == NULL)
  465.                 return false;
  466.  
  467.         dvo->i2c_bus = adapter;
  468.         dvo->dev_priv = ns;
  469.         ns->quiet = true;
  470.  
  471.         if (!ns2501_readb(dvo, NS2501_VID_LO, &ch))
  472.                 goto out;
  473.  
  474.         if (ch != (NS2501_VID & 0xff)) {
  475.                 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
  476.                               ch, adapter->name, dvo->slave_addr);
  477.                 goto out;
  478.         }
  479.  
  480.         if (!ns2501_readb(dvo, NS2501_DID_LO, &ch))
  481.                 goto out;
  482.  
  483.         if (ch != (NS2501_DID & 0xff)) {
  484.                 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
  485.                               ch, adapter->name, dvo->slave_addr);
  486.                 goto out;
  487.         }
  488.         ns->quiet = false;
  489.  
  490.         DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
  491.  
  492.         return true;
  493.  
  494. out:
  495.         kfree(ns);
  496.         return false;
  497. }
  498.  
  499. static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo)
  500. {
  501.         /*
  502.          * This is a Laptop display, it doesn't have hotplugging.
  503.          * Even if not, the detection bit of the 2501 is unreliable as
  504.          * it only works for some display types.
  505.          * It is even more unreliable as the PLL must be active for
  506.          * allowing reading from the chiop.
  507.          */
  508.         return connector_status_connected;
  509. }
  510.  
  511. static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
  512.                                               struct drm_display_mode *mode)
  513. {
  514.         DRM_DEBUG_KMS
  515.             ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
  516.              mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
  517.  
  518.         /*
  519.          * Currently, these are all the modes I have data from.
  520.          * More might exist. Unclear how to find the native resolution
  521.          * of the panel in here so we could always accept it
  522.          * by disabling the scaler.
  523.          */
  524.         if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) ||
  525.             (mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) ||
  526.             (mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) {
  527.                 return MODE_OK;
  528.         } else {
  529.                 return MODE_ONE_SIZE;   /* Is this a reasonable error? */
  530.         }
  531. }
  532.  
  533. static void ns2501_mode_set(struct intel_dvo_device *dvo,
  534.                             struct drm_display_mode *mode,
  535.                             struct drm_display_mode *adjusted_mode)
  536. {
  537.         struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
  538.         int mode_idx, i;
  539.  
  540.         DRM_DEBUG_KMS
  541.             ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
  542.              mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
  543.  
  544.         if (mode->hdisplay == 640 && mode->vdisplay == 480)
  545.                 mode_idx = MODE_640x480;
  546.         else if (mode->hdisplay == 800 && mode->vdisplay == 600)
  547.                 mode_idx = MODE_800x600;
  548.         else if (mode->hdisplay == 1024 && mode->vdisplay == 768)
  549.                 mode_idx = MODE_1024x768;
  550.         else
  551.                 return;
  552.  
  553.         /* Hopefully doing it every time won't hurt... */
  554.         for (i = 0; i < ARRAY_SIZE(regs_init); i++)
  555.                 ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value);
  556.  
  557.         ns->regs = regs_1024x768[mode_idx];
  558.  
  559.         for (i = 0; i < 84; i++)
  560.                 ns2501_writeb(dvo, ns->regs[i].offset, ns->regs[i].value);
  561. }
  562.  
  563. /* set the NS2501 power state */
  564. static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
  565. {
  566.         unsigned char ch;
  567.  
  568.         if (!ns2501_readb(dvo, NS2501_REG8, &ch))
  569.                 return false;
  570.  
  571.         return ch & NS2501_8_PD;
  572. }
  573.  
  574. /* set the NS2501 power state */
  575. static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
  576. {
  577.         struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
  578.  
  579.         DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
  580.  
  581.         if (enable) {
  582.                 if (WARN_ON(ns->regs[83].offset != 0x08 ||
  583.                             ns->regs[84].offset != 0x41 ||
  584.                             ns->regs[85].offset != 0xc0))
  585.                         return;
  586.  
  587.                 ns2501_writeb(dvo, 0xc0, ns->regs[85].value | 0x08);
  588.  
  589.                 ns2501_writeb(dvo, 0x41, ns->regs[84].value);
  590.  
  591.                 ns2501_writeb(dvo, 0x34, 0x01);
  592.                 msleep(15);
  593.  
  594.                 ns2501_writeb(dvo, 0x08, 0x35);
  595.                 if (!(ns->regs[83].value & NS2501_8_BPAS))
  596.                         ns2501_writeb(dvo, 0x08, 0x31);
  597.                 msleep(200);
  598.  
  599.                 ns2501_writeb(dvo, 0x34, 0x03);
  600.  
  601.                 ns2501_writeb(dvo, 0xc0, ns->regs[85].value);
  602.         } else {
  603.                 ns2501_writeb(dvo, 0x34, 0x01);
  604.                 msleep(200);
  605.  
  606.                 ns2501_writeb(dvo, 0x08, 0x34);
  607.                 msleep(15);
  608.  
  609.                 ns2501_writeb(dvo, 0x34, 0x00);
  610.         }
  611. }
  612.  
  613. static void ns2501_destroy(struct intel_dvo_device *dvo)
  614. {
  615.         struct ns2501_priv *ns = dvo->dev_priv;
  616.  
  617.         if (ns) {
  618.                 kfree(ns);
  619.                 dvo->dev_priv = NULL;
  620.         }
  621. }
  622.  
  623. struct intel_dvo_dev_ops ns2501_ops = {
  624.         .init = ns2501_init,
  625.         .detect = ns2501_detect,
  626.         .mode_valid = ns2501_mode_valid,
  627.         .mode_set = ns2501_mode_set,
  628.         .dpms = ns2501_dpms,
  629.         .get_hw_state = ns2501_get_hw_state,
  630.         .destroy = ns2501_destroy,
  631. };
  632.