CHROMIUM: drm/anx7808: Add cable detection IRQ.
[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         int cable_det_irq;
36         struct regulator *vdd_mydp;
37         struct i2c_client *tx_p0;
38         struct i2c_client *tx_p1;
39         struct i2c_client *tx_p2;
40         struct i2c_client *rx_p0;
41         struct i2c_client *rx_p1;
42 };
43
44 static struct i2c_client *anx7808_addr_to_client(struct anx7808_data *anx7808,
45                                                  uint16_t addr)
46 {
47         switch (addr >> 8) {
48         case TX_P0:
49                 return anx7808->tx_p0;
50         case TX_P1:
51                 return anx7808->tx_p1;
52         case TX_P2:
53                 return anx7808->tx_p2;
54         case RX_P0:
55                 return anx7808->rx_p0;
56         case RX_P1:
57                 return anx7808->rx_p1;
58         default:
59                 break;
60         }
61         DRM_ERROR("Invalid i2c address %04x.\n", addr);
62         return NULL;
63 }
64
65 static int anx7808_read_reg(struct anx7808_data *anx7808, uint16_t addr,
66                             uint8_t *value)
67 {
68         int ret = 0;
69         struct i2c_client *client = anx7808_addr_to_client(anx7808, addr);
70
71         if (client == NULL) {
72                 *value = 0;
73                 return -EINVAL;
74         }
75
76         ret = i2c_smbus_read_byte_data(client, addr & 0xff);
77         if (ret < 0) {
78                 DRM_ERROR("Failed to read i2c addr=%04x.\n", addr);
79                 *value = 0;
80                 return ret;
81         }
82         *value = ret;
83         return 0;
84 }
85
86 static int anx7808_power_on(struct anx7808_data *anx7808)
87 {
88         int ret = 0;
89
90         DRM_INFO("Powering on ANX7808.\n");
91
92         gpio_set_value(anx7808->reset_gpio, 0);
93         usleep_range(1000, 2000);
94         gpio_set_value(anx7808->pd_gpio, 0);
95         usleep_range(2000, 4000);
96         ret = regulator_enable(anx7808->vdd_mydp);
97         if (ret < 0) {
98                 DRM_ERROR("Failed to power on ANX7808: %d", ret);
99                 return ret;
100         }
101         msleep(20);
102         gpio_set_value(anx7808->reset_gpio, 1);
103         return 0;
104 }
105
106 static int anx7808_power_off(struct anx7808_data *anx7808)
107 {
108         int ret = 0;
109
110         DRM_INFO("Powering off ANX7808.\n");
111
112         gpio_set_value(anx7808->reset_gpio, 0);
113         usleep_range(1000, 2000);
114         ret = regulator_disable(anx7808->vdd_mydp);
115         if (ret < 0) {
116                 DRM_ERROR("Failed to power off ANX7808: %d", ret);
117                 return ret;
118         }
119         usleep_range(5000, 10000);
120         gpio_set_value(anx7808->pd_gpio, 1);
121         usleep_range(1000, 2000);
122         return ret;
123 }
124
125 static int anx7808_chip_located(struct anx7808_data *anx7808)
126 {
127         int ret = 0;
128         uint16_t id;
129         uint8_t idh = 0, idl = 0;
130         ret |= anx7808_read_reg(anx7808, SP_TX_DEV_IDL_REG, &idl);
131         ret |= anx7808_read_reg(anx7808, SP_TX_DEV_IDH_REG, &idh);
132         if (ret)
133                 return ret;
134         id = idl | (idh << 8);
135         if (id != ANX7808_DEVICE_ID) {
136                 DRM_ERROR("ANX7808 not found.  ID reg contains: %04x\n", id);
137                 return -ENODEV;
138         }
139         DRM_INFO("ANX7808 found.\n");
140         return 0;
141 }
142
143 static irqreturn_t anx7808_cable_det_isr(int irq, void *data)
144 {
145         DRM_INFO("Detected cable insertion.\n");
146
147         return IRQ_HANDLED;
148 }
149
150 static void anx7808_free_gpios(struct anx7808_data *anx7808)
151 {
152         gpio_free(anx7808->cable_det_gpio);
153         gpio_free(anx7808->intp_gpio);
154         gpio_free(anx7808->reset_gpio);
155         gpio_free(anx7808->pd_gpio);
156 }
157
158 static void unregister_i2c_clients(struct anx7808_data *anx7808)
159 {
160         if (anx7808->rx_p1)
161                 i2c_unregister_device(anx7808->rx_p1);
162         if (anx7808->rx_p0)
163                 i2c_unregister_device(anx7808->rx_p0);
164         if (anx7808->tx_p2)
165                 i2c_unregister_device(anx7808->tx_p2);
166         if (anx7808->tx_p1)
167                 i2c_unregister_device(anx7808->tx_p1);
168 }
169
170 static int anx7808_probe(struct i2c_client *client,
171                         const struct i2c_device_id *id)
172 {
173         int ret = 0;
174         struct device_node *node = client->dev.of_node;
175         struct anx7808_data *anx7808;
176
177         anx7808 = devm_kzalloc(&client->dev, sizeof(struct anx7808_data),
178                                GFP_KERNEL);
179         if (!anx7808) {
180                 DRM_ERROR("Failed to allocate platform_data.\n");
181                 return -ENOMEM;
182         }
183         i2c_set_clientdata(client, anx7808);
184
185         anx7808->vdd_mydp = regulator_get(&client->dev, "vdd_mydp");
186         if (IS_ERR(anx7808->vdd_mydp)) {
187                 DRM_ERROR("Failed to find regulator vdd_mydp.\n");
188                 return PTR_ERR(anx7808->vdd_mydp);
189         }
190
191         anx7808->pd_gpio = of_get_named_gpio(node, "pd-gpio", 0);
192         if (!gpio_is_valid(anx7808->pd_gpio)) {
193                 DRM_ERROR("Failed to locate pd-gpio.\n");
194                 ret = anx7808->pd_gpio;
195                 goto err_reg;
196         }
197
198         anx7808->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
199         if (!gpio_is_valid(anx7808->reset_gpio)) {
200                 DRM_ERROR("Failed to locate reset-gpio.\n");
201                 ret = anx7808->reset_gpio;
202                 goto err_reg;
203         }
204
205         anx7808->intp_gpio = of_get_named_gpio(node, "intp-gpio", 0);
206         if (!gpio_is_valid(anx7808->intp_gpio)) {
207                 DRM_ERROR("Failed to locate intp-gpio.\n");
208                 ret = anx7808->intp_gpio;
209                 goto err_reg;
210         }
211
212         anx7808->cable_det_gpio = of_get_named_gpio(node, "cable-det-gpio", 0);
213         if (!gpio_is_valid(anx7808->cable_det_gpio)) {
214                 DRM_ERROR("Failed to locate cable-det-gpio.\n");
215                 ret = anx7808->cable_det_gpio;
216                 goto err_reg;
217         }
218
219         ret = gpio_request_one(anx7808->pd_gpio, GPIOF_OUT_INIT_HIGH,
220                                "anx7808_pd_gpio");
221         if (ret) {
222                 DRM_ERROR("Failed to request pd_gpio.\n");
223                 goto err_gpio;
224         }
225
226         ret = gpio_request_one(anx7808->reset_gpio, GPIOF_OUT_INIT_LOW,
227                                "anx7808_reset_gpio");
228         if (ret) {
229                 DRM_ERROR("Failed to request reset_gpio.\n");
230                 goto err_gpio;
231         }
232
233         ret = gpio_request_one(anx7808->intp_gpio, GPIOF_DIR_IN,
234                                "anx7808_intp_gpio");
235         if (ret) {
236                 DRM_ERROR("Failed to request intp_gpio.\n");
237                 goto err_gpio;
238         }
239
240         ret = gpio_request_one(anx7808->cable_det_gpio, GPIOF_DIR_IN,
241                                "anx7808_cable_det_gpio");
242         if (ret) {
243                 DRM_ERROR("Failed to request cable_det_gpio.\n");
244                 goto err_gpio;
245         }
246
247         anx7808->tx_p0 = client;
248         if (!((anx7808->tx_p0->addr) == TX_P0 >> 1)) {
249                 DRM_ERROR("I2C client address %02x != expected value %02x.\n",
250                           anx7808->tx_p0->addr, TX_P0 >> 1);
251                 goto err_i2c;
252         }
253         anx7808->tx_p1 = i2c_new_dummy(client->adapter, TX_P1 >> 1);
254         if (!anx7808->tx_p1) {
255                 DRM_ERROR("Failed to reserve i2c bus %02x.\n", TX_P1 >> 1);
256                 ret = -EINVAL;
257                 goto err_i2c;
258         }
259         anx7808->tx_p2 = i2c_new_dummy(client->adapter, TX_P2 >> 1);
260         if (!anx7808->tx_p2) {
261                 DRM_ERROR("Failed to reserve i2c bus %02x.\n", TX_P2 >> 1);
262                 ret = -EINVAL;
263                 goto err_i2c;
264         }
265         anx7808->rx_p0 = i2c_new_dummy(client->adapter, RX_P0 >> 1);
266         if (!anx7808->rx_p0) {
267                 DRM_ERROR("Failed to reserve i2c bus %02x.\n", RX_P0 >> 1);
268                 ret = -EINVAL;
269                 goto err_i2c;
270         }
271         anx7808->rx_p1 = i2c_new_dummy(client->adapter, RX_P1 >> 1);
272         if (!anx7808->rx_p1) {
273                 DRM_ERROR("Failed to reserve i2c bus %02x.\n", RX_P1 >> 1);
274                 ret = -EINVAL;
275                 goto err_i2c;
276         }
277
278         anx7808_power_on(anx7808);
279         ret = anx7808_chip_located(anx7808);
280         anx7808_power_off(anx7808);
281         if (ret)
282                 goto err_i2c;
283
284         anx7808->cable_det_irq = gpio_to_irq(anx7808->cable_det_gpio);
285         if (anx7808->cable_det_irq < 0) {
286                 DRM_ERROR("Failed to get irq: %d\n", anx7808->cable_det_irq);
287                 goto err_i2c;
288         }
289
290         ret = devm_request_irq(&client->dev,
291                                anx7808->cable_det_irq,
292                                anx7808_cable_det_isr,
293                                IRQF_TRIGGER_RISING,
294                                "anx7808_cable_det",
295                                anx7808);
296         if (ret < 0) {
297                 DRM_ERROR("Failed to request irq: %d\n", ret);
298                 goto err_i2c;
299         }
300
301         DRM_INFO("ANX7808 initialization successful.\n");
302
303         return 0;
304 err_i2c:
305         unregister_i2c_clients(anx7808);
306 err_gpio:
307         anx7808_free_gpios(anx7808);
308 err_reg:
309         regulator_put(anx7808->vdd_mydp);
310         return ret;
311 }
312
313 static int anx7808_remove(struct i2c_client *client)
314 {
315         struct anx7808_data *anx7808 = i2c_get_clientdata(client);
316         unregister_i2c_clients(anx7808);
317         anx7808_free_gpios(anx7808);
318         regulator_put(anx7808->vdd_mydp);
319         return 0;
320 }
321
322 static const struct i2c_device_id anx7808_id[] = {
323         { "anx7808", 0 },
324         { }
325 };
326
327 MODULE_DEVICE_TABLE(i2c, anx7808_id);
328
329 static struct i2c_driver anx7808_driver = {
330         .driver = {
331                 .name = "anx7808",
332                 .owner = THIS_MODULE,
333         },
334         .probe = anx7808_probe,
335         .remove = anx7808_remove,
336         .id_table = anx7808_id,
337 };
338
339 static int __init anx7808_init(void)
340 {
341         int ret = 0;
342
343         ret = i2c_add_driver(&anx7808_driver);
344         if (ret < 0)
345                 DRM_ERROR("Failed to register anx7808 i2c driver.\n");
346         return ret;
347 }
348
349 static void __exit anx7808_exit(void)
350 {
351         i2c_del_driver(&anx7808_driver);
352 }
353
354 module_init(anx7808_init);
355 module_exit(anx7808_exit);
356
357 MODULE_DESCRIPTION("ANX7808 driver");
358 MODULE_AUTHOR("Jeremy Thorpe <jeremyt@chromium.org>");
359 MODULE_LICENSE("GPL");