1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2002-2010, Intel Corporation.
3*4882a593Smuzhiyun * Copyright (c) 2014 ATRON electronic GmbH
4*4882a593Smuzhiyun * Author: Jan Safrata <jan.nikitenko@gmail.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining a copy
7*4882a593Smuzhiyun * of this software and associated documentation files (the "Software"), to deal
8*4882a593Smuzhiyun * in the Software without restriction, including without limitation the rights
9*4882a593Smuzhiyun * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10*4882a593Smuzhiyun * copies of the Software, and to permit persons to whom the Software is
11*4882a593Smuzhiyun * furnished to do so, subject to the following conditions:
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * The above copyright notice and this permission notice shall be included in
14*4882a593Smuzhiyun * all copies or substantial portions of the Software.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*4882a593Smuzhiyun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*4882a593Smuzhiyun * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*4882a593Smuzhiyun * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*4882a593Smuzhiyun * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22*4882a593Smuzhiyun * THE SOFTWARE.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <linux/delay.h>
27*4882a593Smuzhiyun #include <linux/i2c-algo-bit.h>
28*4882a593Smuzhiyun #include <linux/i2c.h>
29*4882a593Smuzhiyun #include <linux/init.h>
30*4882a593Smuzhiyun #include <linux/io.h>
31*4882a593Smuzhiyun #include <linux/kernel.h>
32*4882a593Smuzhiyun #include <linux/module.h>
33*4882a593Smuzhiyun #include <linux/pci.h>
34*4882a593Smuzhiyun #include <linux/types.h>
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #include "psb_drv.h"
37*4882a593Smuzhiyun #include "psb_intel_reg.h"
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /*
41*4882a593Smuzhiyun * LPC GPIO based I2C bus for LVDS of Atom E6xx
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /*-----------------------------------------------------------------------------
45*4882a593Smuzhiyun * LPC Register Offsets. Used for LVDS GPIO Bit Bashing. Registers are part
46*4882a593Smuzhiyun * Atom E6xx [D31:F0]
47*4882a593Smuzhiyun ----------------------------------------------------------------------------*/
48*4882a593Smuzhiyun #define RGEN 0x20
49*4882a593Smuzhiyun #define RGIO 0x24
50*4882a593Smuzhiyun #define RGLVL 0x28
51*4882a593Smuzhiyun #define RGTPE 0x2C
52*4882a593Smuzhiyun #define RGTNE 0x30
53*4882a593Smuzhiyun #define RGGPE 0x34
54*4882a593Smuzhiyun #define RGSMI 0x38
55*4882a593Smuzhiyun #define RGTS 0x3C
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* The LVDS GPIO clock lines are GPIOSUS[3]
58*4882a593Smuzhiyun * The LVDS GPIO data lines are GPIOSUS[4]
59*4882a593Smuzhiyun */
60*4882a593Smuzhiyun #define GPIO_CLOCK 0x08
61*4882a593Smuzhiyun #define GPIO_DATA 0x10
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #define LPC_READ_REG(chan, r) inl((chan)->reg + (r))
64*4882a593Smuzhiyun #define LPC_WRITE_REG(chan, r, val) outl((val), (chan)->reg + (r))
65*4882a593Smuzhiyun
get_clock(void * data)66*4882a593Smuzhiyun static int get_clock(void *data)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct psb_intel_i2c_chan *chan = data;
69*4882a593Smuzhiyun u32 val, tmp;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun val = LPC_READ_REG(chan, RGIO);
72*4882a593Smuzhiyun val |= GPIO_CLOCK;
73*4882a593Smuzhiyun LPC_WRITE_REG(chan, RGIO, val);
74*4882a593Smuzhiyun tmp = LPC_READ_REG(chan, RGLVL);
75*4882a593Smuzhiyun val = (LPC_READ_REG(chan, RGLVL) & GPIO_CLOCK) ? 1 : 0;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun return val;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
get_data(void * data)80*4882a593Smuzhiyun static int get_data(void *data)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun struct psb_intel_i2c_chan *chan = data;
83*4882a593Smuzhiyun u32 val, tmp;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun val = LPC_READ_REG(chan, RGIO);
86*4882a593Smuzhiyun val |= GPIO_DATA;
87*4882a593Smuzhiyun LPC_WRITE_REG(chan, RGIO, val);
88*4882a593Smuzhiyun tmp = LPC_READ_REG(chan, RGLVL);
89*4882a593Smuzhiyun val = (LPC_READ_REG(chan, RGLVL) & GPIO_DATA) ? 1 : 0;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun return val;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
set_clock(void * data,int state_high)94*4882a593Smuzhiyun static void set_clock(void *data, int state_high)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun struct psb_intel_i2c_chan *chan = data;
97*4882a593Smuzhiyun u32 val;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (state_high) {
100*4882a593Smuzhiyun val = LPC_READ_REG(chan, RGIO);
101*4882a593Smuzhiyun val |= GPIO_CLOCK;
102*4882a593Smuzhiyun LPC_WRITE_REG(chan, RGIO, val);
103*4882a593Smuzhiyun } else {
104*4882a593Smuzhiyun val = LPC_READ_REG(chan, RGIO);
105*4882a593Smuzhiyun val &= ~GPIO_CLOCK;
106*4882a593Smuzhiyun LPC_WRITE_REG(chan, RGIO, val);
107*4882a593Smuzhiyun val = LPC_READ_REG(chan, RGLVL);
108*4882a593Smuzhiyun val &= ~GPIO_CLOCK;
109*4882a593Smuzhiyun LPC_WRITE_REG(chan, RGLVL, val);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
set_data(void * data,int state_high)113*4882a593Smuzhiyun static void set_data(void *data, int state_high)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun struct psb_intel_i2c_chan *chan = data;
116*4882a593Smuzhiyun u32 val;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (state_high) {
119*4882a593Smuzhiyun val = LPC_READ_REG(chan, RGIO);
120*4882a593Smuzhiyun val |= GPIO_DATA;
121*4882a593Smuzhiyun LPC_WRITE_REG(chan, RGIO, val);
122*4882a593Smuzhiyun } else {
123*4882a593Smuzhiyun val = LPC_READ_REG(chan, RGIO);
124*4882a593Smuzhiyun val &= ~GPIO_DATA;
125*4882a593Smuzhiyun LPC_WRITE_REG(chan, RGIO, val);
126*4882a593Smuzhiyun val = LPC_READ_REG(chan, RGLVL);
127*4882a593Smuzhiyun val &= ~GPIO_DATA;
128*4882a593Smuzhiyun LPC_WRITE_REG(chan, RGLVL, val);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
oaktrail_lvds_i2c_init(struct drm_encoder * encoder)132*4882a593Smuzhiyun void oaktrail_lvds_i2c_init(struct drm_encoder *encoder)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun struct drm_device *dev = encoder->dev;
135*4882a593Smuzhiyun struct gma_encoder *gma_encoder = to_gma_encoder(encoder);
136*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
137*4882a593Smuzhiyun struct psb_intel_i2c_chan *chan;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun chan = kzalloc(sizeof(struct psb_intel_i2c_chan), GFP_KERNEL);
140*4882a593Smuzhiyun if (!chan)
141*4882a593Smuzhiyun return;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun chan->drm_dev = dev;
144*4882a593Smuzhiyun chan->reg = dev_priv->lpc_gpio_base;
145*4882a593Smuzhiyun strncpy(chan->adapter.name, "gma500 LPC", I2C_NAME_SIZE - 1);
146*4882a593Smuzhiyun chan->adapter.owner = THIS_MODULE;
147*4882a593Smuzhiyun chan->adapter.algo_data = &chan->algo;
148*4882a593Smuzhiyun chan->adapter.dev.parent = &dev->pdev->dev;
149*4882a593Smuzhiyun chan->algo.setsda = set_data;
150*4882a593Smuzhiyun chan->algo.setscl = set_clock;
151*4882a593Smuzhiyun chan->algo.getsda = get_data;
152*4882a593Smuzhiyun chan->algo.getscl = get_clock;
153*4882a593Smuzhiyun chan->algo.udelay = 100;
154*4882a593Smuzhiyun chan->algo.timeout = usecs_to_jiffies(2200);
155*4882a593Smuzhiyun chan->algo.data = chan;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun i2c_set_adapdata(&chan->adapter, chan);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun set_data(chan, 1);
160*4882a593Smuzhiyun set_clock(chan, 1);
161*4882a593Smuzhiyun udelay(50);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (i2c_bit_add_bus(&chan->adapter)) {
164*4882a593Smuzhiyun kfree(chan);
165*4882a593Smuzhiyun return;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun gma_encoder->ddc_bus = chan;
169*4882a593Smuzhiyun }
170