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

extcon: extcon-axp288: Use P-Unit semaphore lock for register accesses

use low level P-Unit semaphore lock for axp288 register
accesses directly and for more than one access a time,
to reduce the number of times this semaphore is locked
and released which is an expensive operation.

i2c-bus to the XPower is shared between the kernel and the
SoCs P-Unit. The P-Unit has a semaphore wich the kernel must
lock for axp288 register accesses. When the P-Unit semaphore
is locked CPU and GPU power states cannot change or the system
will freeze.

The P-Unit semaphore lock is already managed inside the regmap
access logic, but for each access the semaphore is locked and
released. So use directly iosf_mbi_(un)block_punit_i2c_access(),
we are safe in doing so because nested calls to the same
semaphore are turned to nops.

Suggested-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Tested-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Fabio Aiuto <fabioaiuto83@gmail.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>

authored by

Fabio Aiuto and committed by
Chanwoo Choi
968bd3f0 3177308a

+30 -3
+1 -1
drivers/extcon/Kconfig
··· 23 23 24 24 config EXTCON_AXP288 25 25 tristate "X-Power AXP288 EXTCON support" 26 - depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI 26 + depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI && IOSF_MBI 27 27 select USB_ROLE_SWITCH 28 28 help 29 29 Say Y here to enable support for USB peripheral detection
+29 -2
drivers/extcon/extcon-axp288.c
··· 24 24 25 25 #include <asm/cpu_device_id.h> 26 26 #include <asm/intel-family.h> 27 + #include <asm/iosf_mbi.h> 27 28 28 29 /* Power source status register */ 29 30 #define PS_STAT_VBUS_TRIGGER BIT(0) ··· 216 215 unsigned int cable = info->previous_cable; 217 216 bool vbus_attach = false; 218 217 218 + ret = iosf_mbi_block_punit_i2c_access(); 219 + if (ret < 0) 220 + return ret; 221 + 219 222 vbus_attach = axp288_get_vbus_attach(info); 220 223 if (!vbus_attach) 221 224 goto no_vbus; ··· 258 253 } 259 254 260 255 no_vbus: 256 + iosf_mbi_unblock_punit_i2c_access(); 257 + 261 258 extcon_set_state_sync(info->edev, info->previous_cable, false); 262 259 if (info->previous_cable == EXTCON_CHG_USB_SDP) 263 260 extcon_set_state_sync(info->edev, EXTCON_USB, false); ··· 282 275 return 0; 283 276 284 277 dev_det_ret: 278 + iosf_mbi_unblock_punit_i2c_access(); 279 + 285 280 if (ret < 0) 286 281 dev_err(info->dev, "failed to detect BC Mod\n"); 287 282 ··· 314 305 return IRQ_HANDLED; 315 306 } 316 307 317 - static void axp288_extcon_enable(struct axp288_extcon_info *info) 308 + static int axp288_extcon_enable(struct axp288_extcon_info *info) 318 309 { 310 + int ret = 0; 311 + 312 + ret = iosf_mbi_block_punit_i2c_access(); 313 + if (ret < 0) 314 + return ret; 315 + 319 316 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, 320 317 BC_GLOBAL_RUN, 0); 321 318 /* Enable the charger detection logic */ 322 319 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, 323 320 BC_GLOBAL_RUN, BC_GLOBAL_RUN); 321 + 322 + iosf_mbi_unblock_punit_i2c_access(); 323 + 324 + return ret; 324 325 } 325 326 326 327 static void axp288_put_role_sw(void *data) ··· 403 384 } 404 385 } 405 386 387 + ret = iosf_mbi_block_punit_i2c_access(); 388 + if (ret < 0) 389 + return ret; 390 + 406 391 info->vbus_attach = axp288_get_vbus_attach(info); 407 392 408 393 axp288_extcon_log_rsi(info); 394 + 395 + iosf_mbi_unblock_punit_i2c_access(); 409 396 410 397 /* Initialize extcon device */ 411 398 info->edev = devm_extcon_dev_allocate(&pdev->dev, ··· 466 441 } 467 442 468 443 /* Start charger cable type detection */ 469 - axp288_extcon_enable(info); 444 + ret = axp288_extcon_enable(info); 445 + if (ret < 0) 446 + return ret; 470 447 471 448 device_init_wakeup(dev, true); 472 449 platform_set_drvdata(pdev, info);