| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * I2C bus driver for Amlogic Meson SoCs |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 9 | 6 | */ |
|---|
| 10 | 7 | |
|---|
| 11 | 8 | #include <linux/bitfield.h> |
|---|
| .. | .. |
|---|
| 14 | 11 | #include <linux/i2c.h> |
|---|
| 15 | 12 | #include <linux/interrupt.h> |
|---|
| 16 | 13 | #include <linux/io.h> |
|---|
| 14 | +#include <linux/iopoll.h> |
|---|
| 17 | 15 | #include <linux/kernel.h> |
|---|
| 18 | 16 | #include <linux/module.h> |
|---|
| 19 | 17 | #include <linux/of.h> |
|---|
| .. | .. |
|---|
| 227 | 225 | writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1); |
|---|
| 228 | 226 | } |
|---|
| 229 | 227 | |
|---|
| 228 | +static void meson_i2c_transfer_complete(struct meson_i2c *i2c, u32 ctrl) |
|---|
| 229 | +{ |
|---|
| 230 | + if (ctrl & REG_CTRL_ERROR) { |
|---|
| 231 | + /* |
|---|
| 232 | + * The bit is set when the IGNORE_NAK bit is cleared |
|---|
| 233 | + * and the device didn't respond. In this case, the |
|---|
| 234 | + * I2C controller automatically generates a STOP |
|---|
| 235 | + * condition. |
|---|
| 236 | + */ |
|---|
| 237 | + dev_dbg(i2c->dev, "error bit set\n"); |
|---|
| 238 | + i2c->error = -ENXIO; |
|---|
| 239 | + i2c->state = STATE_IDLE; |
|---|
| 240 | + } else { |
|---|
| 241 | + if (i2c->state == STATE_READ && i2c->count) |
|---|
| 242 | + meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, |
|---|
| 243 | + i2c->count); |
|---|
| 244 | + |
|---|
| 245 | + i2c->pos += i2c->count; |
|---|
| 246 | + |
|---|
| 247 | + if (i2c->pos >= i2c->msg->len) |
|---|
| 248 | + i2c->state = STATE_IDLE; |
|---|
| 249 | + } |
|---|
| 250 | +} |
|---|
| 251 | + |
|---|
| 230 | 252 | static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) |
|---|
| 231 | 253 | { |
|---|
| 232 | 254 | struct meson_i2c *i2c = dev_id; |
|---|
| .. | .. |
|---|
| 246 | 268 | return IRQ_NONE; |
|---|
| 247 | 269 | } |
|---|
| 248 | 270 | |
|---|
| 249 | | - if (ctrl & REG_CTRL_ERROR) { |
|---|
| 250 | | - /* |
|---|
| 251 | | - * The bit is set when the IGNORE_NAK bit is cleared |
|---|
| 252 | | - * and the device didn't respond. In this case, the |
|---|
| 253 | | - * I2C controller automatically generates a STOP |
|---|
| 254 | | - * condition. |
|---|
| 255 | | - */ |
|---|
| 256 | | - dev_dbg(i2c->dev, "error bit set\n"); |
|---|
| 257 | | - i2c->error = -ENXIO; |
|---|
| 258 | | - i2c->state = STATE_IDLE; |
|---|
| 259 | | - complete(&i2c->done); |
|---|
| 260 | | - goto out; |
|---|
| 261 | | - } |
|---|
| 271 | + meson_i2c_transfer_complete(i2c, ctrl); |
|---|
| 262 | 272 | |
|---|
| 263 | | - if (i2c->state == STATE_READ && i2c->count) |
|---|
| 264 | | - meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); |
|---|
| 265 | | - |
|---|
| 266 | | - i2c->pos += i2c->count; |
|---|
| 267 | | - |
|---|
| 268 | | - if (i2c->pos >= i2c->msg->len) { |
|---|
| 269 | | - i2c->state = STATE_IDLE; |
|---|
| 273 | + if (i2c->state == STATE_IDLE) { |
|---|
| 270 | 274 | complete(&i2c->done); |
|---|
| 271 | 275 | goto out; |
|---|
| 272 | 276 | } |
|---|
| .. | .. |
|---|
| 296 | 300 | } |
|---|
| 297 | 301 | |
|---|
| 298 | 302 | static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg, |
|---|
| 299 | | - int last) |
|---|
| 303 | + int last, bool atomic) |
|---|
| 300 | 304 | { |
|---|
| 301 | 305 | unsigned long time_left, flags; |
|---|
| 302 | 306 | int ret = 0; |
|---|
| 307 | + u32 ctrl; |
|---|
| 303 | 308 | |
|---|
| 304 | 309 | i2c->msg = msg; |
|---|
| 305 | 310 | i2c->last = last; |
|---|
| .. | .. |
|---|
| 317 | 322 | |
|---|
| 318 | 323 | i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; |
|---|
| 319 | 324 | meson_i2c_prepare_xfer(i2c); |
|---|
| 320 | | - reinit_completion(&i2c->done); |
|---|
| 325 | + |
|---|
| 326 | + if (!atomic) |
|---|
| 327 | + reinit_completion(&i2c->done); |
|---|
| 321 | 328 | |
|---|
| 322 | 329 | /* Start the transfer */ |
|---|
| 323 | 330 | meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); |
|---|
| 324 | 331 | |
|---|
| 325 | | - time_left = msecs_to_jiffies(I2C_TIMEOUT_MS); |
|---|
| 326 | | - time_left = wait_for_completion_timeout(&i2c->done, time_left); |
|---|
| 332 | + if (atomic) { |
|---|
| 333 | + ret = readl_poll_timeout_atomic(i2c->regs + REG_CTRL, ctrl, |
|---|
| 334 | + !(ctrl & REG_CTRL_STATUS), |
|---|
| 335 | + 10, I2C_TIMEOUT_MS * 1000); |
|---|
| 336 | + } else { |
|---|
| 337 | + time_left = msecs_to_jiffies(I2C_TIMEOUT_MS); |
|---|
| 338 | + time_left = wait_for_completion_timeout(&i2c->done, time_left); |
|---|
| 339 | + |
|---|
| 340 | + if (!time_left) |
|---|
| 341 | + ret = -ETIMEDOUT; |
|---|
| 342 | + } |
|---|
| 327 | 343 | |
|---|
| 328 | 344 | /* |
|---|
| 329 | 345 | * Protect access to i2c struct and registers from interrupt |
|---|
| .. | .. |
|---|
| 332 | 348 | */ |
|---|
| 333 | 349 | spin_lock_irqsave(&i2c->lock, flags); |
|---|
| 334 | 350 | |
|---|
| 351 | + if (atomic && !ret) |
|---|
| 352 | + meson_i2c_transfer_complete(i2c, ctrl); |
|---|
| 353 | + |
|---|
| 335 | 354 | /* Abort any active operation */ |
|---|
| 336 | 355 | meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); |
|---|
| 337 | 356 | |
|---|
| 338 | | - if (!time_left) { |
|---|
| 357 | + if (ret) |
|---|
| 339 | 358 | i2c->state = STATE_IDLE; |
|---|
| 340 | | - ret = -ETIMEDOUT; |
|---|
| 341 | | - } |
|---|
| 342 | 359 | |
|---|
| 343 | 360 | if (i2c->error) |
|---|
| 344 | 361 | ret = i2c->error; |
|---|
| .. | .. |
|---|
| 348 | 365 | return ret; |
|---|
| 349 | 366 | } |
|---|
| 350 | 367 | |
|---|
| 351 | | -static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
|---|
| 352 | | - int num) |
|---|
| 368 | +static int meson_i2c_xfer_messages(struct i2c_adapter *adap, |
|---|
| 369 | + struct i2c_msg *msgs, int num, bool atomic) |
|---|
| 353 | 370 | { |
|---|
| 354 | 371 | struct meson_i2c *i2c = adap->algo_data; |
|---|
| 355 | 372 | int i, ret = 0; |
|---|
| 356 | 373 | |
|---|
| 357 | | - clk_enable(i2c->clk); |
|---|
| 358 | | - |
|---|
| 359 | 374 | for (i = 0; i < num; i++) { |
|---|
| 360 | | - ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1); |
|---|
| 375 | + ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1, atomic); |
|---|
| 361 | 376 | if (ret) |
|---|
| 362 | 377 | break; |
|---|
| 363 | 378 | } |
|---|
| 364 | 379 | |
|---|
| 365 | | - clk_disable(i2c->clk); |
|---|
| 366 | | - |
|---|
| 367 | 380 | return ret ?: i; |
|---|
| 381 | +} |
|---|
| 382 | + |
|---|
| 383 | +static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
|---|
| 384 | + int num) |
|---|
| 385 | +{ |
|---|
| 386 | + return meson_i2c_xfer_messages(adap, msgs, num, false); |
|---|
| 387 | +} |
|---|
| 388 | + |
|---|
| 389 | +static int meson_i2c_xfer_atomic(struct i2c_adapter *adap, |
|---|
| 390 | + struct i2c_msg *msgs, int num) |
|---|
| 391 | +{ |
|---|
| 392 | + return meson_i2c_xfer_messages(adap, msgs, num, true); |
|---|
| 368 | 393 | } |
|---|
| 369 | 394 | |
|---|
| 370 | 395 | static u32 meson_i2c_func(struct i2c_adapter *adap) |
|---|
| .. | .. |
|---|
| 373 | 398 | } |
|---|
| 374 | 399 | |
|---|
| 375 | 400 | static const struct i2c_algorithm meson_i2c_algorithm = { |
|---|
| 376 | | - .master_xfer = meson_i2c_xfer, |
|---|
| 377 | | - .functionality = meson_i2c_func, |
|---|
| 401 | + .master_xfer = meson_i2c_xfer, |
|---|
| 402 | + .master_xfer_atomic = meson_i2c_xfer_atomic, |
|---|
| 403 | + .functionality = meson_i2c_func, |
|---|
| 378 | 404 | }; |
|---|
| 379 | 405 | |
|---|
| 380 | 406 | static int meson_i2c_probe(struct platform_device *pdev) |
|---|
| 381 | 407 | { |
|---|
| 382 | 408 | struct device_node *np = pdev->dev.of_node; |
|---|
| 383 | 409 | struct meson_i2c *i2c; |
|---|
| 384 | | - struct resource *mem; |
|---|
| 385 | 410 | struct i2c_timings timings; |
|---|
| 386 | 411 | int irq, ret = 0; |
|---|
| 387 | 412 | |
|---|
| .. | .. |
|---|
| 406 | 431 | return PTR_ERR(i2c->clk); |
|---|
| 407 | 432 | } |
|---|
| 408 | 433 | |
|---|
| 409 | | - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 410 | | - i2c->regs = devm_ioremap_resource(&pdev->dev, mem); |
|---|
| 434 | + i2c->regs = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 411 | 435 | if (IS_ERR(i2c->regs)) |
|---|
| 412 | 436 | return PTR_ERR(i2c->regs); |
|---|
| 413 | 437 | |
|---|
| 414 | 438 | irq = platform_get_irq(pdev, 0); |
|---|
| 415 | | - if (irq < 0) { |
|---|
| 416 | | - dev_err(&pdev->dev, "can't find IRQ\n"); |
|---|
| 439 | + if (irq < 0) |
|---|
| 417 | 440 | return irq; |
|---|
| 418 | | - } |
|---|
| 419 | 441 | |
|---|
| 420 | 442 | ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c); |
|---|
| 421 | 443 | if (ret < 0) { |
|---|
| .. | .. |
|---|
| 423 | 445 | return ret; |
|---|
| 424 | 446 | } |
|---|
| 425 | 447 | |
|---|
| 426 | | - ret = clk_prepare(i2c->clk); |
|---|
| 448 | + ret = clk_prepare_enable(i2c->clk); |
|---|
| 427 | 449 | if (ret < 0) { |
|---|
| 428 | 450 | dev_err(&pdev->dev, "can't prepare clock\n"); |
|---|
| 429 | 451 | return ret; |
|---|
| .. | .. |
|---|
| 443 | 465 | */ |
|---|
| 444 | 466 | meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); |
|---|
| 445 | 467 | |
|---|
| 446 | | - ret = i2c_add_adapter(&i2c->adap); |
|---|
| 447 | | - if (ret < 0) { |
|---|
| 448 | | - clk_unprepare(i2c->clk); |
|---|
| 449 | | - return ret; |
|---|
| 450 | | - } |
|---|
| 451 | | - |
|---|
| 452 | 468 | /* Disable filtering */ |
|---|
| 453 | 469 | meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, |
|---|
| 454 | 470 | REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0); |
|---|
| 455 | 471 | |
|---|
| 456 | 472 | meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); |
|---|
| 473 | + |
|---|
| 474 | + ret = i2c_add_adapter(&i2c->adap); |
|---|
| 475 | + if (ret < 0) { |
|---|
| 476 | + clk_disable_unprepare(i2c->clk); |
|---|
| 477 | + return ret; |
|---|
| 478 | + } |
|---|
| 457 | 479 | |
|---|
| 458 | 480 | return 0; |
|---|
| 459 | 481 | } |
|---|
| .. | .. |
|---|
| 463 | 485 | struct meson_i2c *i2c = platform_get_drvdata(pdev); |
|---|
| 464 | 486 | |
|---|
| 465 | 487 | i2c_del_adapter(&i2c->adap); |
|---|
| 466 | | - clk_unprepare(i2c->clk); |
|---|
| 488 | + clk_disable_unprepare(i2c->clk); |
|---|
| 467 | 489 | |
|---|
| 468 | 490 | return 0; |
|---|
| 469 | 491 | } |
|---|