1 | /* |
2 | * Copyright 2012 Red Hat Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the |
6 | * "Software"), to deal in the Software without restriction, including |
7 | * without limitation the rights to use, copy, modify, merge, publish, |
8 | * distribute, sub license, and/or sell copies of the Software, and to |
9 | * permit persons to whom the Software is furnished to do so, subject to |
10 | * the following conditions: |
11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
15 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, |
16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
17 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
18 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
19 | * |
20 | * The above copyright notice and this permission notice (including the |
21 | * next paragraph) shall be included in all copies or substantial portions |
22 | * of the Software. |
23 | * |
24 | */ |
25 | /* |
26 | * Authors: Dave Airlie <airlied@redhat.com> |
27 | */ |
28 | |
29 | #include <linux/export.h> |
30 | #include <linux/i2c-algo-bit.h> |
31 | #include <linux/i2c.h> |
32 | #include <linux/pci.h> |
33 | |
34 | #include "mgag200_drv.h" |
35 | |
36 | static int mga_i2c_read_gpio(struct mga_device *mdev) |
37 | { |
38 | WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); |
39 | return RREG8(DAC_DATA); |
40 | } |
41 | |
42 | static void mga_i2c_set_gpio(struct mga_device *mdev, int mask, int val) |
43 | { |
44 | int tmp; |
45 | |
46 | WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); |
47 | tmp = (RREG8(DAC_DATA) & mask) | val; |
48 | WREG_DAC(MGA1064_GEN_IO_CTL, tmp); |
49 | WREG_DAC(MGA1064_GEN_IO_DATA, 0); |
50 | } |
51 | |
52 | static inline void mga_i2c_set(struct mga_device *mdev, int mask, int state) |
53 | { |
54 | if (state) |
55 | state = 0; |
56 | else |
57 | state = mask; |
58 | mga_i2c_set_gpio(mdev, mask: ~mask, val: state); |
59 | } |
60 | |
61 | static void mga_gpio_setsda(void *data, int state) |
62 | { |
63 | struct mga_i2c_chan *i2c = data; |
64 | struct mga_device *mdev = to_mga_device(dev: i2c->dev); |
65 | mga_i2c_set(mdev, mask: i2c->data, state); |
66 | } |
67 | |
68 | static void mga_gpio_setscl(void *data, int state) |
69 | { |
70 | struct mga_i2c_chan *i2c = data; |
71 | struct mga_device *mdev = to_mga_device(dev: i2c->dev); |
72 | mga_i2c_set(mdev, mask: i2c->clock, state); |
73 | } |
74 | |
75 | static int mga_gpio_getsda(void *data) |
76 | { |
77 | struct mga_i2c_chan *i2c = data; |
78 | struct mga_device *mdev = to_mga_device(dev: i2c->dev); |
79 | return (mga_i2c_read_gpio(mdev) & i2c->data) ? 1 : 0; |
80 | } |
81 | |
82 | static int mga_gpio_getscl(void *data) |
83 | { |
84 | struct mga_i2c_chan *i2c = data; |
85 | struct mga_device *mdev = to_mga_device(dev: i2c->dev); |
86 | return (mga_i2c_read_gpio(mdev) & i2c->clock) ? 1 : 0; |
87 | } |
88 | |
89 | static void mgag200_i2c_release(void *res) |
90 | { |
91 | struct mga_i2c_chan *i2c = res; |
92 | |
93 | i2c_del_adapter(adap: &i2c->adapter); |
94 | } |
95 | |
96 | int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c) |
97 | { |
98 | struct drm_device *dev = &mdev->base; |
99 | const struct mgag200_device_info *info = mdev->info; |
100 | int ret; |
101 | |
102 | WREG_DAC(MGA1064_GEN_IO_CTL2, 1); |
103 | WREG_DAC(MGA1064_GEN_IO_DATA, 0xff); |
104 | WREG_DAC(MGA1064_GEN_IO_CTL, 0); |
105 | |
106 | i2c->data = BIT(info->i2c.data_bit); |
107 | i2c->clock = BIT(info->i2c.clock_bit); |
108 | i2c->adapter.owner = THIS_MODULE; |
109 | i2c->adapter.dev.parent = dev->dev; |
110 | i2c->dev = dev; |
111 | i2c_set_adapdata(adap: &i2c->adapter, data: i2c); |
112 | snprintf(buf: i2c->adapter.name, size: sizeof(i2c->adapter.name), fmt: "mga i2c" ); |
113 | |
114 | i2c->adapter.algo_data = &i2c->bit; |
115 | |
116 | i2c->bit.udelay = 10; |
117 | i2c->bit.timeout = 2; |
118 | i2c->bit.data = i2c; |
119 | i2c->bit.setsda = mga_gpio_setsda; |
120 | i2c->bit.setscl = mga_gpio_setscl; |
121 | i2c->bit.getsda = mga_gpio_getsda; |
122 | i2c->bit.getscl = mga_gpio_getscl; |
123 | |
124 | ret = i2c_bit_add_bus(&i2c->adapter); |
125 | if (ret) |
126 | return ret; |
127 | |
128 | return devm_add_action_or_reset(dev->dev, mgag200_i2c_release, i2c); |
129 | } |
130 | |