-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Slave mode driver is based on the concept of i2c-designware driver. Signed-off-by: Juergen Fitschen <me@jue.yt> [ludovic.desroches@microchip.com: rework Kconfig and replace IS_ENABLED by defined] Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
- Loading branch information
Juergen Fitschen
authored and
Wolfram Sang
committed
Mar 24, 2019
1 parent
ad7d142
commit 9d3ca54
Showing
5 changed files
with
198 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* i2c slave support for Atmel's AT91 Two-Wire Interface (TWI) | ||
* | ||
* Copyright (C) 2017 Juergen Fitschen <me@jue.yt> | ||
*/ | ||
|
||
#include <linux/err.h> | ||
#include <linux/i2c.h> | ||
#include <linux/interrupt.h> | ||
#include <linux/pm_runtime.h> | ||
|
||
#include "i2c-at91.h" | ||
|
||
static irqreturn_t atmel_twi_interrupt_slave(int irq, void *dev_id) | ||
{ | ||
struct at91_twi_dev *dev = dev_id; | ||
const unsigned status = at91_twi_read(dev, AT91_TWI_SR); | ||
const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR); | ||
u8 value; | ||
|
||
if (!irqstatus) | ||
return IRQ_NONE; | ||
|
||
/* slave address has been detected on I2C bus */ | ||
if (irqstatus & AT91_TWI_SVACC) { | ||
if (status & AT91_TWI_SVREAD) { | ||
i2c_slave_event(dev->slave, | ||
I2C_SLAVE_READ_REQUESTED, &value); | ||
writeb_relaxed(value, dev->base + AT91_TWI_THR); | ||
at91_twi_write(dev, AT91_TWI_IER, | ||
AT91_TWI_TXRDY | AT91_TWI_EOSACC); | ||
} else { | ||
i2c_slave_event(dev->slave, | ||
I2C_SLAVE_WRITE_REQUESTED, &value); | ||
at91_twi_write(dev, AT91_TWI_IER, | ||
AT91_TWI_RXRDY | AT91_TWI_EOSACC); | ||
} | ||
at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_SVACC); | ||
} | ||
|
||
/* byte transmitted to remote master */ | ||
if (irqstatus & AT91_TWI_TXRDY) { | ||
i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, &value); | ||
writeb_relaxed(value, dev->base + AT91_TWI_THR); | ||
} | ||
|
||
/* byte received from remote master */ | ||
if (irqstatus & AT91_TWI_RXRDY) { | ||
value = readb_relaxed(dev->base + AT91_TWI_RHR); | ||
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED, &value); | ||
} | ||
|
||
/* master sent stop */ | ||
if (irqstatus & AT91_TWI_EOSACC) { | ||
at91_twi_write(dev, AT91_TWI_IDR, | ||
AT91_TWI_TXRDY | AT91_TWI_RXRDY | AT91_TWI_EOSACC); | ||
at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_SVACC); | ||
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &value); | ||
} | ||
|
||
return IRQ_HANDLED; | ||
} | ||
|
||
static int at91_reg_slave(struct i2c_client *slave) | ||
{ | ||
struct at91_twi_dev *dev = i2c_get_adapdata(slave->adapter); | ||
|
||
if (dev->slave) | ||
return -EBUSY; | ||
|
||
if (slave->flags & I2C_CLIENT_TEN) | ||
return -EAFNOSUPPORT; | ||
|
||
/* Make sure twi_clk doesn't get turned off! */ | ||
pm_runtime_get_sync(dev->dev); | ||
|
||
dev->slave = slave; | ||
dev->smr = AT91_TWI_SMR_SADR(slave->addr); | ||
|
||
at91_init_twi_bus(dev); | ||
at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_SVACC); | ||
|
||
dev_info(dev->dev, "entered slave mode (ADR=%d)\n", slave->addr); | ||
|
||
return 0; | ||
} | ||
|
||
static int at91_unreg_slave(struct i2c_client *slave) | ||
{ | ||
struct at91_twi_dev *dev = i2c_get_adapdata(slave->adapter); | ||
|
||
WARN_ON(!dev->slave); | ||
|
||
dev_info(dev->dev, "leaving slave mode\n"); | ||
|
||
dev->slave = NULL; | ||
dev->smr = 0; | ||
|
||
at91_init_twi_bus(dev); | ||
|
||
pm_runtime_put(dev->dev); | ||
|
||
return 0; | ||
} | ||
|
||
static u32 at91_twi_func(struct i2c_adapter *adapter) | ||
{ | ||
return I2C_FUNC_SLAVE | I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | ||
| I2C_FUNC_SMBUS_READ_BLOCK_DATA; | ||
} | ||
|
||
static const struct i2c_algorithm at91_twi_algorithm_slave = { | ||
.reg_slave = at91_reg_slave, | ||
.unreg_slave = at91_unreg_slave, | ||
.functionality = at91_twi_func, | ||
}; | ||
|
||
int at91_twi_probe_slave(struct platform_device *pdev, | ||
u32 phy_addr, struct at91_twi_dev *dev) | ||
{ | ||
int rc; | ||
|
||
rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt_slave, | ||
0, dev_name(dev->dev), dev); | ||
if (rc) { | ||
dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc); | ||
return rc; | ||
} | ||
|
||
dev->adapter.algo = &at91_twi_algorithm_slave; | ||
|
||
return 0; | ||
} | ||
|
||
void at91_init_twi_bus_slave(struct at91_twi_dev *dev) | ||
{ | ||
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSDIS); | ||
if (dev->slave_detected && dev->smr) { | ||
at91_twi_write(dev, AT91_TWI_SMR, dev->smr); | ||
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVEN); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters