From b8d02950d8c50611c2784c7a40e0b3003acf8d49 Mon Sep 17 00:00:00 2001 From: guowenxue <guowenxue@gmail.com> Date: Thu, 18 Jul 2024 09:38:11 +0800 Subject: [PATCH] Patch:IGKBoard-IMX8MP: Add HDMI support --- kernel/patches/igkboard-imx8mp/linux-imx-lf-6.1.36-2.1.0.patch | 1105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 1,029 insertions(+), 76 deletions(-) diff --git a/kernel/patches/igkboard-imx8mp/linux-imx-lf-6.1.36-2.1.0.patch b/kernel/patches/igkboard-imx8mp/linux-imx-lf-6.1.36-2.1.0.patch index 7a5846a..35f779b 100644 --- a/kernel/patches/igkboard-imx8mp/linux-imx-lf-6.1.36-2.1.0.patch +++ b/kernel/patches/igkboard-imx8mp/linux-imx-lf-6.1.36-2.1.0.patch @@ -10,10 +10,10 @@ +dtb-$(CONFIG_ARCH_MXC) += igkboard-imx8mp.dtb diff --git a/arch/arm64/boot/dts/freescale/igkboard-imx8mp.dts b/arch/arm64/boot/dts/freescale/igkboard-imx8mp.dts new file mode 100644 -index 000000000..5b20a7cdc +index 000000000..016d92023 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/igkboard-imx8mp.dts -@@ -0,0 +1,471 @@ +@@ -0,0 +1,829 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree Source for LingYun IGKBoard(IoT Gateway Kits Board) - imx8mp @@ -52,8 +52,78 @@ + sysled { + label = "sysled"; + gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>; -+ default-state = "heartbeat"; ++ default-state = "on"; ++ linux,default-trigger = "heartbeat"; + }; ++ ++ ledred { ++ label = "redled"; ++ gpios = <&gpio3 21 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ ++ ledgreen { ++ label = "greenled"; ++ gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ ++ ledblue { ++ label = "blueled"; ++ gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; ++ default-state = "on"; ++ linux,default-trigger = "timer"; ++ }; ++ }; ++ ++ keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_keys>; ++ status = "okay"; ++ ++ key1 { ++ label = "K1"; ++ gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; ++ linux,code = <BTN_1>; ++ }; ++ ++ key2 { ++ label = "K2"; ++ gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; ++ linux,code = <BTN_2>; ++ }; ++ ++ key3 { ++ label = "K3"; ++ gpios = <&gpio5 26 GPIO_ACTIVE_LOW>; ++ linux,code = <BTN_3>; ++ }; ++ ++ key4 { ++ label = "K4"; ++ gpios = <&gpio5 27 GPIO_ACTIVE_LOW>; ++ linux,code = <BTN_4>; ++ }; ++ }; ++ ++ sound-wm8960 { ++ compatible = "fsl,imx-audio-wm8960"; ++ model = "wm8960-audio"; ++ audio-cpu = <&sai3>; ++ audio-codec = <&codec>; ++ audio-asrc = <&easrc>; ++ //hp-det-gpio = <&gpio4 29 0>; ++ audio-routing = ++ "Headphone Jack", "HP_L", ++ "Headphone Jack", "HP_R", ++ "Ext Spk", "SPK_LP", ++ "Ext Spk", "SPK_LN", ++ "Ext Spk", "SPK_RP", ++ "Ext Spk", "SPK_RN", ++ "LINPUT1", "Mic Jack", ++ "LINPUT3", "Mic Jack", ++ "Mic Jack", "MICB"; + }; +}; + @@ -100,7 +170,6 @@ + | TF Card on SD2 | + +------------------------+*/ + -+#if 0 +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; @@ -111,7 +180,6 @@ + no-1-8-v; + status = "okay"; +}; -+#endif + +/*+------------------------+ + | Typec USB for download | @@ -207,16 +275,212 @@ +}; + +/*+------------------------+ ++ | Misc Devices | ++ +------------------------+*/ ++ ++/* Buzzer */ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm1>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++ ++ codec: wm8960@1a { ++ compatible = "wlf,wm8960"; ++ reg = <0x1a>; ++ clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1>; ++ clock-names = "mclk"; ++ wlf,shared-lrclk; ++ }; ++ ++ ms1112@4a { ++ compatible = "ms,ms1112"; ++ reg = <0x4a>; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ channel@2 { ++ reg = <2>; ++ ti,gain = <0>; ++ ti,datarate = <3>; ++ ti,mode = <1>; ++ }; ++ ++ channel@3{ ++ reg = <3>; ++ ti,gain = <0>; ++ ti,datarate = <3>; ++ ti,mode = <1>; ++ }; ++ }; ++ ++ rtc1208@6f { ++ compatible = "isil,isl1208"; ++ reg = <0x6f>; ++ status = "okay"; ++ }; ++}; ++ ++/*+------------------------+ ++ | WM8960 Audio Codec | ++ +------------------------+*/ ++ ++&sai3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sai3>; ++ assigned-clocks = <&clk IMX8MP_CLK_SAI3>; ++ assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; ++ assigned-clock-rates = <12288000>; ++ clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_IPG>, <&clk IMX8MP_CLK_DUMMY>, ++ <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1>, <&clk IMX8MP_CLK_DUMMY>, ++ <&clk IMX8MP_CLK_DUMMY>; ++ clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; ++ fsl,sai-mclk-direction-output; ++ status = "okay"; ++}; ++ ++&easrc { ++ fsl,asrc-rate = <48000>; ++ status = "okay"; ++}; ++ ++&xcvr { ++ #sound-dai-cells = <0>; ++ status = "okay"; ++}; ++ ++&sdma2 { ++ status = "okay"; ++}; ++ ++/*+------------------------+ ++ | HDMI Display | ++ +------------------------+*/ ++ ++&irqsteer_hdmi { ++ status = "okay"; ++}; ++ ++&hdmi_blk_ctrl { ++ status = "okay"; ++}; ++ ++&hdmi_pavi { ++ status = "okay"; ++}; ++ ++&hdmi { ++ status = "okay"; ++}; ++ ++&hdmiphy { ++ status = "okay"; ++}; ++ ++&lcdif3 { ++ status = "okay"; ++ ++ thres-low = <1 2>; /* (FIFO * 1 / 2) */ ++ thres-high = <3 4>; /* (FIFO * 3 / 4) */ ++}; ++ ++/*+------------------------+ ++ | CAN/RS485 interface | ++ +------------------------+*/ ++ ++/* RS485 */ ++&uart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart3>; ++ status = "okay"; ++}; ++ ++/* CAN */ ++&flexcan1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan1>; ++ status = "okay"; ++}; ++ ++&flexcan2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan2>; ++ status = "okay"; ++}; ++ ++/*+------------------------+ ++ | MikroBUS interface | ++ +------------------------+*/ ++ ++/* Same as RPi 40Pin extend interface: #32 */ ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm3>; ++ status = "okay"; ++}; ++ ++/* Same as RPi 40Pin extend interface: #19, #21, #23, #24 */ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ assigned-clocks = <&clk IMX8MP_CLK_UART1>; ++ assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>; ++ status = "okay"; ++}; ++ ++/* Same as RPi 40Pin extend interface */ ++&ecspi2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ fsl,spi-num-chipselects = <1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi2>; ++ cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++ ++ spidev@0 { ++ compatible = "fsl,spidev", "semtech,sx1301"; ++ reg = <0>; ++ spi-max-frequency = <2000000>; ++ }; ++}; ++ ++/* Same as RPi 40Pin extend interface: #3, #5 */ ++&i2c5 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c5>; ++ status = "okay"; ++ ++ hdc1080@40 { ++ compatible = "ti,hdc1080"; ++ reg = <0x40>; ++ status = "okay"; ++ }; ++ ++ eeprom@50 { ++ compatible = "microchip,24c32", "atmel,24c32"; ++ reg = <0x50>; ++ pagesize = <32>; ++ num-addresses = <8>; ++ }; ++}; ++ ++/*+------------------------+ + | PCA9450CHN PMIC | + +------------------------+*/ + +&i2c1 { + clock-frequency = <400000>; -+ pinctrl-names = "default", "gpio"; ++ pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; -+ pinctrl-1 = <&pinctrl_i2c1_gpio>; -+ scl-gpios = <&gpio5 14 GPIO_ACTIVE_HIGH>; -+ sda-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; + status = "okay"; + + pmic@25 { @@ -317,16 +581,62 @@ + +&iomuxc { + pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; + -+ pinctrl_leds: ledsgrp { ++ pinctrl_hog: hoggrp { + fsl,pins = < -+ MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x140 ++ MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL 0x400001c2 ++ MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA 0x400001c2 ++ MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD 0x40000010 ++ MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC 0x40000010 ++ /* ++ * M.2 pin20 & pin21 need to be set to 11 for 88W9098 to select the ++ * default Reference Clock Frequency ++ */ ++ MX8MP_IOMUXC_SD1_DATA7__GPIO2_IO09 0x1c4 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B 0xc6 ++ >; ++ }; ++ ++ pinctrl_leds: ledsgrp { ++ fsl,pins = < ++ MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x140 ++ MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14 0x140 ++ MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09 0x140 ++ MX8MP_IOMUXC_SAI5_RXD0__GPIO3_IO21 0x140 ++ >; ++ }; ++ ++ pinctrl_keys: keysgrp { ++ fsl,pins = < ++ MX8MP_IOMUXC_ECSPI1_MISO__GPIO5_IO08 0x140 ++ MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09 0x140 ++ MX8MP_IOMUXC_UART3_RXD__GPIO5_IO26 0x140 ++ MX8MP_IOMUXC_UART3_TXD__GPIO5_IO27 0x140 ++ >; ++ }; ++ ++ pinctrl_pwm1: pwm1grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_GPIO1_IO08__PWM1_OUT 0x116 ++ >; ++ }; ++ ++ pinctrl_pwm3: pwm3grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_SAI5_RXC__PWM3_OUT 0x116 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x140 ++ MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x140 + >; + }; + @@ -337,6 +647,36 @@ + >; + }; + ++ pinctrl_uart3: uart3grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX 0x82 ++ MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX 0x82 ++ >; ++ }; ++ ++ pinctrl_flexcan1: flexcan1grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_SPDIF_TX__CAN1_TX 0x154 ++ MX8MP_IOMUXC_SPDIF_RX__CAN1_RX 0x154 ++ >; ++ }; ++ ++ pinctrl_flexcan2: flexcan2grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX 0x154 ++ MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX 0x154 ++ >; ++ }; ++ ++ pinctrl_ecspi2: ecspi2grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x82 ++ MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x82 ++ MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x82 ++ MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13 0x40000 ++ >; ++ }; ++ + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c3 @@ -344,10 +684,28 @@ + >; + }; + -+ pinctrl_i2c1_gpio: i2c1grp-gpio { ++ pinctrl_i2c2: i2c2grp { + fsl,pins = < -+ MX8MP_IOMUXC_I2C1_SCL__GPIO5_IO14 0x1c3 -+ MX8MP_IOMUXC_I2C1_SDA__GPIO5_IO15 0x1c3 ++ MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c2 ++ MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA 0x400001c2 ++ >; ++ }; ++ ++ pinctrl_i2c5: i2c5grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_SD1_CMD__I2C5_SDA 0x400001c2 ++ MX8MP_IOMUXC_SD1_CLK__I2C5_SCL 0x400001c2 ++ >; ++ }; ++ ++ pinctrl_sai3: sai3grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC 0xd6 ++ MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK 0xd6 ++ MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00 0xd6 ++ MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00 0xd6 ++ MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK 0xd6 ++ MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29 0xd6 + >; + }; + @@ -487,10 +845,10 @@ +}; diff --git a/arch/arm64/configs/igkboard-imx8mp_defconfig b/arch/arm64/configs/igkboard-imx8mp_defconfig new file mode 100644 -index 000000000..6b6fe01d9 +index 000000000..b0f923742 --- /dev/null +++ b/arch/arm64/configs/igkboard-imx8mp_defconfig -@@ -0,0 +1,1118 @@ +@@ -0,0 +1,1103 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y @@ -518,10 +876,12 @@ +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y ++CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y ++CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PROFILING=y +CONFIG_ARCH_KEEMBAY=y @@ -652,7 +1012,8 @@ +CONFIG_QRTR_SMD=m +CONFIG_QRTR_TUN=m +CONFIG_NET_PKTGEN=m -+CONFIG_CAN=m ++CONFIG_CAN=y ++CONFIG_CAN_ISOTP=y +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y @@ -677,8 +1038,6 @@ +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=y +CONFIG_MAC80211_LEDS=y -+CONFIG_NET_9P=y -+CONFIG_NET_9P_VIRTIO=y +CONFIG_NFC=m +CONFIG_NFC_NCI=m +CONFIG_NFC_S3FWRN5_I2C=m @@ -747,8 +1106,7 @@ +CONFIG_BLK_DEV_NVME=y +CONFIG_SRAM=y +CONFIG_PCI_ENDPOINT_TEST=y -+CONFIG_EEPROM_AT24=m -+CONFIG_EEPROM_AT25=m ++CONFIG_EEPROM_AT24=y +CONFIG_UACCE=m +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y @@ -836,7 +1194,7 @@ +CONFIG_REALTEK_PHY=y +CONFIG_ROCKCHIP_PHY=y +CONFIG_VITESSE_PHY=y -+CONFIG_CAN_FLEXCAN=m ++CONFIG_CAN_FLEXCAN=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS_MUX_MULTIPLEXER=y +CONFIG_MDIO_BUS_MUX_MMIOREG=y @@ -950,22 +1308,8 @@ +CONFIG_PINCTRL_IMX8ULP=y +CONFIG_PINCTRL_IMX93=y +CONFIG_PINCTRL_S32V234=y -+CONFIG_GPIO_ALTERA=m -+CONFIG_GPIO_DWAPB=y -+CONFIG_GPIO_IMX_RPMSG=y -+CONFIG_GPIO_MB86S7X=y -+CONFIG_GPIO_MPC8XXX=y ++CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_MXC=y -+CONFIG_GPIO_PL061=y -+CONFIG_GPIO_WCD934X=m -+CONFIG_GPIO_XGENE=y -+CONFIG_GPIO_MAX732X=y -+CONFIG_GPIO_PCA953X=y -+CONFIG_GPIO_PCA953X_IRQ=y -+CONFIG_GPIO_ADP5585=y -+CONFIG_GPIO_BD9571MWV=m -+CONFIG_GPIO_MAX77620=y -+CONFIG_GPIO_SL28CPLD=m +CONFIG_POWER_RESET_BRCMSTB=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y @@ -1052,6 +1396,7 @@ +CONFIG_RC_DEVICES=y +CONFIG_IR_GPIO_CIR=m +CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_SUPPORT_FILTER=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y @@ -1145,6 +1490,7 @@ +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_LP855X=m +CONFIG_BACKLIGHT_GPIO=y ++CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set @@ -1204,6 +1550,19 @@ +CONFIG_SND_SOC_LPASS_VA_MACRO=m +CONFIG_SND_SIMPLE_CARD=y +CONFIG_SND_AUDIO_GRAPH_CARD=y ++CONFIG_HID_A4TECH=y ++CONFIG_HID_APPLE=y ++CONFIG_HID_BELKIN=y ++CONFIG_HID_CHERRY=y ++CONFIG_HID_CHICONY=y ++CONFIG_HID_CYPRESS=y ++CONFIG_HID_EZKEY=y ++CONFIG_HID_ITE=y ++CONFIG_HID_KENSINGTON=y ++CONFIG_HID_LOGITECH=y ++CONFIG_HID_REDRAGON=y ++CONFIG_HID_MICROSOFT=y ++CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=m +CONFIG_I2C_HID_ACPI=m +CONFIG_I2C_HID_OF=m @@ -1318,29 +1677,8 @@ +CONFIG_EDAC_LAYERSCAPE=m +CONFIG_EDAC_SYNOPSYS=y +CONFIG_RTC_CLASS=y -+CONFIG_RTC_DRV_DS1307=m -+CONFIG_RTC_DRV_HYM8563=m -+CONFIG_RTC_DRV_MAX77686=y -+CONFIG_RTC_DRV_RK808=m -+CONFIG_RTC_DRV_PCF85363=m -+CONFIG_RTC_DRV_M41T80=m -+CONFIG_RTC_DRV_RX8581=m -+CONFIG_RTC_DRV_RV3028=m -+CONFIG_RTC_DRV_RV8803=m -+CONFIG_RTC_DRV_S5M=y -+CONFIG_RTC_DRV_DS3232=y -+CONFIG_RTC_DRV_PCF2127=m -+CONFIG_RTC_DRV_PCF2131=m -+CONFIG_RTC_DRV_EFI=y -+CONFIG_RTC_DRV_CROS_EC=y -+CONFIG_RTC_DRV_FSL_FTM_ALARM=m -+CONFIG_RTC_DRV_PL031=y -+CONFIG_RTC_DRV_SNVS=y -+CONFIG_RTC_DRV_BBNSM=y -+CONFIG_RTC_DRV_IMX_SC=y -+CONFIG_RTC_DRV_IMX_RPMSG=y ++CONFIG_RTC_DRV_ISL1208=y +CONFIG_DMADEVICES=y -+CONFIG_BCM_SBA_RAID=m +CONFIG_FSL_EDMA=y +CONFIG_FSL_QDMA=m +CONFIG_FSL_EDMA_V3=y @@ -1431,23 +1769,20 @@ +CONFIG_IIO_ST_ACCEL_3AXIS=m +CONFIG_IMX8QXP_ADC=y +CONFIG_IMX93_ADC=y -+CONFIG_MAX9611=m -+CONFIG_QCOM_SPMI_VADC=m -+CONFIG_QCOM_SPMI_ADC5=m -+CONFIG_IIO_CROS_EC_SENSORS_CORE=m -+CONFIG_IIO_CROS_EC_SENSORS=m -+CONFIG_FXAS21002C=y ++CONFIG_MS1112=y ++CONFIG_BMG160=m +CONFIG_IIO_ST_GYRO_3AXIS=m ++CONFIG_MAX30100=m ++CONFIG_MAX30102=m ++CONFIG_DHT11=y ++CONFIG_HDC100X=y ++CONFIG_HTS221=y +CONFIG_FXOS8700_I2C=y +CONFIG_RPMSG_IIO_PEDOMETER=m +CONFIG_INV_MPU6050_I2C=m +CONFIG_IIO_ST_LSM6DSX=y -+CONFIG_IIO_CROS_EC_LIGHT_PROX=m +CONFIG_SENSORS_ISL29018=y -+CONFIG_VCNL4000=m -+CONFIG_VCNL4035=m +CONFIG_IIO_ST_MAGN_3AXIS=m -+CONFIG_IIO_CROS_EC_BARO=m +CONFIG_MPL3115=y +CONFIG_MS5611=m +CONFIG_MS5611_I2C=m @@ -1501,8 +1836,6 @@ +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y -+CONFIG_BTRFS_FS=m -+CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y @@ -1511,21 +1844,28 @@ +CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m +CONFIG_VFAT_FS=y ++CONFIG_EXFAT_FS=y ++CONFIG_NTFS_FS=y ++CONFIG_NTFS_RW=y ++CONFIG_NTFS3_FS=y ++CONFIG_NTFS3_64BIT_CLUSTER=y ++CONFIG_NTFS3_LZX_XPRESS=y ++CONFIG_NTFS3_FS_POSIX_ACL=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_EFIVAR_FS=y +CONFIG_JFFS2_FS=y -+CONFIG_UBIFS_FS=y -+CONFIG_SQUASHFS=y -+CONFIG_SQUASHFS_XZ=y +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y -+CONFIG_9P_FS=y +CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_CODEPAGE_936=y ++CONFIG_NLS_CODEPAGE_950=y ++CONFIG_NLS_CODEPAGE_874=y +CONFIG_NLS_ISO8859_1=y ++CONFIG_NLS_UTF8=y +CONFIG_TRUSTED_KEYS=m +# CONFIG_TRUSTED_KEYS_TPM is not set +# CONFIG_TRUSTED_KEYS_TEE is not set @@ -1553,12 +1893,16 @@ +CONFIG_CRYPTO_CHACHA20POLY1305=m +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_TLS=m ++CONFIG_CRYPTO_BLAKE2B=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_STREEBOG=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m ++CONFIG_CRYPTO_XXHASH=m ++CONFIG_CRYPTO_LZO=y ++CONFIG_CRYPTO_ZSTD=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m @@ -1591,7 +1935,6 @@ +CONFIG_CRC8=y +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_PRINTK_TIME=y -+CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +CONFIG_DEBUG_INFO_REDUCED=y +CONFIG_MAGIC_SYSRQ=y @@ -1609,3 +1952,613 @@ +CONFIG_CORESIGHT_CPU_DEBUG=m +CONFIG_CORESIGHT_CTI=m +CONFIG_MEMTEST=y +diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig +index 3946eb595..15278c13c 100644 +--- a/drivers/iio/adc/Kconfig ++++ b/drivers/iio/adc/Kconfig +@@ -1164,6 +1164,18 @@ config TI_ADC161S626 + This driver can also be built as a module. If so, the module will be + called ti-adc161s626. + ++config MS1112 ++ tristate "Ruimeng Technology MS1112 ADC" ++ depends on I2C ++ select IIO_BUFFER ++ select IIO_TRIGGERED_BUFFER ++ help ++ If you say yes here you get support for Ruimeng Technology ADS1015 ++ ADC chip. ++ ++ This driver can also be built as a module. If so, the module will be ++ called ms1112. ++ + config TI_ADS1015 + tristate "Texas Instruments ADS1015 ADC" + depends on I2C +diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile +index 83233c38c..f403164cf 100644 +--- a/drivers/iio/adc/Makefile ++++ b/drivers/iio/adc/Makefile +@@ -104,6 +104,7 @@ obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o + obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o + obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o + obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o ++obj-$(CONFIG_MS1112) += ms1112.o + obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o + obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o + obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o +diff --git a/drivers/iio/adc/ms1112.c b/drivers/iio/adc/ms1112.c +new file mode 100644 +index 000000000..cf8ea5c66 +--- /dev/null ++++ b/drivers/iio/adc/ms1112.c +@@ -0,0 +1,569 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * MS1112 - Ruimeng Technology Analog-to-Digital Converter ++ * ++ * Copyright (c) 2024, LingYun IoT System Studio. ++ * ++ * IIO driver for MS1112 ADC 7-bit I2C slave address: 0x4A ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/gpio.h> ++#include <linux/cdev.h> ++#include <linux/device.h> ++#include <linux/of_gpio.h> ++#include <linux/semaphore.h> ++#include <linux/timer.h> ++#include <linux/i2c.h> ++#include <asm/uaccess.h> ++#include <asm/io.h> ++#include <linux/iio/iio.h> ++#include <linux/iio/driver.h> ++ ++#define MS1112_DRV_NAME "ms1112" ++ ++#define MS1112_CONV_REG 0x00 ++#define MS1112_CFG_REG 0x01 ++#define MS1112_DEFAULT_CONFIG 0xFC ++ ++#define MS1112_CHANNELS 4 ++#define MS1112_CFG_DR_SHIFT 2 ++#define MS1112_CFG_MOD_SHIFT 4 ++#define MS1112_CFG_PGA_SHIFT 0 ++#define MS1112_CFG_MUX_SHIFT 5 ++ ++#define MS1112_CFG_DR_MASK GENMASK(3, 2) ++#define MS1112_CFG_MOD_MASK BIT(4) ++#define MS1112_CFG_PGA_MASK GENMASK(1, 0) ++#define MS1112_CFG_MUX_MASK GENMASK(6, 5) ++ ++#define MS1112_DEFAULT_PGA 0 ++#define MS1112_DEFAULT_DATA_RATE 3 ++#define MS1112_DEFAULT_CHAN 2 ++#define MS1112_DEFAULT_MODE 1 ++ ++#define MS1112_CONTINUOUS 0 ++#define MS1112_SINGLESHOT 1 ++ ++struct ms1112_chip_data { ++ struct iio_chan_spec const *channels; ++ int num_channels; ++ const struct iio_info *info; ++ const int *data_rate; ++ const int data_rate_len; ++ const int *scale; ++ const int scale_len; ++ bool has_comparator; ++}; ++ ++enum ms1112_channels { ++ MS1112_AIN0_AIN1 = 0, ++ MS1112_AIN2, ++ MS1112_AIN0, ++ MS1112_AIN1, ++ MS1112_TIMESTAMP, ++}; ++ ++static const int ms1112_data_rate[] = { ++ 240,60,30,15 ++}; ++ ++static const int ms1112_fullscale_range[] = { ++ 2048 ++}; ++ ++static const int ms1112_scale[] = { /* 12bit ADC */ ++ 2048,11, ++ 2048,13, ++ 2048,14, ++ 2048,15 ++}; ++ ++#define FIT_CHECK(_testbits, _fitbits) \ ++ ( \ ++ (_fitbits) * \ ++ !!sizeof(struct { \ ++ static_assert((_testbits) <= (_fitbits)); \ ++ int pad; \ ++ }) \ ++ ) ++ ++#define MS1112_V_CHAN(_chan, _addr, _realbits, _shift, _event_spec, _num_event_specs) { \ ++ .type = IIO_VOLTAGE, \ ++ .indexed = 1, \ ++ .address = _addr, \ ++ .channel = _chan, \ ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ ++ BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ ++ .info_mask_shared_by_all_available = \ ++ BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ ++ .scan_index = _addr, \ ++ .scan_type = { \ ++ .sign = 's', \ ++ .realbits = (_realbits), \ ++ .storagebits = FIT_CHECK((_realbits) + (_shift), 16), \ ++ .shift = (_shift), \ ++ .endianness = IIO_CPU, \ ++ }, \ ++ .event_spec = (_event_spec), \ ++ .num_event_specs = (_num_event_specs), \ ++ .datasheet_name = "AIN"#_chan, \ ++} ++ ++#define MS1112_V_DIFF_CHAN(_chan, _chan2, _addr, _realbits, _shift, _event_spec, _num_event_specs) { \ ++ .type = IIO_VOLTAGE, \ ++ .differential = 1, \ ++ .indexed = 1, \ ++ .address = _addr, \ ++ .channel = _chan, \ ++ .channel2 = _chan2, \ ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ ++ BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ ++ .info_mask_shared_by_all_available = \ ++ BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ ++ .scan_index = _addr, \ ++ .scan_type = { \ ++ .sign = 's', \ ++ .realbits = (_realbits), \ ++ .storagebits = FIT_CHECK((_realbits) + (_shift), 16), \ ++ .shift = (_shift), \ ++ .endianness = IIO_CPU, \ ++ }, \ ++ .event_spec = (_event_spec), \ ++ .num_event_specs = (_num_event_specs), \ ++ .datasheet_name = "AIN"#_chan"-AIN"#_chan2, \ ++} ++ ++struct ms1112_channel_data { ++ bool enabled; ++ unsigned int pga; ++ unsigned int data_rate; ++ unsigned int mode; ++}; ++ ++struct ms1112_thresh_data { ++ int high_thresh; ++ int low_thresh; ++}; ++ ++struct ms1112_data { ++ struct ms1112_channel_data channel_data[MS1112_CHANNELS]; ++ struct ms1112_thresh_data thresh_data[MS1112_CHANNELS]; ++ const struct ms1112_chip_data *chip; ++ struct mutex lock; ++ void *private_data; ++ struct i2c_client *client; ++}; ++ ++/* MS1112 don't use the register address */ ++static int ms1112_read_regs(struct ms1112_data *dev, uint8_t reg, void *buf, uint8_t size) ++{ ++ int ret = 0; ++ struct i2c_msg msg[1]; ++ struct i2c_client *client = dev->client; ++ ++ msg[0].addr = client->addr; ++ msg[0].flags = I2C_M_RD; ++ msg[0].buf = buf; ++ msg[0].len = size; ++ ++ ret = i2c_transfer(client->adapter, msg, 1); ++ if(ret != 1) { ++ dev_err(&dev->client->dev, "%s() i2c_transfer error, ret=%d\n", __func__, ret); ++ ret = -EREMOTEIO; ++ } ++ ++ return ret; ++} ++ ++/* MS1112 don't use the register address */ ++static s32 ms1112_write_regs(struct ms1112_data *dev, uint8_t reg, uint8_t *data, uint8_t bytes) ++{ ++ int ret = 0; ++ struct i2c_msg msg; ++ struct i2c_client *client = dev->client; ++ ++ msg.addr = client->addr; ++ msg.flags = 0; ++ msg.buf = data; ++ msg.len = bytes; ++ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret != 1) { ++ dev_err(&dev->client->dev, "%s() i2c_transfer error, ret=%d\n", __func__, ret); ++ ret = -EREMOTEIO; ++ } ++ ++ return ret; ++} ++ ++static int ms1112_readdata(struct ms1112_data *dev,unsigned int *val) ++{ ++ unsigned char buf[3]; ++ unsigned char rx_data[3]; ++ int rv = 0; ++ ++ rv = ms1112_read_regs(dev, MS1112_CONV_REG, rx_data, 3); ++ if(rv<0) { ++ return rv; ++ } ++ ++ buf[0] = rx_data[0]; ++ buf[1] = rx_data[1]; ++ buf[2] = rx_data[2]; ++ ++ *val = (buf[0]<<8) | buf[1]; ++ return rv; ++} ++ ++static int ms1112_get_adc_result(struct ms1112_data *data, int chan, int *val) ++{ ++ int ret = 0; ++ int pga, dr , mode; ++ uint8_t mask, cfg; ++ ++ if (chan < 0 || chan >= MS1112_CHANNELS) ++ return -EINVAL; ++ ++ mode = data->channel_data[chan].mode; ++ pga = data->channel_data[chan].pga; ++ dr = data->channel_data[chan].data_rate; ++ ++ mask = MS1112_CFG_MUX_MASK | MS1112_CFG_PGA_MASK | ++ MS1112_CFG_DR_MASK | MS1112_CFG_MOD_MASK | MS1112_SINGLESHOT << 7; ++ ++ cfg = chan << MS1112_CFG_MUX_SHIFT | pga << MS1112_CFG_PGA_SHIFT | ++ dr << MS1112_CFG_DR_SHIFT | mode << MS1112_CFG_MOD_SHIFT | MS1112_SINGLESHOT << 7; ++ ++ cfg = (cfg & mask); ++ ++ ms1112_write_regs(data, MS1112_CFG_REG, &cfg, 1); ++ ++ ret = ms1112_readdata(data,val); ++ return ret; ++} ++ ++static int ms1112_set_scale(struct ms1112_data *data, struct iio_chan_spec const *chan, ++ int scale, int uscale) ++{ ++ int i; ++ int fullscale = div_s64((scale * 1000000LL + uscale) << ++ (chan->scan_type.realbits - 1), 1000000); ++ ++ for (i = 0; i < ARRAY_SIZE(ms1112_fullscale_range); i++) { ++ if (ms1112_fullscale_range[i] == fullscale) { ++ data->channel_data[chan->address].pga = i; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int ms1112_set_data_rate(struct ms1112_data *data, int chan, int rate) ++{ ++ int i; ++ ++ for (i = 0; i < data->chip->data_rate_len; i++) { ++ if (data->chip->data_rate[i] == rate) { ++ data->channel_data[chan].data_rate = i; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int ms1112_read_avail(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ const int **vals, int *type, int *length, ++ long mask) ++{ ++ struct ms1112_data *data = iio_priv(indio_dev); ++ ++ if (chan->type != IIO_VOLTAGE) ++ return -EINVAL; ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_SCALE: ++ *type = IIO_VAL_FRACTIONAL_LOG2; ++ *vals = data->chip->scale; ++ *length = data->chip->scale_len; ++ return IIO_AVAIL_LIST; ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ *type = IIO_VAL_INT; ++ *vals = data->chip->data_rate; ++ *length = data->chip->data_rate_len; ++ return IIO_AVAIL_LIST; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ms1112_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) ++{ ++ int ret, idx; ++ struct ms1112_data *data = iio_priv(indio_dev); ++ ++ mutex_lock(&data->lock); ++ switch (mask) { ++ case IIO_CHAN_INFO_RAW: ++ ++ ret = iio_device_claim_direct_mode(indio_dev); ++ if (ret) ++ break; ++ ++ ret = ms1112_get_adc_result(data, chan->address, val); ++ if (ret < 0) { ++ goto release_direct; ++ } ++ ++ *val = sign_extend32(*val >> chan->scan_type.shift, ++ chan->scan_type.realbits - 1); ++ ++ ret = IIO_VAL_INT; ++release_direct: ++ iio_device_release_direct_mode(indio_dev); ++ break; ++ ++ case IIO_CHAN_INFO_SCALE: ++ idx = data->channel_data[chan->address].pga; ++ *val = ms1112_fullscale_range[idx]; ++ *val2 = chan->scan_type.realbits - 1; ++ ret = IIO_VAL_FRACTIONAL_LOG2; ++ break; ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ idx = data->channel_data[chan->address].data_rate; ++ *val = data->chip->data_rate[idx]; ++ ret = IIO_VAL_INT; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ mutex_unlock(&data->lock); ++ ++ return ret; ++} ++ ++static int ms1112_write_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, int val, ++ int val2, long mask) ++{ ++ struct ms1112_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ mutex_lock(&data->lock); ++ switch (mask) { ++ case IIO_CHAN_INFO_SCALE: ++ ret = ms1112_set_scale(data, chan, val, val2); ++ break; ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ ret = ms1112_set_data_rate(data, chan->address, val); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ mutex_unlock(&data->lock); ++ ++ return ret; ++} ++ ++static const struct iio_info ms1112_info = { ++ .read_raw = ms1112_read_raw, ++ .write_raw = ms1112_write_raw, ++ .read_avail = ms1112_read_avail, ++}; ++ ++ ++static const struct iio_chan_spec ms1112_channels[] = { ++ MS1112_V_DIFF_CHAN(0, 1, MS1112_AIN0_AIN1, 16, 0, NULL, 0), ++ MS1112_V_CHAN(2, MS1112_AIN2, 16, 0, NULL, 0), ++ MS1112_V_CHAN(0, MS1112_AIN0, 16, 0, NULL, 0), ++ MS1112_V_CHAN(1, MS1112_AIN1, 16, 0, NULL, 0), ++ IIO_CHAN_SOFT_TIMESTAMP(MS1112_TIMESTAMP), ++}; ++ ++static int ms1112_client_get_channels_config(struct i2c_client *client) ++{ ++ struct iio_dev *indio_dev = i2c_get_clientdata(client); ++ struct ms1112_data *data = iio_priv(indio_dev); ++ struct device *dev = &client->dev; ++ struct fwnode_handle *node; ++ int i = -1; ++ ++ device_for_each_child_node(dev, node) { ++ u32 pval; ++ unsigned int channel; ++ unsigned int pga = MS1112_DEFAULT_PGA; ++ unsigned int data_rate = MS1112_DEFAULT_DATA_RATE; ++ unsigned int mode = MS1112_DEFAULT_MODE; ++ ++ if (fwnode_property_read_u32(node, "reg", &pval)) { ++ dev_err(dev, "invalid reg on %pfw\n", node); ++ continue; ++ } ++ ++ channel = pval; ++ if (channel >= MS1112_CHANNELS) { ++ dev_err(dev, "invalid channel index %d on %pfw\n", ++ channel, node); ++ continue; ++ } ++ ++ if (!fwnode_property_read_u32(node, "ti,gain", &pval)) { ++ pga = pval; ++ if (pga > 3 ) { ++ dev_err(dev, "invalid gain on %pfw\n", node); ++ fwnode_handle_put(node); ++ return -EINVAL; ++ } ++ } ++ ++ if (!fwnode_property_read_u32(node, "ti,datarate", &pval)) { ++ data_rate = pval; ++ if (data_rate > 3) { ++ dev_err(dev, "invalid data_rate on %pfw\n", node); ++ fwnode_handle_put(node); ++ return -EINVAL; ++ } ++ } ++ ++ if (!fwnode_property_read_u32(node, "ti,mode", &pval)) { ++ mode = pval; ++ if (mode > 1) { ++ dev_err(dev, "invalid mode on %pfw\n", node); ++ fwnode_handle_put(node); ++ return -EINVAL; ++ } ++ } ++ ++ ++ data->channel_data[channel].pga = pga; ++ data->channel_data[channel].data_rate = data_rate; ++ data->channel_data[channel].mode = mode; ++ i++; ++ } ++ ++ return i < 0 ? -EINVAL : 0; ++} ++ ++static void ms1112_get_channels_config(struct i2c_client *client) ++{ ++ unsigned int k; ++ ++ struct iio_dev *indio_dev = i2c_get_clientdata(client); ++ struct ms1112_data *data = iio_priv(indio_dev); ++ ++ if (!ms1112_client_get_channels_config(client)) ++ return; ++ ++ /* fallback on default configuration */ ++ for (k = 0; k < MS1112_CHANNELS; ++k) { ++ data->channel_data[k].pga = MS1112_DEFAULT_PGA; ++ data->channel_data[k].data_rate = MS1112_DEFAULT_DATA_RATE; ++ data->channel_data[k].mode = MS1112_DEFAULT_MODE; ++ } ++} ++ ++static int ms1112_probe(struct i2c_client *client,const struct i2c_device_id *id) ++{ ++ struct iio_dev *indio_dev; ++ const struct ms1112_chip_data *chip; ++ struct ms1112_data *data; ++ int ret; ++ int i; ++ ++ chip = device_get_match_data(&client->dev); ++ if (!chip) ++ chip = (const struct ms1112_chip_data *)id->driver_data; ++ if (!chip) ++ return dev_err_probe(&client->dev, -EINVAL, "Unknown chip\n"); ++ ++ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*indio_dev)); ++ if (!indio_dev) ++ return -ENOMEM; ++ ++ data = iio_priv(indio_dev); ++ i2c_set_clientdata(client, indio_dev); ++ ++ mutex_init(&data->lock); ++ ++ indio_dev->name = MS1112_DRV_NAME; ++ indio_dev->info = chip->info; ++ indio_dev->modes = INDIO_DIRECT_MODE; ++ indio_dev->channels = chip->channels; ++ indio_dev->num_channels = chip->num_channels; ++ data->chip = chip; ++ data->client = client; ++ ++ for (i = 0; i < MS1112_CHANNELS; i++) { ++ int realbits = indio_dev->channels[i].scan_type.realbits; ++ ++ data->thresh_data[i].low_thresh = -1 << (realbits - 1); ++ data->thresh_data[i].high_thresh = (1 << (realbits - 1)) - 1; ++ } ++ ++ /* we need to keep this ABI the same as used by hwmon ADS1015 driver */ ++ ms1112_get_channels_config(client); ++ ++ ret = iio_device_register(indio_dev); ++ if (ret) ++ dev_err(&client->dev, "Failed to register IIO device\n"); ++ return ret; ++} ++ ++static void ms1112_remove(struct i2c_client *client) ++{ ++ struct iio_dev *indio_dev = i2c_get_clientdata(client); ++ ++ iio_device_unregister(indio_dev); ++ ++} ++ ++static const struct ms1112_chip_data ms1112_data = { ++ .channels = ms1112_channels, ++ .num_channels = ARRAY_SIZE(ms1112_channels), ++ .info = &ms1112_info, ++ .data_rate = ms1112_data_rate, ++ .data_rate_len = ARRAY_SIZE(ms1112_data_rate), ++ .scale = ms1112_scale, ++ .scale_len = ARRAY_SIZE(ms1112_scale), ++ .has_comparator = false, ++}; ++ ++static const struct i2c_device_id ms1112_id[] = { ++ { "ms1112", (kernel_ulong_t)&ms1112_data }, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, ms1112_id); ++ ++static const struct of_device_id ms1112_of_match[] = { ++ { .compatible = "ms,ms1112" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, ms1112_of_match); ++ ++static struct i2c_driver ms1112_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "ms1112", ++ .of_match_table = ms1112_of_match, ++ }, ++ .probe = ms1112_probe, ++ .remove = ms1112_remove, ++ .id_table = ms1112_id, ++}; ++ ++module_i2c_driver(ms1112_driver); ++ ++MODULE_AUTHOR("Tang Junfeng"); ++MODULE_DESCRIPTION("MS1112 IIO ADC Driver"); ++MODULE_LICENSE("GPL"); -- Gitblit v1.9.1