diff --git a/arch/arm64/boot/dts/nexell/Makefile b/arch/arm64/boot/dts/nexell/Makefile index 46364d6a..7f4dcadb 100644 --- a/arch/arm64/boot/dts/nexell/Makefile +++ b/arch/arm64/boot/dts/nexell/Makefile @@ -1,4 +1,5 @@ dtb-$(CONFIG_ARCH_S5P6818) += s5p6818-nanopi-m3.dtb +dtb-$(CONFIG_ARCH_S5P6818) += s5p6818-nanopi-fire3.dtb always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/nexell/s5p6818-nanopi-fire3.dts b/arch/arm64/boot/dts/nexell/s5p6818-nanopi-fire3.dts new file mode 100644 index 00000000..25ac71dd --- /dev/null +++ b/arch/arm64/boot/dts/nexell/s5p6818-nanopi-fire3.dts @@ -0,0 +1,837 @@ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * Author: Youngbok, Park + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/dts-v1/; +#include +#include +#include +#include +#include "s5p6818.dtsi" + +#define PMIC_PDATA_INIT(_id, _rname, _minuv, \ + _maxuv, _always_on, _boot_on, \ + _init_uv, _init_enable, _slp_slots) \ + regulator-name = _rname; \ + regulator-min-microvolt = <_minuv>; \ + regulator-max-microvolt = <_maxuv>; \ + nx,id = <_id>; \ + nx,always_on = <_always_on>; \ + nx,boot_on = <_boot_on>; \ + nx,init_enable = <_init_enable>; \ + nx,init_uV = <_init_uv>; \ + nx,sleep_slots = <_slp_slots>; + +/ { + memory { + /* Note: Samsung Artik u-boot fixates memory information to values + * specified by CONFIG_SYS_SDRAM_BASE and CONFIG_SYS_SDRAM_SIZE in + * the u-boot configuration. Values specified below are meaningless. + */ + device_type = "memory"; + reg = <0x40000000 0x40000000>; + }; + + aliases { + ethernet0 = &gmac0; + }; + + nx-v4l2 { + status = "okay"; + }; + + soc { + #include "s5p6818-pinctrl.dtsi" + + clocks { + uart0:uart@c00a9000 { clock-frequency = <147500000>; }; + uart1:uart@c00a8000 { clock-frequency = <147500000>; }; + uart2:uart@c00aa000 { clock-frequency = <147500000>; }; + uart3:uart@c00ab000 { clock-frequency = <147500000>; }; + uart4:uart@c006e000 { clock-frequency = <147500000>; }; + uart5:uart@c0084000 { clock-frequency = <147500000>; }; + pwm0:pwm0@c00ba000 { clock-frequency = <100000000>; }; + i2c0:i2c@c00ae000 { clock-frequency = <200000000>; }; + i2c1:i2c@c00af000 { clock-frequency = <200000000>; }; + i2c2:i2c@c00b0000 { clock-frequency = <200000000>; }; + vip1:vip@c00c2000 { src-force = <4>; }; + }; + + serial0:serial@c00a1000 { + status ="okay"; + }; + + serial1:serial@c00a0000 { + status ="okay"; + pinctrl-names = "default"; + pinctrl-0 = <&serial1_pin &serial1_flow>; + }; + + amba { + pl08xdma0:pl08xdma@c0000000 { + use_isr; + + ch12 { + slave_wait_flush_dma; + }; + + ch13 { + slave_wait_flush_dma; + }; + + ch14 { + slave_wait_flush_dma; + }; + + ch15 { + slave_wait_flush_dma; + }; + }; + + pl08xdma1:pl08xdma@c0001000 { + use_isr; + + ch0 { + slave_wait_flush_dma; + }; + + ch1 { + slave_wait_flush_dma; + }; + }; + }; + + dw_mmc_0:dw_mmc@c0062000 { // mappings from kernel 3.x: + bus-width = <4>; // MMC_CAP_4_BIT_DATA + cap-sd-highspeed; // DW_MCI_QUIRK_HIGHSPEED + cap-mmc-highspeed; // also DW_MCI_QUIRK_HIGHSPEED + clock-frequency = <100000000>; // bus_hz: 100 * 1000 * 1000 + card-detect-delay = <200>; // detect_delay_ms + disable-wp; // write protect: -> get_ro; feature not available for micro SD + cd-gpios = <&alive_0 1 GPIO_ACTIVE_LOW>; // card detect: CFG_SDMMC0_DETECT_IO == PAD_GPIO_ALV + 1 + nexell,drive_dly = <0x0>; // DW_MMC_DRIVE_DELAY(0) + nexell,drive_shift = <0x02>; // DW_MMC_DRIVE_PHASE(2) + nexell,sample_dly = <0x00>; // DW_MMC_SAMPLE_DELAY(0) + nexell,sample_shift = <0x01>; // DW_MMC_SAMPLE_PHASE(1) + status = "okay"; + }; + + dw_mmc_1:dw_mmc@c0068000 { + bus-width = <4>; + cap-sd-highspeed; + clock-frequency = <100000000>; + card-detect-delay = <200>; + non-removable; + keep-power-in-suspend; + nexell,drive_dly = <0x0>; + nexell,drive_shift = <0x02>; + nexell,sample_dly = <0x00>; + nexell,sample_shift = <0x01>; + mmc-pwrseq = <&wifi_powerseq>; + status = "okay"; + + /* wifi definition for brcmfmac.ko module */ + brcmf: bcrmf@1 { + compatible = "brcm,bcm4329-fmac"; + reg = <1>; + interrupt-parent = <&gpio_c>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + brcm,powersave-default-off; + }; + }; + + dw_mmc_2:dw_mmc@c0069000 { + bus-width = <4>; // MMC_CAP_4_BIT_DATA + cap-sd-highspeed; // DW_MCI_QUIRK_HIGHSPEED + cap-mmc-highspeed; // also DW_MCI_QUIRK_HIGHSPEED + sd-uhs-ddr50; // MMC_CAP_UHS_DDR50 + cap-mmc-hw-reset; // MMC_CAP_HW_RESET + clock-frequency = <200000000>; // bus_hz: 200 * 1000 * 1000 + card-detect-delay = <200>; // detect_delay_ms + non-removable; // MMC_CAP_NONREMOVABLE + broken-cd; + cd-gpios = <&gpio_c 24 GPIO_ACTIVE_LOW>; // card detect: CFG_SDMMC2_DETECT_IO == PAD_GPIO_C + 24 + nexell,drive_dly = <0x0>; // DW_MMC_DRIVE_DELAY(0) + nexell,drive_shift = <0x03>; // DW_MMC_DRIVE_PHASE(3) + nexell,sample_dly = <0x00>; // DW_MMC_SAMPLE_DELAY(0) + nexell,sample_shift = <0x02>; // DW_MMC_SAMPLE_PHASE(2) + status = "okay"; + }; + + dvfs:dynamic-freq@bb000 { + supply_name = "vdd_arm_spu"; + supply_optional = "vdd_arm_axp"; + vdd_arm_spu-supply = <&VCC1P1_ARM_SPU>; + vdd_arm_axp-supply = <&VCC1P1_ARM_PMIC>; + status = "okay"; + dvfs-tables = < 1400000 1200000 + 1300000 1140000 + 1200000 1100000 + 1100000 1040000 + 1000000 1040000 + 900000 1000000 + 800000 1000000 + 700000 980000 + 600000 980000 + 500000 940000 + 400000 940000>; + }; + + tmuctrl_0: tmuctrl@c0096000 { + status = "okay"; + }; + + thermal-zones { + cpu0_thermal: cpu0-thermal { + thermal-sensors = <&tmuctrl_0>; + polling-delay-passive = <250>; + polling-delay = <1000>; + + trips { + cpu_alert0: cpu-alert-0 { + temperature = <80000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_alert1: cpu-alert-1 { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_alert2: cpu-alert-2 { + temperature = <100000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_crit0: cpu-crit-0 { + temperature = <115000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT 1>; + }; + + map1 { + trip = <&cpu_alert1>; + cooling-device = <&cpu0 1 4>; + }; + + map2 { + trip = <&cpu_alert2>; + cooling-device = <&cpu0 4 10>; + }; + }; + }; + }; + + /* FIXME: bluetooth reset is piggybacked here although their data flow + * goes through serial1 */ + wifi_powerseq: wifi_powerseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = + <&gpio_b 24 GPIO_ACTIVE_LOW /* wifi */ + &gpio_b 8 GPIO_ACTIVE_LOW>; /* bluetooth */ + post-power-on-delay-ms = <50>; + }; + + i2c3_gpio:i2c@0 { + compatible = "i2c-gpio"; + gpios = <&gpio_e 31 0 /* sda */ + &gpio_e 30 0 /* scl */ + >; + i2c-gpio,delay-us = <10>;/* ~100 kHz */ + i2c-gpio,ch =<3>; + }; + + i2c3_gpio:i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + + spu1705@2d { + compatible = "spu1705,fe-pmu"; + reg = <0x2d>; + regulators { + VCC1P1_ARM_SPU: DCDC1 { + regulator-name = "vdd_arm_1.3V"; + regulator-min-microvolt = <905000>; + regulator-max-microvolt = <1265000>; + regulator-always-on; + }; + }; + }; + + axp228@34 { + compatible = "x-powers,axp228"; + reg = <0x34>; + interrupt-parent = <&alive_0>; // CFG_GPIO_PMIC_INTR + interrupts = <0x4 IRQ_TYPE_EDGE_FALLING>; + nx,id = <0>; + /* vdd_arm-supply = <&VCC1P1_ARM_PMIC>; */ + /* vdd_core-supply = <&VCC1P0_CORE_PMIC>; */ + regulators { + VCC_LDO1: + axp22_rtcldo{PMIC_PDATA_INIT( 0, + "axp228_rtcldo", + 3000000, 3000000, 0, 0, 3300000, + 0, 0xF) }; + VCC_LDO2: + axp22_aldo1{PMIC_PDATA_INIT( 1, + "axp228_3p3_alive", + 700000, 3300000, 1, 1, 3300000, + 1, 0xF) }; + VCC_LDO3: + axp22_aldo2{PMIC_PDATA_INIT( 2, + "axp228_1p8_alive", + 700000, 3300000, 1, 1, 1800000, + 1, 0xF) }; + VCC_LDO4: + axp22_aldo3{PMIC_PDATA_INIT( 3, + "axp228_1p0_alive", + 700000, 3300000, 1, 1, 1000000, + 1, 0xF) }; + VCC_LDO5: + axp22_dldo1{PMIC_PDATA_INIT( 4, + "axp228_wide", + 700000, 3300000, 1, 1, 3300000, + 1, 0xF) }; + VCC_LDO6: + axp22_dldo2{PMIC_PDATA_INIT( 5, + "axp228_1p8_cam", + 700000, 3300000, 0, 0, 1800000, + 0, 0xF) }; + VCC_LDO7: + axp22_dldo3{PMIC_PDATA_INIT( 6, + "axp228_dldo3", + 700000, 3300000, 0, 0, 700000, + 0, 0xF) }; + VCC_LDO8: + axp22_dldo4{PMIC_PDATA_INIT( 7, + "axp228_dldo4", + 700000, 3300000, 0, 0, 700000, + 0, 0xF) }; + VCC_LDO9: + axp22_eldo1{PMIC_PDATA_INIT( 8, + "axp228_1p8_sys", + 700000, 3300000, 1, 1, 1800000, + 1, 0xF) }; + VCC_LDO10: + axp22_eldo2{PMIC_PDATA_INIT( 9, + "axp228_3p3_wifi", + 700000, 3300000, 1, 1, 3300000, + 1, 0xF) }; + VCC_LDO11: + axp22_eldo3{PMIC_PDATA_INIT(10, + "axp228_eldo3", + 700000, 3300000, 0, 0, 700000, + 0, 0xF) }; + VCC_LDO12: + axp22_dc5ldo{PMIC_PDATA_INIT(11, + "axp228_1p2_cvbs", + 700000, 1400000, 0, 0, 1200000, + 0, 0xF) }; + VCC_DCDC1: + axp22_dcdc1{PMIC_PDATA_INIT(12, + "axp228_3p3_sys", + 1600000, 3400000, 1, 1, 3300000, + 1, 0xF) }; + VCC1P1_ARM_PMIC: + axp22_dcdc2{PMIC_PDATA_INIT(13, + "axp228_1p1_arm", + 600000, 1540000, 1, 1, 1200000, + 1, 0xF) }; + VCC1P0_CORE_PMIC: + axp22_dcdc3{PMIC_PDATA_INIT(14, + "axp228_1p0_core", + 600000, 1860000, 1, 1, 1200000, + 1, 0xF) }; + VCC_DCDC4: + axp22_dcdc4{PMIC_PDATA_INIT(15, + "axp228_1p5_sys", + 600000, 1540000, 1, 1, 1500000, + 1, 0xF) }; + VCC_DCDC5: + axp22_dcdc5{PMIC_PDATA_INIT(16, + "axp228_1p5_ddr", + 1000000, 2550000, 1, 1, 1500000, + 1, 0xF) }; + VCC_LDOIO0: + axp22_ldoio0{PMIC_PDATA_INIT(17, + "axp228_ldoio0", + 700000, 3300000, 0, 0, 1800000, + 0, 0xF) }; + VCC_LDOIO1: + axp22_ldoio1{PMIC_PDATA_INIT(18, + "axp228_ldoio1", + 700000, 3300000, 0, 0, 1000000, + 0, 0xF) }; + }; + }; + }; + + pinctrl@C0010000 { + key_power: key_power { + nexell,pins = "alive-0"; + nexell,pin-function = <0>; + nexell,pin-pull = <1>; + nexell,pin-strength = <0>; + }; + + touchpanel_irq: touchpanel-irq { + nexell,pins = "gpioc-16"; + nexell,pin-function = <1>; + nexell,pin-pull = <2>; + nexell,pin-strength = <0>; + }; + }; + + nexell_usbphy: nexell-usbphy@c0012000 { + status = "okay"; + }; + + ehci@c0030000 { + status = "okay"; + port@0 { + status = "okay"; + }; + }; + + ohci@c0020000 { + status = "okay"; + port@0 { + status = "okay"; + }; + }; + + dwc2otg@c0040000 { + gpios = <&gpio_d 21 0>; + status = "okay"; + }; + + gmac0:ethernet@c0060000 { + pinctrl-names = "default"; + pinctrl-0 = <&gmac_pins>; + + status = "okay"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + snps,phy-addr = <7>; + snps,reset-gpio = <&gpio_e 22 0>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 30000>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet_phy: ethernet-phy@3 { + reg = <3>; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + + i2c_0:i2c@c00a4000 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + es8316_codec: es8316@11 { + #sound-dai-cells = <0>; + compatible = "everest,es8316"; + reg = <0x11>; + }; + }; + + i2c_1:i2c@c00a5000 { + status = "okay"; + }; + + i2c_2:i2c@c00a6000 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + /* Note: touch sensors are registered by onewire */ + /*touchscreen@38 { + compatible = "edt,edt-ft5506"; + reg = <0x38>; + interrupt-parent = <&gpio_c>; + interrupts = <16 IRQ_TYPE_EDGE_FALLING>; + pinctrl-names = "default"; + pinctrl-0 = <&touchpanel_irq>; + touchscreen-size-x = <1280>; + touchscreen-size-y = <800>; + touchscreen-max-pressure = <255>; + };*/ + + /*touchscreen@46 { + compatible = "ite,it7260"; + reg = <0x46>; + interrupt-parent = <&gpio_c>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&touchpanel_irq>; + };*/ + }; + + pwm:pwm@c0018000 { + // block pwm3_pin - conflicts with spi0_miso (on spi0_bus) drawn on 2.54mm header + pinctrl-0 = <&pwm0_pin &pwm1_pin &pwm2_pin>; + samsung,pwm-outputs = <0>, <1>, <2>; + status = "okay"; + }; + + vip_1:vip@c0064000 { + status = "okay"; + }; + + clipper_1:clipper1@c0064000 { + status = "okay"; + pwms = <&pwm 1 41 0>; /* 1000000000/41 */ + interface_type = ; + pinctrl-names = "default"; + pinctrl-0 = <&vid1_data_clk &vid1_sync> ; + port = <0>; + external_sync = <0>; + data_order = ; + interlace = <0>; + regulator_names = "axp22_dldo2"; + regulator_voltages = <1800000>; + + gpios = <&gpio_c 4 0 + &gpio_c 5 0 + &gpio_c 6 0>; + + sensor { + type = ; + i2c_name = "SP2518"; + i2c_adapter = <0>; + addr = <0x30>; + }; + + power { + enable_seq = < + NX_ACTION_START NX_ACTION_TYPE_GPIO 2 1 0 NX_ACTION_END + NX_ACTION_START NX_ACTION_TYPE_PMIC 0 0 NX_ACTION_END + NX_ACTION_START NX_ACTION_TYPE_PMIC 1 0 NX_ACTION_END + NX_ACTION_START NX_ACTION_TYPE_GPIO 0 0 0 1 0 NX_ACTION_END + NX_ACTION_START NX_ACTION_TYPE_CLOCK 1 10 NX_ACTION_END + NX_ACTION_START NX_ACTION_TYPE_GPIO 0 0 0 NX_ACTION_END + NX_ACTION_START NX_ACTION_TYPE_GPIO 1 1 0 0 1 NX_ACTION_END + NX_ACTION_START NX_ACTION_TYPE_GPIO 1 1 100 NX_ACTION_END + >; + }; + }; + + dp_drm: display_drm { + status = "okay"; + ports { + port@0 { + reg = <0>; + back_color = < 0x0 >; + color_key = < 0x0 >; + /* Port 0 has two RGB planes and one video plane. These planes + * are arranged in z-order: RGB plane 0 is below plane 1, + * video plane may be set at any position in z-order. + * + * Possible names for RGB planes: "primary", "rgb", "cursor" + * Possible name for video plane: "video" + * Two RGB plane names and one video plane name may be specified in + * "plane-names" property. + * RGB plane "primary" will be used as root window. + * RGB plane "cursor" will be used for cursor. + * RGB plane "rgb" and video plane are overlay planes, normally + * not used by X-windows. + * + * Order of plane names specifies z-order of planes, top to bottom. + */ + plane-names = "cursor", "video", "primary"; + }; + port@1 { + reg = <1>; + back_color = < 0x0 >; + color_key = < 0x0 >; + /* Port 1 has one RGB plane and one video plane only. */ + plane-names = "video", "primary"; + }; + }; + }; + + dp_drm_hdmi: display_drm_hdmi { + ddc-i2c-bus = <&i2c_1>; + q_range = <1>; + status = "ok"; + }; + + dp_drm_rgb: display_drm_rgb { + remote-endpoint = <&rgb_panel>; + status = "okay"; + + dp_control { + clk_src_lv0 = <0>; + clk_div_lv0 = <16>; + clk_src_lv1 = <7>; + clk_div_lv1 = <1>; + out_format = <3>; + invert_field = <0>; + swap_rb = <0>; + yc_order = <0>; + delay_mask = < ((1<<0) | (1<<1) | (1<<2) | (1<<3)) >; + d_rgb_pvd = <0>; + d_hsync_cp1 = <0>; + d_vsync_fram = <0>; + d_de_cp2 = <7>; + vs_start_offset = <863>; + ev_start_offset = <863>; + vs_end_offset = <0>; + ev_end_offset = <0>; + }; + }; + + dp_drm_lvds: display_drm_lvds { + status = "ok"; + remote-endpoint = <&lvds_panel>; + dp_control { + clk_src_lv0 = <0>; + clk_div_lv0 = <16>; + clk_src_lv1 = <7>; + clk_div_lv1 = <1>; + out_format = <3>; + }; + }; + + rtc@c0010c00 { + status = "okay"; + }; + + i2s_0:i2s@c0055000 { + #sound-dai-cells = <1>; + sample-rate = <48000>; + frame-bit = <32>; + status = "okay"; + }; + + spdif_tx: spdiftx@c0059000 { + #sound-dai-cells = <1>; + status = "okay"; + }; + + adc:adc@c0053000 { + status = "okay"; + }; + + video-codec@c0080000 { + status = "okay"; + sram = <0 0>; + }; + + scaler@c0066000 { + status = "okay"; + }; + + nano-videodev { + compatible = "nexell,nano-videodev"; + reg = <0xc0102000 0x100>; + reg-names = "mlc.0"; + status = "okay"; + }; + + leds { + compatible = "gpio-leds"; + + green { + label = "green"; + gpios = <&gpio_b 12 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + }; /*** soc ***/ + + panel_lvds { + compatible = "nanopi,nano-panel"; + lvds; + status = "okay"; + + port { + lvds_panel: endpoint { + }; + }; + }; + + panel_rgb { + compatible = "nanopi,nano-panel"; + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&dp_rgb_vclk &dp_rgb_vsync &dp_rgb_hsync + &dp_rgb_de &dp_rgb_R &dp_rgb_G &dp_rgb_B>; + + port { + rgb_panel: endpoint { + }; + }; + }; + + gpio_key: gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&key_power>; + + power { + label = "Power"; + gpios = <&alive_0 0 0>; + linux,code = ; + gpio-key,wakeup; + }; + }; + + spdif_out: spdif-out { + #sound-dai-cells = <0>; + compatible = "linux,spdif-dit"; + status = "okay"; + }; + + /* Audio jack output configured to use with Nexell driver. Not used. + */ + es8316_sound: es8316@i2s0 { + compatible = "nexell,nexell-es8316"; + ch = <0>; + sample-rate = <48000>; + format = "S16"; + hpin-support = <0>; + hpin-gpio = <&gpio_b 27 0>; + hpin-level = <1>; + status = "disabled"; + }; + + /* HDMI output configured to use with Nexell driver. Not used also. + * + * Note that es8316_sound and spdif_sound cannot be enabled together + * because of nexell-pcm device used by both. + */ + spdif_sound { + compatible = "nexell,spdif-transceiver"; + sample_rate = <48000>; + format = "S16"; + status = "disabled"; + }; + + jack_sound { + compatible = "simple-audio-card"; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "Jack"; + simple-audio-card,widgets = + "Headphone", "Headphones", + "Microphone", "Microphone"; + simple-audio-card,routing = + "Headphones", "HPOL", + "Headphones", "HPOR", + "MIC1", "Microphone"; + status = "okay"; + + simple-audio-card,dai-link@0 { + format = "i2s"; + cpu { + sound-dai = <&i2s_0 0>; + }; + + codec { + sound-dai = <&es8316_codec>; + }; + }; + }; + + hdmi_sound { + compatible = "simple-audio-card"; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "HDMI"; + simple-audio-card,widgets = + "Headphone", "TV Out"; + simple-audio-card,routing = + "TV Out", "spdif-out"; + status = "okay"; + + simple-audio-card,dai-link@0 { + cpu { + sound-dai = <&spdif_tx 0>; + }; + + codec { + sound-dai = <&spdif_out>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + blue { + label = "blue"; + gpios = <&gpio_b 12 GPIO_ACTIVE_LOW>; + linux,default-trigger = "mmc1"; + }; + }; + + wifi_bcm4329 { /* wifi definition for bcmdhd.ko module */ + compatible = "nanopi,bcm4329"; + interrupt-parent = <&gpio_c>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + }; + + nanopi-thermistor { + compatible = "friendlyarm,nanopi-thermistor"; + status = "okay"; + + io-channels = <&adc 2>; + io-channel-names = "nanopi-thermistor"; + }; + + nanopi-onewire { + interrupt-parent = <&gic>; + compatible = "friendlyarm,onewire"; + + channel-gpio = <&gpio_c 15 0>; + reg = ; + interrupts = <0 IRQ_TIMER3 0>; + irq-timer = <3>; + }; + + onewire-touch { + compatible = "friendlyarm,onewire-touch"; + interrupt-parent = <&gpio_c>; + interrupts = <16 IRQ_TYPE_NONE>; + i2c-bus = <&i2c_2>; + pinctrl-names = "default"; + pinctrl-0 = <&touchpanel_irq>; + }; +}; + diff --git a/arch/arm64/configs/nanopim3_defconfig b/arch/arm64/configs/nanopim3_defconfig index 662657a2..fba15ac2 100644 --- a/arch/arm64/configs/nanopim3_defconfig +++ b/arch/arm64/configs/nanopim3_defconfig @@ -2032,8 +2032,8 @@ CONFIG_THERMAL_GOV_STEP_WISE=y # CONFIG_THERMAL_GOV_BANG_BANG is not set # CONFIG_THERMAL_GOV_USER_SPACE is not set # CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set -# CONFIG_CPU_THERMAL is not set -# CONFIG_THERMAL_EMULATION is not set +CONFIG_CPU_THERMAL=y +CONFIG_THERMAL_EMULATION=y # CONFIG_QORIQ_THERMAL is not set # @@ -2210,6 +2210,7 @@ CONFIG_REGULATOR_AXP228=y # CONFIG_REGULATOR_PV88080 is not set # CONFIG_REGULATOR_PV88090 is not set # CONFIG_REGULATOR_PWM is not set +CONFIG_REGULATOR_SPU1705=y # CONFIG_REGULATOR_TPS51632 is not set # CONFIG_REGULATOR_TPS62360 is not set # CONFIG_REGULATOR_TPS65023 is not set diff --git a/drivers/cpufreq/nexell-cpufreq.c b/drivers/cpufreq/nexell-cpufreq.c index 94a00121..f698a270 100644 --- a/drivers/cpufreq/nexell-cpufreq.c +++ b/drivers/cpufreq/nexell-cpufreq.c @@ -713,6 +713,7 @@ static void *nxp_cpufreq_make_table(struct platform_device *pdev, struct cpufreq_frequency_table *freq_table; struct cpufreq_asv_ops *ops = &asv_ops; unsigned long (*plat_tbs)[2] = NULL; + unsigned long plat_n_voltage = 0; int tb_size, asv_size = 0; int id = 0, n = 0; @@ -741,17 +742,22 @@ static void *nxp_cpufreq_make_table(struct platform_device *pdev, /* make frequency table with platform data */ if (asv_size > 0) { for (n = 0, id = 0; tb_size > id && asv_size > n; n++) { - if (plat_tbs) { - for (n = 0; asv_size > n; n++) { - if (plat_tbs[id][0] == - dvfs_tables[n][0]) { - dvfs_tables[id][0] = - dvfs_tables[n][0]; - dvfs_tables[id][1] = - dvfs_tables[n][1]; - break; - } - } + if (plat_tbs && plat_tbs[id][1] > 0) + plat_n_voltage = plat_tbs[id][1]; + + if (plat_n_voltage) { + dvfs_tables[id][0] = plat_tbs[id][0]; + dvfs_tables[id][1] = plat_n_voltage; + + } else if (plat_tbs) { + for (n = 0; asv_size > n; n++) { + if (plat_tbs[id][0] == dvfs_tables[n][0]) { + dvfs_tables[id][0] = dvfs_tables[n][0]; + dvfs_tables[id][1] = dvfs_tables[n][1]; + break; + } + } + } else { if (dvfs_tables[n][0] > FREQ_MAX_FREQ_KHZ) continue; @@ -775,6 +781,10 @@ static void *nxp_cpufreq_make_table(struct platform_device *pdev, } } + /* disabling ASV table to active user defined one */ + if (plat_n_voltage) + ops->get_voltage = NULL; + /* End table */ freq_table[id].frequency = CPUFREQ_TABLE_END; *table_size = id; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 32763d82..db3f7cb8 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -776,6 +776,12 @@ config REGULATOR_STM32_VREFBUF This driver can also be built as a module. If so, the module will be called stm32-vrefbuf. +config REGULATOR_SPU1705 + tristate "FriendlyElec SPU1705 regulator driver" + depends on I2C + help + Say Y here to support the voltage regulators on SPU1705 + config REGULATOR_TI_ABB tristate "TI Adaptive Body Bias on-chip LDO" depends on ARCH_OMAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 24b2ff3f..4e6ddfec 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -96,6 +96,7 @@ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o +obj-$(CONFIG_REGULATOR_SPU1705) += spu1705.o obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o diff --git a/drivers/regulator/spu1705.c b/drivers/regulator/spu1705.c new file mode 100644 index 00000000..b021e5d4 --- /dev/null +++ b/drivers/regulator/spu1705.c @@ -0,0 +1,596 @@ +/* + * Regulator driver for STM32 based PMIC chip + * + * Copyright (C) Guangzhou FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyarm.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct spu1705 { + struct device *dev; + struct mutex io_lock; + struct i2c_client *i2c; + int chip_id, chip_rev; + int pwm_en; + int num_regulators; + struct regulator_dev *rdev[SPU1705_NUM_REGULATORS]; + void (*pm_power_off)(void); +#if defined(CONFIG_REGULATOR_SPU1705_REBOOT) + struct notifier_block reboot_handler; + int blocked_uV; +#endif +}; + +static int spu1705_i2c_read(struct i2c_client *client, + unsigned char req, unsigned char *buf, int count) +{ + int ret; + + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &req, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = count, + .buf = buf, + }, + }; + + ret = i2c_transfer(client->adapter, &msgs[0], 2); + if (ret < 0) { + pr_err("spu1705: REQ 0x%02x: i2c xfer error %d\n", req, ret); + return ret; + } + + pr_debug("spu1705: resp %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]); + return 0; +} + +static int spu1705_i2c_write(struct i2c_client *client, + unsigned char req, unsigned char *buf, int count) +{ + int ret; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = count, + .buf = buf, + }, + }; + + ret = i2c_transfer(client->adapter, &msgs[0], 1); + if (ret < 0) { + pr_err("spu1705: REQ 0x%02x: i2c write error %d\n", req, ret); + return ret; + } + + return 0; +} + +/* Supported commands */ +#define SPU1705_GET_INFO 0x21 +#define SPU1705_GET_TIME 0x22 +#define SPU1705_GET_PWM 0x23 +#define SPU1705_SET_TIME 0x11 +#define SPU1705_SET_PWR 0x12 +#define SPU1705_SET_PWM 0x13 + +/* Supported voltages */ +#define SPU1705_MIN_uV 905000 +#define SPU1705_MAX_uV 1265000 +#define SPU1705_INIT_uV 1200000 +#define SPU1705_N_VOLTAGES 96 + +#define VOLT_STEP ((SPU1705_MAX_uV - SPU1705_MIN_uV) / SPU1705_N_VOLTAGES) + +static int spu1705_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) +{ + return (SPU1705_MAX_uV - (VOLT_STEP * index)); +} + +/* DCDC is always enabled */ +static int spu1705_dcdc_is_enabled(struct regulator_dev *dev) +{ + return 1; +} + +static int spu1705_dcdc_enable(struct regulator_dev *dev) +{ + return 0; +} + +static int spu1705_dcdc_disable(struct regulator_dev *dev) +{ + return 0; +} + +static int spu1705_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct spu1705 *priv = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - SPU1705_DCDC1; + unsigned char pwm[4] = { 0 }; + + if (!priv->pwm_en) { + dev_dbg(priv->dev, "get_voltage: %d (default)\n", SPU1705_INIT_uV); + return SPU1705_INIT_uV; + } + + mutex_lock(&priv->io_lock); + spu1705_i2c_read(priv->i2c, SPU1705_GET_PWM, pwm, 2); + mutex_unlock(&priv->io_lock); + + dev_dbg(priv->dev, "get_voltage: buck = %d, pwm = %d, vol = %d\n", + buck, pwm[buck], (SPU1705_MAX_uV - (VOLT_STEP * pwm[buck]))); + + return (SPU1705_MAX_uV - (VOLT_STEP * pwm[buck])); +} + +static int spu1705_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV, + unsigned int *selector) +{ + struct spu1705 *priv = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - SPU1705_DCDC1; + int index; + u8 buf[4]; + int ret; + + index = (SPU1705_MAX_uV - min_uV) / VOLT_STEP; + *selector = index; + +#if defined(CONFIG_REGULATOR_SPU1705_REBOOT) + if (unlikely(min_uV < priv->blocked_uV)) { + dev_dbg(priv->dev, "voltage blocked to %d mV\n", priv->blocked_uV/1000); + return 0; + } +#endif + + mutex_lock(&priv->io_lock); + + buf[0] = SPU1705_SET_PWM; + buf[1] = (buck + 1) & 0xff; + buf[2] = index & 0xff; + spu1705_i2c_write(priv->i2c, SPU1705_SET_PWM, buf, 3); + priv->pwm_en = 1; + + /* verify write */ + buf[0] = 0; + buf[1] = 0; + ret = spu1705_i2c_read(priv->i2c, SPU1705_GET_PWM, buf, 2); + + mutex_unlock(&priv->io_lock); + + if (ret < 0 || buf[buck] != index) + return -EIO; + + dev_dbg(priv->dev, "set DCDC%d (%d, %d) mV --> sel %d\n", buck, + min_uV/1000, max_uV/1000, buf[buck]); + return 0; +} + +static struct regulator_ops spu1705_dcdc_ops = { + .list_voltage = spu1705_dcdc_list_voltage, + .is_enabled = spu1705_dcdc_is_enabled, + .enable = spu1705_dcdc_enable, + .disable = spu1705_dcdc_disable, + .get_voltage = spu1705_dcdc_get_voltage, + .set_voltage = spu1705_dcdc_set_voltage, +}; + +static struct regulator_desc regulators[] = { + { + .name = "DCDC1", + .id = SPU1705_DCDC1, + .ops = &spu1705_dcdc_ops, + .n_voltages = SPU1705_N_VOLTAGES, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC2", + .id = SPU1705_DCDC2, + .ops = &spu1705_dcdc_ops, + .n_voltages = SPU1705_N_VOLTAGES, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, +}; + +static int spu1705_dt_parse_pdata(struct spu1705 *priv, + struct spu1705_platform_data *pdata) +{ + struct device *dev = priv->dev; + struct device_node *regulators_np, *reg_np; + struct spu1705_regulator_subdev *rdata; + int i, ret; + + regulators_np = of_get_child_by_name(dev->of_node, "regulators"); + if (!regulators_np) { + dev_err(dev, "could not find regulators sub-node\n"); + return -EINVAL; + } + + /* count the number of regulators to be supported in pmic */ + ret = of_get_child_count(regulators_np); + if (ret <= 0) { + dev_err(dev, "Error parsing regulator init data, %d\n", ret); + return -EINVAL; + } + + rdata = devm_kzalloc(dev, sizeof(*rdata) * ret, GFP_KERNEL); + if (!rdata) { + of_node_put(regulators_np); + return -ENOMEM; + } + + pdata->num_regulators = ret; + pdata->regulators = rdata; + + for_each_child_of_node(regulators_np, reg_np) { + for (i = 0; i < ARRAY_SIZE(regulators); i++) + if (!of_node_cmp(reg_np->name, regulators[i].name)) + break; + + if (i == ARRAY_SIZE(regulators)) { + dev_warn(dev, "don't know how to configure regulator %s\n", + reg_np->name); + continue; + } + + rdata->id = i; + rdata->initdata = of_get_regulator_init_data(dev, reg_np, ®ulators[i]); + rdata->reg_node = reg_np; + rdata++; + } + + of_node_put(regulators_np); + + return 0; +} + +static int setup_regulators(struct spu1705 *priv, + struct spu1705_platform_data *pdata) +{ + struct regulator_config config = { }; + int i, err; + + priv->num_regulators = pdata->num_regulators; + + for (i = 0; i < pdata->num_regulators; i++) { + int id = pdata->regulators[i].id; + + config.dev = priv->dev; + config.driver_data = priv; + config.init_data = pdata->regulators[i].initdata; + config.of_node = pdata->regulators[i].reg_node; + + priv->rdev[i] = devm_regulator_register(priv->dev, ®ulators[id], + &config); + if (IS_ERR(priv->rdev[i])) { + err = PTR_ERR(priv->rdev[i]); + dev_err(priv->dev, "failed to register regulator %d, err = %d\n", + i, err); + return err; + + } + } + + return 0; +} + +/* Power On/Off support */ +static struct i2c_client *pm_i2c; + +static void spu1705_power_off(void) +{ + struct spu1705 *priv = i2c_get_clientdata(pm_i2c); + u8 buf[4]; + + buf[0] = SPU1705_SET_PWR; + buf[1] = 0x01; + spu1705_i2c_write(pm_i2c, SPU1705_SET_PWR, buf, 2); + + pr_info("spu1705: power off\n"); + + if (priv->pm_power_off) + priv->pm_power_off(); +} + +#if defined(CONFIG_REGULATOR_SPU1705_REBOOT) +static int spu1705_restart_handle(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct spu1705 *priv = + container_of(this, struct spu1705, reboot_handler); + unsigned int sel; + int i; + + priv->blocked_uV = SPU1705_INIT_uV; + + for (i = 0; i < priv->num_regulators; i++) + spu1705_dcdc_set_voltage(priv->rdev[i], + SPU1705_INIT_uV, SPU1705_INIT_uV, &sel); + + return NOTIFY_DONE; +} +#endif + +#define to_i2c_client(d) container_of(d, struct i2c_client, dev) + +static inline void spu1705_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[0] = tm->tm_hour; + data[1] = tm->tm_min; + data[2] = tm->tm_sec; +} + +static ssize_t spu1705_sysfs_show_wakealarm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spu1705 *priv = dev_get_drvdata(dev); + u8 tm[8]; + ssize_t n; + int ret; + + mutex_lock(&priv->io_lock); + ret = spu1705_i2c_read(priv->i2c, SPU1705_GET_TIME, tm, 7); + mutex_unlock(&priv->io_lock); + + if (ret < 0) + return -EIO; + + n = sprintf(buf, "%02d:%02d:%02d", tm[1], tm[2], tm[3]); + if (tm[0]) + n += sprintf(buf + n, " %02d:%02d:%02d\n", tm[4], tm[5], tm[6]); + else + n += sprintf(buf + n, " disabled\n"); + + return n; +} + +#define SPU1705_ALARM_MIN 60 + +static ssize_t spu1705_sysfs_set_wakealarm(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) +{ + struct spu1705 *priv = dev_get_drvdata(dev); + struct rtc_time tm; + struct timeval tv; + unsigned long alarm; + u8 data[8]; + int count = 8; + + do_gettimeofday(&tv); + rtc_time_to_tm(tv.tv_sec, &tm); + spu1705_tm_to_data(&tm, &data[2]); + + alarm = simple_strtoul(buf, NULL, 0); + if (alarm > SPU1705_ALARM_MIN) { + data[1] = 1; + tv.tv_sec += alarm; + rtc_time_to_tm(tv.tv_sec, &tm); + spu1705_tm_to_data(&tm, &data[5]); + dev_info(dev, "wake alarm: %02d:%02d:%02d\n", tm.tm_hour, tm.tm_min, tm.tm_sec); + + } else if (alarm == 0) { + data[1] = 0; + count = 2; + dev_info(dev, "wake alarm: disabled\n"); + + } else { + dev_err(dev, "invalid alarm %lu (0: disable, >%d: enable)\n", + alarm, SPU1705_ALARM_MIN); + return -EINVAL; + } + + mutex_lock(&priv->io_lock); + + data[0] = SPU1705_SET_TIME; + spu1705_i2c_write(priv->i2c, SPU1705_SET_TIME, data, count); + + mutex_unlock(&priv->io_lock); + + return n; +} + +static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, + spu1705_sysfs_show_wakealarm, spu1705_sysfs_set_wakealarm); + +static void spu1705_sysfs_add_device(struct spu1705 *priv) +{ + int err; + + err = device_create_file(priv->dev, &dev_attr_wakealarm); + if (err) + dev_err(priv->dev, "failed to create alarm attribute, %d\n", err); +} + +static int sp1705_identify_chip(struct spu1705 *priv) +{ + unsigned char id[4] = { 0 }; + + if (spu1705_i2c_read(priv->i2c, SPU1705_GET_INFO, id, 4) < 0) + return -1; + + if (!id[0] || !id[1]) + return -1; + + priv->chip_id = id[0]; + priv->chip_rev = id[1] * 100 + id[2]; + priv->pwm_en = id[3]; + + return 0; +} + +static int spu1705_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct spu1705_platform_data *pdata = client->dev.platform_data; + struct spu1705 *priv; + int ret; + + priv = devm_kzalloc(&client->dev, sizeof(struct spu1705), + GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + mutex_init(&priv->io_lock); + priv->i2c = client; + priv->dev = &client->dev; + + if (IS_ENABLED(CONFIG_OF) && priv->dev->of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct spu1705_platform_data), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "could not allocate memory for pdata\n"); + return -ENOMEM; + } + + ret = spu1705_dt_parse_pdata(priv, pdata); + if (ret < 0) + return ret; + } + + if (!pdata) { + dev_err(&client->dev, "No platform init data supplied\n"); + return -ENODEV; + } + + if (sp1705_identify_chip(priv) < 0) { + dev_err(&client->dev, "failed to detect chip\n"); + ret = -ENODEV; + goto err_detect; + } + + ret = setup_regulators(priv, pdata); + if (ret < 0) + goto err_detect; + + i2c_set_clientdata(client, priv); + + /* PM hookup */ + if (pm_power_off) + priv->pm_power_off = pm_power_off; + pm_i2c = client; + pm_power_off = spu1705_power_off; + +#if defined(CONFIG_REGULATOR_SPU1705_REBOOT) + priv->reboot_handler.notifier_call = spu1705_restart_handle; + priv->reboot_handler.priority = 192; + ret = register_reboot_notifier(&priv->reboot_handler); + if (ret) { + dev_err(&client->dev, "can't register restart notifier, %d\n", ret); + return ret; + } +#endif + + spu1705_sysfs_add_device(priv); + + dev_info(&client->dev, "found chip 0x%02x, rev %04d\n", + priv->chip_id, priv->chip_rev); + return 0; + +err_detect: + return ret; +} + +static int spu1705_i2c_remove(struct i2c_client *i2c) +{ + struct spu1705 *priv = i2c_get_clientdata(i2c); + unsigned int sel; + int i; + +#if defined(CONFIG_REGULATOR_SPU1705_REBOOT) + if (unregister_reboot_notifier(&priv->reboot_handler)) + dev_err(priv->dev, "can't unregister restart handler\n"); + return -ENODEV; + } +#endif + + pm_power_off = priv->pm_power_off; + + for (i = 0; i < priv->num_regulators; i++) + spu1705_dcdc_set_voltage(priv->rdev[i], + SPU1705_INIT_uV, SPU1705_INIT_uV, &sel); + + return 0; +} + +static const struct i2c_device_id spu1705_i2c_id[] = { + { "fe-pmu", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, spu1705_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id spu1705_of_match[] = { + { .compatible = "spu1705", }, + {}, +}; +MODULE_DEVICE_TABLE(of, spu1705_of_match); +#endif + +static struct i2c_driver spu1705_i2c_driver = { + .driver = { + .name = "spu1705", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(spu1705_of_match), + }, + .probe = spu1705_i2c_probe, + .remove = spu1705_i2c_remove, + .id_table = spu1705_i2c_id, +}; + +static int __init spu1705_module_init(void) +{ + int ret; + + ret = i2c_add_driver(&spu1705_i2c_driver); + if (ret != 0) + pr_err("Failed to register I2C driver: %d\n", ret); + + return ret; +} +module_init(spu1705_module_init); + +static void __exit spu1705_module_exit(void) +{ + i2c_del_driver(&spu1705_i2c_driver); +} +module_exit(spu1705_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Guangzhou FriendlyElec Computer Tech. Co., Ltd."); +MODULE_DESCRIPTION("SPU1705 PMIC driver"); diff --git a/include/linux/regulator/spu1705.h b/include/linux/regulator/spu1705.h new file mode 100644 index 00000000..03fce65e --- /dev/null +++ b/include/linux/regulator/spu1705.h @@ -0,0 +1,44 @@ +/* + * STM32 based PMIC chip client interface + * + * Copyright (C) Guangzhou FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyarm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __LINUX_REGULATOR_SPU1705_H +#define __LINUX_REGULATOR_SPU1705_H + +#include + +#define SPU1705_DCDC1 0 +#define SPU1705_DCDC2 1 + +#define SPU1705_NUM_REGULATORS 2 + + +struct spu1705_regulator_subdev { + int id; + struct regulator_init_data *initdata; + struct device_node *reg_node; +}; + +struct spu1705_platform_data { + int num_regulators; + struct spu1705_regulator_subdev *regulators; +}; + +#endif /* __LINUX_REGULATOR_SPU1705_H */