Skip to content

Commit fcb82a9

Browse files
fancerwsakernel
authored andcommitted
i2c: designware: Add Baikal-T1 System I2C support
Baikal-T1 System Controller is equipped with a dedicated I2C Controller which functionality is based on the DW APB I2C IP-core, the only difference in a way it' registers are accessed. There are three access register provided in the System Controller registers map, which indirectly address the normal DW APB I2C registers space. So in order to have the Baikal-T1 System I2C Controller supported by the common DW APB I2C driver we created a dedicated Dw I2C controller model quirk, which retrieves the syscon regmap from the parental dt node and creates a new regmap based on it. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Wolfram Sang <wsa@kernel.org>
1 parent b7c3d07 commit fcb82a9

3 files changed

Lines changed: 81 additions & 3 deletions

File tree

drivers/i2c/busses/Kconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,9 @@ config I2C_DESIGNWARE_SLAVE
541541

542542
config I2C_DESIGNWARE_PLATFORM
543543
tristate "Synopsys DesignWare Platform"
544-
select I2C_DESIGNWARE_CORE
545544
depends on (ACPI && COMMON_CLK) || !ACPI
545+
select I2C_DESIGNWARE_CORE
546+
select MFD_SYSCON if MIPS_BAIKAL_T1
546547
help
547548
If you say yes to this option, support will be included for the
548549
Synopsys DesignWare I2C adapter.

drivers/i2c/busses/i2c-designware-core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ struct reset_control;
183183
* struct dw_i2c_dev - private i2c-designware data
184184
* @dev: driver model device node
185185
* @map: IO registers map
186+
* @sysmap: System controller registers map
186187
* @base: IO registers pointer
187188
* @ext: Extended IO registers pointer
188189
* @cmd_complete: tx completion indicator
@@ -235,6 +236,7 @@ struct reset_control;
235236
struct dw_i2c_dev {
236237
struct device *dev;
237238
struct regmap *map;
239+
struct regmap *sysmap;
238240
void __iomem *base;
239241
void __iomem *ext;
240242
struct completion cmd_complete;
@@ -290,6 +292,7 @@ struct dw_i2c_dev {
290292
#define ACCESS_NO_IRQ_SUSPEND 0x00000002
291293

292294
#define MODEL_MSCC_OCELOT 0x00000100
295+
#define MODEL_BAIKAL_BT1 0x00000200
293296
#define MODEL_MASK 0x00000f00
294297

295298
int i2c_dw_init_regmap(struct dw_i2c_dev *dev);

drivers/i2c/busses/i2c-designware-platdrv.c

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
#include <linux/interrupt.h>
1919
#include <linux/io.h>
2020
#include <linux/kernel.h>
21+
#include <linux/mfd/syscon.h>
2122
#include <linux/module.h>
2223
#include <linux/of.h>
2324
#include <linux/platform_data/i2c-designware.h>
2425
#include <linux/platform_device.h>
2526
#include <linux/pm.h>
2627
#include <linux/pm_runtime.h>
2728
#include <linux/property.h>
29+
#include <linux/regmap.h>
2830
#include <linux/reset.h>
2931
#include <linux/sched.h>
3032
#include <linux/slab.h>
@@ -58,6 +60,63 @@ MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
5860
#endif
5961

6062
#ifdef CONFIG_OF
63+
#define BT1_I2C_CTL 0x100
64+
#define BT1_I2C_CTL_ADDR_MASK GENMASK(7, 0)
65+
#define BT1_I2C_CTL_WR BIT(8)
66+
#define BT1_I2C_CTL_GO BIT(31)
67+
#define BT1_I2C_DI 0x104
68+
#define BT1_I2C_DO 0x108
69+
70+
static int bt1_i2c_read(void *context, unsigned int reg, unsigned int *val)
71+
{
72+
struct dw_i2c_dev *dev = context;
73+
int ret;
74+
75+
/*
76+
* Note these methods shouldn't ever fail because the system controller
77+
* registers are memory mapped. We check the return value just in case.
78+
*/
79+
ret = regmap_write(dev->sysmap, BT1_I2C_CTL,
80+
BT1_I2C_CTL_GO | (reg & BT1_I2C_CTL_ADDR_MASK));
81+
if (ret)
82+
return ret;
83+
84+
return regmap_read(dev->sysmap, BT1_I2C_DO, val);
85+
}
86+
87+
static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val)
88+
{
89+
struct dw_i2c_dev *dev = context;
90+
int ret;
91+
92+
ret = regmap_write(dev->sysmap, BT1_I2C_DI, val);
93+
if (ret)
94+
return ret;
95+
96+
return regmap_write(dev->sysmap, BT1_I2C_CTL,
97+
BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK));
98+
}
99+
100+
static struct regmap_config bt1_i2c_cfg = {
101+
.reg_bits = 32,
102+
.val_bits = 32,
103+
.reg_stride = 4,
104+
.fast_io = true,
105+
.reg_read = bt1_i2c_read,
106+
.reg_write = bt1_i2c_write,
107+
.max_register = DW_IC_COMP_TYPE,
108+
};
109+
110+
static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
111+
{
112+
dev->sysmap = syscon_node_to_regmap(dev->dev->of_node->parent);
113+
if (IS_ERR(dev->sysmap))
114+
return PTR_ERR(dev->sysmap);
115+
116+
dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg);
117+
return PTR_ERR_OR_ZERO(dev->map);
118+
}
119+
61120
#define MSCC_ICPU_CFG_TWI_DELAY 0x0
62121
#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
63122
#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
@@ -90,10 +149,16 @@ static int dw_i2c_of_configure(struct platform_device *pdev)
90149
static const struct of_device_id dw_i2c_of_match[] = {
91150
{ .compatible = "snps,designware-i2c", },
92151
{ .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
152+
{ .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 },
93153
{},
94154
};
95155
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
96156
#else
157+
static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
158+
{
159+
return -ENODEV;
160+
}
161+
97162
static inline int dw_i2c_of_configure(struct platform_device *pdev)
98163
{
99164
return -ENODEV;
@@ -111,10 +176,19 @@ static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
111176
static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)
112177
{
113178
struct platform_device *pdev = to_platform_device(dev->dev);
179+
int ret;
114180

115-
dev->base = devm_platform_ioremap_resource(pdev, 0);
181+
switch (dev->flags & MODEL_MASK) {
182+
case MODEL_BAIKAL_BT1:
183+
ret = bt1_i2c_request_regs(dev);
184+
break;
185+
default:
186+
dev->base = devm_platform_ioremap_resource(pdev, 0);
187+
ret = PTR_ERR_OR_ZERO(dev->base);
188+
break;
189+
}
116190

117-
return PTR_ERR_OR_ZERO(dev->base);
191+
return ret;
118192
}
119193

120194
static int dw_i2c_plat_probe(struct platform_device *pdev)

0 commit comments

Comments
 (0)