1 | // SPDX-License-Identifier: MIT |
2 | /* |
3 | * Permission is hereby granted, free of charge, to any person obtaining a |
4 | * copy of this software and associated documentation files (the |
5 | * "Software"), to deal in the Software without restriction, including |
6 | * without limitation the rights to use, copy, modify, merge, publish, |
7 | * distribute, sub license, and/or sell copies of the Software, and to |
8 | * permit persons to whom the Software is furnished to do so, subject to |
9 | * the following conditions: |
10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
12 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
13 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
14 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, |
15 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
16 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
17 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
18 | * |
19 | * The above copyright notice and this permission notice (including the |
20 | * next paragraph) shall be included in all copies or substantial portions |
21 | * of the Software. |
22 | */ |
23 | |
24 | #include <drm/drm_managed.h> |
25 | #include <drm/drm_print.h> |
26 | |
27 | #include "ast_drv.h" |
28 | |
29 | static void ast_i2c_setsda(void *i2c_priv, int data) |
30 | { |
31 | struct ast_i2c_chan *i2c = i2c_priv; |
32 | struct ast_device *ast = to_ast_device(dev: i2c->dev); |
33 | int i; |
34 | u8 ujcrb7, jtemp; |
35 | |
36 | for (i = 0; i < 0x10000; i++) { |
37 | ujcrb7 = ((data & 0x01) ? 0 : 1) << 2; |
38 | ast_set_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0xf1, val: ujcrb7); |
39 | jtemp = ast_get_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0x04); |
40 | if (ujcrb7 == jtemp) |
41 | break; |
42 | } |
43 | } |
44 | |
45 | static void ast_i2c_setscl(void *i2c_priv, int clock) |
46 | { |
47 | struct ast_i2c_chan *i2c = i2c_priv; |
48 | struct ast_device *ast = to_ast_device(dev: i2c->dev); |
49 | int i; |
50 | u8 ujcrb7, jtemp; |
51 | |
52 | for (i = 0; i < 0x10000; i++) { |
53 | ujcrb7 = ((clock & 0x01) ? 0 : 1); |
54 | ast_set_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0xf4, val: ujcrb7); |
55 | jtemp = ast_get_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0x01); |
56 | if (ujcrb7 == jtemp) |
57 | break; |
58 | } |
59 | } |
60 | |
61 | static int ast_i2c_getsda(void *i2c_priv) |
62 | { |
63 | struct ast_i2c_chan *i2c = i2c_priv; |
64 | struct ast_device *ast = to_ast_device(dev: i2c->dev); |
65 | uint32_t val, val2, count, pass; |
66 | |
67 | count = 0; |
68 | pass = 0; |
69 | val = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0x20) >> 5) & 0x01; |
70 | do { |
71 | val2 = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0x20) >> 5) & 0x01; |
72 | if (val == val2) { |
73 | pass++; |
74 | } else { |
75 | pass = 0; |
76 | val = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0x20) >> 5) & 0x01; |
77 | } |
78 | } while ((pass < 5) && (count++ < 0x10000)); |
79 | |
80 | return val & 1 ? 1 : 0; |
81 | } |
82 | |
83 | static int ast_i2c_getscl(void *i2c_priv) |
84 | { |
85 | struct ast_i2c_chan *i2c = i2c_priv; |
86 | struct ast_device *ast = to_ast_device(dev: i2c->dev); |
87 | uint32_t val, val2, count, pass; |
88 | |
89 | count = 0; |
90 | pass = 0; |
91 | val = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0x10) >> 4) & 0x01; |
92 | do { |
93 | val2 = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0x10) >> 4) & 0x01; |
94 | if (val == val2) { |
95 | pass++; |
96 | } else { |
97 | pass = 0; |
98 | val = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, index: 0xb7, preserve_mask: 0x10) >> 4) & 0x01; |
99 | } |
100 | } while ((pass < 5) && (count++ < 0x10000)); |
101 | |
102 | return val & 1 ? 1 : 0; |
103 | } |
104 | |
105 | static void ast_i2c_release(struct drm_device *dev, void *res) |
106 | { |
107 | struct ast_i2c_chan *i2c = res; |
108 | |
109 | i2c_del_adapter(adap: &i2c->adapter); |
110 | kfree(objp: i2c); |
111 | } |
112 | |
113 | struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev) |
114 | { |
115 | struct ast_i2c_chan *i2c; |
116 | int ret; |
117 | |
118 | i2c = kzalloc(size: sizeof(struct ast_i2c_chan), GFP_KERNEL); |
119 | if (!i2c) |
120 | return NULL; |
121 | |
122 | i2c->adapter.owner = THIS_MODULE; |
123 | i2c->adapter.dev.parent = dev->dev; |
124 | i2c->dev = dev; |
125 | i2c_set_adapdata(adap: &i2c->adapter, data: i2c); |
126 | snprintf(buf: i2c->adapter.name, size: sizeof(i2c->adapter.name), |
127 | fmt: "AST i2c bit bus" ); |
128 | i2c->adapter.algo_data = &i2c->bit; |
129 | |
130 | i2c->bit.udelay = 20; |
131 | i2c->bit.timeout = 2; |
132 | i2c->bit.data = i2c; |
133 | i2c->bit.setsda = ast_i2c_setsda; |
134 | i2c->bit.setscl = ast_i2c_setscl; |
135 | i2c->bit.getsda = ast_i2c_getsda; |
136 | i2c->bit.getscl = ast_i2c_getscl; |
137 | ret = i2c_bit_add_bus(&i2c->adapter); |
138 | if (ret) { |
139 | drm_err(dev, "Failed to register bit i2c\n" ); |
140 | goto out_kfree; |
141 | } |
142 | |
143 | ret = drmm_add_action_or_reset(dev, ast_i2c_release, i2c); |
144 | if (ret) |
145 | return NULL; |
146 | return i2c; |
147 | |
148 | out_kfree: |
149 | kfree(objp: i2c); |
150 | return NULL; |
151 | } |
152 | |