| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright Intel Corporation (C) 2017. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 5 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 6 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 9 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 10 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 11 | | - * more details. |
|---|
| 12 | | - * |
|---|
| 13 | | - * You should have received a copy of the GNU General Public License along with |
|---|
| 14 | | - * this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 15 | 4 | * |
|---|
| 16 | 5 | * Based on the i2c-axxia.c driver. |
|---|
| 17 | 6 | */ |
|---|
| .. | .. |
|---|
| 80 | 69 | * @fifo_size: size of the FIFO passed in. |
|---|
| 81 | 70 | * @isr_mask: cached copy of local ISR enables. |
|---|
| 82 | 71 | * @isr_status: cached copy of local ISR status. |
|---|
| 83 | | - * @lock: spinlock for IRQ synchronization. |
|---|
| 84 | 72 | * @isr_mutex: mutex for IRQ thread. |
|---|
| 85 | 73 | */ |
|---|
| 86 | 74 | struct altr_i2c_dev { |
|---|
| .. | .. |
|---|
| 97 | 85 | u32 fifo_size; |
|---|
| 98 | 86 | u32 isr_mask; |
|---|
| 99 | 87 | u32 isr_status; |
|---|
| 100 | | - spinlock_t lock; /* IRQ synchronization */ |
|---|
| 101 | 88 | struct mutex isr_mutex; |
|---|
| 102 | 89 | }; |
|---|
| 103 | 90 | |
|---|
| 104 | 91 | static void |
|---|
| 105 | 92 | altr_i2c_int_enable(struct altr_i2c_dev *idev, u32 mask, bool enable) |
|---|
| 106 | 93 | { |
|---|
| 107 | | - unsigned long flags; |
|---|
| 108 | 94 | u32 int_en; |
|---|
| 109 | | - |
|---|
| 110 | | - spin_lock_irqsave(&idev->lock, flags); |
|---|
| 111 | 95 | |
|---|
| 112 | 96 | int_en = readl(idev->base + ALTR_I2C_ISER); |
|---|
| 113 | 97 | if (enable) |
|---|
| .. | .. |
|---|
| 116 | 100 | idev->isr_mask = int_en & ~mask; |
|---|
| 117 | 101 | |
|---|
| 118 | 102 | writel(idev->isr_mask, idev->base + ALTR_I2C_ISER); |
|---|
| 119 | | - |
|---|
| 120 | | - spin_unlock_irqrestore(&idev->lock, flags); |
|---|
| 121 | 103 | } |
|---|
| 122 | 104 | |
|---|
| 123 | 105 | static void altr_i2c_int_clear(struct altr_i2c_dev *idev, u32 mask) |
|---|
| .. | .. |
|---|
| 160 | 142 | (ALTR_I2C_THRESHOLD << ALTR_I2C_CTRL_TCT_SHFT); |
|---|
| 161 | 143 | u32 t_high, t_low; |
|---|
| 162 | 144 | |
|---|
| 163 | | - if (idev->bus_clk_rate <= 100000) { |
|---|
| 145 | + if (idev->bus_clk_rate <= I2C_MAX_STANDARD_MODE_FREQ) { |
|---|
| 164 | 146 | tmp &= ~ALTR_I2C_CTRL_BSPEED; |
|---|
| 165 | 147 | /* Standard mode SCL 50/50 */ |
|---|
| 166 | 148 | t_high = divisor * 1 / 2; |
|---|
| .. | .. |
|---|
| 357 | 339 | |
|---|
| 358 | 340 | time_left = wait_for_completion_timeout(&idev->msg_complete, |
|---|
| 359 | 341 | ALTR_I2C_XFER_TIMEOUT); |
|---|
| 342 | + mutex_lock(&idev->isr_mutex); |
|---|
| 360 | 343 | altr_i2c_int_enable(idev, imask, false); |
|---|
| 361 | 344 | |
|---|
| 362 | 345 | value = readl(idev->base + ALTR_I2C_STATUS) & ALTR_I2C_STAT_CORE; |
|---|
| .. | .. |
|---|
| 369 | 352 | } |
|---|
| 370 | 353 | |
|---|
| 371 | 354 | altr_i2c_core_disable(idev); |
|---|
| 355 | + mutex_unlock(&idev->isr_mutex); |
|---|
| 372 | 356 | |
|---|
| 373 | 357 | return idev->msg_err; |
|---|
| 374 | 358 | } |
|---|
| .. | .. |
|---|
| 400 | 384 | static int altr_i2c_probe(struct platform_device *pdev) |
|---|
| 401 | 385 | { |
|---|
| 402 | 386 | struct altr_i2c_dev *idev = NULL; |
|---|
| 403 | | - struct resource *res; |
|---|
| 404 | 387 | int irq, ret; |
|---|
| 405 | 388 | |
|---|
| 406 | 389 | idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL); |
|---|
| 407 | 390 | if (!idev) |
|---|
| 408 | 391 | return -ENOMEM; |
|---|
| 409 | 392 | |
|---|
| 410 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 411 | | - idev->base = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 393 | + idev->base = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 412 | 394 | if (IS_ERR(idev->base)) |
|---|
| 413 | 395 | return PTR_ERR(idev->base); |
|---|
| 414 | 396 | |
|---|
| 415 | 397 | irq = platform_get_irq(pdev, 0); |
|---|
| 416 | | - if (irq < 0) { |
|---|
| 417 | | - dev_err(&pdev->dev, "missing interrupt resource\n"); |
|---|
| 398 | + if (irq < 0) |
|---|
| 418 | 399 | return irq; |
|---|
| 419 | | - } |
|---|
| 420 | 400 | |
|---|
| 421 | 401 | idev->i2c_clk = devm_clk_get(&pdev->dev, NULL); |
|---|
| 422 | 402 | if (IS_ERR(idev->i2c_clk)) { |
|---|
| .. | .. |
|---|
| 426 | 406 | |
|---|
| 427 | 407 | idev->dev = &pdev->dev; |
|---|
| 428 | 408 | init_completion(&idev->msg_complete); |
|---|
| 429 | | - spin_lock_init(&idev->lock); |
|---|
| 430 | 409 | mutex_init(&idev->isr_mutex); |
|---|
| 431 | 410 | |
|---|
| 432 | 411 | ret = device_property_read_u32(idev->dev, "fifo-size", |
|---|
| .. | .. |
|---|
| 441 | 420 | &idev->bus_clk_rate); |
|---|
| 442 | 421 | if (ret) { |
|---|
| 443 | 422 | dev_err(&pdev->dev, "Default to 100kHz\n"); |
|---|
| 444 | | - idev->bus_clk_rate = 100000; /* default clock rate */ |
|---|
| 423 | + idev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; /* default clock rate */ |
|---|
| 445 | 424 | } |
|---|
| 446 | 425 | |
|---|
| 447 | | - if (idev->bus_clk_rate > 400000) { |
|---|
| 426 | + if (idev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ) { |
|---|
| 448 | 427 | dev_err(&pdev->dev, "invalid clock-frequency %d\n", |
|---|
| 449 | 428 | idev->bus_clk_rate); |
|---|
| 450 | 429 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 464 | 443 | return ret; |
|---|
| 465 | 444 | } |
|---|
| 466 | 445 | |
|---|
| 446 | + mutex_lock(&idev->isr_mutex); |
|---|
| 467 | 447 | altr_i2c_init(idev); |
|---|
| 448 | + mutex_unlock(&idev->isr_mutex); |
|---|
| 468 | 449 | |
|---|
| 469 | 450 | i2c_set_adapdata(&idev->adapter, idev); |
|---|
| 470 | 451 | strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); |
|---|