2014年9月23日 星期二

GPIO觸發LED

前置條件:
1. LED是用keypad 的backlight LED
2. GPIO 為INPUT (似按button後導通)

 整體行為:
當GPIO為 PULL_HIGH時, LED亮
當GPIO為 PULL_DOWN時, LED滅

相關的driver code:
kernel/drivers/led/led-class.c, led-core.c, leds-qpnp.c, led-triggers.c, ledtrig-gpio.c
看完code可發現, 此功能若依kernel的code 只能用 device node的設定來變更GPIO的pin值,
無法用devicetree 來直接指定 (所以此文是修改啟動script來設定GPIO pin number)



1. 開啟 kernel 功能 (修改 default_config 檔: kernel/arch/arm/configs/msm8974_defconfig )
 加入: 
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_BACKLIGHT=y
 CONFIG_LEDS_TRIGGER_GPIO=y
 CONFIG_LEDS_TRIGGER_DEFAULT_ON=y

2. 設定GPIO行為 (修改 kernel/arch/arm/mach-msm/board-msm8974-gpiomux.c)
static struct gpiomux_setting button_act_cfg = {
        .func = GPIOMUX_FUNC_GPIO,
        .drv = GPIOMUX_DRV_2MA,
        .pull = GPIOMUX_PULL_NONE,
        .dir = GPIOMUX_IN,
};

static struct gpiomux_setting button_sus_cfg = {
        .func = GPIOMUX_FUNC_GPIO,
        .drv = GPIOMUX_DRV_2MA,
        .pull = GPIOMUX_PULL_DOWN,
};

static struct msm_gpiomux_config msm_BUTTON_config[] __initdata = {
        {
                .gpio = GPIO_BUTTON,  //79
                .settings = {
                        [GPIOMUX_ACTIVE]  = &button_act_cfg,
                        [GPIOMUX_SUSPENDED]  = &button_sus_cfg,
                },
        },
};

void __init msm_msmd8974_init_gpiomux(void)
{
...
msm_gpiomux_install(msm_BUTTON_config, ARRAY_SIZE(msm_BUTTON_config));
}

