1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright Intel Corporation (C) 2017. |
4 | * |
5 | * Based on the i2c-axxia.c driver. |
6 | */ |
7 | #include <linux/clk.h> |
8 | #include <linux/clkdev.h> |
9 | #include <linux/err.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/iopoll.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/module.h> |
14 | #include <linux/io.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/platform_device.h> |
17 | |
18 | #define ALTR_I2C_TFR_CMD 0x00 /* Transfer Command register */ |
19 | #define ALTR_I2C_TFR_CMD_STA BIT(9) /* send START before byte */ |
20 | #define ALTR_I2C_TFR_CMD_STO BIT(8) /* send STOP after byte */ |
21 | #define ALTR_I2C_TFR_CMD_RW_D BIT(0) /* Direction of transfer */ |
22 | #define ALTR_I2C_RX_DATA 0x04 /* RX data FIFO register */ |
23 | #define ALTR_I2C_CTRL 0x08 /* Control register */ |
24 | #define ALTR_I2C_CTRL_RXT_SHFT 4 /* RX FIFO Threshold */ |
25 | #define ALTR_I2C_CTRL_TCT_SHFT 2 /* TFER CMD FIFO Threshold */ |
26 | #define ALTR_I2C_CTRL_BSPEED BIT(1) /* Bus Speed (1=Fast) */ |
27 | #define ALTR_I2C_CTRL_EN BIT(0) /* Enable Core (1=Enable) */ |
28 | #define ALTR_I2C_ISER 0x0C /* Interrupt Status Enable register */ |
29 | #define ALTR_I2C_ISER_RXOF_EN BIT(4) /* Enable RX OVERFLOW IRQ */ |
30 | #define ALTR_I2C_ISER_ARB_EN BIT(3) /* Enable ARB LOST IRQ */ |
31 | #define ALTR_I2C_ISER_NACK_EN BIT(2) /* Enable NACK DET IRQ */ |
32 | #define ALTR_I2C_ISER_RXRDY_EN BIT(1) /* Enable RX Ready IRQ */ |
33 | #define ALTR_I2C_ISER_TXRDY_EN BIT(0) /* Enable TX Ready IRQ */ |
34 | #define ALTR_I2C_ISR 0x10 /* Interrupt Status register */ |
35 | #define ALTR_I2C_ISR_RXOF BIT(4) /* RX OVERFLOW IRQ */ |
36 | #define ALTR_I2C_ISR_ARB BIT(3) /* ARB LOST IRQ */ |
37 | #define ALTR_I2C_ISR_NACK BIT(2) /* NACK DET IRQ */ |
38 | #define ALTR_I2C_ISR_RXRDY BIT(1) /* RX Ready IRQ */ |
39 | #define ALTR_I2C_ISR_TXRDY BIT(0) /* TX Ready IRQ */ |
40 | #define ALTR_I2C_STATUS 0x14 /* Status register */ |
41 | #define ALTR_I2C_STAT_CORE BIT(0) /* Core Status (0=idle) */ |
42 | #define ALTR_I2C_TC_FIFO_LVL 0x18 /* Transfer FIFO LVL register */ |
43 | #define ALTR_I2C_RX_FIFO_LVL 0x1C /* Receive FIFO LVL register */ |
44 | #define ALTR_I2C_SCL_LOW 0x20 /* SCL low count register */ |
45 | #define ALTR_I2C_SCL_HIGH 0x24 /* SCL high count register */ |
46 | #define ALTR_I2C_SDA_HOLD 0x28 /* SDA hold count register */ |
47 | |
48 | #define ALTR_I2C_ALL_IRQ (ALTR_I2C_ISR_RXOF | ALTR_I2C_ISR_ARB | \ |
49 | ALTR_I2C_ISR_NACK | ALTR_I2C_ISR_RXRDY | \ |
50 | ALTR_I2C_ISR_TXRDY) |
51 | |
52 | #define ALTR_I2C_THRESHOLD 0 /* IRQ Threshold at 1 element */ |
53 | #define ALTR_I2C_DFLT_FIFO_SZ 4 |
54 | #define ALTR_I2C_TIMEOUT 100000 /* 100ms */ |
55 | #define ALTR_I2C_XFER_TIMEOUT (msecs_to_jiffies(250)) |
56 | |
57 | /** |
58 | * struct altr_i2c_dev - I2C device context |
59 | * @base: pointer to register struct |
60 | * @msg: pointer to current message |
61 | * @msg_len: number of bytes transferred in msg |
62 | * @msg_err: error code for completed message |
63 | * @msg_complete: xfer completion object |
64 | * @dev: device reference |
65 | * @adapter: core i2c abstraction |
66 | * @i2c_clk: clock reference for i2c input clock |
67 | * @bus_clk_rate: current i2c bus clock rate |
68 | * @buf: ptr to msg buffer for easier use. |
69 | * @fifo_size: size of the FIFO passed in. |
70 | * @isr_mask: cached copy of local ISR enables. |
71 | * @isr_status: cached copy of local ISR status. |
72 | * @isr_mutex: mutex for IRQ thread. |
73 | */ |
74 | struct altr_i2c_dev { |
75 | void __iomem *base; |
76 | struct i2c_msg *msg; |
77 | size_t msg_len; |
78 | int msg_err; |
79 | struct completion msg_complete; |
80 | struct device *dev; |
81 | struct i2c_adapter adapter; |
82 | struct clk *i2c_clk; |
83 | u32 bus_clk_rate; |
84 | u8 *buf; |
85 | u32 fifo_size; |
86 | u32 isr_mask; |
87 | u32 isr_status; |
88 | struct mutex isr_mutex; |
89 | }; |
90 | |
91 | static void |
92 | altr_i2c_int_enable(struct altr_i2c_dev *idev, u32 mask, bool enable) |
93 | { |
94 | u32 int_en; |
95 | |
96 | int_en = readl(addr: idev->base + ALTR_I2C_ISER); |
97 | if (enable) |
98 | idev->isr_mask = int_en | mask; |
99 | else |
100 | idev->isr_mask = int_en & ~mask; |
101 | |
102 | writel(val: idev->isr_mask, addr: idev->base + ALTR_I2C_ISER); |
103 | } |
104 | |
105 | static void altr_i2c_int_clear(struct altr_i2c_dev *idev, u32 mask) |
106 | { |
107 | u32 int_en = readl(addr: idev->base + ALTR_I2C_ISR); |
108 | |
109 | writel(val: int_en | mask, addr: idev->base + ALTR_I2C_ISR); |
110 | } |
111 | |
112 | static void altr_i2c_core_disable(struct altr_i2c_dev *idev) |
113 | { |
114 | u32 tmp = readl(addr: idev->base + ALTR_I2C_CTRL); |
115 | |
116 | writel(val: tmp & ~ALTR_I2C_CTRL_EN, addr: idev->base + ALTR_I2C_CTRL); |
117 | } |
118 | |
119 | static void altr_i2c_core_enable(struct altr_i2c_dev *idev) |
120 | { |
121 | u32 tmp = readl(addr: idev->base + ALTR_I2C_CTRL); |
122 | |
123 | writel(val: tmp | ALTR_I2C_CTRL_EN, addr: idev->base + ALTR_I2C_CTRL); |
124 | } |
125 | |
126 | static void altr_i2c_reset(struct altr_i2c_dev *idev) |
127 | { |
128 | altr_i2c_core_disable(idev); |
129 | altr_i2c_core_enable(idev); |
130 | } |
131 | |
132 | static inline void altr_i2c_stop(struct altr_i2c_dev *idev) |
133 | { |
134 | writel(ALTR_I2C_TFR_CMD_STO, addr: idev->base + ALTR_I2C_TFR_CMD); |
135 | } |
136 | |
137 | static void altr_i2c_init(struct altr_i2c_dev *idev) |
138 | { |
139 | u32 divisor = clk_get_rate(clk: idev->i2c_clk) / idev->bus_clk_rate; |
140 | u32 clk_mhz = clk_get_rate(clk: idev->i2c_clk) / 1000000; |
141 | u32 tmp = (ALTR_I2C_THRESHOLD << ALTR_I2C_CTRL_RXT_SHFT) | |
142 | (ALTR_I2C_THRESHOLD << ALTR_I2C_CTRL_TCT_SHFT); |
143 | u32 t_high, t_low; |
144 | |
145 | if (idev->bus_clk_rate <= I2C_MAX_STANDARD_MODE_FREQ) { |
146 | tmp &= ~ALTR_I2C_CTRL_BSPEED; |
147 | /* Standard mode SCL 50/50 */ |
148 | t_high = divisor * 1 / 2; |
149 | t_low = divisor * 1 / 2; |
150 | } else { |
151 | tmp |= ALTR_I2C_CTRL_BSPEED; |
152 | /* Fast mode SCL 33/66 */ |
153 | t_high = divisor * 1 / 3; |
154 | t_low = divisor * 2 / 3; |
155 | } |
156 | writel(val: tmp, addr: idev->base + ALTR_I2C_CTRL); |
157 | |
158 | dev_dbg(idev->dev, "rate=%uHz per_clk=%uMHz -> ratio=1:%u\n" , |
159 | idev->bus_clk_rate, clk_mhz, divisor); |
160 | |
161 | /* Reset controller */ |
162 | altr_i2c_reset(idev); |
163 | |
164 | /* SCL High Time */ |
165 | writel(val: t_high, addr: idev->base + ALTR_I2C_SCL_HIGH); |
166 | /* SCL Low Time */ |
167 | writel(val: t_low, addr: idev->base + ALTR_I2C_SCL_LOW); |
168 | /* SDA Hold Time, 300ns */ |
169 | writel(val: 3 * clk_mhz / 10, addr: idev->base + ALTR_I2C_SDA_HOLD); |
170 | |
171 | /* Mask all master interrupt bits */ |
172 | altr_i2c_int_enable(idev, ALTR_I2C_ALL_IRQ, enable: false); |
173 | } |
174 | |
175 | /* |
176 | * altr_i2c_transfer - On the last byte to be transmitted, send |
177 | * a Stop bit on the last byte. |
178 | */ |
179 | static void altr_i2c_transfer(struct altr_i2c_dev *idev, u32 data) |
180 | { |
181 | /* On the last byte to be transmitted, send STOP */ |
182 | if (idev->msg_len == 1) |
183 | data |= ALTR_I2C_TFR_CMD_STO; |
184 | if (idev->msg_len > 0) |
185 | writel(val: data, addr: idev->base + ALTR_I2C_TFR_CMD); |
186 | } |
187 | |
188 | /* |
189 | * altr_i2c_empty_rx_fifo - Fetch data from RX FIFO until end of |
190 | * transfer. Send a Stop bit on the last byte. |
191 | */ |
192 | static void altr_i2c_empty_rx_fifo(struct altr_i2c_dev *idev) |
193 | { |
194 | size_t rx_fifo_avail = readl(addr: idev->base + ALTR_I2C_RX_FIFO_LVL); |
195 | int bytes_to_transfer = min(rx_fifo_avail, idev->msg_len); |
196 | |
197 | while (bytes_to_transfer-- > 0) { |
198 | *idev->buf++ = readl(addr: idev->base + ALTR_I2C_RX_DATA); |
199 | idev->msg_len--; |
200 | altr_i2c_transfer(idev, data: 0); |
201 | } |
202 | } |
203 | |
204 | /* |
205 | * altr_i2c_fill_tx_fifo - Fill TX FIFO from current message buffer. |
206 | */ |
207 | static int altr_i2c_fill_tx_fifo(struct altr_i2c_dev *idev) |
208 | { |
209 | size_t tx_fifo_avail = idev->fifo_size - readl(addr: idev->base + |
210 | ALTR_I2C_TC_FIFO_LVL); |
211 | int bytes_to_transfer = min(tx_fifo_avail, idev->msg_len); |
212 | int ret = idev->msg_len - bytes_to_transfer; |
213 | |
214 | while (bytes_to_transfer-- > 0) { |
215 | altr_i2c_transfer(idev, data: *idev->buf++); |
216 | idev->msg_len--; |
217 | } |
218 | |
219 | return ret; |
220 | } |
221 | |
222 | static irqreturn_t altr_i2c_isr_quick(int irq, void *_dev) |
223 | { |
224 | struct altr_i2c_dev *idev = _dev; |
225 | irqreturn_t ret = IRQ_HANDLED; |
226 | |
227 | /* Read IRQ status but only interested in Enabled IRQs. */ |
228 | idev->isr_status = readl(addr: idev->base + ALTR_I2C_ISR) & idev->isr_mask; |
229 | if (idev->isr_status) |
230 | ret = IRQ_WAKE_THREAD; |
231 | |
232 | return ret; |
233 | } |
234 | |
235 | static irqreturn_t altr_i2c_isr(int irq, void *_dev) |
236 | { |
237 | int ret; |
238 | bool read, finish = false; |
239 | struct altr_i2c_dev *idev = _dev; |
240 | u32 status = idev->isr_status; |
241 | |
242 | mutex_lock(&idev->isr_mutex); |
243 | if (!idev->msg) { |
244 | dev_warn(idev->dev, "unexpected interrupt\n" ); |
245 | altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ); |
246 | goto out; |
247 | } |
248 | read = (idev->msg->flags & I2C_M_RD) != 0; |
249 | |
250 | /* handle Lost Arbitration */ |
251 | if (unlikely(status & ALTR_I2C_ISR_ARB)) { |
252 | altr_i2c_int_clear(idev, ALTR_I2C_ISR_ARB); |
253 | idev->msg_err = -EAGAIN; |
254 | finish = true; |
255 | } else if (unlikely(status & ALTR_I2C_ISR_NACK)) { |
256 | dev_dbg(idev->dev, "Could not get ACK\n" ); |
257 | idev->msg_err = -ENXIO; |
258 | altr_i2c_int_clear(idev, ALTR_I2C_ISR_NACK); |
259 | altr_i2c_stop(idev); |
260 | finish = true; |
261 | } else if (read && unlikely(status & ALTR_I2C_ISR_RXOF)) { |
262 | /* handle RX FIFO Overflow */ |
263 | altr_i2c_empty_rx_fifo(idev); |
264 | altr_i2c_int_clear(idev, ALTR_I2C_ISR_RXRDY); |
265 | altr_i2c_stop(idev); |
266 | dev_err(idev->dev, "RX FIFO Overflow\n" ); |
267 | finish = true; |
268 | } else if (read && (status & ALTR_I2C_ISR_RXRDY)) { |
269 | /* RX FIFO needs service? */ |
270 | altr_i2c_empty_rx_fifo(idev); |
271 | altr_i2c_int_clear(idev, ALTR_I2C_ISR_RXRDY); |
272 | if (!idev->msg_len) |
273 | finish = true; |
274 | } else if (!read && (status & ALTR_I2C_ISR_TXRDY)) { |
275 | /* TX FIFO needs service? */ |
276 | altr_i2c_int_clear(idev, ALTR_I2C_ISR_TXRDY); |
277 | if (idev->msg_len > 0) |
278 | altr_i2c_fill_tx_fifo(idev); |
279 | else |
280 | finish = true; |
281 | } else { |
282 | dev_warn(idev->dev, "Unexpected interrupt: 0x%x\n" , status); |
283 | altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ); |
284 | } |
285 | |
286 | if (finish) { |
287 | /* Wait for the Core to finish */ |
288 | ret = readl_poll_timeout_atomic(idev->base + ALTR_I2C_STATUS, |
289 | status, |
290 | !(status & ALTR_I2C_STAT_CORE), |
291 | 1, ALTR_I2C_TIMEOUT); |
292 | if (ret) |
293 | dev_err(idev->dev, "message timeout\n" ); |
294 | altr_i2c_int_enable(idev, ALTR_I2C_ALL_IRQ, enable: false); |
295 | altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ); |
296 | complete(&idev->msg_complete); |
297 | dev_dbg(idev->dev, "Message Complete\n" ); |
298 | } |
299 | out: |
300 | mutex_unlock(lock: &idev->isr_mutex); |
301 | |
302 | return IRQ_HANDLED; |
303 | } |
304 | |
305 | static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg) |
306 | { |
307 | u32 imask = ALTR_I2C_ISR_RXOF | ALTR_I2C_ISR_ARB | ALTR_I2C_ISR_NACK; |
308 | unsigned long time_left; |
309 | u32 value; |
310 | u8 addr = i2c_8bit_addr_from_msg(msg); |
311 | |
312 | mutex_lock(&idev->isr_mutex); |
313 | idev->msg = msg; |
314 | idev->msg_len = msg->len; |
315 | idev->buf = msg->buf; |
316 | idev->msg_err = 0; |
317 | reinit_completion(x: &idev->msg_complete); |
318 | altr_i2c_core_enable(idev); |
319 | |
320 | /* Make sure RX FIFO is empty */ |
321 | do { |
322 | readl(addr: idev->base + ALTR_I2C_RX_DATA); |
323 | } while (readl(addr: idev->base + ALTR_I2C_RX_FIFO_LVL)); |
324 | |
325 | writel(ALTR_I2C_TFR_CMD_STA | addr, addr: idev->base + ALTR_I2C_TFR_CMD); |
326 | |
327 | if ((msg->flags & I2C_M_RD) != 0) { |
328 | imask |= ALTR_I2C_ISER_RXOF_EN | ALTR_I2C_ISER_RXRDY_EN; |
329 | altr_i2c_int_enable(idev, mask: imask, enable: true); |
330 | /* write the first byte to start the RX */ |
331 | altr_i2c_transfer(idev, data: 0); |
332 | } else { |
333 | imask |= ALTR_I2C_ISR_TXRDY; |
334 | altr_i2c_int_enable(idev, mask: imask, enable: true); |
335 | altr_i2c_fill_tx_fifo(idev); |
336 | } |
337 | mutex_unlock(lock: &idev->isr_mutex); |
338 | |
339 | time_left = wait_for_completion_timeout(x: &idev->msg_complete, |
340 | ALTR_I2C_XFER_TIMEOUT); |
341 | mutex_lock(&idev->isr_mutex); |
342 | altr_i2c_int_enable(idev, mask: imask, enable: false); |
343 | |
344 | value = readl(addr: idev->base + ALTR_I2C_STATUS) & ALTR_I2C_STAT_CORE; |
345 | if (value) |
346 | dev_err(idev->dev, "Core Status not IDLE...\n" ); |
347 | |
348 | if (time_left == 0) { |
349 | idev->msg_err = -ETIMEDOUT; |
350 | dev_dbg(idev->dev, "Transaction timed out.\n" ); |
351 | } |
352 | |
353 | altr_i2c_core_disable(idev); |
354 | mutex_unlock(lock: &idev->isr_mutex); |
355 | |
356 | return idev->msg_err; |
357 | } |
358 | |
359 | static int |
360 | altr_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) |
361 | { |
362 | struct altr_i2c_dev *idev = i2c_get_adapdata(adap); |
363 | int i, ret; |
364 | |
365 | for (i = 0; i < num; i++) { |
366 | ret = altr_i2c_xfer_msg(idev, msg: msgs++); |
367 | if (ret) |
368 | return ret; |
369 | } |
370 | return num; |
371 | } |
372 | |
373 | static u32 altr_i2c_func(struct i2c_adapter *adap) |
374 | { |
375 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; |
376 | } |
377 | |
378 | static const struct i2c_algorithm altr_i2c_algo = { |
379 | .master_xfer = altr_i2c_xfer, |
380 | .functionality = altr_i2c_func, |
381 | }; |
382 | |
383 | static int altr_i2c_probe(struct platform_device *pdev) |
384 | { |
385 | struct altr_i2c_dev *idev = NULL; |
386 | int irq, ret; |
387 | |
388 | idev = devm_kzalloc(dev: &pdev->dev, size: sizeof(*idev), GFP_KERNEL); |
389 | if (!idev) |
390 | return -ENOMEM; |
391 | |
392 | idev->base = devm_platform_ioremap_resource(pdev, index: 0); |
393 | if (IS_ERR(ptr: idev->base)) |
394 | return PTR_ERR(ptr: idev->base); |
395 | |
396 | irq = platform_get_irq(pdev, 0); |
397 | if (irq < 0) |
398 | return irq; |
399 | |
400 | idev->i2c_clk = devm_clk_get(dev: &pdev->dev, NULL); |
401 | if (IS_ERR(ptr: idev->i2c_clk)) { |
402 | dev_err(&pdev->dev, "missing clock\n" ); |
403 | return PTR_ERR(ptr: idev->i2c_clk); |
404 | } |
405 | |
406 | idev->dev = &pdev->dev; |
407 | init_completion(x: &idev->msg_complete); |
408 | mutex_init(&idev->isr_mutex); |
409 | |
410 | ret = device_property_read_u32(dev: idev->dev, propname: "fifo-size" , |
411 | val: &idev->fifo_size); |
412 | if (ret) { |
413 | dev_err(&pdev->dev, "FIFO size set to default of %d\n" , |
414 | ALTR_I2C_DFLT_FIFO_SZ); |
415 | idev->fifo_size = ALTR_I2C_DFLT_FIFO_SZ; |
416 | } |
417 | |
418 | ret = device_property_read_u32(dev: idev->dev, propname: "clock-frequency" , |
419 | val: &idev->bus_clk_rate); |
420 | if (ret) { |
421 | dev_err(&pdev->dev, "Default to 100kHz\n" ); |
422 | idev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; /* default clock rate */ |
423 | } |
424 | |
425 | if (idev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ) { |
426 | dev_err(&pdev->dev, "invalid clock-frequency %d\n" , |
427 | idev->bus_clk_rate); |
428 | return -EINVAL; |
429 | } |
430 | |
431 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq, handler: altr_i2c_isr_quick, |
432 | thread_fn: altr_i2c_isr, IRQF_ONESHOT, |
433 | devname: pdev->name, dev_id: idev); |
434 | if (ret) { |
435 | dev_err(&pdev->dev, "failed to claim IRQ %d\n" , irq); |
436 | return ret; |
437 | } |
438 | |
439 | ret = clk_prepare_enable(clk: idev->i2c_clk); |
440 | if (ret) { |
441 | dev_err(&pdev->dev, "failed to enable clock\n" ); |
442 | return ret; |
443 | } |
444 | |
445 | mutex_lock(&idev->isr_mutex); |
446 | altr_i2c_init(idev); |
447 | mutex_unlock(lock: &idev->isr_mutex); |
448 | |
449 | i2c_set_adapdata(adap: &idev->adapter, data: idev); |
450 | strscpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); |
451 | idev->adapter.owner = THIS_MODULE; |
452 | idev->adapter.algo = &altr_i2c_algo; |
453 | idev->adapter.dev.parent = &pdev->dev; |
454 | idev->adapter.dev.of_node = pdev->dev.of_node; |
455 | |
456 | platform_set_drvdata(pdev, data: idev); |
457 | |
458 | ret = i2c_add_adapter(adap: &idev->adapter); |
459 | if (ret) { |
460 | clk_disable_unprepare(clk: idev->i2c_clk); |
461 | return ret; |
462 | } |
463 | dev_info(&pdev->dev, "Altera SoftIP I2C Probe Complete\n" ); |
464 | |
465 | return 0; |
466 | } |
467 | |
468 | static void altr_i2c_remove(struct platform_device *pdev) |
469 | { |
470 | struct altr_i2c_dev *idev = platform_get_drvdata(pdev); |
471 | |
472 | clk_disable_unprepare(clk: idev->i2c_clk); |
473 | i2c_del_adapter(adap: &idev->adapter); |
474 | } |
475 | |
476 | /* Match table for of_platform binding */ |
477 | static const struct of_device_id altr_i2c_of_match[] = { |
478 | { .compatible = "altr,softip-i2c-v1.0" }, |
479 | {}, |
480 | }; |
481 | MODULE_DEVICE_TABLE(of, altr_i2c_of_match); |
482 | |
483 | static struct platform_driver altr_i2c_driver = { |
484 | .probe = altr_i2c_probe, |
485 | .remove_new = altr_i2c_remove, |
486 | .driver = { |
487 | .name = "altera-i2c" , |
488 | .of_match_table = altr_i2c_of_match, |
489 | }, |
490 | }; |
491 | |
492 | module_platform_driver(altr_i2c_driver); |
493 | |
494 | MODULE_DESCRIPTION("Altera Soft IP I2C bus driver" ); |
495 | MODULE_AUTHOR("Thor Thayer <thor.thayer@linux.intel.com>" ); |
496 | MODULE_LICENSE("GPL v2" ); |
497 | |