| .. | .. |
|---|
| 9 | 9 | * Copyright (C) 2009 Provigent Ltd. |
|---|
| 10 | 10 | */ |
|---|
| 11 | 11 | |
|---|
| 12 | +#include <linux/bits.h> |
|---|
| 13 | +#include <linux/compiler_types.h> |
|---|
| 14 | +#include <linux/completion.h> |
|---|
| 15 | +#include <linux/dev_printk.h> |
|---|
| 16 | +#include <linux/errno.h> |
|---|
| 12 | 17 | #include <linux/i2c.h> |
|---|
| 13 | | -#include <linux/pm_qos.h> |
|---|
| 18 | +#include <linux/regmap.h> |
|---|
| 19 | +#include <linux/types.h> |
|---|
| 14 | 20 | |
|---|
| 15 | 21 | #define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ |
|---|
| 16 | 22 | I2C_FUNC_SMBUS_BYTE | \ |
|---|
| .. | .. |
|---|
| 121 | 127 | #define STATUS_WRITE_IN_PROGRESS 0x1 |
|---|
| 122 | 128 | #define STATUS_READ_IN_PROGRESS 0x2 |
|---|
| 123 | 129 | |
|---|
| 124 | | -#define TIMEOUT 20 /* ms */ |
|---|
| 125 | | - |
|---|
| 126 | 130 | /* |
|---|
| 127 | 131 | * operation modes |
|---|
| 128 | 132 | */ |
|---|
| .. | .. |
|---|
| 171 | 175 | DW_IC_TX_ABRT_TXDATA_NOACK | \ |
|---|
| 172 | 176 | DW_IC_TX_ABRT_GCALL_NOACK) |
|---|
| 173 | 177 | |
|---|
| 178 | +struct clk; |
|---|
| 179 | +struct device; |
|---|
| 180 | +struct reset_control; |
|---|
| 174 | 181 | |
|---|
| 175 | 182 | /** |
|---|
| 176 | 183 | * struct dw_i2c_dev - private i2c-designware data |
|---|
| 177 | 184 | * @dev: driver model device node |
|---|
| 185 | + * @map: IO registers map |
|---|
| 186 | + * @sysmap: System controller registers map |
|---|
| 178 | 187 | * @base: IO registers pointer |
|---|
| 188 | + * @ext: Extended IO registers pointer |
|---|
| 179 | 189 | * @cmd_complete: tx completion indicator |
|---|
| 180 | 190 | * @clk: input reference clock |
|---|
| 191 | + * @pclk: clock required to access the registers |
|---|
| 181 | 192 | * @slave: represent an I2C slave device |
|---|
| 182 | 193 | * @cmd_err: run time hadware error code |
|---|
| 183 | 194 | * @msgs: points to an array of messages currently being transferred |
|---|
| .. | .. |
|---|
| 209 | 220 | * @fp_lcnt: fast plus LCNT value |
|---|
| 210 | 221 | * @hs_hcnt: high speed HCNT value |
|---|
| 211 | 222 | * @hs_lcnt: high speed LCNT value |
|---|
| 212 | | - * @pm_qos: pm_qos_request used while holding a hardware lock on the bus |
|---|
| 213 | 223 | * @acquire_lock: function to acquire a hardware lock on the bus |
|---|
| 214 | 224 | * @release_lock: function to release a hardware lock on the bus |
|---|
| 215 | | - * @pm_disabled: true if power-management should be disabled for this i2c-bus |
|---|
| 225 | + * @shared_with_punit: true if this bus is shared with the SoCs PUNIT |
|---|
| 216 | 226 | * @disable: function to disable the controller |
|---|
| 217 | 227 | * @disable_int: function to disable all interrupts |
|---|
| 218 | 228 | * @init: function to initialize the I2C hardware |
|---|
| 219 | 229 | * @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE |
|---|
| 230 | + * @suspended: set to true if the controller is suspended |
|---|
| 220 | 231 | * |
|---|
| 221 | 232 | * HCNT and LCNT parameters can be used if the platform knows more accurate |
|---|
| 222 | 233 | * values than the one computed based only on the input clock frequency. |
|---|
| .. | .. |
|---|
| 224 | 235 | */ |
|---|
| 225 | 236 | struct dw_i2c_dev { |
|---|
| 226 | 237 | struct device *dev; |
|---|
| 238 | + struct regmap *map; |
|---|
| 239 | + struct regmap *sysmap; |
|---|
| 227 | 240 | void __iomem *base; |
|---|
| 241 | + void __iomem *ext; |
|---|
| 228 | 242 | struct completion cmd_complete; |
|---|
| 229 | 243 | struct clk *clk; |
|---|
| 244 | + struct clk *pclk; |
|---|
| 230 | 245 | struct reset_control *rst; |
|---|
| 231 | 246 | struct i2c_client *slave; |
|---|
| 232 | 247 | u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev); |
|---|
| 233 | | - struct dw_pci_controller *controller; |
|---|
| 234 | 248 | int cmd_err; |
|---|
| 235 | 249 | struct i2c_msg *msgs; |
|---|
| 236 | 250 | int msgs_num; |
|---|
| .. | .. |
|---|
| 262 | 276 | u16 fp_lcnt; |
|---|
| 263 | 277 | u16 hs_hcnt; |
|---|
| 264 | 278 | u16 hs_lcnt; |
|---|
| 265 | | - struct pm_qos_request pm_qos; |
|---|
| 266 | | - int (*acquire_lock)(struct dw_i2c_dev *dev); |
|---|
| 267 | | - void (*release_lock)(struct dw_i2c_dev *dev); |
|---|
| 268 | | - bool pm_disabled; |
|---|
| 279 | + int (*acquire_lock)(void); |
|---|
| 280 | + void (*release_lock)(void); |
|---|
| 281 | + bool shared_with_punit; |
|---|
| 269 | 282 | void (*disable)(struct dw_i2c_dev *dev); |
|---|
| 270 | 283 | void (*disable_int)(struct dw_i2c_dev *dev); |
|---|
| 271 | 284 | int (*init)(struct dw_i2c_dev *dev); |
|---|
| 285 | + int (*set_sda_hold_time)(struct dw_i2c_dev *dev); |
|---|
| 272 | 286 | int mode; |
|---|
| 273 | 287 | struct i2c_bus_recovery_info rinfo; |
|---|
| 288 | + bool suspended; |
|---|
| 274 | 289 | }; |
|---|
| 275 | 290 | |
|---|
| 276 | | -#define ACCESS_SWAP 0x00000001 |
|---|
| 277 | | -#define ACCESS_16BIT 0x00000002 |
|---|
| 278 | | -#define ACCESS_INTR_MASK 0x00000004 |
|---|
| 291 | +#define ACCESS_INTR_MASK 0x00000001 |
|---|
| 292 | +#define ACCESS_NO_IRQ_SUSPEND 0x00000002 |
|---|
| 279 | 293 | |
|---|
| 280 | | -#define MODEL_CHERRYTRAIL 0x00000100 |
|---|
| 294 | +#define MODEL_MSCC_OCELOT 0x00000100 |
|---|
| 295 | +#define MODEL_BAIKAL_BT1 0x00000200 |
|---|
| 296 | +#define MODEL_MASK 0x00000f00 |
|---|
| 281 | 297 | |
|---|
| 282 | | -u32 dw_readl(struct dw_i2c_dev *dev, int offset); |
|---|
| 283 | | -void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); |
|---|
| 284 | | -int i2c_dw_set_reg_access(struct dw_i2c_dev *dev); |
|---|
| 298 | +int i2c_dw_init_regmap(struct dw_i2c_dev *dev); |
|---|
| 285 | 299 | u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset); |
|---|
| 286 | 300 | u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); |
|---|
| 287 | 301 | int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev); |
|---|
| .. | .. |
|---|
| 291 | 305 | void i2c_dw_release_lock(struct dw_i2c_dev *dev); |
|---|
| 292 | 306 | int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); |
|---|
| 293 | 307 | int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev); |
|---|
| 308 | +int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev); |
|---|
| 294 | 309 | u32 i2c_dw_func(struct i2c_adapter *adap); |
|---|
| 295 | 310 | void i2c_dw_disable(struct dw_i2c_dev *dev); |
|---|
| 296 | 311 | void i2c_dw_disable_int(struct dw_i2c_dev *dev); |
|---|
| 297 | 312 | |
|---|
| 298 | 313 | static inline void __i2c_dw_enable(struct dw_i2c_dev *dev) |
|---|
| 299 | 314 | { |
|---|
| 300 | | - dw_writel(dev, 1, DW_IC_ENABLE); |
|---|
| 315 | + regmap_write(dev->map, DW_IC_ENABLE, 1); |
|---|
| 301 | 316 | } |
|---|
| 302 | 317 | |
|---|
| 303 | 318 | static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) |
|---|
| 304 | 319 | { |
|---|
| 305 | | - dw_writel(dev, 0, DW_IC_ENABLE); |
|---|
| 320 | + regmap_write(dev->map, DW_IC_ENABLE, 0); |
|---|
| 306 | 321 | } |
|---|
| 307 | 322 | |
|---|
| 308 | 323 | void __i2c_dw_disable(struct dw_i2c_dev *dev); |
|---|
| 309 | 324 | |
|---|
| 310 | | -extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); |
|---|
| 311 | | -extern int i2c_dw_probe(struct dw_i2c_dev *dev); |
|---|
| 325 | +extern void i2c_dw_configure_master(struct dw_i2c_dev *dev); |
|---|
| 326 | +extern int i2c_dw_probe_master(struct dw_i2c_dev *dev); |
|---|
| 327 | + |
|---|
| 312 | 328 | #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_SLAVE) |
|---|
| 329 | +extern void i2c_dw_configure_slave(struct dw_i2c_dev *dev); |
|---|
| 313 | 330 | extern int i2c_dw_probe_slave(struct dw_i2c_dev *dev); |
|---|
| 314 | 331 | #else |
|---|
| 332 | +static inline void i2c_dw_configure_slave(struct dw_i2c_dev *dev) { } |
|---|
| 315 | 333 | static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; } |
|---|
| 316 | 334 | #endif |
|---|
| 317 | 335 | |
|---|
| 336 | +static inline int i2c_dw_probe(struct dw_i2c_dev *dev) |
|---|
| 337 | +{ |
|---|
| 338 | + switch (dev->mode) { |
|---|
| 339 | + case DW_IC_SLAVE: |
|---|
| 340 | + return i2c_dw_probe_slave(dev); |
|---|
| 341 | + case DW_IC_MASTER: |
|---|
| 342 | + return i2c_dw_probe_master(dev); |
|---|
| 343 | + default: |
|---|
| 344 | + dev_err(dev->dev, "Wrong operation mode: %d\n", dev->mode); |
|---|
| 345 | + return -EINVAL; |
|---|
| 346 | + } |
|---|
| 347 | +} |
|---|
| 348 | + |
|---|
| 349 | +static inline void i2c_dw_configure(struct dw_i2c_dev *dev) |
|---|
| 350 | +{ |
|---|
| 351 | + if (i2c_detect_slave_mode(dev->dev)) |
|---|
| 352 | + i2c_dw_configure_slave(dev); |
|---|
| 353 | + else |
|---|
| 354 | + i2c_dw_configure_master(dev); |
|---|
| 355 | +} |
|---|
| 356 | + |
|---|
| 318 | 357 | #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) |
|---|
| 319 | 358 | extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev); |
|---|
| 320 | | -extern void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev); |
|---|
| 321 | 359 | #else |
|---|
| 322 | 360 | static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; } |
|---|
| 323 | | -static inline void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) {} |
|---|
| 361 | +#endif |
|---|
| 362 | + |
|---|
| 363 | +int i2c_dw_validate_speed(struct dw_i2c_dev *dev); |
|---|
| 364 | +void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev); |
|---|
| 365 | + |
|---|
| 366 | +#if IS_ENABLED(CONFIG_ACPI) |
|---|
| 367 | +int i2c_dw_acpi_configure(struct device *device); |
|---|
| 368 | +#else |
|---|
| 369 | +static inline int i2c_dw_acpi_configure(struct device *device) { return -ENODEV; } |
|---|
| 324 | 370 | #endif |
|---|