CHROMIUM: drm/anx7808: Add hardware probe.
[cascardo/linux.git] / drivers / gpu / drm / bridge / anx7808.c
1 /*
2  * Copyright (C) 2013 Google, Inc.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * Based on code obtained from Analogix Inc with copyright:
14  * Copyright(c) 2012, Analogix Semiconductor. All rights reserved.
15  *
16  */
17
18 #include <linux/delay.h>
19 #include <linux/device.h>
20 #include <linux/i2c.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/of_gpio.h>
24 #include <linux/regulator/consumer.h>
25 #include "drmP.h"
26 #include "anx7808regs.h"
27
28 #define ANX7808_DEVICE_ID 0x7808
29
30 struct anx7808_data {
31         int pd_gpio;
32         int reset_gpio;
33         int intp_gpio;
34         int cable_det_gpio;
35         struct regulator *vdd_mydp;
36         struct i2c_client *tx_p0;
37         struct i2c_client *tx_p1;
38         struct i2c_client *tx_p2;
39         struct i2c_client *rx_p0;
40         struct i2c_client *rx_p1;
41 };
42
43 static struct i2c_client *anx7808_addr_to_client(struct anx7808_data *anx7808,
44                                                  uint16_t addr)
45 {
46         switch (addr >> 8) {
47         case TX_P0:
48                 return anx7808->tx_p0;
49         case TX_P1:
50                 return anx7808->tx_p1;
51         case TX_P2:
52                 return anx7808->tx_p2;
53         case RX_P0:
54                 return anx7808->rx_p0;
55         case RX_P1:
56                 return anx7808->rx_p1;
57         default:
58                 break;
59         }
60         DRM_ERROR("Invalid i2c address %04x.\n", addr);
61         return NULL;
62 }
63
64 static int anx7808_read_reg(struct anx7808_data *anx7808, uint16_t addr,
65                             uint8_t *value)
66 {
67         int ret = 0;
68         struct i2c_client *client = anx7808_addr_to_client(anx7808, addr);
69
70         if (client == NULL) {
71                 *value = 0;
72                 return -EINVAL;
73         }
74
75         ret = i2c_smbus_read_byte_data(client, addr & 0xff);
76         if (ret < 0) {
77                 DRM_ERROR("Failed to read i2c addr=%04x.\n", addr);
78                 *value = 0;
79                 return ret;
80         }
81         *value = ret;
82         return 0;
83 }
84
85 static int anx7808_power_on(struct anx7808_data *anx7808)
86 {
87         int ret = 0;
88
89         DRM_INFO("Powering on ANX7808.\n");
90
91         gpio_set_value(anx7808->reset_gpio, 0);
92         usleep_range(1000, 2000);
93         gpio_set_value(anx7808->pd_gpio, 0);
94         usleep_range(2000, 4000);
95         ret = regulator_enable(anx7808->vdd_mydp);
96         if (ret < 0) {
97                 DRM_ERROR("Failed to power on ANX7808: %d", ret);
98                 return ret;
99         }
100         msleep(20);
101         gpio_set_value(anx7808->reset_gpio, 1);
102         return 0;
103 }
104
105 static int anx7808_power_off(struct anx7808_data *anx7808)
106 {
107         int ret = 0;
108
109         DRM_INFO("Powering off ANX7808.\n");
110
111         gpio_set_value(anx7808->reset_gpio, 0);
112         usleep_range(1000, 2000);
113         ret = regulator_disable(anx7808->vdd_mydp);
114         if (ret < 0) {
115                 DRM_ERROR("Failed to power off ANX7808: %d", ret);
116                 return ret;
117         }
118         usleep_range(5000, 10000);
119         gpio_set_value(anx7808->pd_gpio, 1);
120         usleep_range(1000, 2000);
121         return ret;
122 }
123
124 static int anx7808_chip_located(struct anx7808_data *anx7808)
125 {
126         int ret = 0;
127         uint16_t id;
128         uint8_t idh = 0, idl = 0;
129         ret |= anx7808_read_reg(anx7808, SP_TX_DEV_IDL_REG, &idl);
130         ret |= anx7808_read_reg(anx7808, SP_TX_DEV_IDH_REG, &idh);
131         if (ret)
132                 return ret;
133         id = idl | (idh << 8);
134         if (id != ANX7808_DEVICE_ID) {
135                 DRM_ERROR("ANX7808 not found.  ID reg contains: %04x\n", id);
136                 return -ENODEV;
137         }
138         DRM_INFO("ANX7808 found.\n");
139         return 0;
140 }
141
142 static void anx7808_free_gpios(struct anx7808_data *anx7808)
143 {
144         gpio_free(anx7808->cable_det_gpio);
145         gpio_free(anx7808->intp_gpio);
146         gpio_free(anx7808->reset_gpio);
147         gpio_free(anx7808->pd_gpio);
148 }
149
150 static void unregister_i2c_clients(struct anx7808_data *anx7808)
151 {
152         if (anx7808->rx_p1)
153                 i2c_unregister_device(anx7808->rx_p1);
154         if (anx7808->rx_p0)
155                 i2c_unregister_device(anx7808->rx_p0);
156         if (anx7808->tx_p2)
157                 i2c_unregister_device(anx7808->tx_p2);
158         if (anx7808->tx_p1)
159                 i2c_unregister_device(anx7808->tx_p1);
160 }
161
162 static int anx7808_probe(struct i2c_client *client,
163                         const struct i2c_device_id *id)
164 {
165         int ret = 0;
166         struct device_node *node = client->dev.of_node;
167         struct anx7808_data *anx7808;
168
169         anx7808 = devm_kzalloc(&client->dev, sizeof(struct anx7808_data),
170                                GFP_KERNEL);
171         if (!anx7808) {
172                 DRM_ERROR("Failed to allocate platform_data.\n");
173                 return -ENOMEM;
174         }
175         i2c_set_clientdata(client, anx7808);
176
177         anx7808->vdd_mydp = regulator_get(&client->dev, "vdd_mydp");
178         if (IS_ERR(anx7808->vdd_mydp)) {
179                 DRM_ERROR("Failed to find regulator vdd_mydp.\n");
180                 return PTR_ERR(anx7808->vdd_mydp);
181         }
182
183         anx7808->pd_gpio = of_get_named_gpio(node, "pd-gpio", 0);
184         if (!gpio_is_valid(anx7808->pd_gpio)) {
185                 DRM_ERROR("Failed to locate pd-gpio.\n");
186                 ret = anx7808->pd_gpio;
187                 goto err_reg;
188         }
189
190         anx7808->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
191         if (!gpio_is_valid(anx7808->reset_gpio)) {
192                 DRM_ERROR("Failed to locate reset-gpio.\n");
193                 ret = anx7808->reset_gpio;
194                 goto err_reg;
195         }
196
197         anx7808->intp_gpio = of_get_named_gpio(node, "intp-gpio", 0);
198         if (!gpio_is_valid(anx7808->intp_gpio)) {
199                 DRM_ERROR("Failed to locate intp-gpio.\n");
200                 ret = anx7808->intp_gpio;
201                 goto err_reg;
202         }
203
204         anx7808->cable_det_gpio = of_get_named_gpio(node, "cable-det-gpio", 0);
205         if (!gpio_is_valid(anx7808->cable_det_gpio)) {
206                 DRM_ERROR("Failed to locate cable-det-gpio.\n");
207                 ret = anx7808->cable_det_gpio;
208                 goto err_reg;
209         }
210
211         ret = gpio_request_one(anx7808->pd_gpio, GPIOF_OUT_INIT_HIGH,
212                                "anx7808_pd_gpio");
213         if (ret) {
214                 DRM_ERROR("Failed to request pd_gpio.\n");
215                 goto err_gpio;
216         }
217
218         ret = gpio_request_one(anx7808->reset_gpio, GPIOF_OUT_INIT_LOW,
219                                "anx7808_reset_gpio");
220         if (ret) {
221                 DRM_ERROR("Failed to request reset_gpio.\n");
222                 goto err_gpio;
223         }
224
225         ret = gpio_request_one(anx7808->intp_gpio, GPIOF_DIR_IN,
226                                "anx7808_intp_gpio");
227         if (ret) {
228                 DRM_ERROR("Failed to request intp_gpio.\n");
229                 goto err_gpio;
230         }
231
232         ret = gpio_request_one(anx7808->cable_det_gpio, GPIOF_DIR_IN,
233                                "anx7808_cable_det_gpio");
234         if (ret) {
235                 DRM_ERROR("Failed to request cable_det_gpio.\n");
236                 goto err_gpio;
237         }
238
239         anx7808->tx_p0 = client;
240         if (!((anx7808->tx_p0->addr) == TX_P0 >> 1)) {
241                 DRM_ERROR("I2C client address %02x != expected value %02x.\n",
242                           anx7808->tx_p0->addr, TX_P0 >> 1);
243                 goto err_i2c;
244         }
245         anx7808->tx_p1 = i2c_new_dummy(client->adapter, TX_P1 >> 1);
246         if (!anx7808->tx_p1) {
247                 DRM_ERROR("Failed to reserve i2c bus %02x.\n", TX_P1 >> 1);
248                 ret = -EINVAL;
249                 goto err_i2c;
250         }
251         anx7808->tx_p2 = i2c_new_dummy(client->adapter, TX_P2 >> 1);
252         if (!anx7808->tx_p2) {
253                 DRM_ERROR("Failed to reserve i2c bus %02x.\n", TX_P2 >> 1);
254                 ret = -EINVAL;
255                 goto err_i2c;
256         }
257         anx7808->rx_p0 = i2c_new_dummy(client->adapter, RX_P0 >> 1);
258         if (!anx7808->rx_p0) {
259                 DRM_ERROR("Failed to reserve i2c bus %02x.\n", RX_P0 >> 1);
260                 ret = -EINVAL;
261                 goto err_i2c;
262         }
263         anx7808->rx_p1 = i2c_new_dummy(client->adapter, RX_P1 >> 1);
264         if (!anx7808->rx_p1) {
265                 DRM_ERROR("Failed to reserve i2c bus %02x.\n", RX_P1 >> 1);
266                 ret = -EINVAL;
267                 goto err_i2c;
268         }
269
270         anx7808_power_on(anx7808);
271         ret = anx7808_chip_located(anx7808);
272         anx7808_power_off(anx7808);
273         if (ret)
274                 goto err_i2c;
275
276         DRM_INFO("ANX7808 initialization successful.\n");
277
278         return 0;
279 err_i2c:
280         unregister_i2c_clients(anx7808);
281 err_gpio:
282         anx7808_free_gpios(anx7808);
283 err_reg:
284         regulator_put(anx7808->vdd_mydp);
285         return ret;
286 }
287
288 static int anx7808_remove(struct i2c_client *client)
289 {
290         struct anx7808_data *anx7808 = i2c_get_clientdata(client);
291         unregister_i2c_clients(anx7808);
292         anx7808_free_gpios(anx7808);
293         regulator_put(anx7808->vdd_mydp);
294         return 0;
295 }
296
297 static const struct i2c_device_id anx7808_id[] = {
298         { "anx7808", 0 },
299         { }
300 };
301
302 MODULE_DEVICE_TABLE(i2c, anx7808_id);
303
304 static struct i2c_driver anx7808_driver = {
305         .driver = {
306                 .name = "anx7808",
307                 .owner = THIS_MODULE,
308         },
309         .probe = anx7808_probe,
310         .remove = anx7808_remove,
311         .id_table = anx7808_id,
312 };
313
314 static int __init anx7808_init(void)
315 {
316         int ret = 0;
317
318         ret = i2c_add_driver(&anx7808_driver);
319         if (ret < 0)
320                 DRM_ERROR("Failed to register anx7808 i2c driver.\n");
321         return ret;
322 }
323
324 static void __exit anx7808_exit(void)
325 {
326         i2c_del_driver(&anx7808_driver);
327 }
328
329 module_init(anx7808_init);
330 module_exit(anx7808_exit);
331
332 MODULE_DESCRIPTION("ANX7808 driver");
333 MODULE_AUTHOR("Jeremy Thorpe <jeremyt@chromium.org>");
334 MODULE_LICENSE("GPL");