ltc2941-battery-gauge.c (16763B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * I2C client/driver for the Linear Technology LTC2941, LTC2942, LTC2943 4 * and LTC2944 Battery Gas Gauge IC 5 * 6 * Copyright (C) 2014 Topic Embedded Systems 7 * 8 * Author: Auryn Verwegen 9 * Author: Mike Looijmans 10 */ 11#include <linux/devm-helpers.h> 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/of_device.h> 15#include <linux/types.h> 16#include <linux/errno.h> 17#include <linux/swab.h> 18#include <linux/i2c.h> 19#include <linux/delay.h> 20#include <linux/power_supply.h> 21#include <linux/slab.h> 22 23#define I16_MSB(x) ((x >> 8) & 0xFF) 24#define I16_LSB(x) (x & 0xFF) 25 26#define LTC294X_WORK_DELAY 10 /* Update delay in seconds */ 27 28#define LTC294X_MAX_VALUE 0xFFFF 29#define LTC294X_MID_SUPPLY 0x7FFF 30 31#define LTC2941_MAX_PRESCALER_EXP 7 32#define LTC2943_MAX_PRESCALER_EXP 6 33 34enum ltc294x_reg { 35 LTC294X_REG_STATUS = 0x00, 36 LTC294X_REG_CONTROL = 0x01, 37 LTC294X_REG_ACC_CHARGE_MSB = 0x02, 38 LTC294X_REG_ACC_CHARGE_LSB = 0x03, 39 LTC294X_REG_CHARGE_THR_HIGH_MSB = 0x04, 40 LTC294X_REG_CHARGE_THR_HIGH_LSB = 0x05, 41 LTC294X_REG_CHARGE_THR_LOW_MSB = 0x06, 42 LTC294X_REG_CHARGE_THR_LOW_LSB = 0x07, 43 LTC294X_REG_VOLTAGE_MSB = 0x08, 44 LTC294X_REG_VOLTAGE_LSB = 0x09, 45 LTC2942_REG_TEMPERATURE_MSB = 0x0C, 46 LTC2942_REG_TEMPERATURE_LSB = 0x0D, 47 LTC2943_REG_CURRENT_MSB = 0x0E, 48 LTC2943_REG_CURRENT_LSB = 0x0F, 49 LTC2943_REG_TEMPERATURE_MSB = 0x14, 50 LTC2943_REG_TEMPERATURE_LSB = 0x15, 51}; 52 53enum ltc294x_id { 54 LTC2941_ID, 55 LTC2942_ID, 56 LTC2943_ID, 57 LTC2944_ID, 58}; 59 60#define LTC2941_REG_STATUS_CHIP_ID BIT(7) 61 62#define LTC2942_REG_CONTROL_MODE_SCAN (BIT(7) | BIT(6)) 63#define LTC2943_REG_CONTROL_MODE_SCAN BIT(7) 64#define LTC294X_REG_CONTROL_PRESCALER_MASK (BIT(5) | BIT(4) | BIT(3)) 65#define LTC294X_REG_CONTROL_SHUTDOWN_MASK (BIT(0)) 66#define LTC294X_REG_CONTROL_PRESCALER_SET(x) \ 67 ((x << 3) & LTC294X_REG_CONTROL_PRESCALER_MASK) 68#define LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED 0 69#define LTC294X_REG_CONTROL_ADC_DISABLE(x) ((x) & ~(BIT(7) | BIT(6))) 70 71struct ltc294x_info { 72 struct i2c_client *client; /* I2C Client pointer */ 73 struct power_supply *supply; /* Supply pointer */ 74 struct power_supply_desc supply_desc; /* Supply description */ 75 struct delayed_work work; /* Work scheduler */ 76 enum ltc294x_id id; /* Chip type */ 77 int charge; /* Last charge register content */ 78 int r_sense; /* mOhm */ 79 int Qlsb; /* nAh */ 80}; 81 82static inline int convert_bin_to_uAh( 83 const struct ltc294x_info *info, int Q) 84{ 85 return ((Q * (info->Qlsb / 10))) / 100; 86} 87 88static inline int convert_uAh_to_bin( 89 const struct ltc294x_info *info, int uAh) 90{ 91 int Q; 92 93 Q = (uAh * 100) / (info->Qlsb/10); 94 return (Q < LTC294X_MAX_VALUE) ? Q : LTC294X_MAX_VALUE; 95} 96 97static int ltc294x_read_regs(struct i2c_client *client, 98 enum ltc294x_reg reg, u8 *buf, int num_regs) 99{ 100 int ret; 101 struct i2c_msg msgs[2] = { }; 102 u8 reg_start = reg; 103 104 msgs[0].addr = client->addr; 105 msgs[0].len = 1; 106 msgs[0].buf = ®_start; 107 108 msgs[1].addr = client->addr; 109 msgs[1].len = num_regs; 110 msgs[1].buf = buf; 111 msgs[1].flags = I2C_M_RD; 112 113 ret = i2c_transfer(client->adapter, &msgs[0], 2); 114 if (ret < 0) { 115 dev_err(&client->dev, "ltc2941 read_reg(0x%x[%d]) failed: %pe\n", 116 reg, num_regs, ERR_PTR(ret)); 117 return ret; 118 } 119 120 dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n", 121 __func__, reg, num_regs, *buf); 122 123 return 0; 124} 125 126static int ltc294x_write_regs(struct i2c_client *client, 127 enum ltc294x_reg reg, const u8 *buf, int num_regs) 128{ 129 int ret; 130 u8 reg_start = reg; 131 132 ret = i2c_smbus_write_i2c_block_data(client, reg_start, num_regs, buf); 133 if (ret < 0) { 134 dev_err(&client->dev, "ltc2941 write_reg(0x%x[%d]) failed: %pe\n", 135 reg, num_regs, ERR_PTR(ret)); 136 return ret; 137 } 138 139 dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n", 140 __func__, reg, num_regs, *buf); 141 142 return 0; 143} 144 145static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp) 146{ 147 int ret; 148 u8 value; 149 u8 control; 150 151 /* Read status and control registers */ 152 ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1); 153 if (ret < 0) 154 return ret; 155 156 control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) | 157 LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED; 158 /* Put device into "monitor" mode */ 159 switch (info->id) { 160 case LTC2942_ID: /* 2942 measures every 2 sec */ 161 control |= LTC2942_REG_CONTROL_MODE_SCAN; 162 break; 163 case LTC2943_ID: 164 case LTC2944_ID: /* 2943 and 2944 measure every 10 sec */ 165 control |= LTC2943_REG_CONTROL_MODE_SCAN; 166 break; 167 default: 168 break; 169 } 170 171 if (value != control) { 172 ret = ltc294x_write_regs(info->client, 173 LTC294X_REG_CONTROL, &control, 1); 174 if (ret < 0) 175 return ret; 176 } 177 178 return 0; 179} 180 181static int ltc294x_read_charge_register(const struct ltc294x_info *info, 182 enum ltc294x_reg reg) 183 { 184 int ret; 185 u8 datar[2]; 186 187 ret = ltc294x_read_regs(info->client, reg, &datar[0], 2); 188 if (ret < 0) 189 return ret; 190 return (datar[0] << 8) + datar[1]; 191} 192 193static int ltc294x_get_charge(const struct ltc294x_info *info, 194 enum ltc294x_reg reg, int *val) 195{ 196 int value = ltc294x_read_charge_register(info, reg); 197 198 if (value < 0) 199 return value; 200 /* When r_sense < 0, this counts up when the battery discharges */ 201 if (info->Qlsb < 0) 202 value -= 0xFFFF; 203 *val = convert_bin_to_uAh(info, value); 204 return 0; 205} 206 207static int ltc294x_set_charge_now(const struct ltc294x_info *info, int val) 208{ 209 int ret; 210 u8 dataw[2]; 211 u8 ctrl_reg; 212 s32 value; 213 214 value = convert_uAh_to_bin(info, val); 215 /* Direction depends on how sense+/- were connected */ 216 if (info->Qlsb < 0) 217 value += 0xFFFF; 218 if ((value < 0) || (value > 0xFFFF)) /* input validation */ 219 return -EINVAL; 220 221 /* Read control register */ 222 ret = ltc294x_read_regs(info->client, 223 LTC294X_REG_CONTROL, &ctrl_reg, 1); 224 if (ret < 0) 225 return ret; 226 /* Disable analog section */ 227 ctrl_reg |= LTC294X_REG_CONTROL_SHUTDOWN_MASK; 228 ret = ltc294x_write_regs(info->client, 229 LTC294X_REG_CONTROL, &ctrl_reg, 1); 230 if (ret < 0) 231 return ret; 232 /* Set new charge value */ 233 dataw[0] = I16_MSB(value); 234 dataw[1] = I16_LSB(value); 235 ret = ltc294x_write_regs(info->client, 236 LTC294X_REG_ACC_CHARGE_MSB, &dataw[0], 2); 237 if (ret < 0) 238 goto error_exit; 239 /* Enable analog section */ 240error_exit: 241 ctrl_reg &= ~LTC294X_REG_CONTROL_SHUTDOWN_MASK; 242 ret = ltc294x_write_regs(info->client, 243 LTC294X_REG_CONTROL, &ctrl_reg, 1); 244 245 return ret < 0 ? ret : 0; 246} 247 248static int ltc294x_set_charge_thr(const struct ltc294x_info *info, 249 enum ltc294x_reg reg, int val) 250{ 251 u8 dataw[2]; 252 s32 value; 253 254 value = convert_uAh_to_bin(info, val); 255 /* Direction depends on how sense+/- were connected */ 256 if (info->Qlsb < 0) 257 value += 0xFFFF; 258 if ((value < 0) || (value > 0xFFFF)) /* input validation */ 259 return -EINVAL; 260 261 /* Set new charge value */ 262 dataw[0] = I16_MSB(value); 263 dataw[1] = I16_LSB(value); 264 return ltc294x_write_regs(info->client, reg, &dataw[0], 2); 265} 266 267static int ltc294x_get_charge_counter( 268 const struct ltc294x_info *info, int *val) 269{ 270 int value = ltc294x_read_charge_register(info, LTC294X_REG_ACC_CHARGE_MSB); 271 272 if (value < 0) 273 return value; 274 value -= LTC294X_MID_SUPPLY; 275 *val = convert_bin_to_uAh(info, value); 276 return 0; 277} 278 279static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val) 280{ 281 int ret; 282 u8 datar[2]; 283 u32 value; 284 285 ret = ltc294x_read_regs(info->client, 286 LTC294X_REG_VOLTAGE_MSB, &datar[0], 2); 287 value = (datar[0] << 8) | datar[1]; 288 switch (info->id) { 289 case LTC2943_ID: 290 value *= 23600 * 2; 291 value /= 0xFFFF; 292 value *= 1000 / 2; 293 break; 294 case LTC2944_ID: 295 value *= 70800 / 5*4; 296 value /= 0xFFFF; 297 value *= 1000 * 5/4; 298 break; 299 default: 300 value *= 6000 * 10; 301 value /= 0xFFFF; 302 value *= 1000 / 10; 303 break; 304 } 305 *val = value; 306 return ret; 307} 308 309static int ltc294x_get_current(const struct ltc294x_info *info, int *val) 310{ 311 int ret; 312 u8 datar[2]; 313 s32 value; 314 315 ret = ltc294x_read_regs(info->client, 316 LTC2943_REG_CURRENT_MSB, &datar[0], 2); 317 value = (datar[0] << 8) | datar[1]; 318 value -= 0x7FFF; 319 if (info->id == LTC2944_ID) 320 value *= 64000; 321 else 322 value *= 60000; 323 /* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm, 324 * the formula below keeps everything in s32 range while preserving 325 * enough digits */ 326 *val = 1000 * (value / (info->r_sense * 0x7FFF)); /* in uA */ 327 return ret; 328} 329 330static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val) 331{ 332 enum ltc294x_reg reg; 333 int ret; 334 u8 datar[2]; 335 u32 value; 336 337 if (info->id == LTC2942_ID) { 338 reg = LTC2942_REG_TEMPERATURE_MSB; 339 value = 6000; /* Full-scale is 600 Kelvin */ 340 } else { 341 reg = LTC2943_REG_TEMPERATURE_MSB; 342 value = 5100; /* Full-scale is 510 Kelvin */ 343 } 344 ret = ltc294x_read_regs(info->client, reg, &datar[0], 2); 345 value *= (datar[0] << 8) | datar[1]; 346 /* Convert to tenths of degree Celsius */ 347 *val = value / 0xFFFF - 2722; 348 return ret; 349} 350 351static int ltc294x_get_property(struct power_supply *psy, 352 enum power_supply_property prop, 353 union power_supply_propval *val) 354{ 355 struct ltc294x_info *info = power_supply_get_drvdata(psy); 356 357 switch (prop) { 358 case POWER_SUPPLY_PROP_CHARGE_FULL: 359 return ltc294x_get_charge(info, LTC294X_REG_CHARGE_THR_HIGH_MSB, 360 &val->intval); 361 case POWER_SUPPLY_PROP_CHARGE_EMPTY: 362 return ltc294x_get_charge(info, LTC294X_REG_CHARGE_THR_LOW_MSB, 363 &val->intval); 364 case POWER_SUPPLY_PROP_CHARGE_NOW: 365 return ltc294x_get_charge(info, LTC294X_REG_ACC_CHARGE_MSB, 366 &val->intval); 367 case POWER_SUPPLY_PROP_CHARGE_COUNTER: 368 return ltc294x_get_charge_counter(info, &val->intval); 369 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 370 return ltc294x_get_voltage(info, &val->intval); 371 case POWER_SUPPLY_PROP_CURRENT_NOW: 372 return ltc294x_get_current(info, &val->intval); 373 case POWER_SUPPLY_PROP_TEMP: 374 return ltc294x_get_temperature(info, &val->intval); 375 default: 376 return -EINVAL; 377 } 378} 379 380static int ltc294x_set_property(struct power_supply *psy, 381 enum power_supply_property psp, 382 const union power_supply_propval *val) 383{ 384 struct ltc294x_info *info = power_supply_get_drvdata(psy); 385 386 switch (psp) { 387 case POWER_SUPPLY_PROP_CHARGE_FULL: 388 return ltc294x_set_charge_thr(info, 389 LTC294X_REG_CHARGE_THR_HIGH_MSB, val->intval); 390 case POWER_SUPPLY_PROP_CHARGE_EMPTY: 391 return ltc294x_set_charge_thr(info, 392 LTC294X_REG_CHARGE_THR_LOW_MSB, val->intval); 393 case POWER_SUPPLY_PROP_CHARGE_NOW: 394 return ltc294x_set_charge_now(info, val->intval); 395 default: 396 return -EPERM; 397 } 398} 399 400static int ltc294x_property_is_writeable( 401 struct power_supply *psy, enum power_supply_property psp) 402{ 403 switch (psp) { 404 case POWER_SUPPLY_PROP_CHARGE_FULL: 405 case POWER_SUPPLY_PROP_CHARGE_EMPTY: 406 case POWER_SUPPLY_PROP_CHARGE_NOW: 407 return 1; 408 default: 409 return 0; 410 } 411} 412 413static void ltc294x_update(struct ltc294x_info *info) 414{ 415 int charge = ltc294x_read_charge_register(info, LTC294X_REG_ACC_CHARGE_MSB); 416 417 if (charge != info->charge) { 418 info->charge = charge; 419 power_supply_changed(info->supply); 420 } 421} 422 423static void ltc294x_work(struct work_struct *work) 424{ 425 struct ltc294x_info *info; 426 427 info = container_of(work, struct ltc294x_info, work.work); 428 ltc294x_update(info); 429 schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); 430} 431 432static enum power_supply_property ltc294x_properties[] = { 433 POWER_SUPPLY_PROP_CHARGE_COUNTER, 434 POWER_SUPPLY_PROP_CHARGE_FULL, 435 POWER_SUPPLY_PROP_CHARGE_EMPTY, 436 POWER_SUPPLY_PROP_CHARGE_NOW, 437 POWER_SUPPLY_PROP_VOLTAGE_NOW, 438 POWER_SUPPLY_PROP_TEMP, 439 POWER_SUPPLY_PROP_CURRENT_NOW, 440}; 441 442static int ltc294x_i2c_probe(struct i2c_client *client, 443 const struct i2c_device_id *id) 444{ 445 struct power_supply_config psy_cfg = {}; 446 struct ltc294x_info *info; 447 struct device_node *np; 448 int ret; 449 u32 prescaler_exp; 450 s32 r_sense; 451 u8 status; 452 453 info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); 454 if (info == NULL) 455 return -ENOMEM; 456 457 i2c_set_clientdata(client, info); 458 459 np = of_node_get(client->dev.of_node); 460 461 info->id = (enum ltc294x_id) (uintptr_t) of_device_get_match_data( 462 &client->dev); 463 info->supply_desc.name = np->name; 464 465 /* r_sense can be negative, when sense+ is connected to the battery 466 * instead of the sense-. This results in reversed measurements. */ 467 ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense); 468 if (ret < 0) 469 return dev_err_probe(&client->dev, ret, 470 "Could not find lltc,resistor-sense in devicetree\n"); 471 info->r_sense = r_sense; 472 473 ret = of_property_read_u32(np, "lltc,prescaler-exponent", 474 &prescaler_exp); 475 if (ret < 0) { 476 dev_warn(&client->dev, 477 "lltc,prescaler-exponent not in devicetree\n"); 478 prescaler_exp = LTC2941_MAX_PRESCALER_EXP; 479 } 480 481 if (info->id == LTC2943_ID) { 482 if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP) 483 prescaler_exp = LTC2943_MAX_PRESCALER_EXP; 484 info->Qlsb = ((340 * 50000) / r_sense) >> 485 (12 - 2*prescaler_exp); 486 } else { 487 if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP) 488 prescaler_exp = LTC2941_MAX_PRESCALER_EXP; 489 info->Qlsb = ((85 * 50000) / r_sense) >> 490 (7 - prescaler_exp); 491 } 492 493 /* Read status register to check for LTC2942 */ 494 if (info->id == LTC2941_ID || info->id == LTC2942_ID) { 495 ret = ltc294x_read_regs(client, LTC294X_REG_STATUS, &status, 1); 496 if (ret < 0) 497 return dev_err_probe(&client->dev, ret, 498 "Could not read status register\n"); 499 if (status & LTC2941_REG_STATUS_CHIP_ID) 500 info->id = LTC2941_ID; 501 else 502 info->id = LTC2942_ID; 503 } 504 505 info->client = client; 506 info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY; 507 info->supply_desc.properties = ltc294x_properties; 508 switch (info->id) { 509 case LTC2944_ID: 510 case LTC2943_ID: 511 info->supply_desc.num_properties = 512 ARRAY_SIZE(ltc294x_properties); 513 break; 514 case LTC2942_ID: 515 info->supply_desc.num_properties = 516 ARRAY_SIZE(ltc294x_properties) - 1; 517 break; 518 case LTC2941_ID: 519 default: 520 info->supply_desc.num_properties = 521 ARRAY_SIZE(ltc294x_properties) - 3; 522 break; 523 } 524 info->supply_desc.get_property = ltc294x_get_property; 525 info->supply_desc.set_property = ltc294x_set_property; 526 info->supply_desc.property_is_writeable = ltc294x_property_is_writeable; 527 info->supply_desc.external_power_changed = NULL; 528 529 psy_cfg.drv_data = info; 530 531 ret = devm_delayed_work_autocancel(&client->dev, &info->work, 532 ltc294x_work); 533 if (ret) 534 return ret; 535 536 ret = ltc294x_reset(info, prescaler_exp); 537 if (ret < 0) 538 return dev_err_probe(&client->dev, ret, 539 "Communication with chip failed\n"); 540 541 info->supply = devm_power_supply_register(&client->dev, 542 &info->supply_desc, &psy_cfg); 543 if (IS_ERR(info->supply)) 544 return dev_err_probe(&client->dev, PTR_ERR(info->supply), 545 "failed to register ltc2941\n"); 546 547 schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); 548 549 return 0; 550} 551 552static void ltc294x_i2c_shutdown(struct i2c_client *client) 553{ 554 struct ltc294x_info *info = i2c_get_clientdata(client); 555 int ret; 556 u8 value; 557 u8 control; 558 559 /* The LTC2941 does not need any special handling */ 560 if (info->id == LTC2941_ID) 561 return; 562 563 /* Read control register */ 564 ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1); 565 if (ret < 0) 566 return; 567 568 /* Disable continuous ADC conversion as this drains the battery */ 569 control = LTC294X_REG_CONTROL_ADC_DISABLE(value); 570 if (control != value) 571 ltc294x_write_regs(info->client, LTC294X_REG_CONTROL, 572 &control, 1); 573} 574 575#ifdef CONFIG_PM_SLEEP 576 577static int ltc294x_suspend(struct device *dev) 578{ 579 struct i2c_client *client = to_i2c_client(dev); 580 struct ltc294x_info *info = i2c_get_clientdata(client); 581 582 cancel_delayed_work(&info->work); 583 return 0; 584} 585 586static int ltc294x_resume(struct device *dev) 587{ 588 struct i2c_client *client = to_i2c_client(dev); 589 struct ltc294x_info *info = i2c_get_clientdata(client); 590 591 schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); 592 return 0; 593} 594 595static SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume); 596#define LTC294X_PM_OPS (<c294x_pm_ops) 597 598#else 599#define LTC294X_PM_OPS NULL 600#endif /* CONFIG_PM_SLEEP */ 601 602 603static const struct i2c_device_id ltc294x_i2c_id[] = { 604 { "ltc2941", LTC2941_ID, }, 605 { "ltc2942", LTC2942_ID, }, 606 { "ltc2943", LTC2943_ID, }, 607 { "ltc2944", LTC2944_ID, }, 608 { }, 609}; 610MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id); 611 612static const struct of_device_id ltc294x_i2c_of_match[] = { 613 { 614 .compatible = "lltc,ltc2941", 615 .data = (void *)LTC2941_ID, 616 }, 617 { 618 .compatible = "lltc,ltc2942", 619 .data = (void *)LTC2942_ID, 620 }, 621 { 622 .compatible = "lltc,ltc2943", 623 .data = (void *)LTC2943_ID, 624 }, 625 { 626 .compatible = "lltc,ltc2944", 627 .data = (void *)LTC2944_ID, 628 }, 629 { }, 630}; 631MODULE_DEVICE_TABLE(of, ltc294x_i2c_of_match); 632 633static struct i2c_driver ltc294x_driver = { 634 .driver = { 635 .name = "LTC2941", 636 .of_match_table = ltc294x_i2c_of_match, 637 .pm = LTC294X_PM_OPS, 638 }, 639 .probe = ltc294x_i2c_probe, 640 .shutdown = ltc294x_i2c_shutdown, 641 .id_table = ltc294x_i2c_id, 642}; 643module_i2c_driver(ltc294x_driver); 644 645MODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems"); 646MODULE_AUTHOR("Mike Looijmans, Topic Embedded Products"); 647MODULE_DESCRIPTION("LTC2941/LTC2942/LTC2943/LTC2944 Battery Gas Gauge IC driver"); 648MODULE_LICENSE("GPL");