aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mfd/88pm860x-core.c95
-rw-r--r--include/linux/mfd/88pm860x.h22
2 files changed, 117 insertions, 0 deletions
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 17dfe9bb6d27..78c3a9e1fa1e 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -503,6 +503,99 @@ static void device_irq_exit(struct pm860x_chip *chip)
503 free_irq(chip->core_irq, chip); 503 free_irq(chip->core_irq, chip);
504} 504}
505 505
506int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
507{
508 int ret = -EIO;
509 struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
510 chip->client : chip->companion;
511
512 dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
513 dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
514 __func__, chip->osc_vote,
515 chip->osc_status);
516
517 mutex_lock(&chip->osc_lock);
518 /* Update voting status */
519 chip->osc_vote |= client;
520 /* If reference group is off - turn on*/
521 if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
522 chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
523 /* Enable Reference group Vsys */
524 if (pm860x_set_bits(i2c, PM8606_VSYS,
525 PM8606_VSYS_EN, PM8606_VSYS_EN))
526 goto out;
527
528 /*Enable Internal Oscillator */
529 if (pm860x_set_bits(i2c, PM8606_MISC,
530 PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
531 goto out;
532 /* Update status (only if writes succeed) */
533 chip->osc_status = PM8606_REF_GP_OSC_ON;
534 }
535 mutex_unlock(&chip->osc_lock);
536
537 dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
538 __func__, chip->osc_vote,
539 chip->osc_status, ret);
540 return 0;
541out:
542 mutex_unlock(&chip->osc_lock);
543 return ret;
544}
545
546int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
547{
548 int ret = -EIO;
549 struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
550 chip->client : chip->companion;
551
552 dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
553 dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
554 __func__, chip->osc_vote,
555 chip->osc_status);
556
557 mutex_lock(&chip->osc_lock);
558 /*Update voting status */
559 chip->osc_vote &= ~(client);
560 /* If reference group is off and this is the last client to release
561 * - turn off */
562 if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
563 (chip->osc_vote == REF_GP_NO_CLIENTS)) {
564 chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
565 /* Disable Reference group Vsys */
566 if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
567 goto out;
568 /* Disable Internal Oscillator */
569 if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
570 goto out;
571 chip->osc_status = PM8606_REF_GP_OSC_OFF;
572 }
573 mutex_unlock(&chip->osc_lock);
574
575 dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
576 __func__, chip->osc_vote,
577 chip->osc_status, ret);
578 return 0;
579out:
580 mutex_unlock(&chip->osc_lock);
581 return ret;
582}
583
584static void __devinit device_osc_init(struct i2c_client *i2c)
585{
586 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
587
588 mutex_init(&chip->osc_lock);
589 /* init portofino reference group voting and status */
590 /* Disable Reference group Vsys */
591 pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
592 /* Disable Internal Oscillator */
593 pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
594
595 chip->osc_vote = REF_GP_NO_CLIENTS;
596 chip->osc_status = PM8606_REF_GP_OSC_OFF;
597}
598
506static void __devinit device_bk_init(struct pm860x_chip *chip, 599static void __devinit device_bk_init(struct pm860x_chip *chip,
507 struct pm860x_platform_data *pdata) 600 struct pm860x_platform_data *pdata)
508{ 601{
@@ -774,6 +867,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
774 867
775 switch (chip->id) { 868 switch (chip->id) {
776 case CHIP_PM8606: 869 case CHIP_PM8606:
870 device_osc_init(chip->client);
777 device_bk_init(chip, pdata); 871 device_bk_init(chip, pdata);
778 device_led_init(chip, pdata); 872 device_led_init(chip, pdata);
779 break; 873 break;
@@ -785,6 +879,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
785 if (chip->companion) { 879 if (chip->companion) {
786 switch (chip->id) { 880 switch (chip->id) {
787 case CHIP_PM8607: 881 case CHIP_PM8607:
882 device_osc_init(chip->companion);
788 device_bk_init(chip, pdata); 883 device_bk_init(chip, pdata);
789 device_led_init(chip, pdata); 884 device_led_init(chip, pdata);
790 break; 885 break;
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index 8b583f3f7926..84d071ade1d8 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -263,6 +263,22 @@ enum {
263#define PM8607_PD_PREBIAS_MASK (0x1F << 0) 263#define PM8607_PD_PREBIAS_MASK (0x1F << 0)
264#define PM8607_PD_PRECHG_MASK (7 << 5) 264#define PM8607_PD_PRECHG_MASK (7 << 5)
265 265
266#define PM8606_REF_GP_OSC_OFF 0
267#define PM8606_REF_GP_OSC_ON 1
268#define PM8606_REF_GP_OSC_UNKNOWN 2
269
270/* Clients of reference group and 8MHz oscillator in 88PM8606 */
271enum pm8606_ref_gp_and_osc_clients {
272 REF_GP_NO_CLIENTS = 0,
273 WLED1_DUTY = (1<<0), /*PF 0x02.7:0*/
274 WLED2_DUTY = (1<<1), /*PF 0x04.7:0*/
275 WLED3_DUTY = (1<<2), /*PF 0x06.7:0*/
276 RGB1_ENABLE = (1<<3), /*PF 0x07.1*/
277 RGB2_ENABLE = (1<<4), /*PF 0x07.2*/
278 LDO_VBR_EN = (1<<5), /*PF 0x12.0*/
279 REF_GP_MAX_CLIENT = 0xFFFF
280};
281
266/* Interrupt Number in 88PM8607 */ 282/* Interrupt Number in 88PM8607 */
267enum { 283enum {
268 PM8607_IRQ_ONKEY, 284 PM8607_IRQ_ONKEY,
@@ -298,6 +314,7 @@ enum {
298struct pm860x_chip { 314struct pm860x_chip {
299 struct device *dev; 315 struct device *dev;
300 struct mutex irq_lock; 316 struct mutex irq_lock;
317 struct mutex osc_lock;
301 struct i2c_client *client; 318 struct i2c_client *client;
302 struct i2c_client *companion; /* companion chip client */ 319 struct i2c_client *companion; /* companion chip client */
303 struct regmap *regmap; 320 struct regmap *regmap;
@@ -305,11 +322,13 @@ struct pm860x_chip {
305 322
306 int buck3_double; /* DVC ramp slope double */ 323 int buck3_double; /* DVC ramp slope double */
307 unsigned short companion_addr; 324 unsigned short companion_addr;
325 unsigned short osc_vote;
308 int id; 326 int id;
309 int irq_mode; 327 int irq_mode;
310 int irq_base; 328 int irq_base;
311 int core_irq; 329 int core_irq;
312 unsigned char chip_version; 330 unsigned char chip_version;
331 unsigned char osc_status;
313 332
314 unsigned int wakeup_flag; 333 unsigned int wakeup_flag;
315}; 334};
@@ -370,6 +389,9 @@ struct pm860x_platform_data {
370 int num_regulators; 389 int num_regulators;
371}; 390};
372 391
392extern int pm8606_osc_enable(struct pm860x_chip *, unsigned short);
393extern int pm8606_osc_disable(struct pm860x_chip *, unsigned short);
394
373extern int pm860x_reg_read(struct i2c_client *, int); 395extern int pm860x_reg_read(struct i2c_client *, int);
374extern int pm860x_reg_write(struct i2c_client *, int, unsigned char); 396extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
375extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *); 397extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);