From a5969cabbb4660eab42b6ef0412cbbd1200cf14d Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Sat, 12 Oct 2024 07:10:09 +0000 Subject: [PATCH] 修改led为gpio --- kernel/drivers/i2c/busses/i2c-omap.c | 108 ++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 72 insertions(+), 36 deletions(-) diff --git a/kernel/drivers/i2c/busses/i2c-omap.c b/kernel/drivers/i2c/busses/i2c-omap.c index cd9c65f..8955f62 100644 --- a/kernel/drivers/i2c/busses/i2c-omap.c +++ b/kernel/drivers/i2c/busses/i2c-omap.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * TI OMAP I2C master mode driver * @@ -12,16 +13,6 @@ * Juha Yrjölä <juha.yrjola@solidboot.com> * Syed Khasim <x0khasim@ti.com> * Nishant Menon <nm@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> @@ -268,6 +259,8 @@ [OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c, [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30, }; + +static int omap_i2c_xfer_data(struct omap_i2c_dev *omap); static inline void omap_i2c_write_reg(struct omap_i2c_dev *omap, int reg, u16 val) @@ -648,15 +641,28 @@ (1000 * omap->speed / 8); } +static void omap_i2c_wait(struct omap_i2c_dev *omap) +{ + u16 stat; + u16 mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); + int count = 0; + + do { + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); + count++; + } while (!(stat & mask) && count < 5); +} + /* * Low level master read/write transaction. */ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, - struct i2c_msg *msg, int stop) + struct i2c_msg *msg, int stop, bool polling) { struct omap_i2c_dev *omap = i2c_get_adapdata(adap); unsigned long timeout; u16 w; + int ret; dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags, stop); @@ -680,7 +686,8 @@ w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, w); - reinit_completion(&omap->cmd_complete); + if (!polling) + reinit_completion(&omap->cmd_complete); omap->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -732,8 +739,18 @@ * REVISIT: We should abort the transfer on signals, but the bus goes * into arbitration and we're currently unable to recover from it. */ - timeout = wait_for_completion_timeout(&omap->cmd_complete, - OMAP_I2C_TIMEOUT); + if (!polling) { + timeout = wait_for_completion_timeout(&omap->cmd_complete, + OMAP_I2C_TIMEOUT); + } else { + do { + omap_i2c_wait(omap); + ret = omap_i2c_xfer_data(omap); + } while (ret == -EAGAIN); + + timeout = !ret; + } + if (timeout == 0) { dev_err(omap->dev, "controller timed out\n"); omap_i2c_reset(omap); @@ -772,7 +789,8 @@ * to do the work during IRQ processing. */ static int -omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +omap_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg msgs[], int num, + bool polling) { struct omap_i2c_dev *omap = i2c_get_adapdata(adap); int i; @@ -794,7 +812,8 @@ omap->set_mpu_wkup_lat(omap->dev, omap->latency); for (i = 0; i < num; i++) { - r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); + r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)), + polling); if (r != 0) break; } @@ -811,6 +830,18 @@ pm_runtime_mark_last_busy(omap->dev); pm_runtime_put_autosuspend(omap->dev); return r; +} + +static int +omap_i2c_xfer_irq(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + return omap_i2c_xfer_common(adap, msgs, num, false); +} + +static int +omap_i2c_xfer_polling(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + return omap_i2c_xfer_common(adap, msgs, num, true); } static u32 @@ -1027,7 +1058,7 @@ u16 stat; stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); - mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); + mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG) & ~OMAP_I2C_STAT_NACK; if (stat & mask) ret = IRQ_WAKE_THREAD; @@ -1035,10 +1066,8 @@ return ret; } -static irqreturn_t -omap_i2c_isr_thread(int this_irq, void *dev_id) +static int omap_i2c_xfer_data(struct omap_i2c_dev *omap) { - struct omap_i2c_dev *omap = dev_id; u16 bits; u16 stat; int err = 0, count = 0; @@ -1056,7 +1085,8 @@ if (!stat) { /* my work here is done */ - goto out; + err = -EAGAIN; + break; } dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat); @@ -1165,14 +1195,25 @@ } } while (stat); - omap_i2c_complete_cmd(omap, err); + return err; +} -out: +static irqreturn_t +omap_i2c_isr_thread(int this_irq, void *dev_id) +{ + int ret; + struct omap_i2c_dev *omap = dev_id; + + ret = omap_i2c_xfer_data(omap); + if (ret != -EAGAIN) + omap_i2c_complete_cmd(omap, ret); + return IRQ_HANDLED; } static const struct i2c_algorithm omap_i2c_algo = { - .master_xfer = omap_i2c_xfer, + .master_xfer = omap_i2c_xfer_irq, + .master_xfer_atomic = omap_i2c_xfer_polling, .functionality = omap_i2c_func, }; @@ -1314,7 +1355,6 @@ { struct omap_i2c_dev *omap; struct i2c_adapter *adap; - struct resource *mem; const struct omap_i2c_bus_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; @@ -1325,23 +1365,20 @@ u16 minor, major; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (irq < 0) return irq; - } omap = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); if (!omap) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - omap->base = devm_ioremap_resource(&pdev->dev, mem); + omap->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(omap->base)) return PTR_ERR(omap->base); match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); if (match) { - u32 freq = 100000; /* default to 100000 Hz */ + u32 freq = I2C_MAX_STANDARD_MODE_FREQ; pdata = match->data; omap->flags = pdata->flags; @@ -1367,9 +1404,9 @@ pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT); pm_runtime_use_autosuspend(omap->dev); - r = pm_runtime_get_sync(omap->dev); + r = pm_runtime_resume_and_get(omap->dev); if (r < 0) - goto err_free_mem; + goto err_disable_pm; /* * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2. @@ -1388,7 +1425,6 @@ major = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev); break; case OMAP_I2C_SCHEME_1: - /* FALLTHROUGH */ default: omap->regs = (u8 *)reg_map_ip_v2; rev = (rev << 16) | @@ -1477,8 +1513,8 @@ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); pm_runtime_dont_use_autosuspend(omap->dev); pm_runtime_put_sync(omap->dev); +err_disable_pm: pm_runtime_disable(&pdev->dev); -err_free_mem: return r; } @@ -1489,7 +1525,7 @@ int ret; i2c_del_adapter(&omap->adapter); - ret = pm_runtime_get_sync(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) return ret; -- Gitblit v1.6.2