Commit | Line | Data |
---|---|---|
a61127c2 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
5091b7eb AC |
2 | /* |
3 | * Copyright © 2006-2007 Intel Corporation | |
4 | * | |
5091b7eb AC |
5 | * Authors: |
6 | * Eric Anholt <eric@anholt.net> | |
7 | */ | |
0c7b178a | 8 | |
51474335 | 9 | #include <linux/delay.h> |
af3a2cfb | 10 | #include <linux/export.h> |
5091b7eb | 11 | #include <linux/i2c-algo-bit.h> |
51474335 | 12 | #include <linux/i2c.h> |
5091b7eb AC |
13 | |
14 | #include "psb_drv.h" | |
15 | #include "psb_intel_reg.h" | |
16 | ||
17 | /* | |
18 | * Intel GPIO access functions | |
19 | */ | |
20 | ||
21 | #define I2C_RISEFALL_TIME 20 | |
22 | ||
23 | static int get_clock(void *data) | |
24 | { | |
04477e5e | 25 | struct gma_i2c_chan *chan = data; |
5091b7eb AC |
26 | struct drm_device *dev = chan->drm_dev; |
27 | u32 val; | |
28 | ||
29 | val = REG_READ(chan->reg); | |
30 | return (val & GPIO_CLOCK_VAL_IN) != 0; | |
31 | } | |
32 | ||
33 | static int get_data(void *data) | |
34 | { | |
04477e5e | 35 | struct gma_i2c_chan *chan = data; |
5091b7eb AC |
36 | struct drm_device *dev = chan->drm_dev; |
37 | u32 val; | |
38 | ||
39 | val = REG_READ(chan->reg); | |
40 | return (val & GPIO_DATA_VAL_IN) != 0; | |
41 | } | |
42 | ||
43 | static void set_clock(void *data, int state_high) | |
44 | { | |
04477e5e | 45 | struct gma_i2c_chan *chan = data; |
5091b7eb AC |
46 | struct drm_device *dev = chan->drm_dev; |
47 | u32 reserved = 0, clock_bits; | |
48 | ||
49 | /* On most chips, these bits must be preserved in software. */ | |
50 | reserved = | |
51 | REG_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | |
52 | GPIO_CLOCK_PULLUP_DISABLE); | |
53 | ||
54 | if (state_high) | |
55 | clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; | |
56 | else | |
57 | clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | | |
58 | GPIO_CLOCK_VAL_MASK; | |
59 | REG_WRITE(chan->reg, reserved | clock_bits); | |
60 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | |
61 | } | |
62 | ||
63 | static void set_data(void *data, int state_high) | |
64 | { | |
04477e5e | 65 | struct gma_i2c_chan *chan = data; |
5091b7eb AC |
66 | struct drm_device *dev = chan->drm_dev; |
67 | u32 reserved = 0, data_bits; | |
68 | ||
69 | /* On most chips, these bits must be preserved in software. */ | |
70 | reserved = | |
71 | REG_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | |
72 | GPIO_CLOCK_PULLUP_DISABLE); | |
73 | ||
74 | if (state_high) | |
75 | data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; | |
76 | else | |
77 | data_bits = | |
78 | GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | | |
79 | GPIO_DATA_VAL_MASK; | |
80 | ||
81 | REG_WRITE(chan->reg, reserved | data_bits); | |
82 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | |
83 | } | |
84 | ||
85 | /** | |
04477e5e | 86 | * gma_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg |
5091b7eb | 87 | * @dev: DRM device |
5091b7eb AC |
88 | * @reg: GPIO reg to use |
89 | * @name: name for this bus | |
90 | * | |
91 | * Creates and registers a new i2c bus with the Linux i2c layer, for use | |
92 | * in output probing and control (e.g. DDC or SDVO control functions). | |
93 | * | |
94 | * Possible values for @reg include: | |
95 | * %GPIOA | |
96 | * %GPIOB | |
97 | * %GPIOC | |
98 | * %GPIOD | |
99 | * %GPIOE | |
100 | * %GPIOF | |
101 | * %GPIOG | |
102 | * %GPIOH | |
103 | * see PRM for details on how these different busses are used. | |
104 | */ | |
04477e5e PJ |
105 | struct gma_i2c_chan *gma_i2c_create(struct drm_device *dev, const u32 reg, |
106 | const char *name) | |
5091b7eb | 107 | { |
04477e5e | 108 | struct gma_i2c_chan *chan; |
5091b7eb | 109 | |
04477e5e | 110 | chan = kzalloc(sizeof(struct gma_i2c_chan), GFP_KERNEL); |
5091b7eb AC |
111 | if (!chan) |
112 | goto out_free; | |
113 | ||
114 | chan->drm_dev = dev; | |
115 | chan->reg = reg; | |
ba1677f7 PJ |
116 | snprintf(chan->base.name, I2C_NAME_SIZE, "intel drm %s", name); |
117 | chan->base.owner = THIS_MODULE; | |
118 | chan->base.algo_data = &chan->algo; | |
119 | chan->base.dev.parent = dev->dev; | |
5091b7eb AC |
120 | chan->algo.setsda = set_data; |
121 | chan->algo.setscl = set_clock; | |
122 | chan->algo.getsda = get_data; | |
123 | chan->algo.getscl = get_clock; | |
124 | chan->algo.udelay = 20; | |
125 | chan->algo.timeout = usecs_to_jiffies(2200); | |
126 | chan->algo.data = chan; | |
127 | ||
ba1677f7 | 128 | i2c_set_adapdata(&chan->base, chan); |
5091b7eb | 129 | |
ba1677f7 | 130 | if (i2c_bit_add_bus(&chan->base)) |
5091b7eb AC |
131 | goto out_free; |
132 | ||
133 | /* JJJ: raise SCL and SDA? */ | |
134 | set_data(chan, 1); | |
135 | set_clock(chan, 1); | |
136 | udelay(20); | |
137 | ||
138 | return chan; | |
139 | ||
140 | out_free: | |
141 | kfree(chan); | |
142 | return NULL; | |
143 | } | |
144 | ||
145 | /** | |
04477e5e | 146 | * gma_i2c_destroy - unregister and free i2c bus resources |
93c3ffc8 | 147 | * @chan: channel to free |
5091b7eb AC |
148 | * |
149 | * Unregister the adapter from the i2c layer, then free the structure. | |
150 | */ | |
04477e5e | 151 | void gma_i2c_destroy(struct gma_i2c_chan *chan) |
5091b7eb AC |
152 | { |
153 | if (!chan) | |
154 | return; | |
155 | ||
ba1677f7 | 156 | i2c_del_adapter(&chan->base); |
5091b7eb AC |
157 | kfree(chan); |
158 | } |