mirror of https://gitee.com/openkylin/linux.git
i2c: at91: add support for the HOLD field
The hold field allows to configure the data hold time which can be set with the help of the generic binding 'i2c-sda-hold-time-ns'. This feature has been introduced with SAMA5D4 SoC family. Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
d7a4c76336
commit
cc018e3612
|
@ -3,7 +3,7 @@ I2C for Atmel platforms
|
||||||
Required properties :
|
Required properties :
|
||||||
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
|
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
|
||||||
"atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
|
"atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
|
||||||
"atmel,at91sam9x5-i2c" or "atmel,sama5d2-i2c"
|
"atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c" or "atmel,sama5d2-i2c"
|
||||||
- reg: physical base address of the controller and length of memory mapped
|
- reg: physical base address of the controller and length of memory mapped
|
||||||
region.
|
region.
|
||||||
- interrupts: interrupt number to the cpu.
|
- interrupts: interrupt number to the cpu.
|
||||||
|
@ -17,6 +17,8 @@ Optional properties:
|
||||||
- dma-names: should contain "tx" and "rx".
|
- dma-names: should contain "tx" and "rx".
|
||||||
- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
|
- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
|
||||||
capable I2C controllers.
|
capable I2C controllers.
|
||||||
|
- i2c-sda-hold-time-ns: TWD hold time, only available for "atmel,sama5d4-i2c"
|
||||||
|
and "atmel,sama5d2-i2c".
|
||||||
- Child nodes conforming to i2c bus binding
|
- Child nodes conforming to i2c bus binding
|
||||||
|
|
||||||
Examples :
|
Examples :
|
||||||
|
@ -52,6 +54,7 @@ i2c0: i2c@f8034600 {
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
clocks = <&flx0>;
|
clocks = <&flx0>;
|
||||||
atmel,fifo-size = <16>;
|
atmel,fifo-size = <16>;
|
||||||
|
i2c-sda-hold-time-ns = <336>;
|
||||||
|
|
||||||
wm8731: wm8731@1a {
|
wm8731: wm8731@1a {
|
||||||
compatible = "wm8731";
|
compatible = "wm8731";
|
||||||
|
|
|
@ -64,6 +64,8 @@
|
||||||
#define AT91_TWI_IADR 0x000c /* Internal Address Register */
|
#define AT91_TWI_IADR 0x000c /* Internal Address Register */
|
||||||
|
|
||||||
#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
|
#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
|
||||||
|
#define AT91_TWI_CWGR_HOLD_MAX 0x1f
|
||||||
|
#define AT91_TWI_CWGR_HOLD(x) (((x) & AT91_TWI_CWGR_HOLD_MAX) << 24)
|
||||||
|
|
||||||
#define AT91_TWI_SR 0x0020 /* Status Register */
|
#define AT91_TWI_SR 0x0020 /* Status Register */
|
||||||
#define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */
|
#define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */
|
||||||
|
@ -110,6 +112,7 @@ struct at91_twi_pdata {
|
||||||
unsigned clk_offset;
|
unsigned clk_offset;
|
||||||
bool has_unre_flag;
|
bool has_unre_flag;
|
||||||
bool has_alt_cmd;
|
bool has_alt_cmd;
|
||||||
|
bool has_hold_field;
|
||||||
struct at_dma_slave dma_slave;
|
struct at_dma_slave dma_slave;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -187,10 +190,11 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev)
|
||||||
*/
|
*/
|
||||||
static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
|
static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
|
||||||
{
|
{
|
||||||
int ckdiv, cdiv, div;
|
int ckdiv, cdiv, div, hold = 0;
|
||||||
struct at91_twi_pdata *pdata = dev->pdata;
|
struct at91_twi_pdata *pdata = dev->pdata;
|
||||||
int offset = pdata->clk_offset;
|
int offset = pdata->clk_offset;
|
||||||
int max_ckdiv = pdata->clk_max_div;
|
int max_ckdiv = pdata->clk_max_div;
|
||||||
|
u32 twd_hold_time_ns = 0;
|
||||||
|
|
||||||
div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
|
div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
|
||||||
2 * twi_clk) - offset);
|
2 * twi_clk) - offset);
|
||||||
|
@ -204,8 +208,33 @@ static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
|
||||||
cdiv = 255;
|
cdiv = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
|
if (pdata->has_hold_field) {
|
||||||
dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
|
of_property_read_u32(dev->dev->of_node, "i2c-sda-hold-time-ns",
|
||||||
|
&twd_hold_time_ns);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hold time = HOLD + 3 x T_peripheral_clock
|
||||||
|
* Use clk rate in kHz to prevent overflows when computing
|
||||||
|
* hold.
|
||||||
|
*/
|
||||||
|
hold = DIV_ROUND_UP(twd_hold_time_ns
|
||||||
|
* (clk_get_rate(dev->clk) / 1000), 1000000);
|
||||||
|
hold -= 3;
|
||||||
|
if (hold < 0)
|
||||||
|
hold = 0;
|
||||||
|
if (hold > AT91_TWI_CWGR_HOLD_MAX) {
|
||||||
|
dev_warn(dev->dev,
|
||||||
|
"HOLD field set to its maximum value (%d instead of %d)\n",
|
||||||
|
AT91_TWI_CWGR_HOLD_MAX, hold);
|
||||||
|
hold = AT91_TWI_CWGR_HOLD_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv
|
||||||
|
| AT91_TWI_CWGR_HOLD(hold);
|
||||||
|
|
||||||
|
dev_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns)\n",
|
||||||
|
cdiv, ckdiv, hold, twd_hold_time_ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
|
static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
|
||||||
|
@ -797,6 +826,7 @@ static struct at91_twi_pdata at91rm9200_config = {
|
||||||
.clk_offset = 3,
|
.clk_offset = 3,
|
||||||
.has_unre_flag = true,
|
.has_unre_flag = true,
|
||||||
.has_alt_cmd = false,
|
.has_alt_cmd = false,
|
||||||
|
.has_hold_field = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct at91_twi_pdata at91sam9261_config = {
|
static struct at91_twi_pdata at91sam9261_config = {
|
||||||
|
@ -804,6 +834,7 @@ static struct at91_twi_pdata at91sam9261_config = {
|
||||||
.clk_offset = 4,
|
.clk_offset = 4,
|
||||||
.has_unre_flag = false,
|
.has_unre_flag = false,
|
||||||
.has_alt_cmd = false,
|
.has_alt_cmd = false,
|
||||||
|
.has_hold_field = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct at91_twi_pdata at91sam9260_config = {
|
static struct at91_twi_pdata at91sam9260_config = {
|
||||||
|
@ -811,6 +842,7 @@ static struct at91_twi_pdata at91sam9260_config = {
|
||||||
.clk_offset = 4,
|
.clk_offset = 4,
|
||||||
.has_unre_flag = false,
|
.has_unre_flag = false,
|
||||||
.has_alt_cmd = false,
|
.has_alt_cmd = false,
|
||||||
|
.has_hold_field = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct at91_twi_pdata at91sam9g20_config = {
|
static struct at91_twi_pdata at91sam9g20_config = {
|
||||||
|
@ -818,6 +850,7 @@ static struct at91_twi_pdata at91sam9g20_config = {
|
||||||
.clk_offset = 4,
|
.clk_offset = 4,
|
||||||
.has_unre_flag = false,
|
.has_unre_flag = false,
|
||||||
.has_alt_cmd = false,
|
.has_alt_cmd = false,
|
||||||
|
.has_hold_field = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct at91_twi_pdata at91sam9g10_config = {
|
static struct at91_twi_pdata at91sam9g10_config = {
|
||||||
|
@ -825,6 +858,7 @@ static struct at91_twi_pdata at91sam9g10_config = {
|
||||||
.clk_offset = 4,
|
.clk_offset = 4,
|
||||||
.has_unre_flag = false,
|
.has_unre_flag = false,
|
||||||
.has_alt_cmd = false,
|
.has_alt_cmd = false,
|
||||||
|
.has_hold_field = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct platform_device_id at91_twi_devtypes[] = {
|
static const struct platform_device_id at91_twi_devtypes[] = {
|
||||||
|
@ -854,6 +888,15 @@ static struct at91_twi_pdata at91sam9x5_config = {
|
||||||
.clk_offset = 4,
|
.clk_offset = 4,
|
||||||
.has_unre_flag = false,
|
.has_unre_flag = false,
|
||||||
.has_alt_cmd = false,
|
.has_alt_cmd = false,
|
||||||
|
.has_hold_field = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct at91_twi_pdata sama5d4_config = {
|
||||||
|
.clk_max_div = 7,
|
||||||
|
.clk_offset = 4,
|
||||||
|
.has_unre_flag = false,
|
||||||
|
.has_alt_cmd = false,
|
||||||
|
.has_hold_field = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct at91_twi_pdata sama5d2_config = {
|
static struct at91_twi_pdata sama5d2_config = {
|
||||||
|
@ -861,6 +904,7 @@ static struct at91_twi_pdata sama5d2_config = {
|
||||||
.clk_offset = 4,
|
.clk_offset = 4,
|
||||||
.has_unre_flag = true,
|
.has_unre_flag = true,
|
||||||
.has_alt_cmd = true,
|
.has_alt_cmd = true,
|
||||||
|
.has_hold_field = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id atmel_twi_dt_ids[] = {
|
static const struct of_device_id atmel_twi_dt_ids[] = {
|
||||||
|
@ -882,6 +926,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = {
|
||||||
}, {
|
}, {
|
||||||
.compatible = "atmel,at91sam9x5-i2c",
|
.compatible = "atmel,at91sam9x5-i2c",
|
||||||
.data = &at91sam9x5_config,
|
.data = &at91sam9x5_config,
|
||||||
|
}, {
|
||||||
|
.compatible = "atmel,sama5d4-i2c",
|
||||||
|
.data = &sama5d4_config,
|
||||||
}, {
|
}, {
|
||||||
.compatible = "atmel,sama5d2-i2c",
|
.compatible = "atmel,sama5d2-i2c",
|
||||||
.data = &sama5d2_config,
|
.data = &sama5d2_config,
|
||||||
|
|
Loading…
Reference in New Issue