3. 設定 LED與指定用GPIO觸發 (kernel/arch/arm/boot/dts/msm8974-leds.dtsi)
&pm8941_lsid1 {
...
    qcom,leds@e200 {
    ...
    qcom,kpdbl4 {
                        label = "kpdbl";
                        linux,name = "kpdbl-pwm-4";
                        qcom,mode = "pwm";
                        qcom,pwm-channel = <11>;
                        qcom,pwm-us = <1000>;
                        qcom,id = <7>;
                        qcom,max-current = <20>;
                        qcom,row-id = <3>;
                        qcom,row-src-en;
                        qcom,always-on;
                        qcom,default-state = "off";
                        linux,default-trigger = "gpio";
      };

4. 指定GPIO 值與設定亮度等, 這部份自己找 啟動scripts 放, 我是放在 (device/qcom/common/rootdir/etc/init.qcom.sh)
        echo gpio > /sys/class/leds/kpdbl-pwm-4/trigger
        echo 255 > /sys/class/leds/kpdbl-pwm-4/desired_brightness
        echo 255 > /sys/class/leds/kpdbl-pwm-4/brightness
        echo 79 > /sys/class/leds/kpdbl-pwm-4/gpio

2014年9月10日 星期三

Android 4.4 在選單增加 Display Never Timeout

Android 4.4.x 在選單增加 Display Never Timeout

本文源自: http://ansonlai.iteye.com/blog/1899764

剛抓下來的 android 4.4.x 裡面的 設定--> 顯示 --> 休眠
只有 30 sec, 1 min, 2 min, 5 min, 10 min, 30 min項目,
可是有些情況我們並不想讓 Display 因為省電保護或... 因而關閉顯示(黑畫面)
可是一開始卻並無此項目可選....

Step 1:  改packages/apps/Settings/res/values/arrays.xml

    <!-- Display settings.  The delay in inactivity before the screen is turned off. These are shown in a list dialog. -->
    <string-array name="screen_timeout_entries">
        <item>15 seconds</item>
        <item>30 seconds</item>
        <item>1 minute</item>
        <item>2 minutes</item>
        <item>5 minutes</item>
        <item>10 minutes</item>
        <item>30 minutes</item>
        <item>Never</item>
    </string-array>
<!-- Do not translate. -->
    <string-array name="screen_timeout_values" translatable="false">
        <!-- Do not translate. -->
        <item>15000</item>
        <!-- Do not translate. -->
        <item>30000</item>
        <!-- Do not translate. -->
        <item>60000</item>
        <!-- Do not translate. -->
        <item>120000</item>
        <!-- Do not translate. -->
        <item>300000</item>
        <!-- Do not translate. -->
        <item>600000</item>
        <!-- Do not translate. -->
        <item>1800000</item>
        <item>-1</item>
    </string-array>



Step 2: 修改所有 packages/apps/Settings/res/values-xxxx/array.xml (各語系的顯示)
以英文為例:  packages/apps/Settings/res/values-en-rGB/arrays.xml

  <string-array name="screen_timeout_entries">
    <item msgid="3342301044271143016">"15 seconds"</item>
    <item msgid="8881760709354815449">"30 seconds"</item>
    <item msgid="7589406073232279088">"1 minute"</item>
    <item msgid="7001195990902244174">"2 minutes"</item>
    <item msgid="7489864775127957179">"5 minutes"</item>
    <item msgid="2314124409517439288">"10 minutes"</item>
    <item msgid="6864027152847611413">"30 minutes"</item>
    <item msgid="9989898989898989898">"Never"</item>
  </string-array>


Step 3: 修改code:  packages/apps/Settings/src/com/android/settings/DisplaySettings.java

    private void updateTimeoutPreferenceDescription(long currentTimeout) {
        ListPreference preference = mScreenTimeoutPreference;
        String summary;
        if (currentTimeout < -1) {
            // Unsupported value
            summary = "";
        } else {
            final CharSequence[] entries = preference.getEntries();
            final CharSequence[] values = preference.getEntryValues();
            if (entries == null || entries.length == 0) {
                summary = "";
            } else {
                int best = 0;
                for (int i = 0; i < values.length; i++) {
                    long timeout = Long.parseLong(values[i].toString());
                    if (currentTimeout == timeout) {
                        best = i;
                    }
                }
                summary = preference.getContext().getString(R.string.screen_timeout_summary,
                        entries[best]);
                if(currentTimeout < 0) summary = entries[best].toString();
            }
        }
        preference.setSummary(summary);
    }


Step 4: 修改code: frameworks/base/services/java/com/android/server/power/PowerManagerService.java

    private void updateUserActivitySummaryLocked(long now, int dirty) {
        // Update the status of the user activity timeout timer.
        if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
            mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);

            long nextTimeout = 0;
            if (mWakefulness != WAKEFULNESS_ASLEEP) {
                final int screenOffTimeout = getScreenOffTimeoutLocked();
                final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);

                mUserActivitySummary = 0;
                if (mLastUserActivityTime >= mLastWakeTime) {
                    nextTimeout = mLastUserActivityTime
                            + screenOffTimeout - screenDimDuration;
                    if (now < nextTimeout) {
                        mUserActivitySummary |= USER_ACTIVITY_SCREEN_BRIGHT;
                    } else {
                        nextTimeout = mLastUserActivityTime + screenOffTimeout;
                        if (now < nextTimeout) {
                            mUserActivitySummary |= USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }
                if (mUserActivitySummary == 0
                        && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                    nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
                    if (now < nextTimeout
                            && mDisplayPowerRequest.screenState
                                    != DisplayPowerRequest.SCREEN_STATE_OFF) {
                        mUserActivitySummary = mDisplayPowerRequest.screenState
                                == DisplayPowerRequest.SCREEN_STATE_BRIGHT ?
                                USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM;
                    }
                }
                ////if (mUserActivitySummary != 0) {
                if (mUserActivitySummary != 0 && mScreenOffTimeoutSetting > 0) {
                    Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtTime(msg, nextTimeout);
                }
            } else {
                mUserActivitySummary = 0;
            }

            if (DEBUG_SPEW) {
                Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
                        + wakefulnessToString(mWakefulness)
                        + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                        + ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
            }
        }
    }



源自: http://ansonlai.iteye.com/blog/1899764

2014年9月2日 星期二

msm8974用到的device tree檔

msm8974用到的device tree檔: (LNX.LA.3.5.2-06710-8x74.0 + MSM8974AB)

kernel/arch/arm/boot/dts/

batterydata-palladium.dtsi                   ----> 電池資料檔
dsi-panel-generic-720p-cmd.dtsi        ----> LCD Panel設定
msm8974-gpu.dtsi
msm8974-coresight.dtsi
msm8974-mtp.dtsi
msm8974-rumi.dtsi
msm8974.dtsi
msm8974pro-ab-pm8941.dtsi
msm8974-sim.dtsi
msm8974pro-ab-pm8941-mtp.dts
msm8974-smp2p.dtsi
msm8974-ion.dtsi
msm8974pro.dtsi
msm8974-v2.dtsi
msm8974-bus.dtsi
msm8974-keypad.dtsi
msm8974pro-ion.dtsi
msm8974-v2-iommu-domains.dtsi
msm8974-camera.dtsi
msm8974-leds.dtsi
msm8974pro-pm8941.dtsi
msm8974-v2-iommu.dtsi
msm8974-camera-sensor-mtp.dtsi
msm8974-mdss.dtsi
msm8974pro-pm.dtsi
msm8974-v2-pm.dtsi
msm8974-clock.dtsi
msm8974-mdss-panels.dtsi
msm8974-regulator.dtsi
msm-gdsc.dtsi
msm-iommu-v1.dtsi
msm-pm8841.dtsi
msm-pm8941.dtsi
msm-pm8x41-rpm-regulator.dtsi
msm-rdbg.dtsi
skeleton.dtsi


由 arch/arm/mach-msm/Makefile.boot 決定要 compile 那幾棵 device tree, 以下是只採用 msm8974pro-ab-pm8941-mtp.dtb 為 root之tree
# MSM8974
   zreladdr-$(CONFIG_ARCH_MSM8974)      := 0x00008000
        dtb-$(CONFIG_ARCH_MSM8974)      += msm8974pro-ab-pm8941-mtp.dtb