Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: designware: Do not require clock when SSCN and FFCN are provided

The current driver uses input clock source frequency to calculate
values for [SS|FS]_[HC|LC] registers. However, when booting ACPI, we do not
currently have a good way to provide the frequency information.
Instead, we can leverage the SSCN and FFCN ACPI methods, which can be used
to directly provide these values. So, the clock information should
no longer be required during probing.

However, since clk can be invalid, additional checks must be done where
we are making use of it.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Tested-by: Loc Ho <lho@apm.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Suravee Suthikulpanit and committed by
Wolfram Sang
b33af11d fa5b0bfa

+35 -18
+15 -7
drivers/i2c/busses/i2c-designware-core.c
··· 271 271 enable ? "en" : "dis"); 272 272 } 273 273 274 + static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) 275 + { 276 + /* 277 + * Clock is not necessary if we got LCNT/HCNT values directly from 278 + * the platform code. 279 + */ 280 + if (WARN_ON_ONCE(!dev->get_clk_rate_khz)) 281 + return 0; 282 + return dev->get_clk_rate_khz(dev); 283 + } 284 + 274 285 /** 275 286 * i2c_dw_init() - initialize the designware i2c master hardware 276 287 * @dev: device private data ··· 292 281 */ 293 282 int i2c_dw_init(struct dw_i2c_dev *dev) 294 283 { 295 - u32 input_clock_khz; 296 284 u32 hcnt, lcnt; 297 285 u32 reg; 298 286 u32 sda_falling_time, scl_falling_time; ··· 304 294 return ret; 305 295 } 306 296 } 307 - 308 - input_clock_khz = dev->get_clk_rate_khz(dev); 309 297 310 298 reg = dw_readl(dev, DW_IC_COMP_TYPE); 311 299 if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) { ··· 333 325 hcnt = dev->ss_hcnt; 334 326 lcnt = dev->ss_lcnt; 335 327 } else { 336 - hcnt = i2c_dw_scl_hcnt(input_clock_khz, 328 + hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), 337 329 4000, /* tHD;STA = tHIGH = 4.0 us */ 338 330 sda_falling_time, 339 331 0, /* 0: DW default, 1: Ideal */ 340 332 0); /* No offset */ 341 - lcnt = i2c_dw_scl_lcnt(input_clock_khz, 333 + lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), 342 334 4700, /* tLOW = 4.7 us */ 343 335 scl_falling_time, 344 336 0); /* No offset */ ··· 352 344 hcnt = dev->fs_hcnt; 353 345 lcnt = dev->fs_lcnt; 354 346 } else { 355 - hcnt = i2c_dw_scl_hcnt(input_clock_khz, 347 + hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), 356 348 600, /* tHD;STA = tHIGH = 0.6 us */ 357 349 sda_falling_time, 358 350 0, /* 0: DW default, 1: Ideal */ 359 351 0); /* No offset */ 360 - lcnt = i2c_dw_scl_lcnt(input_clock_khz, 352 + lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), 361 353 1300, /* tLOW = 1.3 us */ 362 354 scl_falling_time, 363 355 0); /* No offset */
+20 -11
drivers/i2c/busses/i2c-designware-platdrv.c
··· 128 128 } 129 129 #endif 130 130 131 + static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) 132 + { 133 + if (IS_ERR(i_dev->clk)) 134 + return PTR_ERR(i_dev->clk); 135 + 136 + if (prepare) 137 + return clk_prepare_enable(i_dev->clk); 138 + 139 + clk_disable_unprepare(i_dev->clk); 140 + return 0; 141 + } 142 + 131 143 static int dw_i2c_plat_probe(struct platform_device *pdev) 132 144 { 133 145 struct dw_i2c_dev *dev; ··· 217 205 DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; 218 206 219 207 dev->clk = devm_clk_get(&pdev->dev, NULL); 220 - dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; 221 - if (IS_ERR(dev->clk)) 222 - return PTR_ERR(dev->clk); 223 - clk_prepare_enable(dev->clk); 208 + if (!i2c_dw_plat_prepare_clk(dev, true)) { 209 + dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; 224 210 225 - if (!dev->sda_hold_time && ht) { 226 - u32 ic_clk = dev->get_clk_rate_khz(dev); 227 - 228 - dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000, 229 - 1000000); 211 + if (!dev->sda_hold_time && ht) 212 + dev->sda_hold_time = div_u64( 213 + (u64)dev->get_clk_rate_khz(dev) * ht + 500000, 214 + 1000000); 230 215 } 231 216 232 217 if (!dev->tx_fifo_depth) { ··· 306 297 struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); 307 298 308 299 i2c_dw_disable(i_dev); 309 - clk_disable_unprepare(i_dev->clk); 300 + i2c_dw_plat_prepare_clk(i_dev, false); 310 301 311 302 return 0; 312 303 } ··· 316 307 struct platform_device *pdev = to_platform_device(dev); 317 308 struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); 318 309 319 - clk_prepare_enable(i_dev->clk); 310 + i2c_dw_plat_prepare_clk(i_dev, true); 320 311 321 312 if (!i_dev->pm_runtime_disabled) 322 313 i2c_dw_init(i_dev);