xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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