mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-31 02:17:58 +00:00 
			
		
		
		
	Merge branch 'main' into WIFI-14644-AP72TIP-support-dual-image-and-fix-reset-button-issue
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/build-dev.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/build-dev.yml
									
									
									
									
										vendored
									
									
								
							| @@ -21,7 +21,7 @@ jobs: | |||||||
|     strategy: |     strategy: | ||||||
|       fail-fast: false |       fail-fast: false | ||||||
|       matrix: |       matrix: | ||||||
|         target: [ 'cig_wf186h', 'cig_wf186w', 'cig_wf188n', 'cig_wf189', 'cig_wf196', 'cig_wf196', 'cybertan_eww631-a1', 'cybertan_eww631-b1', 'sonicfi_rap630w-312g', 'sonicfi_rap63xc-211g', 'sonicfi_rap630c-311g', 'sonicfi_rap630w-311g', 'sonicfi_rap630w-211g', 'sonicfi_rap650c', 'sonicfi_rap7110c-341x', 'sonicfi_rap750e-h', 'sonicfi_rap750w-311a', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_eap104', 'edgecore_eap105', 'edgecore_eap111', 'edgecore_eap112', 'edgecore_oap101', 'edgecore_oap101-6e', 'edgecore_oap101e', 'edgecore_oap101e-6e', 'edgecore_oap103', 'hfcl_ion4xe', 'hfcl_ion4xi', 'hfcl_ion4x', 'hfcl_ion4x_2', 'hfcl_ion4x_3', 'hfcl_ion4xi_w', 'hfcl_ion4x_w', 'indio_um-305ax', 'senao_iap4300m', 'senao_iap2300m', 'senao_jeap6500', 'udaya_a6-id2', 'udaya_a6-od2', 'yuncore_ax820', 'yuncore_ax840', 'yuncore_fap640', 'yuncore_fap650', 'yuncore_fap655', 'emplus_wap588m', 'zyxel_nwa130be', 'sercomm_ap72tip-v4' ] |         target: [ 'cig_wf186h', 'cig_wf186w', 'cig_wf188n', 'cig_wf189', 'cig_wf196', 'cig_wf196', 'cybertan_eww631-a1', 'cybertan_eww631-b1', 'sonicfi_rap630w-312g', 'sonicfi_rap63xc-211g', 'sonicfi_rap630c-311g', 'sonicfi_rap630w-311g', 'sonicfi_rap630w-211g', 'sonicfi_rap650c', 'sonicfi_rap7110c-341x', 'sonicfi_rap750e-h', 'sonicfi_rap750e-s', 'sonicfi_rap750w-311a', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_eap104', 'edgecore_eap105', 'edgecore_eap111', 'edgecore_eap112', 'edgecore_oap101', 'edgecore_oap101-6e', 'edgecore_oap101e', 'edgecore_oap101e-6e', 'edgecore_oap103', 'hfcl_ion4xe', 'hfcl_ion4xi', 'hfcl_ion4x', 'hfcl_ion4x_2', 'hfcl_ion4x_3', 'hfcl_ion4xi_w', 'hfcl_ion4x_w', 'indio_um-305ax', 'senao_iap4300m', 'senao_iap2300m', 'senao_jeap6500', 'udaya_a6-id2', 'udaya_a6-od2', 'yuncore_ax820', 'yuncore_ax840', 'yuncore_fap640', 'yuncore_fap650', 'yuncore_fap655', 'emplus_wap588m', 'zyxel_nwa130be', 'sercomm_ap72tip-v4' ] | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v3 |     - uses: actions/checkout@v3 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -53,6 +53,11 @@ $(call Package/ath12k-wifi-default) | |||||||
|     TITLE:=board-2.bin for RAP750e_h |     TITLE:=board-2.bin for RAP750e_h | ||||||
| endef | endef | ||||||
|  |  | ||||||
|  | define Package/ath12k-wifi-sonicfi-rap750e-s | ||||||
|  | $(call Package/ath12k-wifi-default) | ||||||
|  |     TITLE:=board-2.bin for RAP750E-S | ||||||
|  | endef | ||||||
|  |  | ||||||
| define Package/ath12k-wifi-sonicfi-rap750w-311a | define Package/ath12k-wifi-sonicfi-rap750w-311a | ||||||
| $(call Package/ath12k-wifi-default) | $(call Package/ath12k-wifi-default) | ||||||
|     TITLE:=board-2.bin for RAP750W_311a |     TITLE:=board-2.bin for RAP750W_311a | ||||||
| @@ -83,6 +88,11 @@ $(call Package/ath12k-wifi-default) | |||||||
|     TITLE:=board-2.bin for NWA130BE |     TITLE:=board-2.bin for NWA130BE | ||||||
| endef | endef | ||||||
|  |  | ||||||
|  | define Package/ath12k-wifi-cig-wf672 | ||||||
|  | $(call Package/ath12k-wifi-default) | ||||||
|  |     TITLE:=board-2.bin for WF672 | ||||||
|  | endef | ||||||
|  |  | ||||||
| define Package/ath12k-wifi-cig-wf189/install | define Package/ath12k-wifi-cig-wf189/install | ||||||
| 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/ | 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/ | ||||||
| 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/ | 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/ | ||||||
| @@ -113,6 +123,15 @@ define Package/ath12k-wifi-sonicfi-rap750e-h/install | |||||||
| 	$(INSTALL_DATA) ./ipq5332_qcn6432.regdb $(1)/lib/firmware/ath12k/QCN6432/hw1.0/regdb.bin | 	$(INSTALL_DATA) ./ipq5332_qcn6432.regdb $(1)/lib/firmware/ath12k/QCN6432/hw1.0/regdb.bin | ||||||
| endef | endef | ||||||
|  |  | ||||||
|  | define Package/ath12k-wifi-sonicfi-rap750e-s/install | ||||||
|  | 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/ | ||||||
|  | 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN6432/hw1.0/ | ||||||
|  | 	$(INSTALL_DATA) ./board-2.bin.rap750e_s.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin | ||||||
|  | 	$(INSTALL_DATA) ./board-2.bin.rap750e_s.QCN6432 $(1)/lib/firmware/ath12k/QCN6432/hw1.0/board-2.bin | ||||||
|  | #	$(INSTALL_DATA) ./ipq5332_qcn6432.regdb $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/regdb.bin | ||||||
|  | 	$(INSTALL_DATA) ./ipq5332_qcn6432.regdb $(1)/lib/firmware/ath12k/QCN6432/hw1.0/regdb.bin | ||||||
|  | endef | ||||||
|  |  | ||||||
| define Package/ath12k-wifi-sonicfi-rap750w-311a/install | define Package/ath12k-wifi-sonicfi-rap750w-311a/install | ||||||
| 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/ | 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/ | ||||||
| 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN6432/hw1.0/ | 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN6432/hw1.0/ | ||||||
| @@ -160,13 +179,22 @@ define Package/ath12k-wifi-zyxel-nwa130be/install | |||||||
| 	$(INSTALL_DATA) ./board-2.bin.nwa130be.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin | 	$(INSTALL_DATA) ./board-2.bin.nwa130be.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin | ||||||
| endef | endef | ||||||
|  |  | ||||||
|  | define Package/ath12k-wifi-cig-wf672/install | ||||||
|  | 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/ | ||||||
|  | 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/ | ||||||
|  | 	$(INSTALL_DATA) ./board-2.bin.wf672.QCN92XX $(1)/lib/firmware/ath12k/QCN92XX/hw1.0/board-2.bin | ||||||
|  | 	$(INSTALL_DATA) ./board-2.bin.wf672.IPQ5332 $(1)/lib/firmware/ath12k/IPQ5332/hw1.0/board-2.bin | ||||||
|  | endef | ||||||
|  |  | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-cig-wf189)) | $(eval $(call BuildPackage,ath12k-wifi-cig-wf189)) | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-edgecore-eap105)) | $(eval $(call BuildPackage,ath12k-wifi-edgecore-eap105)) | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap7110c-341x)) | $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap7110c-341x)) | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750e-h)) | $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750e-h)) | ||||||
|  | $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750e-s)) | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750w-311a)) | $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap750w-311a)) | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-cig-wf189w)) | $(eval $(call BuildPackage,ath12k-wifi-cig-wf189w)) | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-cig-wf189h)) | $(eval $(call BuildPackage,ath12k-wifi-cig-wf189h)) | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip)) | $(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip)) | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip-v4)) | $(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip-v4)) | ||||||
| $(eval $(call BuildPackage,ath12k-wifi-zyxel-nwa130be)) | $(eval $(call BuildPackage,ath12k-wifi-zyxel-nwa130be)) | ||||||
|  | $(eval $(call BuildPackage,ath12k-wifi-cig-wf672)) | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								feeds/qca-wifi-7/ath12k-wifi/board-2.bin.rap750e_s.IPQ5332
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								feeds/qca-wifi-7/ath12k-wifi/board-2.bin.rap750e_s.IPQ5332
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								feeds/qca-wifi-7/ath12k-wifi/board-2.bin.rap750e_s.QCN6432
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								feeds/qca-wifi-7/ath12k-wifi/board-2.bin.rap750e_s.QCN6432
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								feeds/qca-wifi-7/ath12k-wifi/board-2.bin.wf672.IPQ5332
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								feeds/qca-wifi-7/ath12k-wifi/board-2.bin.wf672.IPQ5332
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								feeds/qca-wifi-7/ath12k-wifi/board-2.bin.wf672.QCN92XX
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								feeds/qca-wifi-7/ath12k-wifi/board-2.bin.wf672.QCN92XX
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										30
									
								
								feeds/qca-wifi-7/cig-wifi-mode-sw/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								feeds/qca-wifi-7/cig-wifi-mode-sw/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | include $(TOPDIR)/rules.mk | ||||||
|  | include $(INCLUDE_DIR)/kernel.mk | ||||||
|  |  | ||||||
|  | PKG_NAME:=cig-wifi-mode-switch | ||||||
|  | PKG_RELEASE:=1 | ||||||
|  | PKG_LICENSE:=GPL-2.0 | ||||||
|  |  | ||||||
|  | include $(INCLUDE_DIR)/package.mk | ||||||
|  |  | ||||||
|  | define KernelPackage/cig-wifi-mode-sw | ||||||
|  |   SUBMENU:=Other modules | ||||||
|  |   TITLE:=CIG wifi mode switch tool | ||||||
|  |   FILES:=$(PKG_BUILD_DIR)/cig_rf_switch.ko | ||||||
|  |   AUTOLOAD:=$(call AutoLoad,60,cig_rf_switch) | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | define KernelPackage/cig-wifi-mode-sw/description | ||||||
|  |   CIG wifi mode switch tool for configure wifi mode 2 bands or 3 bands | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | define Build/Compile | ||||||
|  | 	$(KERNEL_MAKE) M="$(PKG_BUILD_DIR)" modules | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | define KernelPackage/cig-wifi-mode-sw/install | ||||||
|  | 	$(INSTALL_DIR) $(1)/usr/sbin/ | ||||||
|  | 	$(INSTALL_BIN) ./files/cig_wifi_mode_sw $(1)/usr/sbin/cig_wms | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | $(eval $(call KernelPackage,cig-wifi-mode-sw)) | ||||||
							
								
								
									
										11
									
								
								feeds/qca-wifi-7/cig-wifi-mode-sw/files/cig_wifi_mode_sw
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										11
									
								
								feeds/qca-wifi-7/cig-wifi-mode-sw/files/cig_wifi_mode_sw
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | band=$1 | ||||||
|  | if [ $band -eq 2 ] || [ $band -eq 3 ]; then | ||||||
|  | 	echo $band > /proc/rf_switch | ||||||
|  | 	echo "reboot for switch wifi mode 2/3 bands" | ||||||
|  | 	sleep 1 | ||||||
|  | 	reboot | ||||||
|  | else | ||||||
|  | 	echo "error band param" | ||||||
|  | fi | ||||||
							
								
								
									
										1
									
								
								feeds/qca-wifi-7/cig-wifi-mode-sw/src/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								feeds/qca-wifi-7/cig-wifi-mode-sw/src/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | obj-m += cig_rf_switch.o | ||||||
							
								
								
									
										276
									
								
								feeds/qca-wifi-7/cig-wifi-mode-sw/src/cig_rf_switch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								feeds/qca-wifi-7/cig-wifi-mode-sw/src/cig_rf_switch.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,276 @@ | |||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/proc_fs.h> | ||||||
|  | #include <linux/seq_file.h> | ||||||
|  | #include <linux/mmc/core.h> | ||||||
|  | #include <linux/mmc/host.h> | ||||||
|  | #include <linux/major.h> | ||||||
|  | #include <linux/mmc/mmc.h> | ||||||
|  | #include <linux/mmc/card.h> | ||||||
|  | #include <linux/slab.h> | ||||||
|  | #include <linux/string.h> | ||||||
|  | #include <linux/uaccess.h> | ||||||
|  | #include <linux/list.h> | ||||||
|  | #include <linux/pagemap.h> | ||||||
|  |  | ||||||
|  | #define PROC_NAME "rf_switch" | ||||||
|  | #define PARTITION_NAME "RF_SWITCH" | ||||||
|  | #define MAX_DATA_SIZE 2  | ||||||
|  | #define MAX_MMC_DEVICE 2 | ||||||
|  |  | ||||||
|  | struct block_device *target_bdev = NULL; | ||||||
|  | static char current_value[MAX_DATA_SIZE] = "3";  | ||||||
|  |  | ||||||
|  | static unsigned int __blkdev_sectors_to_bio_pages(sector_t nr_sects) | ||||||
|  | { | ||||||
|  | 	sector_t pages = DIV_ROUND_UP_SECTOR_T(nr_sects, PAGE_SIZE / 512); | ||||||
|  |  | ||||||
|  | 	return min(pages, (sector_t)BIO_MAX_VECS); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct block_device *find_mmc_partition(void) | ||||||
|  | { | ||||||
|  | 	struct gendisk *disk = NULL; | ||||||
|  | 	unsigned long idx; | ||||||
|  | 	struct block_device *bdev = NULL; | ||||||
|  | 	unsigned int i; | ||||||
|  | 	 | ||||||
|  | 	for (i = 0; i < MAX_MMC_DEVICE; i++) { | ||||||
|  | 		bdev = blkdev_get_by_dev(MKDEV(MMC_BLOCK_MAJOR, i * CONFIG_MMC_BLOCK_MINORS), FMODE_READ | FMODE_WRITE, NULL); | ||||||
|  | 		if (IS_ERR(bdev)) { | ||||||
|  | 			pr_err("Failed to open MMC device %u: %ld\n", i, PTR_ERR(bdev)); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		disk = bdev->bd_disk; | ||||||
|  | 		if (!disk) { | ||||||
|  | 			blkdev_put(bdev, FMODE_READ | FMODE_WRITE); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		xa_for_each_start(&disk->part_tbl, idx, bdev, 1) { | ||||||
|  | 			if (bdev->bd_meta_info && strcmp(bdev->bd_meta_info->volname, PARTITION_NAME) == 0) { | ||||||
|  | 				pr_info("Found RF_SWITCH partition at device %u\n", i); | ||||||
|  | 				return bdev; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		blkdev_put(bdev, FMODE_READ | FMODE_WRITE); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int read_string_from_emmc(struct block_device *bdev, size_t max_length, char *buffer) | ||||||
|  | { | ||||||
|  | 	struct bio *bio; | ||||||
|  | 	struct page *page; | ||||||
|  | 	int err = 0; | ||||||
|  | 	void *data; | ||||||
|  |  | ||||||
|  | 	page = alloc_page(GFP_KERNEL); | ||||||
|  | 	if (!page) { | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bio = bio_alloc(bdev, __blkdev_sectors_to_bio_pages(1), REQ_OP_READ, GFP_KERNEL); | ||||||
|  | 	bio_set_dev(bio, bdev); | ||||||
|  | 	bio->bi_iter.bi_sector = 0; | ||||||
|  | 	bio_add_page(bio, page, PAGE_SIZE, 0); | ||||||
|  |  | ||||||
|  | 	submit_bio_wait(bio); | ||||||
|  |  | ||||||
|  | 	if (bio->bi_status) { | ||||||
|  | 		err = -EIO; | ||||||
|  | 		goto out_bio; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	data = kmap(page); | ||||||
|  | 	kunmap(page); | ||||||
|  | 	memcpy(buffer, data, max_length - 1); | ||||||
|  | 	buffer[max_length - 1] = '\0'; | ||||||
|  |  | ||||||
|  | out_bio: | ||||||
|  | 	bio_put(bio); | ||||||
|  | 	__free_page(page); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int rf_switch_proc_show(struct seq_file *m, void *v) | ||||||
|  | { | ||||||
|  | 	char buffer[MAX_DATA_SIZE] = {0}; | ||||||
|  | 	int ret; | ||||||
|  | 	 | ||||||
|  | 	ret = read_string_from_emmc(target_bdev, MAX_DATA_SIZE, buffer); | ||||||
|  | 	if (ret) { | ||||||
|  | 		seq_printf(m, "%s\n", current_value); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if (strcmp(buffer, "2") == 0 || strcmp(buffer, "3") == 0) { | ||||||
|  | 		strncpy(current_value, buffer, MAX_DATA_SIZE); | ||||||
|  | 		seq_printf(m, "%s\n", current_value); | ||||||
|  | 	} else { | ||||||
|  | 		seq_printf(m, "%s\n", current_value); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int blkdev_issue_write(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, struct page *page) | ||||||
|  | { | ||||||
|  | 	int ret = 0; | ||||||
|  | 	sector_t bs_mask; | ||||||
|  | 	struct bio *bio; | ||||||
|  | 	 | ||||||
|  | 	int bi_size = 0; | ||||||
|  | 	unsigned int sz; | ||||||
|  | 	 | ||||||
|  | 	if (bdev_read_only(bdev)) | ||||||
|  | 		return -EPERM; | ||||||
|  | 	 | ||||||
|  | 	bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1; | ||||||
|  | 	if ((sector | nr_sects) & bs_mask) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	 | ||||||
|  | 	bio = bio_alloc(bdev, __blkdev_sectors_to_bio_pages(nr_sects), | ||||||
|  | 			REQ_OP_WRITE, gfp_mask); | ||||||
|  | 	if (!bio) { | ||||||
|  | 		pr_err("Couldn't alloc bio"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	bio->bi_iter.bi_sector = sector; | ||||||
|  | 	bio_set_dev(bio, bdev); | ||||||
|  | 	bio_set_op_attrs(bio, REQ_OP_WRITE, 0); | ||||||
|  | 	 | ||||||
|  | 	sz = bdev_logical_block_size(bdev); | ||||||
|  | 	bi_size = bio_add_page(bio, page, sz, 0); | ||||||
|  | 	 | ||||||
|  | 	if(bi_size != sz) { | ||||||
|  | 		pr_err("Couldn't add page to the log block"); | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
|  | 	if (bio) | ||||||
|  | 	{ | ||||||
|  | 		ret = submit_bio_wait(bio); | ||||||
|  | 		bio_put(bio); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return ret; | ||||||
|  | error: | ||||||
|  | 	bio_put(bio); | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int write_data_to_emmc(struct block_device *bdev, const unsigned char *data, unsigned char fill_byte) | ||||||
|  | { | ||||||
|  | 	struct page *page; | ||||||
|  | 	void *ptr; | ||||||
|  | 	sector_t sector_offset = 0; | ||||||
|  | 	int ret = 0; | ||||||
|  | 	 | ||||||
|  | 	if (!bdev || !data) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	 | ||||||
|  | 	page = alloc_page(GFP_KERNEL); | ||||||
|  | 	if (!page) { | ||||||
|  | 		pr_err("Failed to allocate page\n"); | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	ptr = kmap_atomic(page); | ||||||
|  | 	 | ||||||
|  | 	memcpy(ptr, data, MAX_DATA_SIZE); | ||||||
|  | 			 | ||||||
|  | 	memset(ptr + MAX_DATA_SIZE, fill_byte, 512-MAX_DATA_SIZE); | ||||||
|  | 	kunmap_atomic(ptr); | ||||||
|  | 		 | ||||||
|  | 	ret = blkdev_issue_write(bdev, sector_offset , 1 ,GFP_ATOMIC, page); | ||||||
|  | 	if (ret) { | ||||||
|  | 		pr_err("Failed to write to eMMC at offset 0: %d\n", ret); | ||||||
|  | 		__free_page(page); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	sync_blockdev(bdev);  | ||||||
|  | 	__free_page(page); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t rf_switch_proc_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos) | ||||||
|  | { | ||||||
|  | 	unsigned char buffer[MAX_DATA_SIZE] = {0}; | ||||||
|  | 	int ret; | ||||||
|  | 	 | ||||||
|  | 	if (count != MAX_DATA_SIZE) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	 | ||||||
|  | 	if (copy_from_user(buffer, user_buffer, count)) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 	 | ||||||
|  | 	buffer[count -1] = '\0'; | ||||||
|  | 	 | ||||||
|  | 	if (strcmp(buffer, "2") != 0 && strcmp(buffer, "3") != 0) { | ||||||
|  | 		pr_err("Invalid value: %s. Only '2' or '3' are allowed.\n", buffer); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	ret = write_data_to_emmc(target_bdev,  buffer, 0xFF); | ||||||
|  | 	if (ret) { | ||||||
|  | 		pr_err("Failed to write to RF_SWITCH\n"); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	strncpy(current_value, buffer, MAX_DATA_SIZE); | ||||||
|  | 	 | ||||||
|  | 	return count; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int rf_switch_proc_open(struct inode *inode, struct file *file) | ||||||
|  | { | ||||||
|  | 	return single_open(file, rf_switch_proc_show, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const struct proc_ops rf_switch_proc_fops = { | ||||||
|  | 	.proc_open = rf_switch_proc_open, | ||||||
|  | 	.proc_read = seq_read, | ||||||
|  | 	.proc_write = rf_switch_proc_write, | ||||||
|  | 	.proc_lseek = seq_lseek, | ||||||
|  | 	.proc_release = single_release, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int __init rf_switch_init(void) | ||||||
|  | { | ||||||
|  | 	target_bdev = find_mmc_partition(); | ||||||
|  | 	if (!target_bdev) { | ||||||
|  | 		pr_err("Failed to find eMMC card or RF_SWITCH partition\n"); | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if (!proc_create(PROC_NAME, 0666, NULL, &rf_switch_proc_fops)) { | ||||||
|  | 		pr_err("Failed to create proc entry\n"); | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	pr_info("RF_SWITCH partition proc interface created\n"); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void __exit rf_switch_exit(void) | ||||||
|  | { | ||||||
|  | 	if (target_bdev) { | ||||||
|  | 		blkdev_put(target_bdev, FMODE_READ | FMODE_WRITE); | ||||||
|  | 		target_bdev = NULL; | ||||||
|  | 	} | ||||||
|  | 	remove_proc_entry(PROC_NAME, NULL); | ||||||
|  | 	pr_info("RF_SWITCH partition proc interface removed\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module_init(rf_switch_init); | ||||||
|  | module_exit(rf_switch_exit); | ||||||
|  |  | ||||||
|  | MODULE_LICENSE("GPL"); | ||||||
|  | MODULE_AUTHOR("Yunxiang Huang"); | ||||||
|  | MODULE_DESCRIPTION("RF_SWITCH partition read/write driver"); | ||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | unchanged: | ||||||
| --- a/hostapd/config_file.c | --- a/hostapd/config_file.c | ||||||
| +++ b/hostapd/config_file.c | +++ b/hostapd/config_file.c | ||||||
| @@ -3003,6 +3003,8 @@ static int hostapd_config_fill(struct ho | @@ -3003,6 +3003,8 @@ static int hostapd_config_fill(struct ho | ||||||
| @@ -9,12 +10,10 @@ | |||||||
|  #endif /* CONFIG_IEEE80211R_AP */ |  #endif /* CONFIG_IEEE80211R_AP */ | ||||||
|  #ifndef CONFIG_NO_CTRL_IFACE |  #ifndef CONFIG_NO_CTRL_IFACE | ||||||
|  	} else if (os_strcmp(buf, "ctrl_interface") == 0) { |  	} else if (os_strcmp(buf, "ctrl_interface") == 0) { | ||||||
| @@ -4958,8 +4960,22 @@ int hostapd_set_iface(struct hostapd_con | @@ -4982,6 +4982,19 @@ struct hostapd_config * hostapd_config_r | ||||||
|  		return -1; |  	fclose(f); | ||||||
|  	} |  | ||||||
|   |   | ||||||
| -	for (i = 0; i < conf->num_bss; i++) |  	for (i = 0; i < conf->num_bss; i++) { | ||||||
| +	for (i = 0; i < conf->num_bss; i++) { |  | ||||||
| +		if (*conf->bss[i]->ft_key) { | +		if (*conf->bss[i]->ft_key) { | ||||||
| +			u8 buffer[128]; | +			u8 buffer[128]; | ||||||
| +			sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X %02X%02X%02X%02X%02X%02X %s", MAC2STR(conf->bss[i]->bssid), MAC2STR(conf->bss[i]->bssid), conf->bss[i]->ft_key); | +			sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X %02X%02X%02X%02X%02X%02X %s", MAC2STR(conf->bss[i]->bssid), MAC2STR(conf->bss[i]->bssid), conf->bss[i]->ft_key); | ||||||
| @@ -25,14 +24,12 @@ | |||||||
| +			add_r0kh(conf->bss[i], buffer); | +			add_r0kh(conf->bss[i], buffer); | ||||||
| +			sprintf(buffer, "00:00:00:00:00:00 00:00:00:00:00:00 %s", conf->bss[i]->ft_key); | +			sprintf(buffer, "00:00:00:00:00:00 00:00:00:00:00:00 %s", conf->bss[i]->ft_key); | ||||||
| +			add_r1kh(conf->bss[i], buffer); | +			add_r1kh(conf->bss[i], buffer); | ||||||
| +			hexstr2bin(conf->bss[i]->bssid, conf->bss[i]->r1_key_holder, FT_R1KH_ID_LEN);  | +			hexstr2bin(conf->bss[i]->bssid, conf->bss[i]->r1_key_holder, FT_R1KH_ID_LEN); | ||||||
| +			conf->bss[i]->r0_key_holder_bssid = 1; | +			conf->bss[i]->r0_key_holder_bssid = 1; | ||||||
| +		} | +		} | ||||||
|  		hostapd_set_security_params(conf->bss[i], 0); |  		hostapd_set_security_params(conf->bss[i], 1); | ||||||
| +	} |  #ifdef CONFIG_IEEE80211BE | ||||||
|   |  		if (conf->ieee80211be && conf->bss[i]->ieee80211w > 0 | ||||||
|  	if (hostapd_config_check(conf, 0)) { |  | ||||||
|  		wpa_printf(MSG_ERROR, "Configuration check failed"); |  | ||||||
| --- a/src/ap/ap_config.h | --- a/src/ap/ap_config.h | ||||||
| +++ b/src/ap/ap_config.h | +++ b/src/ap/ap_config.h | ||||||
| @@ -398,6 +398,7 @@ struct hostapd_bss_config { | @@ -398,6 +398,7 @@ struct hostapd_bss_config { | ||||||
|   | |||||||
| @@ -785,6 +785,7 @@ int hostapd_ucode_sta_auth(struct hostapd_data *hapd, struct sta_info *sta) | |||||||
|  |  | ||||||
| void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta) | void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta) | ||||||
| { | { | ||||||
|  | 	struct hostapd_sta_wpa_psk_short *psk = sta->psk; | ||||||
| 	char addr[sizeof(MACSTR)]; | 	char addr[sizeof(MACSTR)]; | ||||||
| 	uc_value_t *val, *cur; | 	uc_value_t *val, *cur; | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
| @@ -801,6 +802,8 @@ void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta | |||||||
| 	val = ucv_object_new(vm); | 	val = ucv_object_new(vm); | ||||||
| 	if (sta->psk_idx) | 	if (sta->psk_idx) | ||||||
| 		ucv_object_add(val, "psk_idx", ucv_int64_new(sta->psk_idx - 1)); | 		ucv_object_add(val, "psk_idx", ucv_int64_new(sta->psk_idx - 1)); | ||||||
|  | 	if (sta->psk) | ||||||
|  | 		ucv_object_add(val, "psk", ucv_string_new(sta->psk->passphrase)); | ||||||
| 	uc_value_push(ucv_get(val)); | 	uc_value_push(ucv_get(val)); | ||||||
|  |  | ||||||
| 	val = wpa_ucode_call(3); | 	val = wpa_ucode_call(3); | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ sercomm,ap72tip) | |||||||
| 	;; | 	;; | ||||||
| sonicfi,rap7110c-341x|\ | sonicfi,rap7110c-341x|\ | ||||||
| sonicfi,rap750e-h|\ | sonicfi,rap750e-h|\ | ||||||
|  | sonicfi,rap750e-s|\ | ||||||
| sonicfi,rap750w-311a) | sonicfi,rap750w-311a) | ||||||
| 	ucidef_set_led_default "power" "POWER" "pwm:blue" "on" | 	ucidef_set_led_default "power" "POWER" "pwm:blue" "on" | ||||||
| 	;; | 	;; | ||||||
|   | |||||||
| @@ -13,13 +13,15 @@ ipq53xx_setup_interfaces() | |||||||
| 		ucidef_set_interfaces_lan_wan "eth1 eth2 eth3 eth4 eth5" "eth0" | 		ucidef_set_interfaces_lan_wan "eth1 eth2 eth3 eth4 eth5" "eth0" | ||||||
| 		;; | 		;; | ||||||
| 	cig,wf189|\ | 	cig,wf189|\ | ||||||
|  | 	cig,wf672|\ | ||||||
| 	edgecore,eap105|\ | 	edgecore,eap105|\ | ||||||
| 	sercomm,ap72tip|\ | 	sercomm,ap72tip|\ | ||||||
| 	sonicfi,rap750w-311a) | 	sonicfi,rap750w-311a) | ||||||
| 		ucidef_set_interfaces_lan_wan "eth1" "eth0" | 		ucidef_set_interfaces_lan_wan "eth1" "eth0" | ||||||
| 		;; | 		;; | ||||||
| 	sonicfi,rap7110c-341x|\ | 	sonicfi,rap7110c-341x|\ | ||||||
| 	sonicfi,rap750e-h) | 	sonicfi,rap750e-h|\) | ||||||
|  | 	sonicfi,rap750e-s) | ||||||
| 		ucidef_set_interfaces_lan_wan "" "eth0" | 		ucidef_set_interfaces_lan_wan "" "eth0" | ||||||
| 		;; | 		;; | ||||||
| 	cig,wf189w) | 	cig,wf189w) | ||||||
| @@ -43,21 +45,35 @@ qcom_setup_macs() | |||||||
| { | { | ||||||
|         local board="$1" |         local board="$1" | ||||||
|         case $board in |         case $board in | ||||||
| 	cig,wf189w|\ |         cig,wf189w|\ | ||||||
| 	cig,wf189h|\ |         cig,wf189h|\ | ||||||
|         cig,wf189) |         cig,wf189) | ||||||
| 		mtd=$(find_mtd_chardev "0:APPSBLENV") |                 mtd=$(find_mtd_chardev "0:APPSBLENV") | ||||||
| 		[ -z "$mtd" ] && return; |                 [ -z "$mtd" ] && return; | ||||||
| 		mac=$(grep eth1addr= $mtd | cut -d= -f2) |                 mac=$(grep eth1addr= $mtd | cut -d= -f2) | ||||||
|                 [ -z "$mac" ] && return; |                 [ -z "$mac" ] && return; | ||||||
|                 wan_mac=$(macaddr_canonicalize $mac) |                 wan_mac=$(macaddr_canonicalize $mac) | ||||||
|                 lan_mac=$(macaddr_add "$wan_mac" 1) |                 lan_mac=$(macaddr_add "$wan_mac" 1) | ||||||
|                 ucidef_set_network_device_mac eth0 $wan_mac |                 ucidef_set_network_device_mac eth0 $wan_mac | ||||||
|                 ucidef_set_network_device_mac eth1 $lan_mac |                 ucidef_set_network_device_mac eth1 $lan_mac | ||||||
|                 ucidef_set_label_macaddr $wan_mac |                 ucidef_set_label_macaddr $wan_mac | ||||||
| 		ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 2) |                 ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 2) | ||||||
| 		ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 3) |                 ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 3) | ||||||
| 		ucidef_set_wireless_macaddr_base 6g $(macaddr_add "$wan_mac" 4) |                 ucidef_set_wireless_macaddr_base 6g $(macaddr_add "$wan_mac" 4) | ||||||
|  |                 ;; | ||||||
|  |         cig,wf672) | ||||||
|  |                 mmc=$(find_mmc_part "0:APPSBLENV") | ||||||
|  |                 [ -z "$mmc" ] && return; | ||||||
|  |                 mac=$(grep eth1addr= $mmc | cut -d= -f2) | ||||||
|  |                 [ -z "$mac" ] && return; | ||||||
|  |                 wan_mac=$(macaddr_canonicalize $mac) | ||||||
|  |                 lan_mac=$(macaddr_add "$wan_mac" 1) | ||||||
|  |                 ucidef_set_network_device_mac eth0 $wan_mac | ||||||
|  |                 ucidef_set_network_device_mac eth1 $lan_mac | ||||||
|  |                 ucidef_set_label_macaddr $wan_mac | ||||||
|  |                 ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 2) | ||||||
|  |                 ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 3) | ||||||
|  |                 ucidef_set_wireless_macaddr_base 6g $(macaddr_add "$wan_mac" 4) | ||||||
|                 ;; |                 ;; | ||||||
|         sercomm,ap72tip) |         sercomm,ap72tip) | ||||||
|                 wan_mac=$(cat /sys/class/net/eth0/address) |                 wan_mac=$(cat /sys/class/net/eth0/address) | ||||||
| @@ -69,9 +85,13 @@ qcom_setup_macs() | |||||||
|         edgecore,eap105) |         edgecore,eap105) | ||||||
|                 wan_mac=$(cat /sys/class/net/eth0/address) |                 wan_mac=$(cat /sys/class/net/eth0/address) | ||||||
|                 lan_mac=$(macaddr_add "$wan_mac" 1) |                 lan_mac=$(macaddr_add "$wan_mac" 1) | ||||||
|  |                 ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 2) | ||||||
|  |                 ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 3) | ||||||
|  |                 ucidef_set_wireless_macaddr_base 6g $(macaddr_add "$wan_mac" 4) | ||||||
| 		;; | 		;; | ||||||
|         sonicfi,rap7110c-341x|\ |         sonicfi,rap7110c-341x|\ | ||||||
|         sonicfi,rap750e-h) |         sonicfi,rap750e-h|\ | ||||||
|  |         sonicfi,rap750e-s) | ||||||
|                 wan_mac=$(cat /sys/class/net/eth0/address) |                 wan_mac=$(cat /sys/class/net/eth0/address) | ||||||
|                 ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 1) |                 ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 1) | ||||||
|                 ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 2) |                 ucidef_set_wireless_macaddr_base 5g $(macaddr_add "$wan_mac" 2) | ||||||
|   | |||||||
| @@ -23,6 +23,39 @@ caldata_extract() { | |||||||
|                 caldata_die "failed to extract calibration data from $mtd" |                 caldata_die "failed to extract calibration data from $mtd" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | cig_ipq5322_cal() { | ||||||
|  | 	local ext_ant=0 | ||||||
|  |  | ||||||
|  | 	[ -f /sys/firmware/devicetree/base/soc@0/wifi@c0000000/ext_antenna ] && ext_ant=1	 | ||||||
|  |  | ||||||
|  | 	if [ "$ext_ant" = "0" ]; then | ||||||
|  | 		caldata_extract_mmc "0:ART" 0x1000 0x20000 | ||||||
|  | 	else | ||||||
|  | 		caldata_extract_mmc "0:ART" 0xbd800 0x20000 | ||||||
|  | 	fi | ||||||
|  | } | ||||||
|  |  | ||||||
|  | cig_qcn92xx_cal() { | ||||||
|  | 	local bands=$(cat /proc/rf_switch) | ||||||
|  | 	local ext_ant=0 | ||||||
|  | 	 | ||||||
|  | 	[ -f /sys/firmware/devicetree/base/soc@0/wifi@c0000000/ext_antenna ] && ext_ant=1	 | ||||||
|  |  | ||||||
|  | 	if [ "$bands" = "2" ]; then | ||||||
|  | 		if [ "$ext_ant" = "0" ]; then | ||||||
|  | 			caldata_extract_mmc "0:ART" 0x8b800 0x2d000 | ||||||
|  | 		else | ||||||
|  | 			caldata_extract_mmc "0:ART" 0xe3000 0x2d000 | ||||||
|  | 		fi | ||||||
|  | 	else | ||||||
|  | 		if [ "$ext_ant" = "0" ]; then | ||||||
|  | 			caldata_extract_mmc "0:ART" 0x58800 0x2d000 | ||||||
|  | 		else | ||||||
|  | 			caldata_extract_mmc "0:ART" 0x115000 0x2d000 | ||||||
|  | 		fi | ||||||
|  | 	fi | ||||||
|  | } | ||||||
|  |  | ||||||
| board=$(board_name) | board=$(board_name) | ||||||
| case "$FIRMWARE" in | case "$FIRMWARE" in | ||||||
| ath12k/IPQ5332/hw1.0/caldata.bin) | ath12k/IPQ5332/hw1.0/caldata.bin) | ||||||
| @@ -36,10 +69,14 @@ ath12k/IPQ5332/hw1.0/caldata.bin) | |||||||
| 	zyxel,nwa130be) | 	zyxel,nwa130be) | ||||||
| 		caldata_extract "0:ART" 0x1000 0x20000  | 		caldata_extract "0:ART" 0x1000 0x20000  | ||||||
| 		;; | 		;; | ||||||
|  | 	cig,wf672) | ||||||
|  | 		cig_ipq5322_cal | ||||||
|  | 		;; | ||||||
| 	sonicfi,rap7110c-341x) | 	sonicfi,rap7110c-341x) | ||||||
| 		caldata_extract_mmc "0:ART" 0x1000 0xF800 | 		caldata_extract_mmc "0:ART" 0x1000 0xF800 | ||||||
| 		;; | 		;; | ||||||
| 	sonicfi,rap750e-h|\ | 	sonicfi,rap750e-h|\ | ||||||
|  | 	sonicfi,rap750e-s|\ | ||||||
| 	sonicfi,rap750w-311a) | 	sonicfi,rap750w-311a) | ||||||
| 		caldata_extract "0:ART" 0x1000 0xf800 | 		caldata_extract "0:ART" 0x1000 0xf800 | ||||||
| 		;; | 		;; | ||||||
| @@ -54,6 +91,9 @@ ath12k/QCN92XX/hw1.0/cal-pci-0001:01:00.0.bin) | |||||||
| 	zyxel,nwa130be) | 	zyxel,nwa130be) | ||||||
| 		caldata_extract "0:ART" 0x58800 0x2d000 | 		caldata_extract "0:ART" 0x58800 0x2d000 | ||||||
| 		;; | 		;; | ||||||
|  | 	cig,wf672) | ||||||
|  | 		cig_qcn92xx_cal | ||||||
|  | 		;; | ||||||
| 	sonicfi,rap7110c-341x) | 	sonicfi,rap7110c-341x) | ||||||
| 		caldata_extract_mmc "0:ART" 0x58800 0x2d000 | 		caldata_extract_mmc "0:ART" 0x58800 0x2d000 | ||||||
| 		;; | 		;; | ||||||
| @@ -62,6 +102,7 @@ ath12k/QCN92XX/hw1.0/cal-pci-0001:01:00.0.bin) | |||||||
| ath12k/QCN6432/hw1.0/caldata_1.bin) | ath12k/QCN6432/hw1.0/caldata_1.bin) | ||||||
| 	case "$board" in | 	case "$board" in | ||||||
| 	sonicfi,rap750e-h|\ | 	sonicfi,rap750e-h|\ | ||||||
|  | 	sonicfi,rap750e-s|\ | ||||||
| 	sonicfi,rap750w-311a) | 	sonicfi,rap750w-311a) | ||||||
| 		caldata_extract "0:ART" 0x12800 0x18800 | 		caldata_extract "0:ART" 0x12800 0x18800 | ||||||
| 		;; | 		;; | ||||||
|   | |||||||
| @@ -0,0 +1,20 @@ | |||||||
|  | # /etc/hotplug.d/iface/85-greqos | ||||||
|  | [ "$ACTION" == "ifup" ] || exit 0 | ||||||
|  |  | ||||||
|  | . /lib/functions.sh | ||||||
|  |  | ||||||
|  | case "$(board_name)" in | ||||||
|  | cig,wf189|\ | ||||||
|  | cig,wf189w|\ | ||||||
|  | cig,wf189h|\ | ||||||
|  | cig,wf672) | ||||||
|  |     case "$INTERFACE" in | ||||||
|  |       gre*) | ||||||
|  |         dev=$(ubus call network.interface.$INTERFACE status | jsonfilter -e '@.l3_device') | ||||||
|  |         [ -n "$dev" ] && { | ||||||
|  |           tc qdisc del dev $dev root 2>/dev/null | ||||||
|  |           tc qdisc add dev $dev root noqueue | ||||||
|  |         } | ||||||
|  |         ;; | ||||||
|  |     esac | ||||||
|  | esac | ||||||
| @@ -57,6 +57,52 @@ sonicfi_dualimage_check() { | |||||||
| 	fi | 	fi | ||||||
| } | } | ||||||
|  |  | ||||||
|  | spi_nor_emmc_do_upgrade_bootconfig() { | ||||||
|  | 	local tar_file="$1" | ||||||
|  |  | ||||||
|  | 	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') | ||||||
|  | 	board_dir=${board_dir%/} | ||||||
|  | 	[ -f /proc/boot_info/bootconfig0/getbinary_bootconfig ] || { | ||||||
|  | 		echo "bootconfig does not exist" | ||||||
|  | 		exit | ||||||
|  | 	} | ||||||
|  | 	CI_ROOTPART="$(cat /proc/boot_info/bootconfig0/rootfs/upgradepartition)" | ||||||
|  | 	CI_KERNPART="$(cat /proc/boot_info/bootconfig0/0:HLOS/upgradepartition)" | ||||||
|  |  | ||||||
|  | 	[ -n "$CI_KERNPART" -a -n "$CI_ROOTPART" ] || { | ||||||
|  | 		echo "kernel or rootfs partition is unknown" | ||||||
|  | 		exit | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	local primary="0" | ||||||
|  | 	[ "$(cat /proc/boot_info/bootconfig0/rootfs/primaryboot)" = "0" ] && primary="1" | ||||||
|  | 	echo "$primary" > /proc/boot_info/bootconfig0/rootfs/primaryboot 2>/dev/null | ||||||
|  | 	echo "$primary" > /proc/boot_info/bootconfig0/0:HLOS/primaryboot 2>/dev/null | ||||||
|  | 	cp /proc/boot_info/bootconfig0/getbinary_bootconfig /tmp/bootconfig | ||||||
|  |  | ||||||
|  | 	do_flash_emmc $tar_file $CI_KERNPART $board_dir kernel | ||||||
|  | 	do_flash_emmc $tar_file $CI_ROOTPART $board_dir root | ||||||
|  |  | ||||||
|  | 	local emmcblock="$(find_mmc_part "rootfs_data")" | ||||||
|  | 	if [ -e "$emmcblock" ]; then | ||||||
|  | 		mkfs.ext4 -F "$emmcblock" | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | 	for part in "0:BOOTCONFIG" "0:BOOTCONFIG1"; do | ||||||
|  | 				local mtdchar=$(echo $(find_mtd_chardev $part) | sed 's/^.\{5\}//') | ||||||
|  | 				if [ -n "$mtdchar" ]; then | ||||||
|  | 						echo start to update $mtdchar | ||||||
|  | 						mtd -qq write /proc/boot_info/bootconfig0/getbinary_bootconfig "/dev/${mtdchar}" 2>/dev/null && echo update mtd $mtdchar | ||||||
|  | 			   else | ||||||
|  | 						emmcblock=$(find_mmc_part $part) | ||||||
|  | 						echo erase ${emmcblock} | ||||||
|  | 						dd if=/dev/zero of=${emmcblock} 2> /dev/null | ||||||
|  | 						echo update $emmcblock | ||||||
|  | 						dd if=/tmp/bootconfig of=${emmcblock} 2> /dev/null | ||||||
|  | 				fi | ||||||
|  | 	done | ||||||
|  | } | ||||||
|  |  | ||||||
| emmc_do_upgrade() { | emmc_do_upgrade() { | ||||||
| 	local tar_file="$1" | 	local tar_file="$1" | ||||||
| 	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') | 	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') | ||||||
| @@ -100,6 +146,9 @@ platform_do_upgrade() { | |||||||
| 		fi | 		fi | ||||||
| 		nand_upgrade_tar "$1" | 		nand_upgrade_tar "$1" | ||||||
| 		;; | 		;; | ||||||
|  | 	cig,wf672) | ||||||
|  | 		spi_nor_emmc_do_upgrade_bootconfig $1 | ||||||
|  | 		;; | ||||||
| 	edgecore,eap105) | 	edgecore,eap105) | ||||||
| 		if [ "$(find_mtd_chardev rootfs)" ]; then | 		if [ "$(find_mtd_chardev rootfs)" ]; then | ||||||
| 			CI_UBIPART="rootfs" | 			CI_UBIPART="rootfs" | ||||||
| @@ -119,6 +168,7 @@ platform_do_upgrade() { | |||||||
| 		emmc_do_upgrade "$1" | 		emmc_do_upgrade "$1" | ||||||
| 		;; | 		;; | ||||||
| 	sonicfi,rap750e-h|\ | 	sonicfi,rap750e-h|\ | ||||||
|  | 	sonicfi,rap750e-s|\ | ||||||
| 	sonicfi,rap750w-311a) | 	sonicfi,rap750w-311a) | ||||||
| 		sonicfi_dualimage_check | 		sonicfi_dualimage_check | ||||||
| 		nand_upgrade_tar "$1" | 		nand_upgrade_tar "$1" | ||||||
|   | |||||||
							
								
								
									
										548
									
								
								feeds/qca-wifi-7/ipq53xx/dts/ipq5332-cig-wf672.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										548
									
								
								feeds/qca-wifi-7/ipq53xx/dts/ipq5332-cig-wf672.dts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,548 @@ | |||||||
