1313 *
1414 * ChangeLog:
1515 * Aug.18, 2020 Kenneth Chan <kenneth.t.chan@gmail.com>
16+ * add support for battery charging threshold (eco mode)
1617 * resolve hotkey double trigger
1718 * add write support to mute
1819 * fix sticky_key init bug
@@ -147,7 +148,10 @@ MODULE_LICENSE("GPL");
147148#define METHOD_HKEY_SQTY "SQTY"
148149#define METHOD_HKEY_SINF "SINF"
149150#define METHOD_HKEY_SSET "SSET"
150- #define HKEY_NOTIFY 0x80
151+ #define METHOD_ECWR "\\_SB.ECWR"
152+ #define HKEY_NOTIFY 0x80
153+ #define ECO_MODE_OFF 0x00
154+ #define ECO_MODE_ON 0x80
151155
152156#define ACPI_PCC_DRIVER_NAME "Panasonic Laptop Support"
153157#define ACPI_PCC_DEVICE_NAME "Hotkey"
@@ -156,7 +160,7 @@ MODULE_LICENSE("GPL");
156160#define ACPI_PCC_INPUT_PHYS "panasonic/hkey0"
157161
158162/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
159- ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00
163+ ECO_MODEs: 0x03 = off, 0x83 = on
160164*/
161165enum SINF_BITS { SINF_NUM_BATTERIES = 0 ,
162166 SINF_LCD_TYPE ,
@@ -168,7 +172,7 @@ enum SINF_BITS { SINF_NUM_BATTERIES = 0,
168172 SINF_DC_CUR_BRIGHT ,
169173 SINF_MUTE ,
170174 SINF_RESERVED ,
171- SINF_ENV_STATE ,
175+ SINF_ECO_MODE = 0x0A ,
172176 SINF_STICKY_KEY = 0x80 ,
173177 };
174178/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
@@ -222,6 +226,7 @@ struct pcc_acpi {
222226 acpi_handle handle ;
223227 unsigned long num_sifr ;
224228 int sticky_key ;
229+ int eco_mode ;
225230 int mute ;
226231 u32 * sinf ;
227232 struct acpi_device * device ;
@@ -534,6 +539,77 @@ static ssize_t sticky_key_store(struct device *dev, struct device_attribute *att
534539 return count ;
535540}
536541
542+ static ssize_t eco_mode_show (struct device * dev , struct device_attribute * attr ,
543+ char * buf )
544+ {
545+ struct acpi_device * acpi = to_acpi_device (dev );
546+ struct pcc_acpi * pcc = acpi_driver_data (acpi );
547+ int result ;
548+
549+ if (!acpi_pcc_retrieve_biosdata (pcc ))
550+ return - EIO ;
551+
552+ switch (pcc -> sinf [SINF_ECO_MODE ]) {
553+ case (ECO_MODE_OFF + 3 ):
554+ result = 0 ;
555+ break ;
556+ case (ECO_MODE_ON + 3 ):
557+ result = 1 ;
558+ break ;
559+ default :
560+ result = - EIO ;
561+ break ;
562+ }
563+ return snprintf (buf , PAGE_SIZE , "%u\n" , result );
564+ }
565+
566+ static ssize_t eco_mode_store (struct device * dev , struct device_attribute * attr ,
567+ const char * buf , size_t count )
568+ {
569+ struct acpi_device * acpi = to_acpi_device (dev );
570+ struct pcc_acpi * pcc = acpi_driver_data (acpi );
571+ int err , state ;
572+
573+ union acpi_object param [2 ];
574+ struct acpi_object_list input ;
575+ acpi_status status ;
576+
577+ param [0 ].type = ACPI_TYPE_INTEGER ;
578+ param [0 ].integer .value = 0x15 ;
579+ param [1 ].type = ACPI_TYPE_INTEGER ;
580+ input .count = 2 ;
581+ input .pointer = param ;
582+
583+ err = kstrtoint (buf , 0 , & state );
584+ if (err )
585+ return err ;
586+
587+ switch (state ) {
588+ case 0 :
589+ param [1 ].integer .value = ECO_MODE_OFF ;
590+ pcc -> sinf [SINF_ECO_MODE ] = 0 ;
591+ pcc -> eco_mode = 0 ;
592+ break ;
593+ case 1 :
594+ param [1 ].integer .value = ECO_MODE_ON ;
595+ pcc -> sinf [SINF_ECO_MODE ] = 1 ;
596+ pcc -> eco_mode = 1 ;
597+ break ;
598+ default :
599+ /* nothing to do */
600+ return count ;
601+ }
602+
603+ status = acpi_evaluate_object (NULL , METHOD_ECWR ,
604+ & input , NULL );
605+ if (ACPI_FAILURE (status )) {
606+ pr_err ("%s evaluation failed\n" , METHOD_ECWR );
607+ return - EINVAL ;
608+ }
609+
610+ return count ;
611+ }
612+
537613static ssize_t cdpower_show (struct device * dev , struct device_attribute * attr ,
538614 char * buf )
539615{
@@ -556,13 +632,15 @@ static DEVICE_ATTR_RO(numbatt);
556632static DEVICE_ATTR_RO (lcdtype );
557633static DEVICE_ATTR_RW (mute );
558634static DEVICE_ATTR_RW (sticky_key );
635+ static DEVICE_ATTR_RW (eco_mode );
559636static DEVICE_ATTR_RW (cdpower );
560637
561638static struct attribute * pcc_sysfs_entries [] = {
562639 & dev_attr_numbatt .attr ,
563640 & dev_attr_lcdtype .attr ,
564641 & dev_attr_mute .attr ,
565642 & dev_attr_sticky_key .attr ,
643+ & dev_attr_eco_mode .attr ,
566644 & dev_attr_cdpower .attr ,
567645 NULL ,
568646};
@@ -714,6 +792,7 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
714792 return - EINVAL ;
715793
716794 acpi_pcc_write_sset (pcc , SINF_MUTE , pcc -> mute );
795+ acpi_pcc_write_sset (pcc , SINF_ECO_MODE , pcc -> eco_mode );
717796 acpi_pcc_write_sset (pcc , SINF_STICKY_KEY , pcc -> sticky_key );
718797
719798 return 0 ;
@@ -784,6 +863,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
784863 acpi_pcc_write_sset (pcc , SINF_STICKY_KEY , 0 );
785864 pcc -> sticky_key = 0 ;
786865
866+ pcc -> eco_mode = pcc -> sinf [SINF_ECO_MODE ];
787867 pcc -> mute = pcc -> sinf [SINF_MUTE ];
788868
789869 /* add sysfs attributes */
0 commit comments