|
@@ -164,6 +164,7 @@ struct hw_bank {
|
|
|
* @id_event: indicates there is an id event, and handled at ci_otg_work
|
|
|
* @b_sess_valid_event: indicates there is a vbus event, and handled
|
|
|
* at ci_otg_work
|
|
|
+ * @imx28_write_fix: Freescale imx28 needs swp instruction for writing
|
|
|
*/
|
|
|
struct ci_hdrc {
|
|
|
struct device *dev;
|
|
@@ -202,6 +203,7 @@ struct ci_hdrc {
|
|
|
struct dentry *debugfs;
|
|
|
bool id_event;
|
|
|
bool b_sess_valid_event;
|
|
|
+ bool imx28_write_fix;
|
|
|
};
|
|
|
|
|
|
static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)
|
|
@@ -250,6 +252,26 @@ static inline u32 hw_read(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask)
|
|
|
return ioread32(ci->hw_bank.regmap[reg]) & mask;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_SOC_IMX28
|
|
|
+static inline void imx28_ci_writel(u32 val, volatile void __iomem *addr)
|
|
|
+{
|
|
|
+ __asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr));
|
|
|
+}
|
|
|
+#else
|
|
|
+static inline void imx28_ci_writel(u32 val, volatile void __iomem *addr)
|
|
|
+{
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+static inline void __hw_write(struct ci_hdrc *ci, u32 val,
|
|
|
+ void __iomem *addr)
|
|
|
+{
|
|
|
+ if (ci->imx28_write_fix)
|
|
|
+ imx28_ci_writel(val, addr);
|
|
|
+ else
|
|
|
+ iowrite32(val, addr);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* hw_write: writes to a hw register
|
|
|
* @reg: register index
|
|
@@ -263,7 +285,7 @@ static inline void hw_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
|
|
|
data = (ioread32(ci->hw_bank.regmap[reg]) & ~mask)
|
|
|
| (data & mask);
|
|
|
|
|
|
- iowrite32(data, ci->hw_bank.regmap[reg]);
|
|
|
+ __hw_write(ci, data, ci->hw_bank.regmap[reg]);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -278,7 +300,7 @@ static inline u32 hw_test_and_clear(struct ci_hdrc *ci, enum ci_hw_regs reg,
|
|
|
{
|
|
|
u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask;
|
|
|
|
|
|
- iowrite32(val, ci->hw_bank.regmap[reg]);
|
|
|
+ __hw_write(ci, val, ci->hw_bank.regmap[reg]);
|
|
|
return val;
|
|
|
}
|
|
|
|