|  | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) | ||||||
|  | /* | ||||||
|  |  * IPQ5332 RDP468 board device tree source | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. | ||||||
|  |  * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /dts-v1/; | ||||||
|  |  | ||||||
|  | #include <dt-bindings/gpio/gpio.h> | ||||||
|  | #include <dt-bindings/input/input.h> | ||||||
|  | #include <dt-bindings/leds/common.h> | ||||||
|  | #include "ipq5332.dtsi" | ||||||
|  | #include "ipq5332-default-memory.dtsi" | ||||||
|  |  | ||||||
|  | / { | ||||||
|  | 	model = "CIG WF672"; | ||||||
|  | 	compatible = "cig,wf672", "qcom,ipq5332-rdp468", "qcom,ipq5332"; | ||||||
|  |  | ||||||
|  | 	aliases { | ||||||
|  | 		serial0 = &blsp1_uart0; | ||||||
|  | 		serial1 = &blsp1_uart1; | ||||||
|  | 		ethernet0 = "/soc/dp1"; | ||||||
|  | 		ethernet1 = "/soc/dp2"; | ||||||
|  | 		led-boot = &led_power_green; | ||||||
|  | 		led-failsafe = &led_power_red; | ||||||
|  | 		led-running = &led_power_green; | ||||||
|  | 		led-upgrade = &led_power_green; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	chosen { | ||||||
|  | 		stdout-path = "serial0"; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	soc@0 { | ||||||
|  | 		mdio:mdio@90000 { | ||||||
|  | 			pinctrl-0 = <&mdio1_pins>; | ||||||
|  | 			pinctrl-names = "default"; | ||||||
|  | 			/*gpio51 for manhattan reset*/ | ||||||
|  | 			phy-reset-gpio = <&tlmm 21 GPIO_ACTIVE_LOW>; | ||||||
|  | 			phyaddr_fixup = <0xC90F018>; | ||||||
|  | 			uniphyaddr_fixup = <0xC90F014>; | ||||||
|  | 			mdio_clk_fixup; /* MDIO clock sequence fix up flag */ | ||||||
|  | 			status = "okay"; | ||||||
|  |  | ||||||
|  | 			phy0: ethernet-phy@0 { | ||||||
|  | 				reg = <1>; | ||||||
|  | 				compatible ="ethernet-phy-ieee802.3-c45"; | ||||||
|  | 				fixup; | ||||||
|  | 			}; | ||||||
|  | 			phy1: ethernet-phy@1 { | ||||||
|  | 				reg = <30>; | ||||||
|  | 				fixup; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		ess-instance { | ||||||
|  | 			num_devices = <0x1>; | ||||||
|  |  | ||||||
|  | 			ess-switch@3a000000 { | ||||||
|  | 				switch_cpu_bmp = <0x1>;  /* cpu port bitmap */ | ||||||
|  | 				switch_lan_bmp = <0x2>; /* lan port bitmap */ | ||||||
|  | 				switch_wan_bmp = <0x4>; /* wan port bitmap */ | ||||||
|  | 				switch_mac_mode = <0xc>; /* mac mode for uniphy instance0*/ | ||||||
|  | 				switch_mac_mode1 = <0xe>; /* mac mode for uniphy instance1*/ | ||||||
|  | 				switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/ | ||||||
|  |  | ||||||
|  | 				qcom,port_phyinfo { | ||||||
|  | 					port@0 { | ||||||
|  | 						port_id = <1>; | ||||||
|  | 						phy_address = <1>; | ||||||
|  | 						ethernet-phy-ieee802.3-c45; | ||||||
|  | 						forced-speed = <2500>; | ||||||
|  | 						forced-duplex = <1>; | ||||||
|  | 						mdiobus = <&mdio>; | ||||||
|  | 					}; | ||||||
|  | 					port@1 { | ||||||
|  | 						port_id = <2>; | ||||||
|  | 						phy_address = <30>; | ||||||
|  | 						phy_i2c_address =<30>; | ||||||
|  | 						phy-i2c-mode; | ||||||
|  | 						sfp_rx_los_pin = <&tlmm 43 0>; | ||||||
|  | 						sfp_mod_present_pin = <&tlmm 45 0>; | ||||||
|  | 						sfp_tx_dis_pin = <&extgpio 11 0>; | ||||||
|  | 						media-type = "sfp"; /* fiber mode */ | ||||||
|  | 					}; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		dp2 { | ||||||
|  | 			device_type = "network"; | ||||||
|  | 			compatible = "qcom,nss-dp"; | ||||||
|  | 			qcom,id = <1>; | ||||||
|  | 			reg = <0x3a500000 0x4000>; | ||||||
|  | 			qcom,mactype = <1>; | ||||||
|  | 			local-mac-address = [000000000000]; | ||||||
|  | 			mdio-bus = <&mdio>; | ||||||
|  | 			qcom,phy-mdio-addr = <1>; | ||||||
|  | 			qcom,link-poll = <1>; | ||||||
|  | 			phy-mode = "sgmii"; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		gmac2:dp1 { | ||||||
|  | 			device_type = "network"; | ||||||
|  | 			compatible = "qcom,nss-dp"; | ||||||
|  | 			qcom,id = <2>; | ||||||
|  | 			reg = <0x3a504000 0x4000>; | ||||||
|  | 			qcom,mactype = <1>; | ||||||
|  | 			local-mac-address = [000000000000]; | ||||||
|  | 			qcom,phy-mdio-addr = <30>; | ||||||
|  | 			qcom,link-poll = <1>; | ||||||
|  | 			phy-mode = "sgmii"; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		x5-cpe { | ||||||
|  | 			compatible = "x55-poweron"; | ||||||
|  | 			pwykey = <&extgpio2 13 0>; | ||||||
|  | 			status = "ok"; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		/* EDMA host driver configuration for the board */ | ||||||
|  | 		edma@3ab00000 { | ||||||
|  | 			qcom,txdesc-ring-start = <4>;		/* Tx desc ring start ID */ | ||||||
|  | 			qcom,txdesc-rings = <12>;		/* Total number of Tx desc rings to be provisioned */ | ||||||
|  | 			qcom,mht-txdesc-rings = <8>;            /* Extra Tx desc rings to be provisioned for MHT SW ports */ | ||||||
|  | 			qcom,txcmpl-ring-start = <4>;		/* Tx complete ring start ID */ | ||||||
|  | 			qcom,txcmpl-rings = <12>;		/* Total number of Tx complete rings to be provisioned */ | ||||||
|  | 			qcom,mht-txcmpl-rings = <8>;            /* Extra Tx complete rings to be provisioned for mht sw ports. */ | ||||||
|  | 			qcom,rxfill-ring-start = <4>;		/* Rx fill ring start ID */ | ||||||
|  | 			qcom,rxfill-rings = <4>;		/* Total number of Rx fill rings to be provisioned */ | ||||||
|  | 			qcom,rxdesc-ring-start = <12>;		/* Rx desc ring start ID */ | ||||||
|  | 			qcom,rxdesc-rings = <4>;		/* Total number of Rx desc rings to be provisioned */ | ||||||
|  | 			qcom,rx-page-mode = <0>;		/* Rx fill ring page mode */ | ||||||
|  | 			qcom,tx-map-priority-level = <1>;	/* Tx priority level per port */ | ||||||
|  | 			qcom,rx-map-priority-level = <1>;	/* Rx priority level per core */ | ||||||
|  | 			qcom,ppeds-num = <2>;			/* Number of PPEDS nodes */ | ||||||
|  | 			/* PPE-DS node format: <Rx-fill Tx-cmpl Rx Tx Queue-base Queue-count> */ | ||||||
|  | 			qcom,ppeds-map = <1 1 1 1 32 8>,	/* PPEDS Node#0 ring and queue map */ | ||||||
|  | 					<2 2 2 2 40 8>;		/* PPEDS Node#1 ring and queue map */ | ||||||
|  | 			qcom,txdesc-map = <8 9 10 11>,		/* Port0 per-core Tx ring map */ | ||||||
|  | 					<12 13 14 15>,        /* MHT-Port1 per-core Tx ring map */ | ||||||
|  | 					<4 5 6 7>,            /* MHT-Port2 per-core Tx ring map/packets from  vp*/ | ||||||
|  | 					<16 17 18 19>,        /* MHT-Port3 per-core Tx ring map */ | ||||||
|  | 					<20 21 22 23>;        /* MHT-Port4 per-core Tx ring map */ | ||||||
|  | 			qcom,txdesc-fc-grp-map = <1 2 3 4 5>;   /* Per GMAC flow control group map */ | ||||||
|  | 			qcom,rxfill-map = <4 5 6 7>;		/* Per-core Rx fill ring map */ | ||||||
|  | 			qcom,rxdesc-map = <12 13 14 15>;	/* Per-core Rx desc ring map */ | ||||||
|  | 			qcom,rx-queue-start = <0>;		/* Rx queue start */ | ||||||
|  | 			qcom,rx-ring-queue-map = <0 8 16 24>,	/* Priority 0 queues per-core Rx ring map */ | ||||||
|  | 						<1 9 17 25>,	/* Priority 1 queues per-core Rx ring map */ | ||||||
|  | 						<2 10 18 26>,	/* Priority 2 queues per-core Rx ring map */ | ||||||
|  | 						<3 11 19 27>,	/* Priority 3 queues per-core Rx ring map */ | ||||||
|  | 						<4 12 20 28>,	/* Priority 4 queues per-core Rx ring map */ | ||||||
|  | 						<5 13 21 29>,	/* Priority 5 queues per-core Rx ring map */ | ||||||
|  | 						<6 14 22 30>,	/* Priority 6 queues per-core Rx ring map */ | ||||||
|  | 						<7 15 23 31>;	/* Priority 7 queues per-core Rx ring map */ | ||||||
|  | 			interrupts = <0 163 4>,			/* Tx complete ring id #4 IRQ info */ | ||||||
|  | 				   <0 164 4>,			/* Tx complete ring id #5 IRQ info */ | ||||||
|  | 				   <0 165 4>,			/* Tx complete ring id #6 IRQ info */ | ||||||
|  | 				   <0 166 4>,			/* Tx complete ring id #7 IRQ info */ | ||||||
|  | 				   <0 167 4>,			/* Tx complete ring id #8 IRQ info */ | ||||||
|  | 				   <0 168 4>,			/* Tx complete ring id #9 IRQ info */ | ||||||
|  | 				   <0 169 4>,			/* Tx complete ring id #10 IRQ info */ | ||||||
|  | 				   <0 170 4>,			/* Tx complete ring id #11 IRQ info */ | ||||||
|  | 				   <0 171 4>,			/* Tx complete ring id #12 IRQ info */ | ||||||
|  | 				   <0 172 4>,			/* Tx complete ring id #13 IRQ info */ | ||||||
|  | 				   <0 173 4>,			/* Tx complete ring id #14 IRQ info */ | ||||||
|  | 				   <0 174 4>,			/* Tx complete ring id #15 IRQ info */ | ||||||
|  | 				   <0 139 4>,			/* Rx desc ring id #12 IRQ info */ | ||||||
|  | 				   <0 140 4>,			/* Rx desc ring id #13 IRQ info */ | ||||||
|  | 				   <0 141 4>,			/* Rx desc ring id #14 IRQ info */ | ||||||
|  | 				   <0 142 4>,			/* Rx desc ring id #15 IRQ info */ | ||||||
|  | 				   <0 191 4>,			/* Misc error IRQ info */ | ||||||
|  | 				<0 160 4>,			/* PPEDS Node #1(TxComp ring id #1) TxComplete IRQ info */ | ||||||
|  | 				<0 128 4>,			/* PPEDS Node #1(Rx Desc ring id #1) Rx Desc IRQ info */ | ||||||
|  | 				<0 152 4>,			/* PPEDS Node #1(RxFill Desc ring id #1) Rx Fill IRQ info */ | ||||||
|  | 				<0 161 4>,			/* PPEDS Node #2(TxComp ring id #2) TxComplete IRQ info */ | ||||||
|  | 				<0 129 4>,			/* PPEDS Node #2(Rx Desc ring id #2) Rx Desc IRQ info */ | ||||||
|  | 				<0 153 4>,                      /* PPEDS Node #2(RxFill Desc ring id #2) Rx Fill IRQ info */ | ||||||
|  | 				<0 175 4>,                   /* MHT port Tx complete ring id #16 IRQ info */ | ||||||
|  | 				<0 176 4>,                   /* MHT port Tx complete ring id #17 IRQ info */ | ||||||
|  | 				<0 177 4>,                   /* MHT port Tx complete ring id #18 IRQ info */ | ||||||
|  | 				<0 178 4>,                   /* MHT port Tx complete ring id #19 IRQ info */ | ||||||
|  | 				<0 179 4>,                   /* MHT port Tx complete ring id #20 IRQ info */ | ||||||
|  | 				<0 180 4>,                   /* MHT port Tx complete ring id #21 IRQ info */ | ||||||
|  | 				<0 181 4>,                   /* MHT port Tx complete ring id #22 IRQ info */ | ||||||
|  | 				<0 182 4>;                   /* MHT port Tx complete ring id #23 IRQ info */ | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		pwmleds { | ||||||
|  | 			compatible = "pwm-leds"; | ||||||
|  |  | ||||||
|  | 			led_power_red:red { | ||||||
|  | 				label = "pwm:red"; | ||||||
|  | 				pwms = <&pwm 3 1250000>; | ||||||
|  | 				max-brightness = <160>; | ||||||
|  | 				linux,default-trigger = "none"; | ||||||
|  | 				default-state = "off"; | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			led_power_green:green { | ||||||
|  | 				label = "pwm:green"; | ||||||
|  | 				pwms = <&pwm 2 1250000>; | ||||||
|  | 				max-brightness = <160>; | ||||||
|  | 				linux,default-trigger = "none"; | ||||||
|  | 				default-state = "off"; | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			led_power_blue: blue { | ||||||
|  | 				label = "pwm:blue"; | ||||||
|  | 				pwms = <&pwm 1 1250000>; | ||||||
|  | 				max-brightness = <160>; | ||||||
|  | 				linux,default-trigger = "none"; | ||||||
|  | 				default-state = "off"; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		gpio_keys { | ||||||
|  | 			compatible = "gpio-keys"; | ||||||
|  | 			pinctrl-0 = <&button_pins>; | ||||||
|  | 			pinctrl-names = "default"; | ||||||
|  | 			status = "okay"; | ||||||
|  |  | ||||||
|  | 			button@1 { | ||||||
|  | 				label = "rst"; | ||||||
|  | 				linux,code = <KEY_RESTART>; | ||||||
|  | 				gpios = <&tlmm 24 GPIO_ACTIVE_LOW>; | ||||||
|  | 				linux,input-type = <1>; | ||||||
|  | 				debounce-interval = <60>; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		wsi: wsi { | ||||||
|  | 			id = <0>; | ||||||
|  | 			num_chip = <2>; | ||||||
|  | 			status = "okay"; | ||||||
|  | 			chip_info = <0 1 1>, | ||||||
|  | 				    <1 1 0>; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &wifi0 { | ||||||
|  | 	led-gpio = <&tlmm 36 GPIO_ACTIVE_HIGH>; | ||||||
|  | 	qcom,rproc = <&q6_wcss_pd1>; | ||||||
|  | 	qcom,rproc_rpd = <&q6v5_wcss>; | ||||||
|  | 	qcom,multipd_arch; | ||||||
|  | 	qcom,userpd-subsys-name = "q6v5_wcss_userpd1"; | ||||||
|  | 	memory-region = <&q6_region>; | ||||||
|  | 	qcom,wsi = <&wsi>; | ||||||
|  | 	qcom,wsi_index = <0>; | ||||||
|  | 	qcom,board_id = <0x12>; | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &qcn9224_pcie1 { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &blsp1_uart0 { | ||||||
|  | 	pinctrl-0 = <&serial_0_pins>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &blsp1_uart1 { | ||||||
|  | 	pinctrl-0 = <&serial_1_pins &pta_slic>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &blsp1_i2c1 { | ||||||
|  | 	status = "okay"; | ||||||
|  | 	clock-frequency  = <400000>; | ||||||
|  | 	pinctrl-0 = <&i2c_1_pins>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	extgpio:pca9555@20{ | ||||||
|  | 		compatible = "nxp,pca9555"; | ||||||
|  | 		reg = <0x20>; | ||||||
|  | 		pinctrl-names = "default"; | ||||||
|  | 		gpio-controller; | ||||||
|  | 		#gpio-cells = <2>; | ||||||
|  | 		status = "okay"; | ||||||
|  |  | ||||||
|  | 	}; | ||||||
|  | 	extgpio2:pca9555@21{ | ||||||
|  | 		compatible = "nxp,pca9555"; | ||||||
|  | 		reg = <0x21>; | ||||||
|  | 		pinctrl-names = "default"; | ||||||
|  | 		gpio-controller; | ||||||
|  | 		#gpio-cells = <2>; | ||||||
|  | 		status = "okay"; | ||||||
|  | 	}; | ||||||
|  | 	lsm303_acc@19{ | ||||||
|  | 		compatible = "st,lsm303agr_acc"; | ||||||
|  | 		reg = <0x19>; | ||||||
|  | 	}; | ||||||
|  | 	lsm303_mag@1e{ | ||||||
|  | 		compatible = "st,lsm303agr_mag"; | ||||||
|  | 		reg = <0x1e>; | ||||||
|  | 	}; | ||||||
|  | 	ilps22qs@5c{ | ||||||
|  | 		compatible = "st,ilps22qs"; | ||||||
|  | 		reg = <0x5c>; | ||||||
|  | 	}; | ||||||
|  | 	temp-sense@70 { | ||||||
|  | 		compatible = "ti,tmp103"; | ||||||
|  | 		reg = <0x70>; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &blsp1_spi0 { | ||||||
|  | 	pinctrl-0 = <&spi_0_data_clk_pins &spi_0_cs_pins>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	status = "okay"; | ||||||
|  |  | ||||||
|  | 	flash@0 { | ||||||
|  | 		compatible = "n25q128a11", "micron,n25q128a11", "jedec,spi-nor"; | ||||||
|  | 		reg = <0>; | ||||||
|  | 		#address-cells = <1>; | ||||||
|  | 		#size-cells = <1>; | ||||||
|  | 		spi-max-frequency = <50000000>; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &blsp1_spi2 { | ||||||
|  | 	pinctrl-0 = <&spi_2_pins>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	cs-select = <0>; | ||||||
|  | 	status = "disabled"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &sdhc { | ||||||
|  |         bus-width = <4>; | ||||||
|  |         max-frequency = <192000000>; | ||||||
|  |         mmc-ddr-1_8v; | ||||||
|  |         mmc-hs200-1_8v; | ||||||
|  |         non-removable; | ||||||
|  |         pinctrl-0 = <&sdc_default_state>; | ||||||
|  |         reset = <&tlmm 20 0>; | ||||||
|  |         pinctrl-names = "default"; | ||||||
|  |         status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &sleep_clk { | ||||||
|  | 	clock-frequency = <32000>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &xo { | ||||||
|  | 	clock-frequency = <24000000>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &qpic_bam { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &pcie1_phy_x2 { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &pcie0_phy { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &pcie0 { | ||||||
|  | 	pinctrl-0 = <&pcie0_default_state>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	perst-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &pcie1 { | ||||||
|  | 	pinctrl-0 = <&pcie1_default_state>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	perst-gpios = <&tlmm 47 GPIO_ACTIVE_LOW>; | ||||||
|  | 	status = "okay"; | ||||||
|  |  | ||||||
|  | 	pcie1_rp { | ||||||
|  | 		reg = <0 0 0 0 0>; | ||||||
|  |  | ||||||
|  | 		qcom,mhi@1 { | ||||||
|  | 			reg = <0 0 0 0 0>; | ||||||
|  | 			boot-args = <0x2 0x4 0x34 0x3 0x0 0x0     /* MX Rail, GPIO52, Drive strength 0x3 */ | ||||||
|  | 					0x4 0x4 0x18 0x3 0x0 0x0  /* RFA1p2 Rail, GPIO24, Drive strength 0x3 */ | ||||||
|  | 					0x0 0x4 0x0 0x0 0x0 0x0>; /* End of arguments */ | ||||||
|  | 			memory-region = <&qcn9224_pcie1>; | ||||||
|  | 			qcom,wsi = <&wsi>; | ||||||
|  | 			qcom,wsi_index = <1>; | ||||||
|  | 			qcom,board_id = <0x1015>; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* PINCTRL */ | ||||||
|  |  | ||||||
|  | &tlmm { | ||||||
|  | 	i2c_1_pins: i2c-1-state { | ||||||
|  | 		pins = "gpio29", "gpio30"; | ||||||
|  | 		function = "blsp1_i2c0"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-up; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	spi_2_pins: spi-2-pins { | ||||||
|  | 		pins = "gpio33", "gpio34", "gpio35", "gpio36"; | ||||||
|  | 		function = "blsp2_spi0"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-down; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	 pta_slic: pta_slic { | ||||||
|  | 		pta1_0 { | ||||||
|  | 			pins = "gpio49"; | ||||||
|  | 			function = "pta1_0"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 			bias-disable; | ||||||
|  | 		}; | ||||||
|  | 		pta1_1 { | ||||||
|  | 			pins = "gpio50"; | ||||||
|  | 			function = "pta1_1"; | ||||||
|  |                         drive-strength = <8>; | ||||||
|  | 			bias-disable; | ||||||
|  |                 }; | ||||||
|  | 		pta1_2 { | ||||||
|  | 			pins = "gpio51"; | ||||||
|  | 			function = "pta1_2"; | ||||||
|  |                         drive-strength = <8>; | ||||||
|  | 			bias-disable; | ||||||
|  |                 }; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	spi_0_data_clk_pins: spi-0-data-clk-state { | ||||||
|  | 		pins = "gpio14", "gpio15", "gpio16"; | ||||||
|  | 		function = "blsp0_spi"; | ||||||
|  | 		drive-strength = <2>; | ||||||
|  | 		bias-pull-down; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	spi_0_cs_pins: spi-0-cs-state { | ||||||
|  | 		pins = "gpio17"; | ||||||
|  | 		function = "blsp0_spi"; | ||||||
|  | 		drive-strength = <2>; | ||||||
|  | 		bias-pull-up; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	serial_1_pins: serial1-pinmux { | ||||||
|  | 		pins = "gpio33", "gpio34", "gpio35", "gpio36"; | ||||||
|  | 		function = "blsp1_uart2"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-up; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	button_pins: button-state { | ||||||
|  | 		pins = "gpio24"; | ||||||
|  | 		function = "gpio"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-up; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	pwm_pins: pwm-state { | ||||||
|  |  | ||||||
|  | 		mux_1 { | ||||||
|  | 			pins = "gpio25"; | ||||||
|  | 			function = "pwm2"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 		}; | ||||||
|  | 		mux_2 { | ||||||
|  | 			pins = "gpio26"; | ||||||
|  | 			function = "pwm2"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 		}; | ||||||
|  | 		mux_3 { | ||||||
|  | 			pins = "gpio31"; | ||||||
|  | 			function = "pwm1"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	sdc_default_state: sdc-default-state { | ||||||
|  |                 clk-pins { | ||||||
|  |                         pins = "gpio13"; | ||||||
|  |                         function = "sdc_clk"; | ||||||
|  |                         drive-strength = <8>; | ||||||
|  |                         bias-disable; | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 cmd-pins { | ||||||
|  |                         pins = "gpio12"; | ||||||
|  |                         function = "sdc_cmd"; | ||||||
|  |                         drive-strength = <8>; | ||||||
|  |                         bias-pull-up; | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 data-pins { | ||||||
|  |                         pins = "gpio8", "gpio9", "gpio10", "gpio11"; | ||||||
|  |                         function = "sdc_data"; | ||||||
|  |                         drive-strength = <8>; | ||||||
|  |                         bias-pull-up; | ||||||
|  |                 }; | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  | 	pcie0_default_state: pcie0-default-state { | ||||||
|  | 		pins = "gpio38"; | ||||||
|  | 		function = "gpio"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-up; | ||||||
|  | 		output-low; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	pcie1_default_state: pcie1-default-state { | ||||||
|  | 		pins = "gpio47"; | ||||||
|  | 		function = "gpio"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-up; | ||||||
|  | 		output-low; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &license_manager { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &usb3 { | ||||||
|  | 	qcom,select-utmi-as-pipe-clk; | ||||||
|  | 	status = "okay"; | ||||||
|  | 	dwc3@8a00000 { | ||||||
|  |                 /delete-property/ #phy-cells; | ||||||
|  |                 /delete-property/ phys; | ||||||
|  |                 /delete-property/ phy-names; | ||||||
|  |         }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &pwm { | ||||||
|  | 	pinctrl-0 = <&pwm_pins>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	dft-pwm-status = <0>, <0>, <1>, <0>; | ||||||
|  |         poe_type_pin = <&extgpio 0 0 &extgpio 1 0 &extgpio 2 0>; | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &hs_m31phy_0 { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
							
								
								
									
										687
									
								
								feeds/qca-wifi-7/ipq53xx/dts/ipq5332-sonicfi-rap750e-s.dts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										687
									
								
								feeds/qca-wifi-7/ipq53xx/dts/ipq5332-sonicfi-rap750e-s.dts
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,687 @@ | |||||||
|  | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) | ||||||
|  | /* | ||||||
|  |  * IPQ5332 RDP477 board device tree source | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. | ||||||
|  |  * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /dts-v1/; | ||||||
|  |  | ||||||
|  | #include "ipq5332.dtsi" | ||||||
|  | #include <dt-bindings/gpio/gpio.h> | ||||||
|  | #include <dt-bindings/input/input.h> | ||||||
|  | #include <dt-bindings/leds/common.h> | ||||||
|  | #include "ipq5332-default-memory.dtsi" | ||||||
|  |  | ||||||
|  | / { | ||||||
|  | 	model = "SONICFI RAP750E-S"; | ||||||
|  | 	compatible = "sonicfi,rap750e-s","qcom,ipq5332-ap-mi01.3-c2", "qcom,ipq5332"; | ||||||
|  |  | ||||||
|  | #ifdef __IPQ_MEM_PROFILE_512_MB__ | ||||||
|  |        /*	512M Memory Layout for IPQ5332 + QCN6432 | ||||||
|  | 	* +==========+==============+========================+ | ||||||
|  | 	* |         |              |                         | | ||||||
|  | 	* |  Region | Start Offset |          Size           | | ||||||
|  | 	* |         |              |                         | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |   Q6    |              |                         | | ||||||
|  | 	* |  code/  |  0x4A900000  |          20MB           | | ||||||
|  | 	* |  data   |              |                         | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* | IPQ5332 |              |                         | | ||||||
|  | 	* |  data   |  0x4BD00000  |          17MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* | IPQ5332 |              |                         | | ||||||
|  | 	* | M3 Dump |  0x4CE00000  |           1MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* | IPQ5332 |              |                         | | ||||||
|  | 	* |  QDSS   |  0x4CF00000  |           1MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |IPQ5332  |              |                         | | ||||||
|  | 	* |  CALDB  |  0x4D000000  |           3MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* |  data   |  0x4D300000  |          16MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* | M3 Dump |  0x4E300000  |           1MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* |  QDSS   |  0x4E400000  |           1MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* |  CALDB  |  0x4E500000  |           5MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* |MEM_HOLE |  0x4EA00000  |           5MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |         |              |                         | | ||||||
|  | 	* |   MLO   |  0x4EF00000  |          17MB           | | ||||||
|  | 	* +==================================================+ | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |             Rest of memory for Linux             | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* +==================================================+ | ||||||
|  | 	*/ | ||||||
|  |  | ||||||
|  | 	reserved-memory { | ||||||
|  |  | ||||||
|  | 		/delete-node/ m3_dump@4cc00000; | ||||||
|  | 		/delete-node/ q6_etr_dump@1; | ||||||
|  | 		/delete-node/ mlo_global_mem_0@0x4db00000; | ||||||
|  | 		/delete-node/ wcnss@4a900000; | ||||||
|  | 		/delete-node/ q6_caldb_region@4ce00000; | ||||||
|  |  | ||||||
|  | 		q6_mem_regions: q6_mem_regions@4A900000  { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4A900000 0x0 0x4600000>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		q6_code_data: q6_code_data@4A900000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4A900000 0x0 0x1400000>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		q6_ipq5332_data: q6_ipq5332_data@4BD00000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4BD00000 0x0 0x1100000>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		m3_dump: m3_dump@4CE00000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4CE00000 0x0 0x100000>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		q6_etr_region: q6_etr_dump@4CF00000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4CF00000 0x0 0x100000>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		q6_ipq5332_caldb: q6_ipq5332_caldb@4D000000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4D000000 0x0 0x300000>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		q6_qcn6432_data_1: q6_qcn6432_data_1@4D300000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4D300000 0x0 0x1000000>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		m3_dump_qcn6432_1: m3_dump_qcn6432_1@4E300000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4E300000 0x0 0x100000>; | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  | 		q6_qcn6432_etr_1: q6_qcn6432_etr_1@4E400000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4E400000 0x0 0x100000>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		q6_qcn6432_caldb_1: q6_qcn6432_caldb_1@4E500000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4E500000 0x0 0x500000>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		mlo_global_mem0: mlo_global_mem_0@4EF00000 { | ||||||
|  | 			no-map; | ||||||
|  | 			reg = <0x0 0x4EF00000 0x0 0x1100000>; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | #else | ||||||
|  |        /*      1G Memory Layout for IPQ5332 + QCN6432 | ||||||
|  | 	* +==========+==============+========================+ | ||||||
|  | 	* |         |              |                         | | ||||||
|  | 	* |  Region | Start Offset |          Size           | | ||||||
|  | 	* |         |              |                         | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |   Q6    |              |                         | | ||||||
|  | 	* |  code/  |  0x4A900000  |          20MB           | | ||||||
|  | 	* |  data   |              |                         | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* | IPQ5332 |              |                         | | ||||||
|  | 	* |  data   |  0x4BD00000  |          21MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* | IPQ5332 |              |                         | | ||||||
|  | 	* | M3 Dump |  0x4D200000  |           1MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* | IPQ5332 |              |                         | | ||||||
|  | 	* |  QDSS   |  0x4D300000  |           1MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |IPQ5332  |              |                         | | ||||||
|  | 	* |  CALDB  |  0x4D400000  |           5MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* |  data   |  0x4D900000  |          21MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* | M3 Dump |  0x4EE00000  |           1MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* |  QDSS   |  0x4EF00000  |           1MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* |  CALDB  |  0x4F000000  |           5MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |QCN6432_1|              |                         | | ||||||
|  | 	* |MEM_HOLE |  0x4F500000  |           5MB           | | ||||||
|  | 	* +---------+--------------+-------------------------+ | ||||||
|  | 	* |         |              |                         | | ||||||
|  | 	* |   MLO   |  0x4FA00000  |          17MB           | | ||||||
|  | 	* +==================================================+ | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |             Rest of memory for Linux             | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* |                                                  | | ||||||
|  | 	* +==================================================+ | ||||||
|  | 	*/ | ||||||
|  | 	reserved-memory { | ||||||
|  |  | ||||||
|  | 		/delete-node/ m3_dump@4cc00000; | ||||||
|  | 		/delete-node/ q6_etr_dump@1; | ||||||
|  | 		/delete-node/ mlo_global_mem_0@0x4db00000; | ||||||
|  | 		/delete-node/ wcnss@4a900000; | ||||||
|  | 		/delete-node/ q6_caldb_region@4ce00000; | ||||||
|  |  | ||||||
|  | 		q6_mem_regions: q6_mem_regions@4A900000  { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4A900000 0x0 0x5100000>; | ||||||
|  | 		}; | ||||||
|  | 		q6_code_data: q6_code_data@4A900000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4A900000 0x0 0x1400000>; | ||||||
|  | 		}; | ||||||
|  | 		q6_ipq5332_data: q6_ipq5332_data@4BD00000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4BD00000 0x0 0x1500000>; | ||||||
|  | 		}; | ||||||
|  | 		m3_dump: m3_dump@4D200000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4D200000 0x0 0x100000>; | ||||||
|  | 		}; | ||||||
|  | 		q6_etr_region: q6_etr_dump@4D300000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4D300000 0x0 0x100000>; | ||||||
|  | 		}; | ||||||
|  | 		q6_ipq5332_caldb: q6_ipq5332_caldb@4D400000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4D400000 0x0 0x500000>; | ||||||
|  | 		}; | ||||||
|  | 		q6_qcn6432_data_1: q6_qcn6432_data_1@4D900000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4D900000 0x0 0x1500000>; | ||||||
|  | 		}; | ||||||
|  | 		m3_dump_qcn6432_1: m3_dump_qcn6432_1@4EE00000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4EE00000 0x0 0x100000>; | ||||||
|  | 		}; | ||||||
|  | 		q6_qcn6432_etr_1: q6_qcn6432_etr_1@4EF00000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4EF00000 0x0 0x100000>; | ||||||
|  | 		}; | ||||||
|  | 		q6_qcn6432_caldb_1: q6_qcn6432_caldb_1@4F000000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4F000000 0x0 0x500000>; | ||||||
|  | 		}; | ||||||
|  | 		mlo_global_mem0: mlo_global_mem_0@4FA00000 { | ||||||
|  | 		        no-map; | ||||||
|  | 		        reg = <0x0 0x4FA00000 0x0 0x1100000>; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  | 	aliases { | ||||||
|  | 		serial0 = &blsp1_uart0; | ||||||
|  | 		serial1 = &blsp1_uart1; | ||||||
|  | 		ethernet0 = "/soc/dp1"; | ||||||
|  | 		//ethernet1 = "/soc/dp2"; | ||||||
|  | 		led-boot = &led_power; | ||||||
|  | 		led-failsafe = &led_power; | ||||||
|  | 		led-running = &led_power; | ||||||
|  | 		led-upgrade = &led_power; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	chosen { | ||||||
|  | 		stdout-path = "serial0"; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	soc@0 { | ||||||
|  | 		mdio:mdio@90000 { | ||||||
|  | 			pinctrl-0 = <&mdio1_pins>; | ||||||
|  | 			pinctrl-names = "default"; | ||||||
|  | 			/*gpio26 for manhattan reset*/ | ||||||
|  | 			phy-reset-gpio = <&tlmm 26 GPIO_ACTIVE_LOW>; | ||||||
|  | 			status = "okay"; | ||||||
|  |  | ||||||
|  | 			phy0: ethernet-phy@0 { | ||||||
|  | 				reg = <16>; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		gpio_keys { | ||||||
|  | 			compatible = "gpio-keys"; | ||||||
|  | 			pinctrl-0 = <&button_pins>; | ||||||
|  | 			pinctrl-names = "default"; | ||||||
|  | 			status = "okay"; | ||||||
|  |  | ||||||
|  | 			button@1 { | ||||||
|  | 				label = "reset"; | ||||||
|  | 				linux,code = <KEY_RESTART>; | ||||||
|  | 				gpios = <&tlmm 24 GPIO_ACTIVE_LOW>; | ||||||
|  | 				linux,input-type = <1>; | ||||||
|  | 				debounce-interval = <60>; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		pwmleds { | ||||||
|  | 			compatible = "pwm-leds"; | ||||||
|  |  | ||||||
|  | 			red { | ||||||
|  | 				label = "pwm:red"; | ||||||
|  | 				pwms = <&pwm 2 1250000>; | ||||||
|  | 				max-brightness = <255>; | ||||||
|  | 				linux,default-trigger = "none"; | ||||||
|  | 			}; | ||||||
|  | 		 | ||||||
|  | 			green { | ||||||
|  | 				label = "pwm:green"; | ||||||
|  | 				pwms = <&pwm 3 1250000>; | ||||||
|  | 				max-brightness = <255>; | ||||||
|  | 				linux,default-trigger = "none"; | ||||||
|  | 			}; | ||||||
|  | 		 | ||||||
|  | 			led_power: blue { | ||||||
|  | 				label = "pwm:blue"; | ||||||
|  | 				pwms = <&pwm 1 1250000>; | ||||||
|  | 				max-brightness = <255>; | ||||||
|  | 				linux,default-trigger = "none"; | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			white { | ||||||
|  | 				label = "pwm:white"; | ||||||
|  | 				pwms = <&pwm 0 1250000>; | ||||||
|  | 				max-brightness = <255>; | ||||||
|  | 				linux,default-trigger = "none"; | ||||||
|  | 			};			 | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		ess-instance { | ||||||
|  | 			num_devices = <0x1>; | ||||||
|  |  | ||||||
|  | 			ess-switch@3a000000 { | ||||||
|  | 				switch_cpu_bmp = <0x1>;  /* cpu port bitmap */ | ||||||
|  | 				switch_lan_bmp = <0x4>; /* lan port bitmap */ | ||||||
|  | 				switch_wan_bmp = <0x0>; /* wan port bitmap */ | ||||||
|  | 				switch_mac_mode = <0xff>; /* mac mode for uniphy instance0*/ | ||||||
|  | 				switch_mac_mode1 = <0xf>; /* mac mode for uniphy instance1*/ | ||||||
|  | 				switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/ | ||||||
|  |  | ||||||
|  | 				qcom,port_phyinfo { | ||||||
|  | 					port@1 { | ||||||
|  | 						port_id = <2>; | ||||||
|  | 						phy_address = <16>; | ||||||
|  | 					}; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		dp1 { | ||||||
|  | 			device_type = "network"; | ||||||
|  | 			compatible = "qcom,nss-dp"; | ||||||
|  | 			qcom,id = <2>; | ||||||
|  | 			reg = <0x3a504000 0x4000>; | ||||||
|  | 			qcom,mactype = <1>; | ||||||
|  | 			local-mac-address = [000000000000]; | ||||||
|  | 			mdio-bus = <&mdio>; | ||||||
|  | 			qcom,phy-mdio-addr = <16>; | ||||||
|  | 			qcom,link-poll = <1>; | ||||||
|  | 			phy-mode = "sgmii"; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		/* EDMA host driver configuration for the board */ | ||||||
|  | 		edma@3ab00000 { | ||||||
|  | 			qcom,txdesc-ring-start = <4>;		/* Tx desc ring start ID */ | ||||||
|  | 			qcom,txdesc-rings = <12>;		/* Total number of Tx desc rings to be provisioned */ | ||||||
|  | 			qcom,mht-txdesc-rings = <8>;            /* Extra Tx desc rings to be provisioned for MHT SW ports */ | ||||||
|  | 			qcom,txcmpl-ring-start = <4>;		/* Tx complete ring start ID */ | ||||||
|  | 			qcom,txcmpl-rings = <12>;		/* Total number of Tx complete rings to be provisioned */ | ||||||
|  | 			qcom,mht-txcmpl-rings = <8>;            /* Extra Tx complete rings to be provisioned for mht sw ports. */ | ||||||
|  | 			qcom,rxfill-ring-start = <4>;		/* Rx fill ring start ID */ | ||||||
|  | 			qcom,rxfill-rings = <4>;		/* Total number of Rx fill rings to be provisioned */ | ||||||
|  | 			qcom,rxdesc-ring-start = <12>;		/* Rx desc ring start ID */ | ||||||
|  | 			qcom,rxdesc-rings = <4>;		/* Total number of Rx desc rings to be provisioned */ | ||||||
|  | 			qcom,rx-page-mode = <0>;		/* Rx fill ring page mode */ | ||||||
|  | 			qcom,tx-map-priority-level = <1>;	/* Tx priority level per port */ | ||||||
|  | 			qcom,rx-map-priority-level = <1>;	/* Rx priority level per core */ | ||||||
|  | 			qcom,ppeds-num = <2>;			/* Number of PPEDS nodes */ | ||||||
|  | 			/* PPE-DS node format: <Rx-fill Tx-cmpl Rx Tx Queue-base Queue-count> */ | ||||||
|  | 			qcom,ppeds-map = <1 1 1 1 32 8>,	/* PPEDS Node#0 ring and queue map */ | ||||||
|  | 					<2 2 2 2 40 8>;		/* PPEDS Node#1 ring and queue map */ | ||||||
|  | 			qcom,txdesc-map = <8 9 10 11>,		/* Port0 per-core Tx ring map */ | ||||||
|  | 					  <12 13 14 15>,        /* MHT-Port1 per-core Tx ring map */ | ||||||
|  | 					  <4 5 6 7>,            /* MHT-Port2 per-core Tx ring map/packets from  vp*/ | ||||||
|  | 					  <16 17 18 19>,        /* MHT-Port3 per-core Tx ring map */ | ||||||
|  | 					  <20 21 22 23>;        /* MHT-Port4 per-core Tx ring map */ | ||||||
|  | 			qcom,txdesc-fc-grp-map = <1 2 3 4 5>;   /* Per GMAC flow control group map */ | ||||||
|  | 			qcom,rxfill-map = <4 5 6 7>;		/* Per-core Rx fill ring map */ | ||||||
|  | 			qcom,rxdesc-map = <12 13 14 15>;	/* Per-core Rx desc ring map */ | ||||||
|  | 			qcom,rx-queue-start = <0>;		/* Rx queue start */ | ||||||
|  | 			qcom,rx-ring-queue-map = <0 8 16 24>,	/* Priority 0 queues per-core Rx ring map */ | ||||||
|  | 						<1 9 17 25>,	/* Priority 1 queues per-core Rx ring map */ | ||||||
|  | 						<2 10 18 26>,	/* Priority 2 queues per-core Rx ring map */ | ||||||
|  | 						<3 11 19 27>,	/* Priority 3 queues per-core Rx ring map */ | ||||||
|  | 						<4 12 20 28>,	/* Priority 4 queues per-core Rx ring map */ | ||||||
|  | 						<5 13 21 29>,	/* Priority 5 queues per-core Rx ring map */ | ||||||
|  | 						<6 14 22 30>,	/* Priority 6 queues per-core Rx ring map */ | ||||||
|  | 						<7 15 23 31>;	/* Priority 7 queues per-core Rx ring map */ | ||||||
|  | 			interrupts = <0 163 4>,			/* Tx complete ring id #4 IRQ info */ | ||||||
|  | 				   <0 164 4>,			/* Tx complete ring id #5 IRQ info */ | ||||||
|  | 				   <0 165 4>,			/* Tx complete ring id #6 IRQ info */ | ||||||
|  | 				   <0 166 4>,			/* Tx complete ring id #7 IRQ info */ | ||||||
|  | 				   <0 167 4>,			/* Tx complete ring id #8 IRQ info */ | ||||||
|  | 				   <0 168 4>,			/* Tx complete ring id #9 IRQ info */ | ||||||
|  | 				   <0 169 4>,			/* Tx complete ring id #10 IRQ info */ | ||||||
|  | 				   <0 170 4>,			/* Tx complete ring id #11 IRQ info */ | ||||||
|  | 				   <0 171 4>,			/* Tx complete ring id #12 IRQ info */ | ||||||
|  | 				   <0 172 4>,			/* Tx complete ring id #13 IRQ info */ | ||||||
|  | 				   <0 173 4>,			/* Tx complete ring id #14 IRQ info */ | ||||||
|  | 				   <0 174 4>,			/* Tx complete ring id #15 IRQ info */ | ||||||
|  | 				   <0 139 4>,			/* Rx desc ring id #12 IRQ info */ | ||||||
|  | 				   <0 140 4>,			/* Rx desc ring id #13 IRQ info */ | ||||||
|  | 				   <0 141 4>,			/* Rx desc ring id #14 IRQ info */ | ||||||
|  | 				   <0 142 4>,			/* Rx desc ring id #15 IRQ info */ | ||||||
|  | 				   <0 191 4>,			/* Misc error IRQ info */ | ||||||
|  | 				<0 160 4>,			/* PPEDS Node #1(TxComp ring id #1) TxComplete IRQ info */ | ||||||
|  | 				<0 128 4>,			/* PPEDS Node #1(Rx Desc ring id #1) Rx Desc IRQ info */ | ||||||
|  | 				<0 152 4>,			/* PPEDS Node #1(RxFill Desc ring id #1) Rx Fill IRQ info */ | ||||||
|  | 				<0 161 4>,			/* PPEDS Node #2(TxComp ring id #2) TxComplete IRQ info */ | ||||||
|  | 				<0 129 4>,			/* PPEDS Node #2(Rx Desc ring id #2) Rx Desc IRQ info */ | ||||||
|  | 				<0 153 4>,                      /* PPEDS Node #2(RxFill Desc ring id #2) Rx Fill IRQ info */ | ||||||
|  | 				<0 175 4>,                   /* MHT port Tx complete ring id #16 IRQ info */ | ||||||
|  | 				<0 176 4>,                   /* MHT port Tx complete ring id #17 IRQ info */ | ||||||
|  | 				<0 177 4>,                   /* MHT port Tx complete ring id #18 IRQ info */ | ||||||
|  | 				<0 178 4>,                   /* MHT port Tx complete ring id #19 IRQ info */ | ||||||
|  | 				<0 179 4>,                   /* MHT port Tx complete ring id #20 IRQ info */ | ||||||
|  | 				<0 180 4>,                   /* MHT port Tx complete ring id #21 IRQ info */ | ||||||
|  | 				<0 181 4>,                   /* MHT port Tx complete ring id #22 IRQ info */ | ||||||
|  | 				<0 182 4>;                   /* MHT port Tx complete ring id #23 IRQ info */ | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		wsi: wsi { | ||||||
|  | 			id = <0>; | ||||||
|  | 			num_chip = <2>; | ||||||
|  | 			status = "okay"; | ||||||
|  | 			chip_info = <0 1 1>, | ||||||
|  | 				<1 1 0>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		q6v5_wcss: remoteproc@d100000 { | ||||||
|  | 			boot-args = <0x1 0x4 0x3 0x0 0x26 0x2>; | ||||||
|  | 			memory-region = <&q6_mem_regions>; | ||||||
|  |  | ||||||
|  | 			q6_wcss_pd1: remoteproc_pd1 { | ||||||
|  | 				status = "okay"; | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			q6_wcss_pd2: remoteproc_pd2 { | ||||||
|  | 				compatible = "qcom,ipq5332-wcss-pcie-mpd"; | ||||||
|  | 				firmware = "IPQ5332/q6_fw2.mdt"; | ||||||
|  | 				m3_firmware = "qcn6432/iu_fw.mdt"; | ||||||
|  | 				interrupts-extended = <&wcss_smp2p_in 16 0>, | ||||||
|  | 						<&wcss_smp2p_in 17 0>, | ||||||
|  | 						<&wcss_smp2p_in 20 0>, | ||||||
|  | 						<&wcss_smp2p_in 19 0>; | ||||||
|  | 				interrupt-names = "fatal", | ||||||
|  | 						"ready", | ||||||
|  | 						"spawn-ack", | ||||||
|  | 						"stop-ack"; | ||||||
|  | 				qcom,smem-states = <&wcss_smp2p_out 16>, | ||||||
|  | 						<&wcss_smp2p_out 17>, | ||||||
|  | 						<&wcss_smp2p_out 18>; | ||||||
|  | 				qcom,smem-state-names = "shutdown", | ||||||
|  | 							"stop", | ||||||
|  | 							"spawn"; | ||||||
|  | 				status = "okay"; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &blsp1_uart0 { | ||||||
|  | 	pinctrl-0 = <&serial_0_pins>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  | /* | ||||||
|  | &blsp1_uart1 { | ||||||
|  |         pinctrl-0 = <&serial_1_pins>; | ||||||
|  |         pinctrl-names = "default"; | ||||||
|  |         status = "disabled"; | ||||||
|  | }; | ||||||
|  | */ | ||||||
|  | &blsp1_i2c1 { | ||||||
|  | 	clock-frequency  = <400000>; | ||||||
|  | 	pinctrl-0 = <&i2c_1_pins>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &blsp1_spi0 { | ||||||
|  | 	status = "disabled"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &sdhc { | ||||||
|  | 	bus-width = <4>; | ||||||
|  | 	max-frequency = <192000000>; | ||||||
|  | 	mmc-ddr-1_8v; | ||||||
|  | 	mmc-hs200-1_8v; | ||||||
|  | 	non-removable; | ||||||
|  | 	pinctrl-0 = <&sdc_default_state>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	status = "disabled"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &sleep_clk { | ||||||
|  | 	clock-frequency = <32000>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &xo { | ||||||
|  | 	clock-frequency = <24000000>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &qpic_bam { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &qpic_nand { | ||||||
|  | 	pinctrl-0 = <&qspi_default_state>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	status = "okay"; | ||||||
|  |  | ||||||
|  | 	nandcs@0 { | ||||||
|  | 		reg = <0>; | ||||||
|  | 		#address-cells = <1>; | ||||||
|  | 		#size-cells = <1>; | ||||||
|  |  | ||||||
|  | 		nand-ecc-strength = <8>; | ||||||
|  | 		nand-ecc-step-size = <512>; | ||||||
|  | 		nand-bus-width = <8>; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* PINCTRL */ | ||||||
|  |  | ||||||
|  | &tlmm { | ||||||
|  | 	qspi_default_state: qspi-default-state { | ||||||
|  | 		qspi_clock { | ||||||
|  | 			pins = "gpio13"; | ||||||
|  | 			function = "qspi_clk"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 			bias-pull-down; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		qspi_cs { | ||||||
|  | 			pins = "gpio12"; | ||||||
|  | 			function = "qspi_cs"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 			bias-pull-up; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		qspi_data { | ||||||
|  | 			pins = "gpio8", "gpio9", "gpio10", "gpio11"; | ||||||
|  | 			function = "qspi_data"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 			bias-pull-down; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	pwm_pins: pwm_pinmux { | ||||||
|  | 			/* PWM LED GREEN */ | ||||||
|  | 			mux_1 { | ||||||
|  | 				pins = "gpio43"; | ||||||
|  | 				function = "pwm0"; | ||||||
|  | 				drive-strength = <8>; | ||||||
|  | 			}; | ||||||
|  | 			/* PWM LED BLUE */ | ||||||
|  | 			mux_2 { | ||||||
|  | 				pins = "gpio45"; | ||||||
|  | 				function = "pwm0"; | ||||||
|  | 				drive-strength = <8>; | ||||||
|  | 			}; | ||||||
|  | 			/* PWM LED RED */ | ||||||
|  | 			mux_3 { | ||||||
|  | 				pins = "gpio44"; | ||||||
|  | 				function = "pwm0"; | ||||||
|  | 				drive-strength = <8>; | ||||||
|  | 			}; | ||||||
|  | 			/* PWM LED WHITE */ | ||||||
|  | 			mux_4 { | ||||||
|  | 				pins = "gpio46"; | ||||||
|  | 				function = "pwm0"; | ||||||
|  | 				drive-strength = <8>; | ||||||
|  | 			}; | ||||||
|  | 	}; | ||||||
|  | /* | ||||||
|  | 	serial_1_pins: serial1-pinmux { | ||||||
|  | 		pins = "gpio33", "gpio34", "gpio35", "gpio36"; | ||||||
|  | 		function = "blsp1_uart2"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-up; | ||||||
|  | 	}; | ||||||
|  | */ | ||||||
|  | 	i2c_1_pins: i2c-1-state { | ||||||
|  | 		pins = "gpio29", "gpio30"; | ||||||
|  | 		function = "blsp1_i2c0"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-up; | ||||||
|  | 	}; | ||||||
|  | /* | ||||||
|  | 	gpio_leds_default: gpio-leds-default-state { | ||||||
|  | 		pins = "gpio36"; | ||||||
|  | 		function = "gpio"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-down; | ||||||
|  | 	};  | ||||||
|  | */ | ||||||
|  | 	button_pins: button-state { | ||||||
|  | 		pins = "gpio24"; | ||||||
|  | 		function = "gpio"; | ||||||
|  | 		drive-strength = <8>; | ||||||
|  | 		bias-pull-up; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	sdc_default_state: sdc-default-state { | ||||||
|  | 		clk-pins { | ||||||
|  | 			pins = "gpio13"; | ||||||
|  | 			function = "sdc_clk"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 			bias-disable; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		cmd-pins { | ||||||
|  | 			pins = "gpio12"; | ||||||
|  | 			function = "sdc_cmd"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 			bias-pull-up; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		data-pins { | ||||||
|  | 			pins = "gpio8", "gpio9", "gpio10", "gpio11"; | ||||||
|  | 			function = "sdc_data"; | ||||||
|  | 			drive-strength = <8>; | ||||||
|  | 			bias-pull-up; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &license_manager { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &usb3 { | ||||||
|  | 	qcom,select-utmi-as-pipe-clk; | ||||||
|  | 	status = "disabled"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &pwm { | ||||||
|  | 	pinctrl-0 = <&pwm_pins>; | ||||||
|  | 	used-pwm-indices = <1>, <1>, <1>, <1>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &hs_m31phy_0 { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &wifi0 { | ||||||
|  | 	qcom,multipd_arch; | ||||||
|  | 	qcom,rproc = <&q6_wcss_pd1>; | ||||||
|  | 	qcom,rproc_rpd = <&q6v5_wcss>; | ||||||
|  | 	qcom,userpd-subsys-name = "q6v5_wcss_userpd1"; | ||||||
|  | 	qcom,bdf-addr = <0x4BD00000 0x4BD00000 0x0 0x0 0x0 0x0>; | ||||||
|  | 	qcom,caldb-addr = <0x4D400000 0x4D000000 0x0 0x0 0x0 0x0>; | ||||||
|  | #ifdef __IPQ_MEM_PROFILE_512_MB__ | ||||||
|  | 	qcom,tgt-mem-mode = <1>; | ||||||
|  | 	qcom,caldb-size = <0x300000>; | ||||||
|  | #else | ||||||
|  | 	qcom,tgt-mem-mode = <0>; | ||||||
|  | 	qcom,caldb-size = <0x500000>; | ||||||
|  | #endif | ||||||
|  | 	qcom,board_id = <0x1b>; | ||||||
|  | 	memory-region = <&q6_ipq5332_data>; | ||||||
|  | 	qcom,wsi = <&wsi>; | ||||||
|  | 	qcom,wsi_index = <0>; | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &wifi1 { | ||||||
|  | 	qcom,multipd_arch; | ||||||
|  | 	qcom,rproc = <&q6_wcss_pd2>; | ||||||
|  | 	qcom,rproc_rpd = <&q6v5_wcss>; | ||||||
|  | 	qcom,userpd-subsys-name = "q6v5_wcss_userpd2"; | ||||||
|  | 	qcom,bdf-addr = <0x4D900000 0x4D300000 0x0 0x0 0x0 0x0>; | ||||||
|  | 	qcom,caldb-addr = <0x4F000000 0x4E500000 0x0 0x0 0x0 0x0>; | ||||||
|  | 	qcom,umac-irq-reset-addr = <0x20000884>; | ||||||
|  | 	qcom,caldb-size = <0x500000>; | ||||||
|  | #ifdef __IPQ_MEM_PROFILE_512_MB__ | ||||||
|  | 	qcom,tgt-mem-mode = <1>; | ||||||
|  | #else | ||||||
|  | 	qcom,tgt-mem-mode = <0>; | ||||||
|  | #endif | ||||||
|  | 	qcom,board_id = <0x060>; | ||||||
|  | 	memory-region = <&q6_qcn6432_data_1>; | ||||||
|  | 	qcom,wsi = <&wsi>; | ||||||
|  | 	qcom,wsi_index = <1>; | ||||||
|  | 	status = "okay"; | ||||||
|  | 	interrupts = <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>; | ||||||
|  | 	interrupt-names = "umac_reset"; | ||||||
|  | }; | ||||||
| @@ -0,0 +1,157 @@ | |||||||
|  | /* SPDX-License-Identifier: GPL-2.0-only */ | ||||||
|  | /* | ||||||
|  |  * STMicroelectronics ilps22qs driver | ||||||
|  |  * | ||||||
|  |  * Copyright 2023 STMicroelectronics Inc. | ||||||
|  |  * | ||||||
|  |  * MEMS Software Solutions Team | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef __ST_ILPS22QS_H | ||||||
|  | #define __ST_ILPS22QS_H | ||||||
|  |  | ||||||
|  | #include <linux/bitfield.h> | ||||||
|  | #include <linux/iio/iio.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/mutex.h> | ||||||
|  | #include <linux/of.h> | ||||||
|  | #include <linux/regmap.h> | ||||||
|  | #include <linux/types.h> | ||||||
|  | #include <linux/workqueue.h> | ||||||
|  |  | ||||||
|  | #define ST_ILPS22QS_DEV_NAME			"ilps22qs" | ||||||
|  | #define ST_ILPS28QSW_DEV_NAME			"ilps28qsw" | ||||||
|  |  | ||||||
|  | #define ST_ILPS22QS_WHO_AM_I_ADDR		0x0f | ||||||
|  | #define ST_ILPS22QS_WHOAMI_VAL			0xb4 | ||||||
|  |  | ||||||
|  | #define ST_ILPS22QS_CTRL1_ADDR			0x10 | ||||||
|  | #define ST_ILPS22QS_ODR_MASK			GENMASK(6, 3) | ||||||
|  |  | ||||||
|  | #define ST_ILPS22QS_CTRL2_ADDR			0x11 | ||||||
|  | #define ST_ILPS22QS_SOFT_RESET_MASK		BIT(2) | ||||||
|  | #define ST_ILPS22QS_BDU_MASK			BIT(3) | ||||||
|  |  | ||||||
|  | #define ST_ILPS22QS_CTRL3_ADDR			0x12 | ||||||
|  | #define ST_ILPS22QS_AH_QVAR_EN_MASK		BIT(7) | ||||||
|  | #define ST_ILPS22QS_AH_QVAR_P_AUTO_EN_MASK	BIT(5) | ||||||
|  |  | ||||||
|  | #define ST_ILPS22QS_PRESS_OUT_XL_ADDR		0x28 | ||||||
|  | #define ST_ILPS22QS_TEMP_OUT_L_ADDR		0x2b | ||||||
|  |  | ||||||
|  | #define ST_ILPS22QS_PRESS_FS_AVL_GAIN		(1000000000UL / 4096UL) | ||||||
|  | #define ST_ILPS22QS_TEMP_FS_AVL_GAIN		100 | ||||||
|  | #define ST_ILPS22QS_QVAR_FS_AVL_GAIN		438000 | ||||||
|  |  | ||||||
|  | #define ST_ILPS22QS_SHIFT_VAL(val, mask)	(((val) << __ffs(mask)) & (mask)) | ||||||
|  |  | ||||||
|  | #define ST_ILPS22QS_ODR_LIST_NUM		8 | ||||||
|  |  | ||||||
|  | enum st_ilps22qs_sensor_id { | ||||||
|  | 	ST_ILPS22QS_PRESS = 0, | ||||||
|  | 	ST_ILPS22QS_TEMP, | ||||||
|  | 	ST_ILPS22QS_QVAR, | ||||||
|  | 	ST_ILPS22QS_SENSORS_NUM, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct st_ilps22qs_odr_t { | ||||||
|  | 	u8 hz; | ||||||
|  | 	u8 val; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct st_ilps22qs_reg { | ||||||
|  | 	u8 addr; | ||||||
|  | 	u8 mask; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct st_ilps22qs_odr_table_t { | ||||||
|  | 	u8 size; | ||||||
|  | 	struct st_ilps22qs_reg reg; | ||||||
|  | 	struct st_ilps22qs_odr_t odr_avl[ST_ILPS22QS_ODR_LIST_NUM]; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct st_ilps22qs_hw { | ||||||
|  | 	struct iio_dev *iio_devs[ST_ILPS22QS_SENSORS_NUM]; | ||||||
|  | 	struct workqueue_struct *workqueue; | ||||||
|  | 	struct regulator *vddio_supply; | ||||||
|  | 	struct regulator *vdd_supply; | ||||||
|  | 	struct regmap *regmap; | ||||||
|  | 	struct device *dev; | ||||||
|  | 	struct mutex lock; | ||||||
|  | 	bool interleave; | ||||||
|  | 	u8 enable_mask; | ||||||
|  | 	u8 odr; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct st_ilps22qs_sensor { | ||||||
|  | 	enum st_ilps22qs_sensor_id id; | ||||||
|  | 	struct work_struct iio_work; | ||||||
|  | 	struct st_ilps22qs_hw *hw; | ||||||
|  | 	struct hrtimer hr_timer; | ||||||
|  | 	ktime_t ktime; | ||||||
|  | 	int64_t timestamp; | ||||||
|  | 	char name[32]; | ||||||
|  | 	u32 gain; | ||||||
|  | 	u8 odr; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | extern const struct dev_pm_ops st_ilps22qs_pm_ops; | ||||||
|  |  | ||||||
|  | static inline int st_ilps22qs_update_locked(struct st_ilps22qs_hw *hw, | ||||||
|  | 					    unsigned int addr, | ||||||
|  | 					    unsigned int mask, | ||||||
|  | 					    unsigned int data) | ||||||
|  | { | ||||||
|  | 	unsigned int val = ST_ILPS22QS_SHIFT_VAL(data, mask); | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&hw->lock); | ||||||
|  | 	err = regmap_update_bits(hw->regmap, addr, mask, val); | ||||||
|  | 	mutex_unlock(&hw->lock); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static inline int st_ilps22qs_read_locked(struct st_ilps22qs_hw *hw, | ||||||
|  | 					  unsigned int addr, void *val, | ||||||
|  | 					  unsigned int len) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&hw->lock); | ||||||
|  | 	err = regmap_bulk_read(hw->regmap, addr, val, len); | ||||||
|  | 	mutex_unlock(&hw->lock); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static inline void st_ilps22qs_flush_works(struct st_ilps22qs_hw *hw) | ||||||
|  | { | ||||||
|  | 	flush_workqueue(hw->workqueue); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static inline int st_ilps22qs_destroy_workqueue(struct st_ilps22qs_hw *hw) | ||||||
|  | { | ||||||
|  | 	if (hw->workqueue) | ||||||
|  | 		destroy_workqueue(hw->workqueue); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static inline int st_ilps22qs_allocate_workqueue(struct st_ilps22qs_hw *hw) | ||||||
|  | { | ||||||
|  | 	if (!hw->workqueue) | ||||||
|  | 		hw->workqueue = create_workqueue(ST_ILPS22QS_DEV_NAME); | ||||||
|  |  | ||||||
|  | 	return !hw->workqueue ? -ENOMEM : 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static inline s64 st_ilps22qs_get_time_ns(struct st_ilps22qs_hw *hw) | ||||||
|  | { | ||||||
|  | 	return iio_get_time_ns(hw->iio_devs[ST_ILPS22QS_PRESS]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int st_ilps22qs_probe(struct device *dev, struct regmap *regmap); | ||||||
|  | int st_ilps22qs_remove(struct device *dev); | ||||||
|  |  | ||||||
|  | #endif /* __ST_ILPS22QS_H */ | ||||||
| @@ -0,0 +1,927 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0-only | ||||||
|  | /* | ||||||
|  |  * STMicroelectronics ilps22qs driver | ||||||
|  |  * | ||||||
|  |  * Copyright 2023 STMicroelectronics Inc. | ||||||
|  |  * | ||||||
|  |  * MEMS Software Solutions Team | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <linux/delay.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/iio/buffer.h> | ||||||
|  | #include <linux/iio/events.h> | ||||||
|  | #include <linux/iio/iio.h> | ||||||
|  | #include <linux/iio/kfifo_buf.h> | ||||||
|  | #include <linux/iio/sysfs.h> | ||||||
|  | #include <linux/iio/trigger_consumer.h> | ||||||
|  | #include <linux/iio/triggered_buffer.h> | ||||||
|  | #include <linux/iio/trigger.h> | ||||||
|  | #include <linux/regulator/consumer.h> | ||||||
|  | #include <linux/slab.h> | ||||||
|  | #include <linux/types.h> | ||||||
|  | #include <linux/version.h> | ||||||
|  |  | ||||||
|  | #if KERNEL_VERSION(6, 11, 0) < LINUX_VERSION_CODE | ||||||
|  | #include <linux/unaligned.h> | ||||||
|  | #else /* LINUX_VERSION_CODE */ | ||||||
|  | #include <asm/unaligned.h> | ||||||
|  | #endif /* LINUX_VERSION_CODE */ | ||||||
|  |  | ||||||
|  | #include "st_ilps22qs.h" | ||||||
|  |  | ||||||
|  | static const struct st_ilps22qs_odr_table_t st_ilps22qs_odr_table = { | ||||||
|  | 	.size = ST_ILPS22QS_ODR_LIST_NUM, | ||||||
|  | 	.reg = { | ||||||
|  | 		.addr = ST_ILPS22QS_CTRL1_ADDR, | ||||||
|  | 		.mask = ST_ILPS22QS_ODR_MASK, | ||||||
|  | 	}, | ||||||
|  | 	.odr_avl[0] = {   1, 0x01 }, | ||||||
|  | 	.odr_avl[1] = {   4, 0x02 }, | ||||||
|  | 	.odr_avl[2] = {  10, 0x03 }, | ||||||
|  | 	.odr_avl[3] = {  25, 0x04 }, | ||||||
|  | 	.odr_avl[4] = {  50, 0x05 }, | ||||||
|  | 	.odr_avl[5] = {  75, 0x06 }, | ||||||
|  | 	.odr_avl[6] = { 100, 0x07 }, | ||||||
|  | 	.odr_avl[7] = { 200, 0x08 }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct iio_chan_spec st_ilps22qs_press_channels[] = { | ||||||
|  | 	{ | ||||||
|  | 		.type = IIO_PRESSURE, | ||||||
|  | 		.address = ST_ILPS22QS_PRESS_OUT_XL_ADDR, | ||||||
|  | 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||||||
|  | 				      BIT(IIO_CHAN_INFO_SCALE), | ||||||
|  | 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), | ||||||
|  | 		.channel2 = IIO_NO_MOD, | ||||||
|  | 		.scan_index = 0, | ||||||
|  | 		.scan_type = { | ||||||
|  | 			.sign = 'u', | ||||||
|  | 			.realbits = 24, | ||||||
|  | 			.storagebits = 32, | ||||||
|  | 			.endianness = IIO_LE, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	IIO_CHAN_SOFT_TIMESTAMP(1) | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct iio_chan_spec st_ilps22qs_temp_channels[] = { | ||||||
|  | 	{ | ||||||
|  | 		.type = IIO_TEMP, | ||||||
|  | 		.address = ST_ILPS22QS_TEMP_OUT_L_ADDR, | ||||||
|  | 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||||||
|  | 				      BIT(IIO_CHAN_INFO_SCALE), | ||||||
|  | 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), | ||||||
|  | 		.channel2 = IIO_NO_MOD, | ||||||
|  | 		.scan_index = 0, | ||||||
|  | 		.scan_type = { | ||||||
|  | 			.sign = 's', | ||||||
|  | 			.realbits = 16, | ||||||
|  | 			.storagebits = 16, | ||||||
|  | 			.endianness = IIO_LE, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	IIO_CHAN_SOFT_TIMESTAMP(1) | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct iio_chan_spec st_ilps22qs_qvar_channels[] = { | ||||||
|  | 	{ | ||||||
|  | 		.type = IIO_ALTVOLTAGE, | ||||||
|  | 		.address = ST_ILPS22QS_PRESS_OUT_XL_ADDR, | ||||||
|  | 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||||||
|  | 				      BIT(IIO_CHAN_INFO_SCALE), | ||||||
|  | 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), | ||||||
|  | 		.channel2 = IIO_NO_MOD, | ||||||
|  | 		.scan_index = 0, | ||||||
|  | 		.scan_type = { | ||||||
|  | 			.sign = 's', | ||||||
|  | 			.realbits = 24, | ||||||
|  | 			.storagebits = 32, | ||||||
|  | 			.endianness = IIO_LE, | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	IIO_CHAN_SOFT_TIMESTAMP(1), | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static enum hrtimer_restart | ||||||
|  | st_ilps22qs_poll_function_read(struct hrtimer *timer) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_sensor *sensor; | ||||||
|  |  | ||||||
|  | 	sensor = container_of((struct hrtimer *)timer, | ||||||
|  | 			      struct st_ilps22qs_sensor, hr_timer); | ||||||
|  |  | ||||||
|  | 	sensor->timestamp = st_ilps22qs_get_time_ns(sensor->hw); | ||||||
|  | 	queue_work(sensor->hw->workqueue, &sensor->iio_work); | ||||||
|  |  | ||||||
|  | 	return HRTIMER_NORESTART; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void st_ilps22qs_report_temp(struct st_ilps22qs_sensor *sensor, | ||||||
|  | 				    u8 *tmp, int64_t timestamp) | ||||||
|  | { | ||||||
|  | 	struct iio_dev *iio_dev = sensor->hw->iio_devs[sensor->id]; | ||||||
|  | 	u8 iio_buf[ALIGN(2, sizeof(s64)) + sizeof(s64)]; | ||||||
|  |  | ||||||
|  | 	memcpy(iio_buf, tmp, 2); | ||||||
|  | 	iio_push_to_buffers_with_timestamp(iio_dev, iio_buf, timestamp); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void st_silps22qs_report_press_qvar(struct st_ilps22qs_sensor *sensor, | ||||||
|  | 					   u8 *tmp, int64_t timestamp) | ||||||
|  | { | ||||||
|  | 	u8 iio_buf[ALIGN(3, sizeof(s64)) + sizeof(s64)]; | ||||||
|  | 	struct st_ilps22qs_hw *hw = sensor->hw; | ||||||
|  | 	struct iio_dev *iio_dev; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&hw->lock); | ||||||
|  | 	if (hw->interleave) { | ||||||
|  | 		if (tmp[0] & 0x01) | ||||||
|  | 			iio_dev = sensor->hw->iio_devs[ST_ILPS22QS_QVAR]; | ||||||
|  | 		else | ||||||
|  | 			iio_dev = sensor->hw->iio_devs[ST_ILPS22QS_PRESS]; | ||||||
|  | 	} else { | ||||||
|  | 		iio_dev = sensor->hw->iio_devs[sensor->id]; | ||||||
|  | 	} | ||||||
|  | 	mutex_unlock(&hw->lock); | ||||||
|  |  | ||||||
|  | 	memcpy(iio_buf, tmp, 3); | ||||||
|  | 	iio_push_to_buffers_with_timestamp(iio_dev, iio_buf, timestamp); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void st_ilps22qs_poll_function_work(struct work_struct *iio_work) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_sensor *sensor; | ||||||
|  | 	struct st_ilps22qs_hw *hw; | ||||||
|  | 	ktime_t tmpkt, ktdelta; | ||||||
|  | 	int len; | ||||||
|  | 	int err; | ||||||
|  | 	int id; | ||||||
|  |  | ||||||
|  | 	sensor = container_of((struct work_struct *)iio_work, | ||||||
|  | 			      struct st_ilps22qs_sensor, iio_work); | ||||||
|  | 	hw = sensor->hw; | ||||||
|  | 	id = sensor->id; | ||||||
|  |  | ||||||
|  | 	/* adjust delta time */ | ||||||
|  | 	ktdelta = ktime_set(0, | ||||||
|  | 			    (st_ilps22qs_get_time_ns(hw) - sensor->timestamp)); | ||||||
|  |  | ||||||
|  | 	/* avoid negative value in case of high odr */ | ||||||
|  | 	mutex_lock(&hw->lock); | ||||||
|  | 	if (ktime_after(sensor->ktime, ktdelta)) | ||||||
|  | 		tmpkt = ktime_sub(sensor->ktime, ktdelta); | ||||||
|  | 	else | ||||||
|  | 		tmpkt = sensor->ktime; | ||||||
|  |  | ||||||
|  | 	hrtimer_start(&sensor->hr_timer, tmpkt, HRTIMER_MODE_REL); | ||||||
|  | 	mutex_unlock(&sensor->hw->lock); | ||||||
|  |  | ||||||
|  | 	len = hw->iio_devs[id]->channels->scan_type.realbits >> 3; | ||||||
|  |  | ||||||
|  | 	switch (id) { | ||||||
|  | 	case ST_ILPS22QS_PRESS: | ||||||
|  | 	case ST_ILPS22QS_QVAR: { | ||||||
|  | 		u8 data[3]; | ||||||
|  |  | ||||||
|  | 		err = st_ilps22qs_read_locked(hw, | ||||||
|  | 					    hw->iio_devs[id]->channels->address, | ||||||
|  | 					    data, len); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return; | ||||||
|  |  | ||||||
|  | 		st_silps22qs_report_press_qvar(sensor, data, sensor->timestamp); | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case ST_ILPS22QS_TEMP: { | ||||||
|  | 		u8 data[2]; | ||||||
|  |  | ||||||
|  | 		err = st_ilps22qs_read_locked(hw, | ||||||
|  | 					    hw->iio_devs[id]->channels->address, | ||||||
|  | 					    data, len); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return; | ||||||
|  |  | ||||||
|  | 		st_ilps22qs_report_temp(sensor, data, sensor->timestamp); | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_check_whoami(struct st_ilps22qs_hw *hw) | ||||||
|  | { | ||||||
|  | 	int data; | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	err = regmap_read(hw->regmap, ST_ILPS22QS_WHO_AM_I_ADDR, &data); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(hw->dev, "failed to read whoami register\n"); | ||||||
|  |  | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (data != ST_ILPS22QS_WHOAMI_VAL) { | ||||||
|  | 		dev_err(hw->dev, "unsupported whoami [%02x]\n", data); | ||||||
|  |  | ||||||
|  | 		return -ENODEV; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static __maybe_unused int st_ilps22qs_reg_access(struct iio_dev *iio_dev, | ||||||
|  | 						 unsigned int reg, | ||||||
|  | 						 unsigned int writeval, | ||||||
|  | 						 unsigned int *readval) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev); | ||||||
|  | 	int ret; | ||||||
|  |  | ||||||
|  | 	ret = iio_device_claim_direct_mode(iio_dev); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  |  | ||||||
|  | 	if (readval == NULL) | ||||||
|  | 		ret = regmap_write(sensor->hw->regmap, reg, writeval); | ||||||
|  | 	else | ||||||
|  | 		ret = regmap_read(sensor->hw->regmap, reg, readval); | ||||||
|  |  | ||||||
|  | 	iio_device_release_direct_mode(iio_dev); | ||||||
|  |  | ||||||
|  | 	return (ret < 0) ? ret : 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_get_odr(struct st_ilps22qs_sensor *sensor, u8 odr) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < st_ilps22qs_odr_table.size; i++) { | ||||||
|  | 		if (st_ilps22qs_odr_table.odr_avl[i].hz >= odr) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return i == st_ilps22qs_odr_table.size ? -EINVAL : i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_set_odr(struct st_ilps22qs_sensor *sensor, u8 odr) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_hw *hw = sensor->hw; | ||||||
|  | 	u8 max_odr = odr; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) { | ||||||
|  | 		if ((hw->enable_mask & BIT(i)) && (sensor->id != i)) { | ||||||
|  | 			struct st_ilps22qs_sensor *temp; | ||||||
|  |  | ||||||
|  | 			temp = iio_priv(hw->iio_devs[i]); | ||||||
|  | 			max_odr = max_t(u32, max_odr, temp->odr); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (max_odr != hw->odr) { | ||||||
|  | 		int err, ret; | ||||||
|  |  | ||||||
|  | 		ret = st_ilps22qs_get_odr(sensor, max_odr); | ||||||
|  | 		if (ret < 0) | ||||||
|  | 			return ret; | ||||||
|  |  | ||||||
|  | 		err = st_ilps22qs_update_locked(hw, | ||||||
|  | 					 st_ilps22qs_odr_table.reg.addr, | ||||||
|  | 					 st_ilps22qs_odr_table.reg.mask, | ||||||
|  | 					 st_ilps22qs_odr_table.odr_avl[ret].val); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  |  | ||||||
|  | 		hw->odr = max_odr; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* need hw->lock */ | ||||||
|  | static int st_ilps22qs_set_interleave(struct st_ilps22qs_sensor *sensor, | ||||||
|  | 				      bool enable) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_hw *hw = sensor->hw; | ||||||
|  | 	int otherid = sensor->id == ST_ILPS22QS_PRESS ? ST_ILPS22QS_QVAR : | ||||||
|  | 							ST_ILPS22QS_PRESS; | ||||||
|  | 	int interleave; | ||||||
|  | 	int err = 0; | ||||||
|  |  | ||||||
|  | 	/* both press / qvar enabling ? */ | ||||||
|  | 	mutex_lock(&hw->lock); | ||||||
|  | 	interleave = (!!(hw->enable_mask & BIT(otherid))) && enable; | ||||||
|  | 	if (interleave) { | ||||||
|  | 		unsigned int ctrl1; | ||||||
|  |  | ||||||
|  | 		err = regmap_bulk_read(hw->regmap, | ||||||
|  | 				       ST_ILPS22QS_CTRL1_ADDR, | ||||||
|  | 				       &ctrl1, 1); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			goto unlock; | ||||||
|  |  | ||||||
|  | 		err = regmap_update_bits(hw->regmap, | ||||||
|  | 					 ST_ILPS22QS_CTRL1_ADDR, | ||||||
|  | 					 ST_ILPS22QS_ODR_MASK, 0); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			goto unlock; | ||||||
|  |  | ||||||
|  | 		err = regmap_update_bits(hw->regmap, | ||||||
|  | 					 ST_ILPS22QS_CTRL3_ADDR, | ||||||
|  | 					 ST_ILPS22QS_AH_QVAR_EN_MASK, 0); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			goto unlock; | ||||||
|  |  | ||||||
|  | 		err = regmap_update_bits(hw->regmap, ST_ILPS22QS_CTRL3_ADDR, | ||||||
|  | 					 ST_ILPS22QS_AH_QVAR_P_AUTO_EN_MASK, | ||||||
|  | 					 ST_ILPS22QS_SHIFT_VAL(interleave, | ||||||
|  | 					    ST_ILPS22QS_AH_QVAR_P_AUTO_EN_MASK)); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			goto unlock; | ||||||
|  |  | ||||||
|  | 		err = regmap_update_bits(hw->regmap, ST_ILPS22QS_CTRL1_ADDR, | ||||||
|  | 					 ST_ILPS22QS_ODR_MASK, ctrl1); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			goto unlock; | ||||||
|  | 	} else if (hw->interleave) { | ||||||
|  | 		err = regmap_update_bits(hw->regmap, ST_ILPS22QS_CTRL3_ADDR, | ||||||
|  | 					 ST_ILPS22QS_AH_QVAR_P_AUTO_EN_MASK, 0); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			goto unlock; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hw->interleave = interleave; | ||||||
|  |  | ||||||
|  | unlock: | ||||||
|  | 	mutex_unlock(&hw->lock); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_hw_enable(struct st_ilps22qs_sensor *sensor, bool enable) | ||||||
|  | { | ||||||
|  | 	int ret = 0; | ||||||
|  |  | ||||||
|  | 	switch (sensor->id) { | ||||||
|  | 	case ST_ILPS22QS_QVAR: | ||||||
|  | 	case ST_ILPS22QS_PRESS: | ||||||
|  | 		ret = st_ilps22qs_set_interleave(sensor, enable); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_set_enable(struct st_ilps22qs_sensor *sensor, | ||||||
|  | 				  bool enable) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_hw *hw = sensor->hw; | ||||||
|  | 	u8 odr = enable ? sensor->odr : 0; | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	err = st_ilps22qs_hw_enable(sensor, enable); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	err = st_ilps22qs_set_odr(sensor, odr); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&hw->lock); | ||||||
|  | 	if (enable) { | ||||||
|  | 		ktime_t ktime = ktime_set(0, 1000000000 / sensor->odr); | ||||||
|  |  | ||||||
|  | 		hrtimer_start(&sensor->hr_timer, ktime, HRTIMER_MODE_REL); | ||||||
|  | 		sensor->ktime = ktime; | ||||||
|  | 		hw->enable_mask |= BIT(sensor->id); | ||||||
|  | 	} else { | ||||||
|  | 		cancel_work_sync(&sensor->iio_work); | ||||||
|  | 		hrtimer_cancel(&sensor->hr_timer); | ||||||
|  | 		hw->enable_mask &= ~BIT(sensor->id); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (!hw->interleave) { | ||||||
|  | 		err = regmap_update_bits(hw->regmap, | ||||||
|  | 					 ST_ILPS22QS_CTRL3_ADDR, | ||||||
|  | 					 ST_ILPS22QS_AH_QVAR_EN_MASK, | ||||||
|  | 					 ST_ILPS22QS_SHIFT_VAL(!!(hw->enable_mask & BIT(ST_ILPS22QS_QVAR)), | ||||||
|  | 					  ST_ILPS22QS_AH_QVAR_EN_MASK)); | ||||||
|  | 	} | ||||||
|  | 	mutex_unlock(&hw->lock); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_init_sensors(struct st_ilps22qs_hw *hw) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	/* soft reset the device on power on */ | ||||||
|  | 	err = st_ilps22qs_update_locked(hw, ST_ILPS22QS_CTRL2_ADDR, | ||||||
|  | 					ST_ILPS22QS_SOFT_RESET_MASK, 1); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	usleep_range(50, 60); | ||||||
|  |  | ||||||
|  | 	/* interleave disabled by default */ | ||||||
|  | 	hw->interleave = false; | ||||||
|  |  | ||||||
|  | 	/* enable BDU */ | ||||||
|  | 	return st_ilps22qs_update_locked(hw, ST_ILPS22QS_CTRL1_ADDR, | ||||||
|  | 					 ST_ILPS22QS_BDU_MASK, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t | ||||||
|  | st_ilps22qs_get_sampling_frequency_avail(struct device *dev, | ||||||
|  | 					 struct device_attribute *attr, | ||||||
|  | 					 char *buf) | ||||||
|  | { | ||||||
|  | 	int i, len = 0; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < st_ilps22qs_odr_table.size; i++) { | ||||||
|  | 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", | ||||||
|  | 				 st_ilps22qs_odr_table.odr_avl[i].hz); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	buf[len - 1] = '\n'; | ||||||
|  |  | ||||||
|  | 	return len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_read_raw(struct iio_dev *iio_dev, | ||||||
|  | 				struct iio_chan_spec const *ch, | ||||||
|  | 				int *val, int *val2, long mask) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev); | ||||||
|  | 	struct st_ilps22qs_hw *hw = sensor->hw; | ||||||
|  | 	int ret; | ||||||
|  |  | ||||||
|  | 	switch (mask) { | ||||||
|  | 	case IIO_CHAN_INFO_RAW: { | ||||||
|  | 		u8 data[4] = {}; | ||||||
|  | 		int delay; | ||||||
|  |  | ||||||
|  | 		ret = iio_device_claim_direct_mode(iio_dev); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  |  | ||||||
|  | 		ret = st_ilps22qs_set_enable(sensor, true); | ||||||
|  | 		if (ret < 0) | ||||||
|  | 			goto read_error; | ||||||
|  |  | ||||||
|  | 		delay = 1000000 / sensor->odr; | ||||||
|  | 		usleep_range(delay, 2 * delay); | ||||||
|  |  | ||||||
|  | 		ret = regmap_bulk_read(hw->regmap, ch->address, data, | ||||||
|  | 				       ch->scan_type.realbits >> 3); | ||||||
|  | 		if (ret < 0) | ||||||
|  | 			goto read_error; | ||||||
|  |  | ||||||
|  | 		switch (sensor->id) { | ||||||
|  | 		case ST_ILPS22QS_PRESS: | ||||||
|  | 			*val = (s32)get_unaligned_le32(data); | ||||||
|  | 			break; | ||||||
|  | 		case ST_ILPS22QS_TEMP: | ||||||
|  | 			*val = (s16)get_unaligned_le16(data); | ||||||
|  | 			break; | ||||||
|  | 		case ST_ILPS22QS_QVAR: | ||||||
|  | 			*val = (s32)get_unaligned_le32(data); | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			ret = -ENODEV; | ||||||
|  | 			goto read_error; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | read_error: | ||||||
|  | 		st_ilps22qs_set_enable(sensor, false); | ||||||
|  | 		iio_device_release_direct_mode(iio_dev); | ||||||
|  |  | ||||||
|  | 		if (ret < 0) | ||||||
|  | 			return ret; | ||||||
|  |  | ||||||
|  | 		ret = IIO_VAL_INT; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 	case IIO_CHAN_INFO_SCALE: | ||||||
|  | 		switch (ch->type) { | ||||||
|  | 		case IIO_TEMP: | ||||||
|  | 			*val = 1000; | ||||||
|  | 			*val2 = sensor->gain; | ||||||
|  | 			ret = IIO_VAL_FRACTIONAL; | ||||||
|  | 			break; | ||||||
|  | 		case IIO_PRESSURE: | ||||||
|  | 			*val = 0; | ||||||
|  | 			*val2 = sensor->gain; | ||||||
|  | 			ret = IIO_VAL_INT_PLUS_NANO; | ||||||
|  | 			break; | ||||||
|  | 		case IIO_ALTVOLTAGE: | ||||||
|  | 			*val = 0; | ||||||
|  | 			*val2 = sensor->gain; | ||||||
|  | 			ret = IIO_VAL_INT_PLUS_NANO; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			ret = -ENODEV; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case IIO_CHAN_INFO_SAMP_FREQ: | ||||||
|  | 		*val = sensor->odr; | ||||||
|  | 		ret = IIO_VAL_INT; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		ret = -EINVAL; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_write_raw(struct iio_dev *iio_dev, | ||||||
|  | 				 struct iio_chan_spec const *ch, | ||||||
|  | 				 int val, int val2, long mask) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev); | ||||||
|  | 	int ret; | ||||||
|  |  | ||||||
|  | 	ret = iio_device_claim_direct_mode(iio_dev); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  |  | ||||||
|  | 	switch (mask) { | ||||||
|  | 	case IIO_CHAN_INFO_SAMP_FREQ: | ||||||
|  | 		ret = st_ilps22qs_get_odr(sensor, val); | ||||||
|  | 		if (ret < 0) | ||||||
|  | 			goto exit_fail; | ||||||
|  |  | ||||||
|  | 		sensor->odr = st_ilps22qs_odr_table.odr_avl[ret].hz; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		ret = -EINVAL; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | exit_fail: | ||||||
|  | 	iio_device_release_direct_mode(iio_dev); | ||||||
|  |  | ||||||
|  | 	return ret < 0 ? ret : 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_ilps22qs_get_sampling_frequency_avail); | ||||||
|  |  | ||||||
|  | static struct attribute *st_ilps22qs_press_attributes[] = { | ||||||
|  | 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr, | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct attribute_group st_ilps22qs_press_attribute_group = { | ||||||
|  | 	.attrs = st_ilps22qs_press_attributes, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct iio_info st_ilps22qs_press_info = { | ||||||
|  | 	.attrs = &st_ilps22qs_press_attribute_group, | ||||||
|  | 	.read_raw = st_ilps22qs_read_raw, | ||||||
|  | 	.write_raw = st_ilps22qs_write_raw, | ||||||
|  | 	.debugfs_reg_access = st_ilps22qs_reg_access, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static struct attribute *st_ilps22qs_temp_attributes[] = { | ||||||
|  | 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr, | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct attribute_group st_ilps22qs_temp_attribute_group = { | ||||||
|  | 	.attrs = st_ilps22qs_temp_attributes, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct iio_info st_ilps22qs_temp_info = { | ||||||
|  | 	.attrs = &st_ilps22qs_temp_attribute_group, | ||||||
|  | 	.read_raw = st_ilps22qs_read_raw, | ||||||
|  | 	.write_raw = st_ilps22qs_write_raw, | ||||||
|  | 	.debugfs_reg_access = st_ilps22qs_reg_access, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static struct attribute *st_ilps22qs_qvar_attributes[] = { | ||||||
|  | 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr, | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct attribute_group st_ilps22qs_qvar_attribute_group = { | ||||||
|  | 	.attrs = st_ilps22qs_qvar_attributes, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct iio_info st_ilps22qs_qvar_info = { | ||||||
|  | 	.attrs = &st_ilps22qs_qvar_attribute_group, | ||||||
|  | 	.read_raw = st_ilps22qs_read_raw, | ||||||
|  | 	.write_raw = st_ilps22qs_write_raw, | ||||||
|  | 	.debugfs_reg_access = st_ilps22qs_reg_access, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_preenable(struct iio_dev *iio_dev) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev); | ||||||
|  |  | ||||||
|  | 	return st_ilps22qs_set_enable(sensor, true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_postdisable(struct iio_dev *iio_dev) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_sensor *sensor = iio_priv(iio_dev); | ||||||
|  |  | ||||||
|  | 	return st_ilps22qs_set_enable(sensor, false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const struct iio_buffer_setup_ops st_ilps22qs_fifo_ops = { | ||||||
|  | 	.preenable = st_ilps22qs_preenable, | ||||||
|  | 	.postdisable = st_ilps22qs_postdisable, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void st_ilps22qs_disable_regulator_action(void *_data) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_hw *hw = _data; | ||||||
|  |  | ||||||
|  | 	regulator_disable(hw->vddio_supply); | ||||||
|  | 	regulator_disable(hw->vdd_supply); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int st_ilps22qs_power_enable(struct st_ilps22qs_hw *hw) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	hw->vdd_supply = devm_regulator_get(hw->dev, "vdd"); | ||||||
|  | 	if (IS_ERR(hw->vdd_supply)) { | ||||||
|  | 		if (PTR_ERR(hw->vdd_supply) != -EPROBE_DEFER) | ||||||
|  | 			dev_err(hw->dev, "Failed to get vdd regulator %d\n", | ||||||
|  | 				(int)PTR_ERR(hw->vdd_supply)); | ||||||
|  |  | ||||||
|  | 		return PTR_ERR(hw->vdd_supply); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hw->vddio_supply = devm_regulator_get(hw->dev, "vddio"); | ||||||
|  | 	if (IS_ERR(hw->vddio_supply)) { | ||||||
|  | 		if (PTR_ERR(hw->vddio_supply) != -EPROBE_DEFER) | ||||||
|  | 			dev_err(hw->dev, "Failed to get vddio regulator %d\n", | ||||||
|  | 				(int)PTR_ERR(hw->vddio_supply)); | ||||||
|  |  | ||||||
|  | 		return PTR_ERR(hw->vddio_supply); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = regulator_enable(hw->vdd_supply); | ||||||
|  | 	if (err) { | ||||||
|  | 		dev_err(hw->dev, "Failed to enable vdd regulator: %d\n", err); | ||||||
|  |  | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = regulator_enable(hw->vddio_supply); | ||||||
|  | 	if (err) { | ||||||
|  | 		regulator_disable(hw->vdd_supply); | ||||||
|  |  | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = devm_add_action_or_reset(hw->dev, | ||||||
|  | 				       st_ilps22qs_disable_regulator_action, | ||||||
|  | 				       hw); | ||||||
|  | 	if (err) { | ||||||
|  | 		dev_err(hw->dev, | ||||||
|  | 			"Failed to setup regulator cleanup action %d\n", err); | ||||||
|  |  | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * after the device is powered up, the ILPS22QS performs a 10 ms | ||||||
|  | 	 * boot procedure to load the trimming parameters | ||||||
|  | 	 */ | ||||||
|  | 	usleep_range(10000, 11000); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static struct iio_dev *st_ilps22qs_alloc_iiodev(struct st_ilps22qs_hw *hw, | ||||||
|  | 						enum st_ilps22qs_sensor_id id) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_sensor *sensor; | ||||||
|  | 	struct iio_dev *iio_dev; | ||||||
|  |  | ||||||
|  | 	iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); | ||||||
|  | 	if (!iio_dev) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	iio_dev->modes = INDIO_DIRECT_MODE; | ||||||
|  | 	iio_dev->dev.parent = hw->dev; | ||||||
|  |  | ||||||
|  | 	sensor = iio_priv(iio_dev); | ||||||
|  | 	sensor->hw = hw; | ||||||
|  | 	sensor->id = id; | ||||||
|  | 	sensor->odr = st_ilps22qs_odr_table.odr_avl[0].hz; | ||||||
|  |  | ||||||
|  | 	switch (id) { | ||||||
|  | 	case ST_ILPS22QS_PRESS: | ||||||
|  | 		sensor->gain = ST_ILPS22QS_PRESS_FS_AVL_GAIN; | ||||||
|  | 		scnprintf(sensor->name, sizeof(sensor->name), | ||||||
|  | 			  ST_ILPS22QS_DEV_NAME "_press"); | ||||||
|  | 		iio_dev->channels = st_ilps22qs_press_channels; | ||||||
|  | 		iio_dev->num_channels = ARRAY_SIZE(st_ilps22qs_press_channels); | ||||||
|  | 		iio_dev->info = &st_ilps22qs_press_info; | ||||||
|  | 		break; | ||||||
|  | 	case ST_ILPS22QS_TEMP: | ||||||
|  | 		sensor->gain = ST_ILPS22QS_TEMP_FS_AVL_GAIN; | ||||||
|  | 		scnprintf(sensor->name, sizeof(sensor->name), | ||||||
|  | 			  ST_ILPS22QS_DEV_NAME "_temp"); | ||||||
|  | 		iio_dev->channels = st_ilps22qs_temp_channels; | ||||||
|  | 		iio_dev->num_channels = ARRAY_SIZE(st_ilps22qs_temp_channels); | ||||||
|  | 		iio_dev->info = &st_ilps22qs_temp_info; | ||||||
|  | 		break; | ||||||
|  | 	case ST_ILPS22QS_QVAR: | ||||||
|  | 		sensor->gain = ST_ILPS22QS_QVAR_FS_AVL_GAIN; | ||||||
|  | 		scnprintf(sensor->name, sizeof(sensor->name), | ||||||
|  | 			  ST_ILPS22QS_DEV_NAME "_qvar"); | ||||||
|  | 		iio_dev->channels = st_ilps22qs_qvar_channels; | ||||||
|  | 		iio_dev->num_channels = ARRAY_SIZE(st_ilps22qs_qvar_channels); | ||||||
|  | 		iio_dev->info = &st_ilps22qs_qvar_info; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	iio_dev->name = sensor->name; | ||||||
|  |  | ||||||
|  | 	/* configure sensor hrtimer */ | ||||||
|  | 	hrtimer_init(&sensor->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||||||
|  | 	sensor->hr_timer.function = &st_ilps22qs_poll_function_read; | ||||||
|  | 	INIT_WORK(&sensor->iio_work, st_ilps22qs_poll_function_work); | ||||||
|  |  | ||||||
|  | 	return iio_dev; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int st_ilps22qs_probe(struct device *dev, struct regmap *regmap) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_hw *hw; | ||||||
|  | 	int err, i; | ||||||
|  |  | ||||||
|  | 	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); | ||||||
|  | 	if (!hw) | ||||||
|  | 		return -ENOMEM; | ||||||
|  |  | ||||||
|  | 	mutex_init(&hw->lock); | ||||||
|  |  | ||||||
|  | 	dev_set_drvdata(dev, (void *)hw); | ||||||
|  | 	hw->dev = dev; | ||||||
|  | 	hw->regmap = regmap; | ||||||
|  |  | ||||||
|  | 	err = st_ilps22qs_power_enable(hw); | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	err = st_ilps22qs_check_whoami(hw); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	err = st_ilps22qs_init_sensors(hw); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) { | ||||||
|  |  | ||||||
|  | #if KERNEL_VERSION(5, 13, 0) > LINUX_VERSION_CODE | ||||||
|  | 		struct iio_buffer *buffer; | ||||||
|  | #endif /* LINUX_VERSION_CODE */ | ||||||
|  |  | ||||||
|  | 		hw->iio_devs[i] = st_ilps22qs_alloc_iiodev(hw, i); | ||||||
|  | 		if (!hw->iio_devs[i]) | ||||||
|  | 			return -ENOMEM; | ||||||
|  |  | ||||||
|  | #if KERNEL_VERSION(5, 19, 0) <= LINUX_VERSION_CODE | ||||||
|  | 		err = devm_iio_kfifo_buffer_setup(hw->dev, | ||||||
|  | 						  hw->iio_devs[i], | ||||||
|  | 						  &st_ilps22qs_fifo_ops); | ||||||
|  | 		if (err) | ||||||
|  | 			return err; | ||||||
|  | #elif KERNEL_VERSION(5, 13, 0) <= LINUX_VERSION_CODE | ||||||
|  | 		err = devm_iio_kfifo_buffer_setup(hw->dev, hw->iio_devs[i], | ||||||
|  | 						  INDIO_BUFFER_SOFTWARE, | ||||||
|  | 						  &st_ilps22qs_fifo_ops); | ||||||
|  | 		if (err) | ||||||
|  | 			return err; | ||||||
|  | #else /* LINUX_VERSION_CODE */ | ||||||
|  | 		buffer = devm_iio_kfifo_allocate(hw->dev); | ||||||
|  | 		if (!buffer) | ||||||
|  | 			return -ENOMEM; | ||||||
|  |  | ||||||
|  | 		iio_device_attach_buffer(hw->iio_devs[i], buffer); | ||||||
|  | 		hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE; | ||||||
|  | 		hw->iio_devs[i]->setup_ops = &st_ilps22qs_fifo_ops; | ||||||
|  | #endif /* LINUX_VERSION_CODE */ | ||||||
|  |  | ||||||
|  | 		err = devm_iio_device_register(hw->dev, hw->iio_devs[i]); | ||||||
|  | 		if (err) | ||||||
|  | 			return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = st_ilps22qs_allocate_workqueue(hw); | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	dev_info(dev, "device probed\n"); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(st_ilps22qs_probe); | ||||||
|  |  | ||||||
|  | int st_ilps22qs_remove(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_hw *hw = dev_get_drvdata(dev); | ||||||
|  | 	struct st_ilps22qs_sensor *sensor; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) { | ||||||
|  | 		int err; | ||||||
|  |  | ||||||
|  | 		if (!hw->iio_devs[i]) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		sensor = iio_priv(hw->iio_devs[i]); | ||||||
|  | 		if (!(hw->enable_mask & BIT(sensor->id))) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		err = st_ilps22qs_set_enable(sensor, false); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	st_ilps22qs_flush_works(hw); | ||||||
|  | 	st_ilps22qs_destroy_workqueue(hw); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(st_ilps22qs_remove); | ||||||
|  |  | ||||||
|  | static int __maybe_unused st_ilps22qs_suspend(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_hw *hw = dev_get_drvdata(dev); | ||||||
|  | 	struct st_ilps22qs_sensor *sensor; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) { | ||||||
|  | 		int err; | ||||||
|  |  | ||||||
|  | 		if (!hw->iio_devs[i]) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		sensor = iio_priv(hw->iio_devs[i]); | ||||||
|  | 		if (!(hw->enable_mask & BIT(sensor->id))) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		err = st_ilps22qs_set_odr(sensor, 0); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  |  | ||||||
|  | 		cancel_work_sync(&sensor->iio_work); | ||||||
|  | 		hrtimer_cancel(&sensor->hr_timer); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	dev_info(dev, "Suspending device\n"); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int __maybe_unused st_ilps22qs_resume(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct st_ilps22qs_hw *hw = dev_get_drvdata(dev); | ||||||
|  | 	struct st_ilps22qs_sensor *sensor; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	dev_info(dev, "Resuming device\n"); | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < ST_ILPS22QS_SENSORS_NUM; i++) { | ||||||
|  | 		int err; | ||||||
|  |  | ||||||
|  | 		if (!hw->iio_devs[i]) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		sensor = iio_priv(hw->iio_devs[i]); | ||||||
|  | 		if (!(hw->enable_mask & BIT(sensor->id))) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		err = st_ilps22qs_set_enable(sensor, true); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const struct dev_pm_ops st_ilps22qs_pm_ops = { | ||||||
|  | 	SET_SYSTEM_SLEEP_PM_OPS(st_ilps22qs_suspend, st_ilps22qs_resume) | ||||||
|  | }; | ||||||
|  | EXPORT_SYMBOL(st_ilps22qs_pm_ops); | ||||||
|  |  | ||||||
|  | MODULE_AUTHOR("MEMS Software Solutions Team"); | ||||||
|  | MODULE_DESCRIPTION("STMicroelectronics ilps22qs driver"); | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
| @@ -0,0 +1,86 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0-only | ||||||
|  | /* | ||||||
|  |  * STMicroelectronics ilps22qs i2c driver | ||||||
|  |  * | ||||||
|  |  * Copyright 2023 STMicroelectronics Inc. | ||||||
|  |  * | ||||||
|  |  * MEMS Software Solutions Team | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/i2c.h> | ||||||
|  | #include <linux/iio/iio.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/version.h> | ||||||
|  |  | ||||||
|  | #include "st_ilps22qs.h" | ||||||
|  |  | ||||||
|  | static const struct regmap_config st_ilps22qs_i2c_regmap_config = { | ||||||
|  | 	.reg_bits = 8, | ||||||
|  | 	.val_bits = 8, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #if KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE | ||||||
|  | static int st_ilps22qs_i2c_probe(struct i2c_client *client) | ||||||
|  | #else /* LINUX_VERSION_CODE */ | ||||||
|  | static int st_ilps22qs_i2c_probe(struct i2c_client *client, | ||||||
|  | 				 const struct i2c_device_id *id) | ||||||
|  | #endif /* LINUX_VERSION_CODE */ | ||||||
|  | { | ||||||
|  | 	struct regmap *regmap; | ||||||
|  |  | ||||||
|  | 	regmap = devm_regmap_init_i2c(client, &st_ilps22qs_i2c_regmap_config); | ||||||
|  | 	if (IS_ERR(regmap)) { | ||||||
|  | 		dev_err(&client->dev, | ||||||
|  | 			"Failed to register i2c regmap %d\n", | ||||||
|  | 			(int)PTR_ERR(regmap)); | ||||||
|  |  | ||||||
|  | 		return PTR_ERR(regmap); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return st_ilps22qs_probe(&client->dev, regmap); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE | ||||||
|  | static void st_ilps22qs_i2c_remove(struct i2c_client *client) | ||||||
|  | { | ||||||
|  | 	st_ilps22qs_remove(&client->dev); | ||||||
|  | } | ||||||
|  | #else /* LINUX_VERSION_CODE */ | ||||||
|  | static int st_ilps22qs_i2c_remove(struct i2c_client *client) | ||||||
|  | { | ||||||
|  | 	return st_ilps22qs_remove(&client->dev); | ||||||
|  | } | ||||||
|  | #endif /* LINUX_VERSION_CODE */ | ||||||
|  |  | ||||||
|  | static const struct i2c_device_id st_ilps22qs_ids[] = { | ||||||
|  | 	{ ST_ILPS22QS_DEV_NAME }, | ||||||
|  | 	{ ST_ILPS28QSW_DEV_NAME }, | ||||||
|  | 	{} | ||||||
|  | }; | ||||||
|  | MODULE_DEVICE_TABLE(i2c, st_ilps22qs_ids); | ||||||
|  |  | ||||||
|  | static const struct of_device_id st_ilps22qs_id_table[] = { | ||||||
|  | 	{ .compatible = "st," ST_ILPS22QS_DEV_NAME }, | ||||||
|  | 	{ .compatible = "st," ST_ILPS28QSW_DEV_NAME }, | ||||||
|  | 	{}, | ||||||
|  | }; | ||||||
|  | MODULE_DEVICE_TABLE(of, st_ilps22qs_id_table); | ||||||
|  |  | ||||||
|  | static struct i2c_driver st_ilps22qs_i2c_driver = { | ||||||
|  | 	.driver = { | ||||||
|  | 		.owner = THIS_MODULE, | ||||||
|  | 		.name = "st_" ST_ILPS22QS_DEV_NAME "_i2c", | ||||||
|  | 		.pm = &st_ilps22qs_pm_ops, | ||||||
|  | 		.of_match_table = of_match_ptr(st_ilps22qs_id_table), | ||||||
|  | 	}, | ||||||
|  | 	.probe = st_ilps22qs_i2c_probe, | ||||||
|  | 	.remove = st_ilps22qs_i2c_remove, | ||||||
|  | 	.id_table = st_ilps22qs_ids, | ||||||
|  | }; | ||||||
|  | module_i2c_driver(st_ilps22qs_i2c_driver); | ||||||
|  |  | ||||||
|  | MODULE_AUTHOR("MEMS Software Solutions Team"); | ||||||
|  | MODULE_DESCRIPTION("STMicroelectronics ilps22qs i2c driver"); | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  |  | ||||||
|  | config INPUT_LSM303AGR | ||||||
|  |          tristate "STM LSM303AGR sensor" | ||||||
|  |          depends on I2C && SYSFS | ||||||
|  |          help | ||||||
|  |            This driver support the STMicroelectronics LSM303AGR sensor. | ||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | # | ||||||
|  | # Makefile for the input misc lsm303agr driver. | ||||||
|  | # | ||||||
|  |  | ||||||
|  | # Each configuration option enables a list of files. | ||||||
|  |  | ||||||
|  | obj-$(CONFIG_INPUT_LSM303AGR) += lsm303agr_acc.o lsm303agr_mag.o lsm303agr_acc_i2c.o lsm303agr_mag_i2c.o | ||||||
| @@ -0,0 +1,885 @@ | |||||||
|  | /* | ||||||
|  |  * STMicroelectronics lsm303agr_acc.c driver | ||||||
|  |  * | ||||||
|  |  * Copyright 2016 STMicroelectronics Inc. | ||||||
|  |  * | ||||||
|  |  * Giuseppe Barba <giuseppe.barba@st.com> | ||||||
|  |  * | ||||||
|  |  * Licensed under the GPL-2. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <linux/err.h> | ||||||
|  | #include <linux/errno.h> | ||||||
|  | #include <linux/delay.h> | ||||||
|  | #include <linux/fs.h> | ||||||
|  | #include <linux/i2c.h> | ||||||
|  | #include <linux/input.h> | ||||||
|  | #include <linux/uaccess.h> | ||||||
|  | #include <linux/workqueue.h> | ||||||
|  | #include <linux/irq.h> | ||||||
|  | #include <linux/gpio.h> | ||||||
|  | #include <linux/interrupt.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/device.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/moduleparam.h> | ||||||
|  | #include <linux/version.h> | ||||||
|  |  | ||||||
|  | #include "lsm303agr_core.h" | ||||||
|  |  | ||||||
|  | #define LSM303AGR_ACC_DEV_NAME	"lsm303agr_acc" | ||||||
|  |  | ||||||
|  | #define LSM303AGR_ACC_MIN_POLL_PERIOD_MS 1 | ||||||
|  |  | ||||||
|  | /* I2C slave address */ | ||||||
|  | #define LSM303AGR_ACC_I2C_SAD	0x29 | ||||||
|  | /* Accelerometer Sensor Full Scale */ | ||||||
|  | #define	LSM303AGR_ACC_FS_MSK	0x20 | ||||||
|  | #define LSM303AGR_ACC_G_2G	0x00 | ||||||
|  | #define LSM303AGR_ACC_G_8G	0x20 | ||||||
|  |  | ||||||
|  | #define AXISDATA_REG		0x28 | ||||||
|  | #define WHOAMI_LSM303AGR_ACC	0x33 | ||||||
|  | #define WHO_AM_I		0x0F | ||||||
|  | #define CTRL_REG1		0x20 | ||||||
|  | #define CTRL_REG2		0x23 | ||||||
|  |  | ||||||
|  | #define LSM303AGR_ACC_PM_OFF		0x00 | ||||||
|  | #define LSM303AGR_ACC_ENABLE_ALL_AXIS	0x07 | ||||||
|  | #define LSM303AGR_ACC_AXIS_MSK		0x07 | ||||||
|  | #define LSM303AGR_ACC_ODR_MSK		0xf0 | ||||||
|  | #define LSM303AGR_ACC_LP_MSK		0X08 | ||||||
|  | #define LSM303AGR_ACC_HR_MSK		0X08 | ||||||
|  |  | ||||||
|  | /* device opmode */ | ||||||
|  | enum lsm303agr_acc_opmode { | ||||||
|  | 	LSM303AGR_ACC_OPMODE_NORMAL, | ||||||
|  | 	LSM303AGR_ACC_OPMODE_HR, | ||||||
|  | 	LSM303AGR_ACC_OPMODE_LP, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* Device sensitivities [ug/digit] */ | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_NORMAL_2G	3900 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_NORMAL_4G	7820 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_NORMAL_8G	15630 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_NORMAL_16G	46900 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_HR_2G		980 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_HR_4G		1950 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_HR_8G		3900 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_HR_16G	11720 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_LP_2G		15630 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_LP_4G		31260 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_LP_8G		62520 | ||||||
|  | #define LSM303AGR_ACC_SENSITIVITY_LP_16G	187580 | ||||||
|  |  | ||||||
|  | /* Device shift values */ | ||||||
|  | #define LSM303AGR_ACC_SHIFT_NORMAL_MODE	6 | ||||||
|  | #define LSM303AGR_ACC_SHIFT_HR_MODE	4 | ||||||
|  | #define LSM303AGR_ACC_SHIFT_LP_MODE	8 | ||||||
|  |  | ||||||
|  | const struct { | ||||||
|  | 	u16 shift; | ||||||
|  | 	u32 sensitivity[4]; | ||||||
|  | } lsm303agr_acc_opmode_table[] = { | ||||||
|  | 	{ | ||||||
|  | 		/* normal mode */ | ||||||
|  | 		LSM303AGR_ACC_SHIFT_NORMAL_MODE, | ||||||
|  | 		{ | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_NORMAL_2G, | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_NORMAL_4G, | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_NORMAL_8G, | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_NORMAL_16G | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		/* hr mode */ | ||||||
|  | 		LSM303AGR_ACC_SHIFT_HR_MODE, | ||||||
|  | 		{ | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_HR_2G, | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_HR_4G, | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_HR_8G, | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_HR_16G | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		/* lp mode */ | ||||||
|  | 		LSM303AGR_ACC_SHIFT_LP_MODE, | ||||||
|  | 		{ | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_LP_2G, | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_LP_4G, | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_LP_8G, | ||||||
|  | 			LSM303AGR_ACC_SENSITIVITY_LP_16G | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #define LSM303AGR_ACC_ODR10	0x20  /* 10Hz output data rate */ | ||||||
|  | #define LSM303AGR_ACC_ODR50	0x40  /* 50Hz output data rate */ | ||||||
|  | #define LSM303AGR_ACC_ODR100	0x50  /* 100Hz output data rate */ | ||||||
|  | #define LSM303AGR_ACC_ODR200	0x60  /* 200Hz output data rate */ | ||||||
|  |  | ||||||
|  | /* read and write with mask a given register */ | ||||||
|  | static int lsm303agr_acc_write_data_with_mask(struct lsm303agr_common_data *cdata, | ||||||
|  | 					      u8 reg_addr, u8 mask, u8 *data) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	u8 new_data, old_data = 0; | ||||||
|  |  | ||||||
|  | 	err = cdata->tf->read(cdata->dev, reg_addr, 1, &old_data); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	new_data = ((old_data & (~mask)) | ((*data) & mask)); | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_ACC_DEBUG | ||||||
|  | 	dev_info(cdata->dev, "%s %02x o=%02x d=%02x n=%02x\n", | ||||||
|  | 		 LSM303AGR_ACC_DEV_NAME, reg_addr, old_data, *data, new_data); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	/* Save for caller usage the data that is about to be written */ | ||||||
|  | 	*data = new_data; | ||||||
|  |  | ||||||
|  | 	if (new_data == old_data) | ||||||
|  | 		return 1; | ||||||
|  |  | ||||||
|  | 	return cdata->tf->write(cdata->dev, reg_addr, 1, &new_data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_acc_input_init(struct lsm303agr_sensor_data *sdata, | ||||||
|  | 				    const char* description) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	sdata->input_dev = input_allocate_device(); | ||||||
|  | 	if (!sdata->input_dev) { | ||||||
|  | 		dev_err(sdata->cdata->dev, "input device allocation failed\n"); | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	sdata->input_dev->name = description; | ||||||
|  | 	sdata->input_dev->id.bustype = sdata->cdata->bus_type; | ||||||
|  | 	sdata->input_dev->dev.parent = sdata->cdata->dev; | ||||||
|  |  | ||||||
|  | 	input_set_drvdata(sdata->input_dev, sdata); | ||||||
|  |  | ||||||
|  | 	/* Set the input event characteristics of the probed sensor driver */ | ||||||
|  | 	set_bit(INPUT_EVENT_TYPE, sdata->input_dev->evbit); | ||||||
|  | 	set_bit(INPUT_EVENT_TIME_MSB, sdata->input_dev->mscbit); | ||||||
|  | 	set_bit(INPUT_EVENT_TIME_LSB, sdata->input_dev->mscbit); | ||||||
|  | 	set_bit(INPUT_EVENT_X, sdata->input_dev->mscbit); | ||||||
|  | 	set_bit(INPUT_EVENT_Y, sdata->input_dev->mscbit); | ||||||
|  | 	set_bit(INPUT_EVENT_Z, sdata->input_dev->mscbit); | ||||||
|  |  | ||||||
|  | 	err = input_register_device(sdata->input_dev); | ||||||
|  | 	if (err) { | ||||||
|  | 		dev_err(sdata->cdata->dev, | ||||||
|  | 			"unable to register input device %s\n", | ||||||
|  | 			sdata->input_dev->name); | ||||||
|  | 		input_free_device(sdata->input_dev); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct { | ||||||
|  | 	unsigned int cutoff_ms; | ||||||
|  | 	unsigned int mask; | ||||||
|  | } lsm303agr_acc_odr_table[] = { | ||||||
|  | 	{    5, LSM303AGR_ACC_ODR200  }, /* ODR = 200Hz */ | ||||||
|  | 	{   10, LSM303AGR_ACC_ODR100  }, /* ODR = 100Hz */ | ||||||
|  | 	{   20, LSM303AGR_ACC_ODR50   }, /* ODR = 50Hz */ | ||||||
|  | 	{  100, LSM303AGR_ACC_ODR10   }, /* ODR = 10Hz */ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int lsm303agr_acc_hw_init(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	u8 buf, wai = 0; | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_ACC_DEBUG | ||||||
|  | 	pr_info("%s: hw init start\n", LSM303AGR_ACC_DEV_NAME); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	err = cdata->tf->read(cdata->dev, WHO_AM_I, 1, &wai); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_warn(cdata->dev, "Error reading WHO_AM_I\n"); | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (wai != WHOAMI_LSM303AGR_ACC) { | ||||||
|  | 		dev_err(cdata->dev, | ||||||
|  | 			"device unknown (0x%02x-0x%02x)\n", | ||||||
|  | 			WHOAMI_LSM303AGR_ACC, wai); | ||||||
|  | 		err = -1; /* choose the right coded error */ | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	buf = cdata->sensors[LSM303AGR_ACC_SENSOR].c_odr; | ||||||
|  | 	err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG1, | ||||||
|  | 						 LSM303AGR_ACC_ODR_MSK, &buf); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		goto error; | ||||||
|  |  | ||||||
|  | 	cdata->hw_initialized = 1; | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_ACC_DEBUG | ||||||
|  | 	pr_info("%s: hw init done\n", LSM303AGR_ACC_DEV_NAME); | ||||||
|  | #endif | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | error: | ||||||
|  | 	cdata->hw_initialized = 0; | ||||||
|  | 	dev_err(cdata->dev, "hw init error 0x%02x: %d\n", buf, err); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void lsm303agr_acc_device_power_off(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	u8 buf = LSM303AGR_ACC_PM_OFF; | ||||||
|  |  | ||||||
|  | 	err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG1, | ||||||
|  | 						 LSM303AGR_ACC_ODR_MSK, &buf); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		dev_err(cdata->dev, "soft power off failed: %d\n", err); | ||||||
|  |  | ||||||
|  | 	if (cdata->hw_initialized) | ||||||
|  | 		cdata->hw_initialized = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_acc_device_power_on(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	if (!cdata->hw_initialized) { | ||||||
|  | 		int err = lsm303agr_acc_hw_init(cdata); | ||||||
|  | 		if (err < 0) { | ||||||
|  | 			lsm303agr_acc_device_power_off(cdata); | ||||||
|  | 			return err; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_acc_update_fs_range(struct lsm303agr_common_data *cdata, | ||||||
|  | 					 u8 new_fs_range) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	u8 indx; | ||||||
|  | 	u16 opmode; | ||||||
|  | 	unsigned int new_sensitivity; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  | 	opmode = sdata->opmode; | ||||||
|  |  | ||||||
|  | 	switch (new_fs_range) { | ||||||
|  | 	case LSM303AGR_ACC_G_2G: | ||||||
|  | 		indx = 0; | ||||||
|  | 		break; | ||||||
|  | 	case LSM303AGR_ACC_G_8G: | ||||||
|  | 		indx = 2; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		dev_err(cdata->dev, "invalid fs range requested: %u\n", | ||||||
|  | 			new_fs_range); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Updates configuration register 4 which contains fs range setting */ | ||||||
|  | 	err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG2, | ||||||
|  | 						 LSM303AGR_ACC_FS_MSK, | ||||||
|  | 						 &new_fs_range); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		goto error; | ||||||
|  |  | ||||||
|  | 	new_sensitivity = lsm303agr_acc_opmode_table[opmode].sensitivity[indx]; | ||||||
|  | 	sdata->sensitivity = new_sensitivity; | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_ACC_DEBUG | ||||||
|  | 	dev_info(cdata->dev, "%s shift=%d, sens=%d, opm=%d\n", | ||||||
|  | 		 LSM303AGR_ACC_DEV_NAME, sdata->shift, sdata->sensitivity, | ||||||
|  | 		 sdata->opmode); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | error: | ||||||
|  | 	dev_err(cdata->dev, "update fs range failed %d\n", err); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_acc_update_odr(struct lsm303agr_common_data *cdata, | ||||||
|  | 							int poll_interval) | ||||||
|  | { | ||||||
|  | 	u8 buf; | ||||||
|  | 	int i, err = -1; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Following, looks for the longest possible odr | ||||||
|  | 	 * interval od -x /dev/input/event0 scrolling the | ||||||
|  | 	 * odr_table vector from the end (shortest interval) backward (longest | ||||||
|  | 	 * interval), to support the poll_interval requested by the system. | ||||||
|  | 	 * It must be the longest interval lower then the poll interval | ||||||
|  | 	 */ | ||||||
|  | 	for (i = ARRAY_SIZE(lsm303agr_acc_odr_table) - 1; i >= 0; i--) { | ||||||
|  | 		if ((lsm303agr_acc_odr_table[i].cutoff_ms <= poll_interval) || | ||||||
|  | 		    (i == 0)) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  | 	/* also save requested odr */ | ||||||
|  | 	buf = (sdata->c_odr = lsm303agr_acc_odr_table[i].mask) | | ||||||
|  | 	      LSM303AGR_ACC_ENABLE_ALL_AXIS; | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * If device is currently enabled, we need to write new | ||||||
|  | 	 * configuration out to it | ||||||
|  | 	 */ | ||||||
|  | 	if (atomic_read(&cdata->enabled)) { | ||||||
|  | 		err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG1, | ||||||
|  | 							 LSM303AGR_ACC_ODR_MSK | | ||||||
|  | 							 LSM303AGR_ACC_AXIS_MSK, | ||||||
|  | 							 &buf); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			goto error; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_ACC_DEBUG | ||||||
|  | 	dev_info(cdata->dev, "update odr to 0x%02x,0x%02x: %d\n", | ||||||
|  | 			CTRL_REG1, buf, err); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  |  | ||||||
|  | error: | ||||||
|  | 	dev_err(cdata->dev, "update odr failed 0x%02x,0x%02x: %d\n", | ||||||
|  | 			CTRL_REG1, buf, err); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_acc_update_opmode(struct lsm303agr_common_data *cdata, | ||||||
|  | 				       unsigned short opmode) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  | 	u8 lp = 0, hr = 0, indx = 0; | ||||||
|  |  | ||||||
|  | 	switch (opmode) { | ||||||
|  | 	case LSM303AGR_ACC_OPMODE_NORMAL: | ||||||
|  | 		break; | ||||||
|  | 	case LSM303AGR_ACC_OPMODE_HR: | ||||||
|  | 		hr = (1 << __ffs(LSM303AGR_ACC_LP_MSK)); | ||||||
|  | 		break; | ||||||
|  | 	case LSM303AGR_ACC_OPMODE_LP: | ||||||
|  | 		lp = (1 << __ffs(LSM303AGR_ACC_HR_MSK)); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Set LP bit in CTRL_REG1 */ | ||||||
|  | 	err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG1, | ||||||
|  | 						 LSM303AGR_ACC_LP_MSK, &lp); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		goto error; | ||||||
|  |  | ||||||
|  | 	/* Set HR bit in CTRL_REG4 */ | ||||||
|  | 	err = lsm303agr_acc_write_data_with_mask(cdata, CTRL_REG2, | ||||||
|  | 						 LSM303AGR_ACC_HR_MSK, | ||||||
|  | 						 &hr); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		goto error; | ||||||
|  |  | ||||||
|  | 	/* Change platform data */ | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  | 	sdata->opmode = opmode; | ||||||
|  | 	sdata->shift = lsm303agr_acc_opmode_table[opmode].shift; | ||||||
|  |  | ||||||
|  | 	switch (sdata->fs_range) { | ||||||
|  | 	case LSM303AGR_ACC_G_2G: | ||||||
|  | 		indx = 0; | ||||||
|  | 		break; | ||||||
|  | 	case LSM303AGR_ACC_G_8G: | ||||||
|  | 		indx = 2; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 	sdata->sensitivity = lsm303agr_acc_opmode_table[opmode].sensitivity[indx]; | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_ACC_DEBUG | ||||||
|  | 	dev_info(cdata->dev, "%s shift=%d, sens=%d, opm=%d\n", | ||||||
|  | 		 LSM303AGR_ACC_DEV_NAME, sdata->shift, sdata->sensitivity, | ||||||
|  | 		 sdata->opmode); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  |  | ||||||
|  | error: | ||||||
|  | 	dev_err(cdata->dev, "update opmode failed: %d\n", err); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | lsm303agr_acc_get_acceleration_data(struct lsm303agr_common_data *cdata, int *xyz) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	/* Data bytes from hardware xL, xH, yL, yH, zL, zH */ | ||||||
|  | 	u8 acc_data[6]; | ||||||
|  | 	/* x,y,z hardware data */ | ||||||
|  | 	u32 sensitivity, shift; | ||||||
|  |  | ||||||
|  | 	err = cdata->tf->read(cdata->dev, AXISDATA_REG, 6, acc_data); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	/* Get the current sensitivity and shift values */ | ||||||
|  | 	sensitivity = cdata->sensors[LSM303AGR_ACC_SENSOR].sensitivity; | ||||||
|  | 	shift = cdata->sensors[LSM303AGR_ACC_SENSOR].shift; | ||||||
|  |  | ||||||
|  | 	/* Transform LSBs into ug */ | ||||||
|  | 	xyz[0] = (s32)((s16)(acc_data[0] | (acc_data[1] << 8)) >> shift) * sensitivity; | ||||||
|  | 	xyz[1] = (s32)((s16)(acc_data[2] | (acc_data[3] << 8)) >> shift) * sensitivity; | ||||||
|  | 	xyz[2] = (s32)((s16)(acc_data[4] | (acc_data[5] << 8)) >> shift) * sensitivity; | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_ACC_DEBUG | ||||||
|  | 	dev_info(cdata->dev, "%s read x=%d, y=%d, z=%d\n", | ||||||
|  | 		 LSM303AGR_ACC_DEV_NAME, xyz[0], xyz[1], xyz[2]); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void lsm303agr_acc_report_values(struct lsm303agr_common_data *cdata, | ||||||
|  | 					int *xyz, s64 timestamp) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_X, xyz[0]); | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_Y, xyz[1]); | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_Z, xyz[2]); | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_TIME_MSB, | ||||||
|  | 		    timestamp >> 32); | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_TIME_LSB, | ||||||
|  | 		    timestamp & 0xffffffff); | ||||||
|  | 	input_sync(sdata->input_dev); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lsm303agr_acc_enable(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	if (!atomic_cmpxchg(&cdata->enabled, 0, 1)) { | ||||||
|  | 		int err; | ||||||
|  | 		struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 		mutex_lock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 		sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  | 		err = lsm303agr_acc_device_power_on(cdata); | ||||||
|  | 		if (err < 0) { | ||||||
|  | 			atomic_set(&cdata->enabled, 0); | ||||||
|  | 			return err; | ||||||
|  | 		} | ||||||
|  | 		schedule_delayed_work(&sdata->input_work, | ||||||
|  | 				      msecs_to_jiffies(sdata->poll_interval)); | ||||||
|  |  | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(lsm303agr_acc_enable); | ||||||
|  |  | ||||||
|  | int lsm303agr_acc_disable(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	if (atomic_cmpxchg(&cdata->enabled, 1, 0)) { | ||||||
|  | 		struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 		sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  | 		cancel_delayed_work_sync(&sdata->input_work); | ||||||
|  |  | ||||||
|  | 		mutex_lock(&cdata->lock); | ||||||
|  | 		lsm303agr_acc_device_power_off(cdata); | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(lsm303agr_acc_disable); | ||||||
|  |  | ||||||
|  | static ssize_t attr_get_sched_num_acc(struct device *dev, | ||||||
|  | 				      struct device_attribute *attr, char *buf) | ||||||
|  | { | ||||||
|  | 	int val; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	val = cdata->sensors[LSM303AGR_ACC_SENSOR].schedule_num; | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return sprintf(buf, "%d\n", val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_set_sched_num_acc(struct device *dev, | ||||||
|  | 				      struct device_attribute *attr, | ||||||
|  | 				      const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	unsigned long sched_num; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	if (kstrtoul(buf, 10, &sched_num)) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	cdata->sensors[LSM303AGR_ACC_SENSOR].schedule_num = sched_num; | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_get_polling_rate_acc(struct device *dev, | ||||||
|  | 					 struct device_attribute *attr, | ||||||
|  | 					 char *buf) | ||||||
|  | { | ||||||
|  | 	int val; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	val = cdata->sensors[LSM303AGR_ACC_SENSOR].poll_interval; | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return sprintf(buf, "%d\n", val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_set_polling_rate_acc(struct device *dev, | ||||||
|  | 					 struct device_attribute *attr, | ||||||
|  | 					 const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	unsigned long interval_ms; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	if (kstrtoul(buf, 10, &interval_ms)) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	if (!interval_ms) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  | 	interval_ms = max_t(unsigned int, (unsigned int)interval_ms, | ||||||
|  | 			    sdata->min_interval); | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	sdata->poll_interval = interval_ms; | ||||||
|  | 	lsm303agr_acc_update_odr(cdata, interval_ms); | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_get_range_acc(struct device *dev, | ||||||
|  | 				  struct device_attribute *attr, | ||||||
|  | 				  char *buf) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  | 	char range = 2; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	switch (sdata->fs_range) { | ||||||
|  | 	case LSM303AGR_ACC_G_2G: | ||||||
|  | 		range = 2; | ||||||
|  | 		break; | ||||||
|  | 	case LSM303AGR_ACC_G_8G: | ||||||
|  | 		range = 8; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return sprintf(buf, "%d\n", range); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_set_range_acc(struct device *dev, | ||||||
|  | 				  struct device_attribute *attr, | ||||||
|  | 				  const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	u8 range; | ||||||
|  | 	int err; | ||||||
|  | 	unsigned long val; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  | 	if (kstrtoul(buf, 10, &val)) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	switch (val) { | ||||||
|  | 	case 2: | ||||||
|  | 		range = LSM303AGR_ACC_G_2G; | ||||||
|  | 		break; | ||||||
|  | 	case 8: | ||||||
|  | 		range = LSM303AGR_ACC_G_8G; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		dev_err(cdata->dev, | ||||||
|  | 			"invalid range request: %lu, discarded\n", val); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	err = lsm303agr_acc_update_fs_range(cdata, range); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  | 	sdata->fs_range = range; | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	dev_info(cdata->dev, "range set to: %lu g\n", val); | ||||||
|  |  | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_get_opmode_acc(struct device *dev, | ||||||
|  | 				   struct device_attribute *attr, | ||||||
|  | 				   char *buf) | ||||||
|  | { | ||||||
|  | 	char opmode; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	opmode = cdata->sensors[LSM303AGR_ACC_SENSOR].opmode; | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return sprintf(buf, "%d\n", opmode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_set_opmode_acc(struct device *dev, | ||||||
|  | 				   struct device_attribute *attr, | ||||||
|  | 				   const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	u16 opmode; | ||||||
|  | 	unsigned long val; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	if (kstrtoul(buf, 10, &val)) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	/* Check if argument is valid opmode */ | ||||||
|  | 	switch (val) { | ||||||
|  | 	case LSM303AGR_ACC_OPMODE_NORMAL: | ||||||
|  | 	case LSM303AGR_ACC_OPMODE_HR: | ||||||
|  | 	case LSM303AGR_ACC_OPMODE_LP: | ||||||
|  | 		opmode = val; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		dev_err(cdata->dev, | ||||||
|  | 			"invalid range request: %lu, discarded\n", val); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	err = lsm303agr_acc_update_opmode(cdata, opmode); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	dev_info(cdata->dev, "opmode set to: %u\n", opmode); | ||||||
|  |  | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_get_enable_acc(struct device *dev, | ||||||
|  | 				   struct device_attribute *attr, | ||||||
|  | 				   char *buf) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  | 	int val = atomic_read(&cdata->enabled); | ||||||
|  |  | ||||||
|  | 	return sprintf(buf, "%d\n", val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_set_enable_acc(struct device *dev, | ||||||
|  | 				   struct device_attribute *attr, | ||||||
|  | 				   const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  | 	unsigned long val; | ||||||
|  |  | ||||||
|  | 	if (kstrtoul(buf, 10, &val)) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	if (val) | ||||||
|  | 		lsm303agr_acc_enable(cdata); | ||||||
|  | 	else | ||||||
|  | 		lsm303agr_acc_disable(cdata); | ||||||
|  |  | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static struct device_attribute attributes[] = { | ||||||
|  |  | ||||||
|  | 	__ATTR(pollrate_ms, 0664, attr_get_polling_rate_acc, | ||||||
|  | 	       attr_set_polling_rate_acc), | ||||||
|  | 	__ATTR(range, 0664, attr_get_range_acc, attr_set_range_acc), | ||||||
|  | 	__ATTR(opmode, 0664, attr_get_opmode_acc, attr_set_opmode_acc), | ||||||
|  | 	__ATTR(enable_device, 0664, attr_get_enable_acc, attr_set_enable_acc), | ||||||
|  | 	__ATTR(schedule_num, 0664, attr_get_sched_num_acc, | ||||||
|  | 	       attr_set_sched_num_acc), | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int create_sysfs_interfaces(struct device *dev) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < ARRAY_SIZE(attributes); i++) | ||||||
|  | 		if (device_create_file(dev, attributes + i)) | ||||||
|  | 			goto error; | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | error: | ||||||
|  | 	for (; i >= 0; i--) | ||||||
|  | 		device_remove_file(dev, attributes + i); | ||||||
|  |  | ||||||
|  | 	dev_err(dev, "%s:Unable to create interface\n", __func__); | ||||||
|  |  | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int remove_sysfs_interfaces(struct device *dev) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < ARRAY_SIZE(attributes); i++) | ||||||
|  | 		device_remove_file(dev, attributes + i); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void lsm303agr_acc_input_work_func(struct work_struct *work) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_common_data *cdata; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  | 	int err, xyz[3] = {}; | ||||||
|  |  | ||||||
|  | 	sdata = container_of((struct delayed_work *)work, | ||||||
|  | 			     struct lsm303agr_sensor_data, input_work); | ||||||
|  | 	cdata = sdata->cdata; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	sdata->schedule_num++; | ||||||
|  | 	err = lsm303agr_acc_get_acceleration_data(cdata, xyz); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		dev_err(cdata->dev, "get_acceleration_data failed\n"); | ||||||
|  | 	else | ||||||
|  | 		lsm303agr_acc_report_values(cdata, xyz, lsm303agr_get_time_ns()); | ||||||
|  |  | ||||||
|  | 	schedule_delayed_work(&sdata->input_work, msecs_to_jiffies( | ||||||
|  | 			      sdata->poll_interval)); | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void lsm303agr_acc_input_cleanup(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  | 	input_unregister_device(sdata->input_dev); | ||||||
|  | 	input_free_device(sdata->input_dev); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lsm303agr_acc_probe(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	/* init sensor data structure */ | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_ACC_SENSOR]; | ||||||
|  |  | ||||||
|  | 	sdata->cdata = cdata; | ||||||
|  | 	sdata->poll_interval = 100; | ||||||
|  | 	sdata->min_interval = LSM303AGR_ACC_MIN_POLL_PERIOD_MS; | ||||||
|  |  | ||||||
|  | 	err = lsm303agr_acc_device_power_on(cdata); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "power on failed: %d\n", err); | ||||||
|  | 		goto  err_power_off; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	atomic_set(&cdata->enabled, 1); | ||||||
|  |  | ||||||
|  | 	err = lsm303agr_acc_update_fs_range(cdata, LSM303AGR_ACC_G_2G); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "update_fs_range failed\n"); | ||||||
|  | 		goto  err_power_off; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = lsm303agr_acc_update_odr(cdata, sdata->poll_interval); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "update_odr failed\n"); | ||||||
|  | 		goto  err_power_off; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = lsm303agr_acc_update_opmode(cdata, LSM303AGR_ACC_OPMODE_NORMAL); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "update_opmode failed\n"); | ||||||
|  | 		goto  err_power_off; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = lsm303agr_acc_input_init(sdata, LSM303AGR_ACC_DEV_NAME); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "input init failed\n"); | ||||||
|  | 		goto err_power_off; | ||||||
|  | 	} | ||||||
|  | 	INIT_DELAYED_WORK(&sdata->input_work, lsm303agr_acc_input_work_func); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	err = create_sysfs_interfaces(cdata->dev); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, | ||||||
|  | 		   "device LSM303AGR_ACC_DEV_NAME sysfs register failed\n"); | ||||||
|  | 		goto err_input_cleanup; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	lsm303agr_acc_device_power_off(cdata); | ||||||
|  |  | ||||||
|  | 	/* As default, do not report information */ | ||||||
|  | 	atomic_set(&cdata->enabled, 0); | ||||||
|  |  | ||||||
|  | 	dev_info(cdata->dev, "%s: probed\n", LSM303AGR_ACC_DEV_NAME); | ||||||
|  |  | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | err_input_cleanup: | ||||||
|  | 	lsm303agr_acc_input_cleanup(cdata); | ||||||
|  | err_power_off: | ||||||
|  | 	lsm303agr_acc_device_power_off(cdata); | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  | 	pr_err("%s: Driver Init failed\n", LSM303AGR_ACC_DEV_NAME); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(lsm303agr_acc_probe); | ||||||
|  |  | ||||||
|  | void lsm303agr_acc_remove(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	lsm303agr_acc_disable(cdata); | ||||||
|  | 	lsm303agr_acc_input_cleanup(cdata); | ||||||
|  | 	remove_sysfs_interfaces(cdata->dev); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(lsm303agr_acc_remove); | ||||||
|  |  | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
|  |  | ||||||
| @@ -0,0 +1,207 @@ | |||||||
|  | /* | ||||||
|  |  * STMicroelectronics lsm303agr_acc_i2c.c driver | ||||||
|  |  * | ||||||
|  |  * Copyright 2016 STMicroelectronics Inc. | ||||||
|  |  * | ||||||
|  |  * Giuseppe Barba <giuseppe.barba@st.com> | ||||||
|  |  * | ||||||
|  |  * Licensed under the GPL-2. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <linux/err.h> | ||||||
|  | #include <linux/errno.h> | ||||||
|  | #include <linux/slab.h> | ||||||
|  | #include <linux/delay.h> | ||||||
|  | #include <linux/i2c.h> | ||||||
|  | #include <linux/input.h> | ||||||
|  | #include <linux/uaccess.h> | ||||||
|  | #include <linux/workqueue.h> | ||||||
|  | #include <linux/irq.h> | ||||||
|  | #include <linux/interrupt.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/device.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/moduleparam.h> | ||||||
|  | #include <linux/version.h> | ||||||
|  |  | ||||||
|  | #include "lsm303agr_core.h" | ||||||
|  |  | ||||||
|  | #define I2C_AUTO_INCREMENT	0x80 | ||||||
|  |  | ||||||
|  | /* XXX: caller must hold cdata->lock */ | ||||||
|  | static int lsm303agr_acc_i2c_read(struct device *dev, u8 reg_addr, int len, | ||||||
|  | 				  u8 *data) | ||||||
|  | { | ||||||
|  | 	struct i2c_msg msg[2]; | ||||||
|  | 	struct i2c_client *client = to_i2c_client(dev); | ||||||
|  |  | ||||||
|  | 	if (len > 1) | ||||||
|  | 		reg_addr |= I2C_AUTO_INCREMENT; | ||||||
|  |  | ||||||
|  | 	msg[0].addr = client->addr; | ||||||
|  | 	msg[0].flags = client->flags; | ||||||
|  | 	msg[0].len = 1; | ||||||
|  | 	msg[0].buf = ®_addr; | ||||||
|  |  | ||||||
|  | 	msg[1].addr = client->addr; | ||||||
|  | 	msg[1].flags = client->flags | I2C_M_RD; | ||||||
|  | 	msg[1].len = len; | ||||||
|  | 	msg[1].buf = data; | ||||||
|  |  | ||||||
|  | 	return i2c_transfer(client->adapter, msg, 2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* XXX: caller must hold cdata->lock */ | ||||||
|  | static int lsm303agr_acc_i2c_write(struct device *dev, u8 reg_addr, int len, | ||||||
|  | 				   u8 *data) | ||||||
|  | { | ||||||
|  | 	u8 send[len + 1]; | ||||||
|  | 	struct i2c_msg msg; | ||||||
|  | 	struct i2c_client *client = to_i2c_client(dev); | ||||||
|  |  | ||||||
|  | 	if (len > 1) | ||||||
|  | 		reg_addr |= I2C_AUTO_INCREMENT; | ||||||
|  |  | ||||||
|  | 	send[0] = reg_addr; | ||||||
|  | 	memcpy(&send[1], data, len * sizeof(u8)); | ||||||
|  | 	len++; | ||||||
|  |  | ||||||
|  | 	msg.addr = client->addr; | ||||||
|  | 	msg.flags = client->flags; | ||||||
|  | 	msg.len = len; | ||||||
|  | 	msg.buf = send; | ||||||
|  |  | ||||||
|  | 	return i2c_transfer(client->adapter, &msg, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* I2C IO routines */ | ||||||
|  | static const struct lsm303agr_transfer_function lsm303agr_acc_i2c_tf = { | ||||||
|  | 	.write = lsm303agr_acc_i2c_write, | ||||||
|  | 	.read = lsm303agr_acc_i2c_read, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_PM_SLEEP | ||||||
|  | static int lsm303agr_acc_resume(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct i2c_client *client = to_i2c_client(dev); | ||||||
|  | 	struct lsm303agr_common_data *cdata = i2c_get_clientdata(client); | ||||||
|  |  | ||||||
|  | 	if (cdata->on_before_suspend) | ||||||
|  | 		return lsm303agr_acc_enable(cdata); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_acc_suspend(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct i2c_client *client = to_i2c_client(dev); | ||||||
|  | 	struct lsm303agr_common_data *cdata = i2c_get_clientdata(client); | ||||||
|  |  | ||||||
|  | 	cdata->on_before_suspend = atomic_read(&cdata->enabled); | ||||||
|  | 	return lsm303agr_acc_disable(cdata); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static SIMPLE_DEV_PM_OPS(lsm303agr_acc_pm_ops, | ||||||
|  | 				lsm303agr_acc_suspend, | ||||||
|  | 				lsm303agr_acc_resume); | ||||||
|  |  | ||||||
|  | #define LSM303AGR_ACC_PM_OPS	(&lsm303agr_acc_pm_ops) | ||||||
|  | #else /* CONFIG_PM_SLEEP */ | ||||||
|  | #define LSM303AGR_ACC_PM_OPS	NULL | ||||||
|  | #endif /* CONFIG_PM_SLEEP */ | ||||||
|  |  | ||||||
|  | static int lsm303agr_acc_i2c_probe(struct i2c_client *client, | ||||||
|  | 				   const struct i2c_device_id *id) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	struct lsm303agr_common_data *cdata; | ||||||
|  |  | ||||||
|  | 	dev_info(&client->dev, "probe start.\n"); | ||||||
|  |  | ||||||
|  | 	/* Alloc Common data structure */ | ||||||
|  | 	cdata = kzalloc(sizeof(struct lsm303agr_common_data), GFP_KERNEL); | ||||||
|  | 	if (!cdata) { | ||||||
|  | 		dev_err(&client->dev, "failed to allocate module data\n"); | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cdata->sensor_num = LSM303AGR_MAX_SENSORS_NUM; | ||||||
|  | 	cdata->dev = &client->dev; | ||||||
|  | 	cdata->name = client->name; | ||||||
|  | 	cdata->bus_type = BUS_I2C; | ||||||
|  | 	cdata->tf = &lsm303agr_acc_i2c_tf; | ||||||
|  |  | ||||||
|  | 	i2c_set_clientdata(client, cdata); | ||||||
|  |  | ||||||
|  | 	mutex_init(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	err = lsm303agr_acc_probe(cdata); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		kfree(cdata); | ||||||
|  |  | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE | ||||||
|  | static void lsm303agr_acc_i2c_remove(struct i2c_client *client) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_common_data *cdata = i2c_get_clientdata(client); | ||||||
|  |  | ||||||
|  | 	dev_info(cdata->dev, "driver removing\n"); | ||||||
|  |  | ||||||
|  | 	lsm303agr_acc_remove(cdata); | ||||||
|  | 	kfree(cdata); | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | static int lsm303agr_acc_i2c_remove(struct i2c_client *client) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_common_data *cdata = i2c_get_clientdata(client); | ||||||
|  |  | ||||||
|  | 	dev_info(cdata->dev, "driver removing\n"); | ||||||
|  |  | ||||||
|  | 	lsm303agr_acc_remove(cdata); | ||||||
|  | 	kfree(cdata); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static const struct i2c_device_id lsm303agr_acc_i2c_id[] = { | ||||||
|  | 	{ "lsm303agr_acc", 0 }, | ||||||
|  | 	{ }, | ||||||
|  | }; | ||||||
|  | MODULE_DEVICE_TABLE(i2c, lsm303agr_acc_i2c_id); | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_OF | ||||||
|  | static const struct of_device_id lsm303agr_acc_i2c_id_table[] = { | ||||||
|  | 	{.compatible = "st,lsm303agr_acc", }, | ||||||
|  | 	{ }, | ||||||
|  | }; | ||||||
|  | MODULE_DEVICE_TABLE(of, lsm303agr_acc_i2c_id_table); | ||||||
|  | #endif /* CONFIG_OF */ | ||||||
|  |  | ||||||
|  | static struct i2c_driver lsm303agr_acc_i2c_driver = { | ||||||
|  | 	.driver = { | ||||||
|  | 		.owner = THIS_MODULE, | ||||||
|  | 		.name = "lsm303agr_acc", | ||||||
|  | 		.pm = LSM303AGR_ACC_PM_OPS, | ||||||
|  | #ifdef CONFIG_OF | ||||||
|  | 		.of_match_table = lsm303agr_acc_i2c_id_table, | ||||||
|  | #endif /* CONFIG_OF */ | ||||||
|  | 	}, | ||||||
|  | 	.probe = lsm303agr_acc_i2c_probe, | ||||||
|  | 	.remove = lsm303agr_acc_i2c_remove, | ||||||
|  | 	.id_table = lsm303agr_acc_i2c_id, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module_i2c_driver(lsm303agr_acc_i2c_driver); | ||||||
|  |  | ||||||
|  | MODULE_DESCRIPTION("lsm303agr accelerometer i2c driver"); | ||||||
|  | MODULE_AUTHOR("Armando Visconti"); | ||||||
|  | MODULE_AUTHOR("Matteo Dameno"); | ||||||
|  | MODULE_AUTHOR("Denis Ciocca"); | ||||||
|  | MODULE_AUTHOR("STMicroelectronics"); | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
|  |  | ||||||
| @@ -0,0 +1,104 @@ | |||||||
|  | /* | ||||||
|  |  * STMicroelectronics lsm303agr driver | ||||||
|  |  * | ||||||
|  |  * Copyright 2016 STMicroelectronics Inc. | ||||||
|  |  * | ||||||
|  |  * Giuseppe Barba <giuseppe.barba@st.com> | ||||||
|  |  * | ||||||
|  |  * Licensed under the GPL-2. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef	__LSM303AGR_H__ | ||||||
|  | #define	__LSM303AGR_H__ | ||||||
|  |  | ||||||
|  | #ifdef __KERNEL__ | ||||||
|  |  | ||||||
|  | #define LSM303AGR_MAX_SENSORS_NUM	1 | ||||||
|  | #define LSM303AGR_ACC_SENSOR		0 /* only this sensor */ | ||||||
|  | #define LSM303AGR_MAG_SENSOR		0 /* only this sensor */ | ||||||
|  |  | ||||||
|  | struct lsm303agr_common_data; | ||||||
|  |  | ||||||
|  | /* specific bus I/O functions */ | ||||||
|  | struct lsm303agr_transfer_function { | ||||||
|  | 	int (*write) (struct device *dev, u8 reg_addr, int len, u8 *data); | ||||||
|  | 	int (*read) (struct device *dev, u8 reg_addr, int len, u8 *data); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #if defined(CONFIG_INPUT_LSM303AGR_SPI) || \ | ||||||
|  |     defined(CONFIG_INPUT_LSM303AGR_SPI_MODULE) | ||||||
|  | #define LSM303AGR_RX_MAX_LENGTH		500 | ||||||
|  | #define LSM303AGR_TX_MAX_LENGTH		500 | ||||||
|  |  | ||||||
|  | struct lsm303agr_transfer_buffer { | ||||||
|  | 	u8 rx_buf[LSM303AGR_RX_MAX_LENGTH]; | ||||||
|  | 	u8 tx_buf[LSM303AGR_TX_MAX_LENGTH] ____cacheline_aligned; | ||||||
|  | }; | ||||||
|  | #endif /* CONFIG_INPUT_LSM303AGR_SPI */ | ||||||
|  |  | ||||||
|  | /* Sensor data */ | ||||||
|  | struct lsm303agr_sensor_data { | ||||||
|  | 	struct lsm303agr_common_data *cdata; | ||||||
|  | 	const char* name; | ||||||
|  | 	s64 timestamp; | ||||||
|  | 	u8 enabled; | ||||||
|  | 	u32 c_odr; | ||||||
|  | 	u32 c_gain; | ||||||
|  | 	u8 sindex; | ||||||
|  | 	u8 sample_to_discard; | ||||||
|  | 	u32 poll_interval; | ||||||
|  | 	u32 min_interval; | ||||||
|  | 	u8 fs_range; | ||||||
|  | 	u32 sensitivity; | ||||||
|  | 	u16 shift; | ||||||
|  | 	u16 opmode; | ||||||
|  | 	struct input_dev *input_dev; | ||||||
|  | 	struct delayed_work input_work; | ||||||
|  | 	u32 schedule_num; /* Number of time work_input routine is called */ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct lsm303agr_common_data { | ||||||
|  | 	const char *name; | ||||||
|  | 	struct mutex lock; | ||||||
|  | 	struct device *dev; | ||||||
|  | 	int hw_initialized; | ||||||
|  | 	atomic_t enabled; | ||||||
|  | 	int on_before_suspend; | ||||||
|  | 	u8 sensor_num; | ||||||
|  | 	u16 bus_type; | ||||||
|  | 	struct lsm303agr_sensor_data sensors[LSM303AGR_MAX_SENSORS_NUM]; | ||||||
|  | 	const struct lsm303agr_transfer_function *tf; | ||||||
|  | #if defined(CONFIG_INPUT_LSM303AGR_SPI) || \ | ||||||
|  |     defined(CONFIG_INPUT_LSM303AGR_SPI_MODULE) | ||||||
|  | 	struct lsm303agr_transfer_buffer tb; | ||||||
|  | #endif /* CONFIG_INPUT_LSM303AGR_SPI */ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* Input events used by lsm303agr driver */ | ||||||
|  | #define INPUT_EVENT_TYPE		EV_MSC | ||||||
|  | #define INPUT_EVENT_X			MSC_SERIAL | ||||||
|  | #define INPUT_EVENT_Y			MSC_PULSELED | ||||||
|  | #define INPUT_EVENT_Z			MSC_GESTURE | ||||||
|  | #define INPUT_EVENT_TIME_MSB		MSC_SCAN | ||||||
|  | #define INPUT_EVENT_TIME_LSB		MSC_MAX | ||||||
|  |  | ||||||
|  | static inline s64 lsm303agr_get_time_ns(void) | ||||||
|  | { | ||||||
|  | 	return ktime_to_ns(ktime_get_boottime()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void lsm303agr_acc_remove(struct lsm303agr_common_data *cdata); | ||||||
|  | int lsm303agr_acc_probe(struct lsm303agr_common_data *cdata); | ||||||
|  | int lsm303agr_acc_enable(struct lsm303agr_common_data *cdata); | ||||||
|  | int lsm303agr_acc_disable(struct lsm303agr_common_data *cdata); | ||||||
|  |  | ||||||
|  | void lsm303agr_mag_remove(struct lsm303agr_common_data *cdata); | ||||||
|  | int lsm303agr_mag_probe(struct lsm303agr_common_data *cdata); | ||||||
|  | int lsm303agr_mag_enable(struct lsm303agr_common_data *cdata); | ||||||
|  | int lsm303agr_mag_disable(struct lsm303agr_common_data *cdata); | ||||||
|  |  | ||||||
|  | #endif /* __KERNEL__ */ | ||||||
|  | #endif	/* __LSM303AGR_H__ */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -0,0 +1,556 @@ | |||||||
|  | /* | ||||||
|  |  * STMicroelectronics lsm303agr_mag.c driver | ||||||
|  |  * | ||||||
|  |  * Copyright 2016 STMicroelectronics Inc. | ||||||
|  |  * | ||||||
|  |  * Giuseppe Barba <giuseppe.barba@st.com> | ||||||
|  |  * | ||||||
|  |  * Licensed under the GPL-2. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <linux/err.h> | ||||||
|  | #include <linux/errno.h> | ||||||
|  | #include <linux/delay.h> | ||||||
|  | #include <linux/fs.h> | ||||||
|  | #include <linux/i2c.h> | ||||||
|  | #include <linux/input.h> | ||||||
|  | #include <linux/uaccess.h> | ||||||
|  | #include <linux/workqueue.h> | ||||||
|  | #include <linux/irq.h> | ||||||
|  | #include <linux/gpio.h> | ||||||
|  | #include <linux/interrupt.h> | ||||||
|  | #include <linux/slab.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/device.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/moduleparam.h> | ||||||
|  | #include <linux/version.h> | ||||||
|  |  | ||||||
|  | #include "lsm303agr_core.h" | ||||||
|  |  | ||||||
|  | #define LSM303AGR_MAG_DEV_NAME	"lsm303agr_mag" | ||||||
|  |  | ||||||
|  | /* DEVICE REGISTERS */ | ||||||
|  | #define WHO_AM_I		0x4F | ||||||
|  | #define CFG_REG_A		0x60 | ||||||
|  | #define AXISDATA_REG		0x68 | ||||||
|  | #define WHOAMI_LSM303AGR_MAG	0x40 | ||||||
|  | /* Device operating modes */ | ||||||
|  | #define MD_CONTINUOS_MODE	0x00 | ||||||
|  | #define MD_SINGLE_MODE		0x01 | ||||||
|  | #define MD_IDLE1_MODE		0x02 | ||||||
|  | #define MD_IDLE2_MODE		0x03 | ||||||
|  | #define LSM303AGR_MAG_MODE_MSK	0x03 | ||||||
|  |  | ||||||
|  | /* Device ODRs */ | ||||||
|  | #define LSM303AGR_MAG_ODR10_HZ		0x00 | ||||||
|  | #define LSM303AGR_MAG_ODR20_HZ		0x04 | ||||||
|  | #define LSM303AGR_MAG_ODR50_HZ		0x08 | ||||||
|  | #define LSM303AGR_MAG_ODR100_HZ		0x0C | ||||||
|  | #define LSM303AGR_MAG_ODR_MSK		0x0C | ||||||
|  |  | ||||||
|  | #define LSM303AGR_MAG_SENSITIVITY	1500	/* uGa/LSB */ | ||||||
|  |  | ||||||
|  | /* ODR table */ | ||||||
|  | struct { | ||||||
|  | 	u32 time_ms; | ||||||
|  | 	u32 reg_val; | ||||||
|  | } lsm303agr_mag_odr_table[] = { | ||||||
|  | 	{   10, LSM303AGR_MAG_ODR100_HZ	}, /* ODR = 100Hz */ | ||||||
|  | 	{   20, LSM303AGR_MAG_ODR50_HZ	}, /* ODR = 50Hz */ | ||||||
|  | 	{   50, LSM303AGR_MAG_ODR20_HZ	}, /* ODR = 20Hz */ | ||||||
|  | 	{  100, LSM303AGR_MAG_ODR10_HZ	}, /* ODR = 10Hz */ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* read and write with mask a given register */ | ||||||
|  | static int lsm303agr_mag_write_data_with_mask(struct lsm303agr_common_data *cdata, | ||||||
|  | 					      u8 reg_addr, u8 mask, u8 *data) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	u8 new_data, old_data = 0; | ||||||
|  |  | ||||||
|  | 	err = cdata->tf->read(cdata->dev, reg_addr, 1, &old_data); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	new_data = ((old_data & (~mask)) | ((*data) & mask)); | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_MAG_DEBUG | ||||||
|  | 	dev_info(cdata->dev, "%s %02x o=%02x d=%02x n=%02x\n", | ||||||
|  | 		 LSM303AGR_MAG_DEV_NAME, reg_addr, old_data, *data, new_data); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	/* Save for caller usage the data that is about to be written */ | ||||||
|  | 	*data = new_data; | ||||||
|  |  | ||||||
|  | 	if (new_data == old_data) | ||||||
|  | 		return 1; | ||||||
|  |  | ||||||
|  | 	return cdata->tf->write(cdata->dev, reg_addr, 1, &new_data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lsm303agr_mag_input_init(struct lsm303agr_sensor_data *sdata, | ||||||
|  | 			     const char* description) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	sdata->input_dev = input_allocate_device(); | ||||||
|  | 	if (!sdata->input_dev) { | ||||||
|  | 		dev_err(sdata->cdata->dev, "input device allocation failed\n"); | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	sdata->input_dev->name = description; | ||||||
|  | 	sdata->input_dev->id.bustype = sdata->cdata->bus_type; | ||||||
|  | 	sdata->input_dev->dev.parent = sdata->cdata->dev; | ||||||
|  |  | ||||||
|  | 	input_set_drvdata(sdata->input_dev, sdata); | ||||||
|  |  | ||||||
|  | 	/* Set the input event characteristics of the probed sensor driver */ | ||||||
|  | 	set_bit(INPUT_EVENT_TYPE, sdata->input_dev->evbit ); | ||||||
|  | 	set_bit(INPUT_EVENT_TIME_MSB, sdata->input_dev->mscbit); | ||||||
|  | 	set_bit(INPUT_EVENT_TIME_LSB, sdata->input_dev->mscbit); | ||||||
|  | 	set_bit(INPUT_EVENT_X, sdata->input_dev->mscbit); | ||||||
|  | 	set_bit(INPUT_EVENT_Y, sdata->input_dev->mscbit); | ||||||
|  | 	set_bit(INPUT_EVENT_Z, sdata->input_dev->mscbit); | ||||||
|  |  | ||||||
|  | 	err = input_register_device(sdata->input_dev); | ||||||
|  | 	if (err) { | ||||||
|  | 		dev_err(sdata->cdata->dev, | ||||||
|  | 			"unable to register input device %s\n", | ||||||
|  | 			sdata->input_dev->name); | ||||||
|  | 		input_free_device(sdata->input_dev); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Check if WHO_AM_I is correct */ | ||||||
|  | static int lsm303agr_mag_check_wai(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	u8 wai; | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_MAG_DEBUG | ||||||
|  | 	pr_info("%s: check WAI start\n", LSM303AGR_MAG_DEV_NAME); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	err = cdata->tf->read(cdata->dev, WHO_AM_I, 1, &wai); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_warn(cdata->dev, | ||||||
|  | 		"Error reading WHO_AM_I: is device available/working?\n"); | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (wai != WHOAMI_LSM303AGR_MAG) { | ||||||
|  | 		dev_err(cdata->dev, | ||||||
|  | 			"device unknown. Expected: 0x%02x," " Replies: 0x%02x\n", | ||||||
|  | 			WHOAMI_LSM303AGR_MAG, wai); | ||||||
|  | 		err = -1; /* choose the right coded error */ | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cdata->hw_initialized = 1; | ||||||
|  | #ifdef LSM303AGR_MAG_DEBUG | ||||||
|  | 	pr_info("%s: check WAI done\n", LSM303AGR_MAG_DEV_NAME); | ||||||
|  | #endif | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | error: | ||||||
|  | 	cdata->hw_initialized = 0; | ||||||
|  | 	dev_err(cdata->dev, | ||||||
|  | 		"check WAI error 0x%02x,0x%02x: %d\n", WHO_AM_I, wai, err); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_mag_set_odr(struct lsm303agr_common_data *cdata, u8 odr) | ||||||
|  | { | ||||||
|  | 	u8 odr_reg; | ||||||
|  | 	int err = -1, i; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Following, looks for the longest possible odr interval scrolling the | ||||||
|  | 	 * odr_table vector from the end (shortest interval) backward | ||||||
|  | 	 * (longest interval), to support the poll_interval requested | ||||||
|  | 	 * by the system. It must be the longest interval lower | ||||||
|  | 	 * than the poll interval | ||||||
|  | 	 */ | ||||||
|  | 	for (i = ARRAY_SIZE(lsm303agr_mag_odr_table) - 1; i >= 0; i--) { | ||||||
|  | 		if ((lsm303agr_mag_odr_table[i].time_ms <= odr) || (i == 0)) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	odr_reg = lsm303agr_mag_odr_table[i].reg_val; | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR]; | ||||||
|  | 	sdata->poll_interval = sdata->c_odr = lsm303agr_mag_odr_table[i].time_ms; | ||||||
|  |  | ||||||
|  | 	/* If device is currently enabled, we need to write new | ||||||
|  | 	 *  configuration out to it */ | ||||||
|  | 	if (atomic_read(&cdata->enabled)) { | ||||||
|  | 		err = lsm303agr_mag_write_data_with_mask(cdata, CFG_REG_A, | ||||||
|  | 							 LSM303AGR_MAG_ODR_MSK, | ||||||
|  | 							 &odr_reg); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			goto error; | ||||||
|  | #ifdef LSM303AGR_MAG_DEBUG | ||||||
|  | 		dev_info(cdata->dev, "update odr to 0x%02x,0x%02x: %d\n", | ||||||
|  | 			 CFG_REG_A, odr_reg, err); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return lsm303agr_mag_odr_table[i].time_ms; | ||||||
|  |  | ||||||
|  | error: | ||||||
|  | 	dev_err(cdata->dev, "set odr failed 0x%02x,0x%02x: %d\n", | ||||||
|  | 		CFG_REG_A, odr_reg, err); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_mag_set_device_mode(struct lsm303agr_common_data *cdata, | ||||||
|  | 					 u8 mode) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	err = lsm303agr_mag_write_data_with_mask(cdata, CFG_REG_A, | ||||||
|  | 						 LSM303AGR_MAG_MODE_MSK, | ||||||
|  | 						 &mode); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		goto error; | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_MAG_DEBUG | ||||||
|  | 	dev_info(cdata->dev, "update mode to 0x%02x,0x%02x: %d\n", | ||||||
|  | 			CFG_REG_A, mode, err); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | error: | ||||||
|  | 	dev_err(cdata->dev, | ||||||
|  | 		"set continuos mode failed 0x%02x,0x%02x: %d\n", | ||||||
|  | 		CFG_REG_A, mode, err); | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Set device in continuos mode */ | ||||||
|  | int lsm303agr_mag_enable(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  | 	int err; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	/* Set the magnetometer in continuos mode */ | ||||||
|  | 	err = lsm303agr_mag_set_device_mode(cdata, MD_CONTINUOS_MODE); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "set_continuos failed: %d\n", | ||||||
|  | 			err); | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	atomic_set(&cdata->enabled, 1); | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR]; | ||||||
|  | 	if (lsm303agr_mag_set_odr(cdata, sdata->c_odr) < 0) { | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Start scheduling input */ | ||||||
|  | 	schedule_delayed_work(&sdata->input_work, | ||||||
|  | 			      msecs_to_jiffies(sdata->poll_interval)); | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(lsm303agr_mag_enable); | ||||||
|  |  | ||||||
|  | /* Set device in idle mode */ | ||||||
|  | int lsm303agr_mag_disable(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	if (atomic_cmpxchg(&cdata->enabled, 1, 0)) { | ||||||
|  | 		int err; | ||||||
|  | 		struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 		sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR]; | ||||||
|  | 		cancel_delayed_work_sync(&sdata->input_work); | ||||||
|  |  | ||||||
|  | 		mutex_lock(&cdata->lock); | ||||||
|  | 		/* Set the magnetometer in idle mode */ | ||||||
|  | 		err = lsm303agr_mag_set_device_mode(cdata, MD_IDLE2_MODE); | ||||||
|  | 		if (err < 0) { | ||||||
|  | 			dev_err(cdata->dev, "set_idle failed: %d\n", | ||||||
|  | 				err); | ||||||
|  | 			mutex_unlock(&cdata->lock); | ||||||
|  | 			return err; | ||||||
|  | 		} | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(lsm303agr_mag_disable); | ||||||
|  |  | ||||||
|  | static void lsm303agr_mag_report_event(struct lsm303agr_common_data *cdata, | ||||||
|  | 					int *xyz, s64 timestamp) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR]; | ||||||
|  |  | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_X, xyz[0]); | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_Y, xyz[1]); | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_Z, xyz[2]); | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_TIME_MSB, | ||||||
|  | 		    timestamp >> 32); | ||||||
|  | 	input_event(sdata->input_dev, INPUT_EVENT_TYPE, INPUT_EVENT_TIME_LSB, | ||||||
|  | 		    timestamp & 0xffffffff); | ||||||
|  | 	input_sync(sdata->input_dev); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_mag_get_data(struct lsm303agr_common_data *cdata, | ||||||
|  | 				  int *xyz) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	/* Data bytes from hardware xL, xH, yL, yH, zL, zH */ | ||||||
|  | 	u8 mag_data[6]; | ||||||
|  |  | ||||||
|  | 	err = cdata->tf->read(cdata->dev, AXISDATA_REG, 6, mag_data); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  |  | ||||||
|  | 	/* Transform LSBs into ug */ | ||||||
|  | 	xyz[0] = (s32)((s16)(mag_data[0] | (mag_data[1] << 8))); | ||||||
|  | 	xyz[0] *= LSM303AGR_MAG_SENSITIVITY; | ||||||
|  | 	xyz[1] = (s32)((s16)(mag_data[2] | (mag_data[3] << 8))); | ||||||
|  | 	xyz[1] *= LSM303AGR_MAG_SENSITIVITY; | ||||||
|  | 	xyz[2] = (s32)((s16)(mag_data[4] | (mag_data[5] << 8))); | ||||||
|  | 	xyz[2] *= LSM303AGR_MAG_SENSITIVITY; | ||||||
|  |  | ||||||
|  | #ifdef LSM303AGR_MAG_DEBUG | ||||||
|  | 	dev_info(cdata->dev, "%s read x=%d, y=%d, z=%d\n", | ||||||
|  | 		 LSM303AGR_MAG_DEV_NAME, xyz[0], xyz[1], xyz[2]); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void lsm303agr_mag_input_work_func(struct work_struct *work) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_common_data *cdata; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  | 	int err, xyz[3] = {}; | ||||||
|  |  | ||||||
|  | 	sdata = container_of((struct delayed_work *)work, | ||||||
|  | 			     struct lsm303agr_sensor_data, input_work); | ||||||
|  | 	cdata = sdata->cdata; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	sdata->schedule_num++; | ||||||
|  | 	err = lsm303agr_mag_get_data(cdata, xyz); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		dev_err(cdata->dev, "get_mag_data failed\n"); | ||||||
|  | 	else | ||||||
|  | 		lsm303agr_mag_report_event(cdata, xyz, | ||||||
|  | 					   lsm303agr_get_time_ns()); | ||||||
|  |  | ||||||
|  | 	schedule_delayed_work(&sdata->input_work, | ||||||
|  | 			      msecs_to_jiffies(sdata->poll_interval)); | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void lsm303agr_mag_input_cleanup(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR]; | ||||||
|  | 	input_unregister_device(sdata->input_dev); | ||||||
|  | 	input_free_device(sdata->input_dev); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* SYSFS: set val to polling_ms ATTR */ | ||||||
|  | static ssize_t attr_get_polling_rate_mag(struct device *dev, | ||||||
|  | 					 struct device_attribute *attr, | ||||||
|  | 					 char *buf) | ||||||
|  | { | ||||||
|  | 	u32 val = 0; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR]; | ||||||
|  |  | ||||||
|  | 	/* read from platform data */ | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	val = sdata->poll_interval; | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return sprintf(buf, "%d\n", val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ssize_t attr_set_polling_rate_mag(struct device *dev, | ||||||
|  | 					 struct device_attribute *attr, | ||||||
|  | 					 const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	unsigned long val = 0; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	if (kstrtoul(buf, 10, &val)) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	if (!val) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	/* set ODR */ | ||||||
|  | 	val = lsm303agr_mag_set_odr(cdata, val); | ||||||
|  | 	if (val < 0) { | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* write to platform data */ | ||||||
|  | 	cdata->sensors[LSM303AGR_MAG_SENSOR].poll_interval = val; | ||||||
|  |  | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* SYSFS: set val to enable_device ATTR */ | ||||||
|  | static ssize_t attr_get_enable_mag(struct device *dev, | ||||||
|  | 				   struct device_attribute *attr, | ||||||
|  | 				   char *buf) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  | 	int val = atomic_read(&cdata->enabled); | ||||||
|  |  | ||||||
|  | 	return sprintf(buf, "%d\n", val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* SYSFS: get val from enable_device ATTR */ | ||||||
|  | static ssize_t attr_set_enable_mag(struct device *dev, | ||||||
|  | 				   struct device_attribute *attr, | ||||||
|  | 				   const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	unsigned long val; | ||||||
|  | 	struct lsm303agr_common_data *cdata = dev_get_drvdata(dev); | ||||||
|  |  | ||||||
|  | 	if (kstrtoul(buf, 10, &val)) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	if (val) | ||||||
|  | 		lsm303agr_mag_enable(cdata); | ||||||
|  | 	else | ||||||
|  | 		lsm303agr_mag_disable(cdata); | ||||||
|  |  | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static struct device_attribute lsm303agr_mag_attributes[] = { | ||||||
|  | 	__ATTR(pollrate_ms, 0664, attr_get_polling_rate_mag, | ||||||
|  | 	       attr_set_polling_rate_mag), | ||||||
|  | 	__ATTR(enable_device, 0664, attr_get_enable_mag, attr_set_enable_mag), | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int create_sysfs_interfaces(struct device *dev) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < ARRAY_SIZE(lsm303agr_mag_attributes); i++) | ||||||
|  | 		if (device_create_file(dev, lsm303agr_mag_attributes + i)) | ||||||
|  | 			goto error; | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | error: | ||||||
|  | 	for (; i >= 0; i--) | ||||||
|  | 		device_remove_file(dev, lsm303agr_mag_attributes + i); | ||||||
|  |  | ||||||
|  | 	dev_err(dev, "%s:Unable to create interface\n", __func__); | ||||||
|  |  | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int remove_sysfs_interfaces(struct device *dev) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < ARRAY_SIZE(lsm303agr_mag_attributes); i++) | ||||||
|  | 		device_remove_file(dev, lsm303agr_mag_attributes + i); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lsm303agr_mag_probe(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	struct lsm303agr_sensor_data *sdata; | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	/* init sensor data structure */ | ||||||
|  | 	sdata = &cdata->sensors[LSM303AGR_MAG_SENSOR]; | ||||||
|  | 	sdata->cdata = cdata; | ||||||
|  |  | ||||||
|  | 	/* Check WHO_AM_I */ | ||||||
|  | 	err = lsm303agr_mag_check_wai(cdata); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "check WAI failed\n"); | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Set device ODR to 100ms (10Hz) */ | ||||||
|  | 	err = lsm303agr_mag_set_odr(cdata, 100); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "Set ODR On failed\n"); | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Disable Magnetometer to save power */ | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  | 	err = lsm303agr_mag_disable(cdata); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "Power On failed\n"); | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mutex_lock(&cdata->lock); | ||||||
|  | 	/* Init the input framework */ | ||||||
|  | 	err = lsm303agr_mag_input_init(sdata, LSM303AGR_MAG_DEV_NAME); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, "input init failed\n"); | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  | 	INIT_DELAYED_WORK(&sdata->input_work, lsm303agr_mag_input_work_func); | ||||||
|  |  | ||||||
|  | 	/* Create SYSFS interface */ | ||||||
|  | 	err = create_sysfs_interfaces(cdata->dev); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		dev_err(cdata->dev, | ||||||
|  | 		   "device LSM303AGR_MAG_DEV_NAME sysfs register failed\n"); | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	dev_info(cdata->dev, "%s: probed\n", LSM303AGR_MAG_DEV_NAME); | ||||||
|  | 	mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(lsm303agr_mag_probe); | ||||||
|  |  | ||||||
|  | void lsm303agr_mag_remove(struct lsm303agr_common_data *cdata) | ||||||
|  | { | ||||||
|  | 	lsm303agr_mag_disable(cdata); | ||||||
|  | 	lsm303agr_mag_input_cleanup(cdata); | ||||||
|  | 	remove_sysfs_interfaces(cdata->dev); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(lsm303agr_mag_remove); | ||||||
|  |  | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
| @@ -0,0 +1,210 @@ | |||||||
|  | /* | ||||||
|  |  * STMicroelectronics lsm303agr_mag_i2c.c driver | ||||||
|  |  * | ||||||
|  |  * Copyright 2016 STMicroelectronics Inc. | ||||||
|  |  * | ||||||
|  |  * Giuseppe Barba <giuseppe.barba@st.com> | ||||||
|  |  * | ||||||
|  |  * Licensed under the GPL-2. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <linux/err.h> | ||||||
|  | #include <linux/errno.h> | ||||||
|  | #include <linux/slab.h> | ||||||
|  | #include <linux/delay.h> | ||||||
|  | #include <linux/i2c.h> | ||||||
|  | #include <linux/input.h> | ||||||
|  | #include <linux/uaccess.h> | ||||||
|  | #include <linux/workqueue.h> | ||||||
|  | #include <linux/irq.h> | ||||||
|  | #include <linux/interrupt.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/device.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/moduleparam.h> | ||||||
|  | #include <linux/version.h> | ||||||
|  |  | ||||||
|  | #include "lsm303agr_core.h" | ||||||
|  |  | ||||||
|  | #define I2C_AUTO_INCREMENT	0x80 | ||||||
|  |  | ||||||
|  | /* XXX: caller must hold cdata->lock */ | ||||||
|  | static int lsm303agr_mag_i2c_read(struct device *dev, u8 reg_addr, int len, | ||||||
|  | 				  u8 *data) | ||||||
|  | { | ||||||
|  | 	struct i2c_msg msg[2]; | ||||||
|  | 	struct i2c_client *client = to_i2c_client(dev); | ||||||
|  |  | ||||||
|  | 	if (len > 1) | ||||||
|  | 		reg_addr |= I2C_AUTO_INCREMENT; | ||||||
|  |  | ||||||
|  | 	msg[0].addr = client->addr; | ||||||
|  | 	msg[0].flags = client->flags; | ||||||
|  | 	msg[0].len = 1; | ||||||
|  | 	msg[0].buf = ®_addr; | ||||||
|  |  | ||||||
|  | 	msg[1].addr = client->addr; | ||||||
|  | 	msg[1].flags = client->flags | I2C_M_RD; | ||||||
|  | 	msg[1].len = len; | ||||||
|  | 	msg[1].buf = data; | ||||||
|  |  | ||||||
|  | 	return i2c_transfer(client->adapter, msg, 2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* XXX: caller must hold cdata->lock */ | ||||||
|  | static int lsm303agr_mag_i2c_write(struct device *dev, u8 reg_addr, int len, | ||||||
|  | 				   u8 *data) | ||||||
|  | { | ||||||
|  | 	u8 send[len + 1]; | ||||||
|  | 	struct i2c_msg msg; | ||||||
|  | 	struct i2c_client *client = to_i2c_client(dev); | ||||||
|  |  | ||||||
|  | 	if (len > 1) | ||||||
|  | 		reg_addr |= I2C_AUTO_INCREMENT; | ||||||
|  |  | ||||||
|  | 	send[0] = reg_addr; | ||||||
|  | 	memcpy(&send[1], data, len * sizeof(u8)); | ||||||
|  | 	len++; | ||||||
|  |  | ||||||
|  | 	msg.addr = client->addr; | ||||||
|  | 	msg.flags = client->flags; | ||||||
|  | 	msg.len = len; | ||||||
|  | 	msg.buf = send; | ||||||
|  |  | ||||||
|  | 	return i2c_transfer(client->adapter, &msg, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* I2C IO routines */ | ||||||
|  | static const struct lsm303agr_transfer_function lsm303agr_mag_i2c_tf = { | ||||||
|  | 	.write = lsm303agr_mag_i2c_write, | ||||||
|  | 	.read = lsm303agr_mag_i2c_read, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_PM_SLEEP | ||||||
|  | static int lsm303agr_mag_resume(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct i2c_client *client = to_i2c_client(dev); | ||||||
|  | 	struct lsm303agr_common_data *cdata = i2c_get_clientdata(client); | ||||||
|  |  | ||||||
|  | 	if (cdata->on_before_suspend) | ||||||
|  | 		return lsm303agr_mag_enable(cdata); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int lsm303agr_mag_suspend(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct i2c_client *client = to_i2c_client(dev); | ||||||
|  | 	struct lsm303agr_common_data *cdata = i2c_get_clientdata(client); | ||||||
|  |  | ||||||
|  | 	cdata->on_before_suspend = atomic_read(&cdata->enabled); | ||||||
|  | 	return lsm303agr_mag_disable(cdata); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static SIMPLE_DEV_PM_OPS(lsm303agr_mag_pm_ops, | ||||||
|  | 				lsm303agr_mag_suspend, | ||||||
|  | 				lsm303agr_mag_resume); | ||||||
|  |  | ||||||
|  | #define LSM303AGR_MAG_PM_OPS	(&lsm303agr_mag_pm_ops) | ||||||
|  | #else /* CONFIG_PM_SLEEP */ | ||||||
|  | #define LSM303AGR_MAG_PM_OPS	NULL | ||||||
|  | #endif /* CONFIG_PM_SLEEP */ | ||||||
|  |  | ||||||
|  | static int lsm303agr_mag_i2c_probe(struct i2c_client *client, | ||||||
|  | 				   const struct i2c_device_id *id) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	struct lsm303agr_common_data *cdata; | ||||||
|  |  | ||||||
|  | 	dev_info(&client->dev, "probe start.\n"); | ||||||
|  |  | ||||||
|  | 	/* Alloc Common data structure */ | ||||||
|  | 	cdata = kzalloc(sizeof(struct lsm303agr_common_data), GFP_KERNEL); | ||||||
|  | 	if (cdata == NULL) { | ||||||
|  | 		dev_err(&client->dev, | ||||||
|  | 			"failed to allocate memory for module data\n"); | ||||||
|  | 		mutex_unlock(&cdata->lock); | ||||||
|  |  | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cdata->sensor_num = LSM303AGR_MAX_SENSORS_NUM; | ||||||
|  | 	cdata->dev = &client->dev; | ||||||
|  | 	cdata->name = client->name; | ||||||
|  | 	cdata->bus_type = BUS_I2C; | ||||||
|  | 	cdata->tf = &lsm303agr_mag_i2c_tf; | ||||||
|  |  | ||||||
|  | 	i2c_set_clientdata(client, cdata); | ||||||
|  |  | ||||||
|  | 	mutex_init(&cdata->lock); | ||||||
|  |  | ||||||
|  | 	err = lsm303agr_mag_probe(cdata); | ||||||
|  | 	if (err < 0) { | ||||||
|  | 		kfree(cdata); | ||||||
|  |  | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE | ||||||
|  | static void lsm303agr_mag_i2c_remove(struct i2c_client *client) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_common_data *cdata = i2c_get_clientdata(client); | ||||||
|  |  | ||||||
|  | 	dev_info(cdata->dev, "driver removing\n"); | ||||||
|  |  | ||||||
|  | 	lsm303agr_mag_remove(cdata); | ||||||
|  | 	kfree(cdata); | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | static int lsm303agr_mag_i2c_remove(struct i2c_client *client) | ||||||
|  | { | ||||||
|  | 	struct lsm303agr_common_data *cdata = i2c_get_clientdata(client); | ||||||
|  |  | ||||||
|  | 	dev_info(cdata->dev, "driver removing\n"); | ||||||
|  |  | ||||||
|  | 	lsm303agr_mag_remove(cdata); | ||||||
|  | 	kfree(cdata); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static const struct i2c_device_id lsm303agr_mag_i2c_id[] = { | ||||||
|  | 	{ "lsm303agr_mag", 0 }, | ||||||
|  | 	{ }, | ||||||
|  | }; | ||||||
|  | MODULE_DEVICE_TABLE(i2c, lsm303agr_mag_i2c_id); | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_OF | ||||||
|  | static const struct of_device_id lsm303agr_mag_i2c_id_table[] = { | ||||||
|  | 	{.compatible = "st,lsm303agr_mag", }, | ||||||
|  | 	{ }, | ||||||
|  | }; | ||||||
|  | MODULE_DEVICE_TABLE(of, lsm303agr_mag_i2c_id_table); | ||||||
|  | #endif /* CONFIG_OF */ | ||||||
|  |  | ||||||
|  | static struct i2c_driver lsm303agr_mag_i2c_driver = { | ||||||
|  | 	.driver = { | ||||||
|  | 		.owner = THIS_MODULE, | ||||||
|  | 		.name = "lsm303agr_mag", | ||||||
|  | 		.pm = LSM303AGR_MAG_PM_OPS, | ||||||
|  | #ifdef CONFIG_OF | ||||||
|  | 		.of_match_table = lsm303agr_mag_i2c_id_table, | ||||||
|  | #endif /* CONFIG_OF */ | ||||||
|  | 	}, | ||||||
|  | 	.probe = lsm303agr_mag_i2c_probe, | ||||||
|  | 	.remove = lsm303agr_mag_i2c_remove, | ||||||
|  | 	.id_table = lsm303agr_mag_i2c_id, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module_i2c_driver(lsm303agr_mag_i2c_driver); | ||||||
|  |  | ||||||
|  | MODULE_DESCRIPTION("lsm303agr magnetometer i2c driver"); | ||||||
|  | MODULE_AUTHOR("Armando Visconti"); | ||||||
|  | MODULE_AUTHOR("Matteo Dameno"); | ||||||
|  | MODULE_AUTHOR("Denis Ciocca"); | ||||||
|  | MODULE_AUTHOR("STMicroelectronics"); | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
|  |  | ||||||
							
								
								
									
										228
									
								
								feeds/qca-wifi-7/ipq53xx/files-6.1/drivers/net/phy/rtl8221d.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								feeds/qca-wifi-7/ipq53xx/files-6.1/drivers/net/phy/rtl8221d.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0 | ||||||
|  | /* | ||||||
|  |  * Driver for Rtl PHY | ||||||
|  |  * | ||||||
|  |  * Author: Huang Yunxiang <huangyunxiang@cigtech.com> | ||||||
|  |  * | ||||||
|  |  * Copyright 2024 cig, Inc. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/delay.h> | ||||||
|  | #include <linux/bitfield.h> | ||||||
|  | #include <linux/phy.h> | ||||||
|  |  | ||||||
|  | #define PHY_ID_RTL8221D	0x001CC841 | ||||||
|  | #define BIT_0       0x0001 | ||||||
|  | #define BIT_1       0x0002 | ||||||
|  | #define BIT_2       0x0004 | ||||||
|  | #define BIT_3       0x0008 | ||||||
|  | #define BIT_4       0x0010 | ||||||
|  | #define BIT_5       0x0020 | ||||||
|  | #define BIT_6       0x0040 | ||||||
|  | #define BIT_7       0x0080 | ||||||
|  | #define BIT_8       0x0100 | ||||||
|  | #define BIT_9       0x0200 | ||||||
|  | #define BIT_10      0x0400 | ||||||
|  | #define BIT_11      0x0800 | ||||||
|  | #define BIT_12      0x1000 | ||||||
|  | #define BIT_13      0x2000 | ||||||
|  | #define BIT_14      0x4000 | ||||||
|  | #define BIT_15      0x8000 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static int rtl8221d_config_aneg(struct phy_device *phydev) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static u32 Rtl8226b_is_link(struct phy_device *phydev) | ||||||
|  | { | ||||||
|  |     int phydata = 0; | ||||||
|  |  | ||||||
|  |     int i = 0; | ||||||
|  |  | ||||||
|  |     // must read twice | ||||||
|  |     for(i=0;i<2;i++) | ||||||
|  |     { | ||||||
|  |         phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA402);     | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     phydev->link = (phydata & BIT_2) ? (1) : (0); | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int rtl8221d_read_status(struct phy_device *phydev) | ||||||
|  | { | ||||||
|  | 	int phydata, speed_grp, speed; | ||||||
|  | 	 | ||||||
|  | 	Rtl8226b_is_link(phydev); | ||||||
|  | 	if (phydev->link) | ||||||
|  |    	{ | ||||||
|  | 		phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434); | ||||||
|  | 		speed_grp = (phydata & (BIT_9 | BIT_10)) >> 9; | ||||||
|  | 	        speed = (phydata & (BIT_4 | BIT_5)) >> 4; | ||||||
|  | 		switch(speed_grp) | ||||||
|  | 		{ | ||||||
|  | 			case 0: | ||||||
|  | 			{ | ||||||
|  | 				switch(speed) | ||||||
|  | 				{ | ||||||
|  | 				case 1: | ||||||
|  | 					phydev->speed = SPEED_100; | ||||||
|  | 					break; | ||||||
|  | 				case 2: | ||||||
|  | 					phydev->speed = SPEED_1000; | ||||||
|  | 					break; | ||||||
|  | 				default: | ||||||
|  | 					phydev->speed = SPEED_10; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 			case 1: | ||||||
|  | 			{ | ||||||
|  | 				switch(speed) | ||||||
|  | 				{ | ||||||
|  | 				case 1: | ||||||
|  | 					phydev->speed = SPEED_2500; | ||||||
|  | 					break; | ||||||
|  | 				case 3: | ||||||
|  | 					phydev->speed = SPEED_1000;        // 2.5G lite | ||||||
|  | 					break; | ||||||
|  | 				default: | ||||||
|  | 					phydev->speed = SPEED_10; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 			default: | ||||||
|  | 				phydev->speed = SPEED_10; | ||||||
|  | 				break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  | 		phydev->speed = SPEED_10; | ||||||
|  |     } | ||||||
|  | 	 | ||||||
|  | 	phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434); | ||||||
|  | 	phydev->duplex = (phydata & BIT_3) ? (DUPLEX_FULL) : (DUPLEX_HALF); | ||||||
|  | 	 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int rtl8221d_config_init(struct phy_device *phydev) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 	int phydata; | ||||||
|  | 	u16 timeoutms = 100; | ||||||
|  |  | ||||||
|  | 	err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 	err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7589, 0x71d0); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 	err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7587, 0x3); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 	while(--timeoutms) | ||||||
|  | 	{ | ||||||
|  | 		phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x7587); | ||||||
|  | 		if((phydata & 0x01) == 0) | ||||||
|  | 			break; | ||||||
|  | 		mdelay(10); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x75F3); | ||||||
|  |         phydata &= ~BIT_0; | ||||||
|  |         err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75F3, phydata); | ||||||
|  |         if (err < 0) | ||||||
|  |                 return err; | ||||||
|  | 	phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x697A); | ||||||
|  | 	phydata &= (~(BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_4 | BIT_5)); | ||||||
|  | 	phydata |= 2; | ||||||
|  | 	phydata |=0x8000; | ||||||
|  |         err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x697A, phydata); | ||||||
|  |         if (err < 0) | ||||||
|  |                 return err; | ||||||
|  |  | ||||||
|  | 	phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x697A); | ||||||
|  |  | ||||||
|  | 	Rtl8226b_is_link(phydev); | ||||||
|  | 	if (phydev->link) | ||||||
|  | 	{ | ||||||
|  | 		phydata = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0x0); | ||||||
|  | 		phydata |= BIT_15; | ||||||
|  | 		err = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x0, phydata); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  |  | ||||||
|  | 		while(--timeoutms) | ||||||
|  | 		{ | ||||||
|  | 			phydata = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0x0); | ||||||
|  | 			if (!(phydata & BIT_15)) | ||||||
|  |            			 break; | ||||||
|  | 			mdelay(10); | ||||||
|  | 		} | ||||||
|  | 		err = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x0, phydata); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa400); | ||||||
|  | 		phydata |= BIT_14; | ||||||
|  | 		err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa400, phydata); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  | 		while(--timeoutms) | ||||||
|  |                 { | ||||||
|  |                         phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434); | ||||||
|  |                         if (phydata & BIT_2) | ||||||
|  |                                  break; | ||||||
|  |                         mdelay(10); | ||||||
|  |                 } | ||||||
|  | 		phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa400); | ||||||
|  | 		phydata &= ~BIT_14; | ||||||
|  |                 err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa400, phydata); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int rtl8221d_probe(struct phy_device *phydev) | ||||||
|  | { | ||||||
|  | 	printk("rtl8221d probe"); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static struct phy_driver aqr_driver[] = { | ||||||
|  | { | ||||||
|  | 	PHY_ID_MATCH_MODEL(PHY_ID_RTL8221D), | ||||||
|  | 	.name		= "Rtl 8221D", | ||||||
|  | 	.features	= PHY_GBIT_FEATURES, | ||||||
|  | 	.probe		= rtl8221d_probe, | ||||||
|  | 	.config_init	= rtl8221d_config_init, | ||||||
|  | 	.config_aneg    = rtl8221d_config_aneg, | ||||||
|  | 	.read_status	= rtl8221d_read_status, | ||||||
|  | }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module_phy_driver(aqr_driver); | ||||||
|  |  | ||||||
|  | static struct mdio_device_id __maybe_unused rtl_tbl[] = { | ||||||
|  | 	{ PHY_ID_MATCH_MODEL(PHY_ID_RTL8221D) }, | ||||||
|  | 	{ } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | MODULE_DEVICE_TABLE(mdio, rtl_tbl); | ||||||
|  |  | ||||||
|  | MODULE_DESCRIPTION("rtl8221d PHY driver"); | ||||||
|  | MODULE_AUTHOR("haungyunxiang huangyunxiang@cigtech.com>"); | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
| @@ -79,6 +79,20 @@ define Device/sonicfi_rap750e_h | |||||||
| endef | endef | ||||||
| TARGET_DEVICES += sonicfi_rap750e_h | TARGET_DEVICES += sonicfi_rap750e_h | ||||||
|  |  | ||||||
|  | define Device/sonicfi_rap750e_s | ||||||
|  |   DEVICE_TITLE := SONICFI RAP750E-S | ||||||
|  |   DEVICE_DTS := ipq5332-sonicfi-rap750e-s | ||||||
|  |   DEVICE_DTS_DIR := ../dts | ||||||
|  |   DEVICE_DTS_CONFIG := config@mi01.3-c2 | ||||||
|  |   SUPPORTED_DEVICES := sonicfi,rap750e-s | ||||||
|  |   IMAGES := sysupgrade.tar nand-factory.bin nand-factory.ubi | ||||||
|  |   IMAGE/sysupgrade.tar := sysupgrade-tar | append-metadata | ||||||
|  |   IMAGE/nand-factory.bin := append-ubi | qsdk-ipq-factory-nand | ||||||
|  |   IMAGE/nand-factory.ubi := append-ubi | ||||||
|  |   DEVICE_PACKAGES := ath12k-wifi-sonicfi-rap750e-s ath12k-firmware-ipq5332-peb -ath12k-firmware-qcn92xx | ||||||
|  | endef | ||||||
|  | TARGET_DEVICES += sonicfi_rap750e_s | ||||||
|  |  | ||||||
| define Device/sonicfi_rap750w_311a | define Device/sonicfi_rap750w_311a | ||||||
|   DEVICE_TITLE := SONICFI RAP750W-311A |   DEVICE_TITLE := SONICFI RAP750W-311A | ||||||
|   DEVICE_DTS := ipq5332-sonicfi-rap750w-311a |   DEVICE_DTS := ipq5332-sonicfi-rap750w-311a | ||||||
| @@ -134,3 +148,15 @@ define Device/zyxel_nwa130be | |||||||
|   DEVICE_PACKAGES := ath12k-wifi-zyxel-nwa130be ath12k-firmware-qcn92xx ath12k-firmware-ipq5332 |   DEVICE_PACKAGES := ath12k-wifi-zyxel-nwa130be ath12k-firmware-qcn92xx ath12k-firmware-ipq5332 | ||||||
| endef | endef | ||||||
| TARGET_DEVICES += zyxel_nwa130be | TARGET_DEVICES += zyxel_nwa130be | ||||||
|  |  | ||||||
|  | define Device/cig_wf672 | ||||||
|  |   DEVICE_TITLE := CIG WF672 | ||||||
|  |   DEVICE_DTS := ipq5332-cig-wf672 | ||||||
|  |   DEVICE_DTS_DIR := ../dts | ||||||
|  |   DEVICE_DTS_CONFIG := config@mi01.6 | ||||||
|  |   IMAGES := sysupgrade.tar mmc-factory.bin | ||||||
|  |   IMAGE/mmc-factory.bin := append-ubi | qsdk-ipq-factory-mmc | ||||||
|  |   IMAGE/sysupgrade.tar := sysupgrade-tar | append-metadata | ||||||
|  |   DEVICE_PACKAGES := ath12k-wifi-cig-wf672 ath12k-firmware-ipq5332 ath12k-firmware-qcn92xx | ||||||
|  | endef | ||||||
|  | TARGET_DEVICES += cig_wf672 | ||||||
|   | |||||||
| @@ -0,0 +1,63 @@ | |||||||
|  | --- a/drivers/input/misc/Kconfig	2025-04-22 14:35:28.228629072 +0800 | ||||||
|  | +++ b/drivers/input/misc/Kconfig	2025-04-22 14:42:29.630935581 +0800 | ||||||
|  | @@ -929,4 +929,5 @@ | ||||||
|  |  	  To compile this driver as a module, choose M here: the | ||||||
|  |  	  module will be called stpmic1_onkey. | ||||||
|  |  | ||||||
|  | +source "drivers/input/misc/lsm303agr/Kconfig" | ||||||
|  |  endif | ||||||
|  | --- a/drivers/input/misc/Makefile	2025-04-22 14:35:28.228629072 +0800 | ||||||
|  | +++ b/drivers/input/misc/Makefile	2025-04-22 14:41:23.840267623 +0800 | ||||||
|  | @@ -89,3 +89,4 @@ | ||||||
|  |  obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)	+= xen-kbdfront.o | ||||||
|  |  obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o | ||||||
|  |  obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR)	+= ideapad_slidebar.o | ||||||
|  | +obj-$(CONFIG_INPUT_LSM303AGR)		+= lsm303agr/ | ||||||
|  | --- a/drivers/net/phy/Kconfig	2025-04-22 14:48:04.858191804 +0800 | ||||||
|  | +++ b/drivers/net/phy/Kconfig	2025-04-22 10:17:06.822705335 +0800 | ||||||
|  | @@ -99,6 +99,9 @@ | ||||||
|  |  	tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch" | ||||||
|  |  	select SWCONFIG | ||||||
|  |   | ||||||
|  | +config RTL8221D_PHY | ||||||
|  | +	tristate "Driver for Realtek RTL8221D phy" | ||||||
|  | + | ||||||
|  |  config RTL8306_PHY | ||||||
|  |  	tristate "Driver for Realtek RTL8306S switches" | ||||||
|  |  	select SWCONFIG | ||||||
|  | --- a/drivers/net/phy/Makefile	2025-04-22 14:48:18.254372527 +0800 | ||||||
|  | +++ b/drivers/net/phy/Makefile	2025-04-22 10:17:10.546732447 +0800 | ||||||
|  | @@ -32,6 +32,7 @@ | ||||||
|  |  obj-$(CONFIG_SWCONFIG_B53)	+= b53/ | ||||||
|  |  obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o | ||||||
|  |  obj-$(CONFIG_PSB6970_PHY)	+= psb6970.o | ||||||
|  | +obj-$(CONFIG_RTL8221D_PHY)	+= rtl8221d.o | ||||||
|  |  obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o | ||||||
|  |  obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi.o | ||||||
|  |  obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o | ||||||
|  | --- a/drivers/iio/pressure/Kconfig  2025-05-13 15:16:05.019840003 +0800 | ||||||
|  | +++ b/drivers/iio/pressure/Kconfig  2025-05-13 15:17:45.032040654 +0800 | ||||||
|  | @@ -266,4 +266,11 @@ | ||||||
|  |  	tristate | ||||||
|  |  	select REGMAP_SPI | ||||||
|  |   | ||||||
|  | +config ILPS22QS | ||||||
|  | +	tristate "ILPS22QS pressure support" | ||||||
|  | +	help | ||||||
|  | +	  Say Y to enable support ILPS22QS | ||||||
|  | + | ||||||
|  | +	  To compile this driver as a module, choose M here: the | ||||||
|  | +	  module will be called ILPS22QS. | ||||||
|  |  endmenu | ||||||
|  |  | ||||||
|  | --- a/drivers/iio/pressure/Makefile  2025-05-13 15:17:58.049195788 +0800 | ||||||
|  | +++ b/drivers/iio/pressure/Makefile  2025-05-13 15:19:07.205016058 +0800 | ||||||
|  | @@ -31,6 +31,8 @@ | ||||||
|  |  obj-$(CONFIG_ZPA2326) += zpa2326.o | ||||||
|  |  obj-$(CONFIG_ZPA2326_I2C) += zpa2326_i2c.o | ||||||
|  |  obj-$(CONFIG_ZPA2326_SPI) += zpa2326_spi.o | ||||||
|  | +obj-$(CONFIG_ILPS22QS) += st_ilps22qs.o | ||||||
|  | +st_ilps22qs-objs := st_ilps22qs_i2c.o st_ilps22qs_core.o | ||||||
|  |   | ||||||
|  |  obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o | ||||||
|  |  obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o | ||||||
| @@ -702,3 +702,44 @@ define KernelPackage/llcc_perfmon/description | |||||||
| endef | endef | ||||||
|  |  | ||||||
| $(eval $(call KernelPackage,llcc_perfmon)) | $(eval $(call KernelPackage,llcc_perfmon)) | ||||||
|  |  | ||||||
|  | define KernelPackage/input-lsm303agr | ||||||
|  |   SUBMENU:=$(OTHER_MENU) | ||||||
|  |   TITLE:=LSM303AGR Driver | ||||||
|  |   DEPENDS+=@TARGET_ipq53xx | ||||||
|  |   KCONFIG:=CONFIG_INPUT_LSM303AGR=y | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | define KernelPackage/input-lsm303agr/description | ||||||
|  |   lsm303agr driver support | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | $(eval $(call KernelPackage,input-lsm303agr)) | ||||||
|  |  | ||||||
|  | define KernelPackage/rtl8221d-phy | ||||||
|  |   SUBMENU:=$(OTHER_MENU) | ||||||
|  |   TITLE:=RTL8221d PHY Driver | ||||||
|  |   DEPENDS+=@TARGET_ipq53xx | ||||||
|  |   KCONFIG:=CONFIG_RTL8221D_PHY=y | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | define KernelPackage/rtl8221d-phy/description | ||||||
|  |   RTL8221d PHY driver support | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | $(eval $(call KernelPackage,rtl8221d-phy)) | ||||||
|  |  | ||||||
|  | define KernelPackage/iio-ilps22qs | ||||||
|  |   SUBMENU:=$(IIO_MENU) | ||||||
|  |   TITLE:= pressure sensors ilps22qs Driver | ||||||
|  |   DEPENDS+=@TARGET_ipq53xx +kmod-iio-core +kmod-industrialio-triggered-buffer | ||||||
|  |   KCONFIG:=CONFIG_ILPS22QS | ||||||
|  |   FILES:=$(LINUX_DIR)/drivers/iio/pressure/st_ilps22qs.ko | ||||||
|  |   AUTOLOAD:=$(call AutoLoad,80,st_ilps22qs) | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | define KernelPackage/iio-ilps22qs/description | ||||||
|  |   pressure sensors ilps22qs driver support | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | $(eval $(call KernelPackage,iio-ilps22qs)) | ||||||
|   | |||||||
| @@ -25,6 +25,10 @@ cig,wf660a) | |||||||
| 	mmc_dev=$(echo $(find_mmc_part "0:ETHPHYFW") | sed 's/^.\{5\}//') | 	mmc_dev=$(echo $(find_mmc_part "0:ETHPHYFW") | sed 's/^.\{5\}//') | ||||||
| 	[ -n "$mmc_dev" ] && mount -t ext4 /dev/$mmc_dev /certificates | 	[ -n "$mmc_dev" ] && mount -t ext4 /dev/$mmc_dev /certificates | ||||||
| 	;; | 	;; | ||||||
|  | cig,wf672) | ||||||
|  | 	mmc_dev=$(echo $(find_mmc_part "cert") | sed 's/^.\{5\}//') | ||||||
|  | 	[ -n "$mmc_dev" ] && mount -t ext4 /dev/$mmc_dev /certificates | ||||||
|  | 	;; | ||||||
| sonicfi,rap7110c-341x) | sonicfi,rap7110c-341x) | ||||||
| 	mmc_dev=$(echo $(find_mmc_part "certificates") | sed 's/^.\{5\}//') | 	mmc_dev=$(echo $(find_mmc_part "certificates") | sed 's/^.\{5\}//') | ||||||
| 	[ -n "$mmc_dev" ] && mount -t squashfs /dev/$mmc_dev /certificates | 	[ -n "$mmc_dev" ] && mount -t squashfs /dev/$mmc_dev /certificates | ||||||
| @@ -82,6 +86,8 @@ cig,wf189|\ | |||||||
| cig,wf189w|\ | cig,wf189w|\ | ||||||
| cig,wf189h|\ | cig,wf189h|\ | ||||||
| cig,wf186h|\ | cig,wf186h|\ | ||||||
|  | cig,wf196|\ | ||||||
|  | cig,wf188n|\ | ||||||
| yuncore,ax840|\ | yuncore,ax840|\ | ||||||
| yuncore,fap655) | yuncore,fap655) | ||||||
| 	PART_NAME=rootfs_1 | 	PART_NAME=rootfs_1 | ||||||
|   | |||||||
| @@ -4,10 +4,10 @@ PKG_NAME:=ucentral-schema | |||||||
| PKG_RELEASE:=1 | PKG_RELEASE:=1 | ||||||
|  |  | ||||||
| PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git | PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git | ||||||
| PKG_MIRROR_HASH:=cbb6508faa5e0b640e1990a806383f9f13fb5da75f38114f4f32e9c14b9845f1 | PKG_MIRROR_HASH:=ee5d5073bd9ae88590e419f94eb6c59f04a2fc0c3117be435bcb885e0ea28bf1 | ||||||
| PKG_SOURCE_PROTO:=git | PKG_SOURCE_PROTO:=git | ||||||
| PKG_SOURCE_DATE:=2025-01-27 | PKG_SOURCE_DATE:=2025-01-27 | ||||||
| PKG_SOURCE_VERSION:=9710867e1a2c775fa424fd7780ba6132eaa6fd9c | PKG_SOURCE_VERSION:=b4cfdc6a1caa279ae8c6c42b6932620fb2aed9c1 | ||||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||||
| PKG_LICENSE:=BSD-3-Clause | PKG_LICENSE:=BSD-3-Clause | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								profiles/cig_wf672.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								profiles/cig_wf672.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | --- | ||||||
|  | profile: cig_wf672 | ||||||
|  | target: ipq53xx | ||||||
|  | subtarget: generic | ||||||
|  | description: Build image for the CIG WF672 | ||||||
|  | image: bin/targets/ipq53xx/generic/openwrt-ipq53xx-cig_wf672-squashfs-sysupgrade.tar | ||||||
|  | feeds: | ||||||
|  |   - name: qca | ||||||
|  |     path: ../../feeds/qca-wifi-7 | ||||||
|  | include: | ||||||
|  |   - ucentral-ap | ||||||
|  | packages: | ||||||
|  |   - ipq53xx | ||||||
|  |   - ftm | ||||||
|  |   - qca-ssdk-shell | ||||||
|  |   - iperf3 | ||||||
|  |   - sysstat | ||||||
|  |   - kmod-cig-wifi-mode-sw | ||||||
|  |   - kmod-input-lsm303agr | ||||||
|  |   - kmod-rtl8221d-phy | ||||||
|  |   - kmod-gpio-pca953x | ||||||
|  |   - kmod-hwmon-tmp103 | ||||||
|  |   - kmod-iio-ilps22qs | ||||||
| @@ -44,6 +44,7 @@ packages: | |||||||
|   - morse-regdb |   - morse-regdb | ||||||
| include: | include: | ||||||
|   - ucentral-ap |   - ucentral-ap | ||||||
|  |   - hostapd | ||||||
| diffconfig: |   | diffconfig: |   | ||||||
|   # CONFIG_PACKAGE_kmod-nft-offload is not set |   # CONFIG_PACKAGE_kmod-nft-offload is not set | ||||||
|   # CONFIG_PACKAGE_procd-ujail is not set |   # CONFIG_PACKAGE_procd-ujail is not set | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								profiles/sonicfi_rap750e-s.yml
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										16
									
								
								profiles/sonicfi_rap750e-s.yml
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | --- | ||||||
|  | profile: sonicfi_rap750e_s | ||||||
|  | target: ipq53xx | ||||||
|  | subtarget: generic | ||||||
|  | description: Build image for the SONICFI RAP750E-S | ||||||
|  | image: bin/targets/ipq53xx/generic/openwrt-ipq53xx-sonicfi_rap750e_s-squashfs-sysupgrade.tar | ||||||
|  | feeds: | ||||||
|  |   - name: qca | ||||||
|  |     path: ../../feeds/qca-wifi-7 | ||||||
|  | include: | ||||||
|  |   - ucentral-ap | ||||||
|  | packages: | ||||||
|  |   - ipq53xx | ||||||
|  |   - qca-ssdk-shell | ||||||
|  | diffconfig: | | ||||||
|  |   CONFIG_KERNEL_IPQ_MEM_PROFILE=512 | ||||||
		Reference in New Issue
	
	Block a user
	 Mike Ding
					Mike Ding