1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright © 2006-2007 Intel Corporation |
4 | * |
5 | * Authors: |
6 | * Eric Anholt <eric@anholt.net> |
7 | */ |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/export.h> |
11 | #include <linux/i2c-algo-bit.h> |
12 | #include <linux/i2c.h> |
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 | { |
25 | struct gma_i2c_chan *chan = data; |
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 | { |
35 | struct gma_i2c_chan *chan = data; |
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 | { |
45 | struct gma_i2c_chan *chan = data; |
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 | { |
65 | struct gma_i2c_chan *chan = data; |
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 | /** |
86 | * gma_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg |
87 | * @dev: DRM device |
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 | */ |
105 | struct gma_i2c_chan *gma_i2c_create(struct drm_device *dev, const u32 reg, |
106 | const char *name) |
107 | { |
108 | struct gma_i2c_chan *chan; |
109 | |
110 | chan = kzalloc(size: sizeof(struct gma_i2c_chan), GFP_KERNEL); |
111 | if (!chan) |
112 | goto out_free; |
113 | |
114 | chan->drm_dev = dev; |
115 | chan->reg = reg; |
116 | snprintf(buf: chan->base.name, I2C_NAME_SIZE, fmt: "intel drm %s" , name); |
117 | chan->base.owner = THIS_MODULE; |
118 | chan->base.algo_data = &chan->algo; |
119 | chan->base.dev.parent = dev->dev; |
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(u: 2200); |
126 | chan->algo.data = chan; |
127 | |
128 | i2c_set_adapdata(adap: &chan->base, data: chan); |
129 | |
130 | if (i2c_bit_add_bus(&chan->base)) |
131 | goto out_free; |
132 | |
133 | /* JJJ: raise SCL and SDA? */ |
134 | set_data(data: chan, state_high: 1); |
135 | set_clock(data: chan, state_high: 1); |
136 | udelay(20); |
137 | |
138 | return chan; |
139 | |
140 | out_free: |
141 | kfree(objp: chan); |
142 | return NULL; |
143 | } |
144 | |
145 | /** |
146 | * gma_i2c_destroy - unregister and free i2c bus resources |
147 | * @chan: channel to free |
148 | * |
149 | * Unregister the adapter from the i2c layer, then free the structure. |
150 | */ |
151 | void gma_i2c_destroy(struct gma_i2c_chan *chan) |
152 | { |
153 | if (!chan) |
154 | return; |
155 | |
156 | i2c_del_adapter(adap: &chan->base); |
157 | kfree(objp: chan); |
158 | } |
159 | |