mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-29 09:32:34 +00:00 
			
		
		
		
	Compare commits
	
		
			13 Commits
		
	
	
		
			staging-ea
			...
			WIFI-14644
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d4c44e5893 | ||
|   | 9e5d121cd9 | ||
|   | 0a4c10d6cc | ||
|   | edfd2883f5 | ||
|   | f6ac6f791e | ||
|   | 88fe15a985 | ||
|   | a9f47c9e1e | ||
|   | f17314a2d3 | ||
|   | 29739ebd13 | ||
|   | 3caba52dba | ||
|   | 44bcc50815 | ||
|   | 942d7c15b4 | ||
|   | 25be7aef1a | 
							
								
								
									
										2
									
								
								.github/workflows/build-dev.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/build-dev.yml
									
									
									
									
										vendored
									
									
								
							| @@ -21,7 +21,7 @@ jobs: | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       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' ] | ||||
|         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: | ||||
|     - uses: actions/checkout@v3 | ||||
|  | ||||
|   | ||||
| @@ -53,6 +53,11 @@ $(call Package/ath12k-wifi-default) | ||||
|     TITLE:=board-2.bin for RAP750e_h | ||||
| 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 | ||||
| $(call Package/ath12k-wifi-default) | ||||
|     TITLE:=board-2.bin for RAP750W_311a | ||||
| @@ -83,6 +88,11 @@ $(call Package/ath12k-wifi-default) | ||||
|     TITLE:=board-2.bin for NWA130BE | ||||
| 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 | ||||
| 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/QCN92XX/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 | ||||
| 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 | ||||
| 	$(INSTALL_DIR) $(1)/lib/firmware/ath12k/IPQ5332/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 | ||||
| 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-edgecore-eap105)) | ||||
| $(eval $(call BuildPackage,ath12k-wifi-sonicfi-rap7110c-341x)) | ||||
| $(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-cig-wf189w)) | ||||
| $(eval $(call BuildPackage,ath12k-wifi-cig-wf189h)) | ||||
| $(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip)) | ||||
| $(eval $(call BuildPackage,ath12k-wifi-sercomm-ap72tip-v4)) | ||||
| $(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 | ||||
| +++ b/hostapd/config_file.c | ||||
| @@ -3003,6 +3003,8 @@ static int hostapd_config_fill(struct ho | ||||
| @@ -9,12 +10,10 @@ | ||||
|  #endif /* CONFIG_IEEE80211R_AP */ | ||||
|  #ifndef CONFIG_NO_CTRL_IFACE | ||||
|  	} else if (os_strcmp(buf, "ctrl_interface") == 0) { | ||||
| @@ -4958,8 +4960,22 @@ int hostapd_set_iface(struct hostapd_con | ||||
|  		return -1; | ||||
|  	} | ||||
| @@ -4982,6 +4982,19 @@ struct hostapd_config * hostapd_config_r | ||||
|  	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) { | ||||
| +			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); | ||||
| @@ -25,14 +24,12 @@ | ||||
| +			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); | ||||
| +			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; | ||||
| +		} | ||||
|  		hostapd_set_security_params(conf->bss[i], 0); | ||||
| +	} | ||||
|   | ||||
|  	if (hostapd_config_check(conf, 0)) { | ||||
|  		wpa_printf(MSG_ERROR, "Configuration check failed"); | ||||
|  		hostapd_set_security_params(conf->bss[i], 1); | ||||
|  #ifdef CONFIG_IEEE80211BE | ||||
|  		if (conf->ieee80211be && conf->bss[i]->ieee80211w > 0 | ||||
| --- a/src/ap/ap_config.h | ||||
| +++ b/src/ap/ap_config.h | ||||
| @@ -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) | ||||
| { | ||||
| 	struct hostapd_sta_wpa_psk_short *psk = sta->psk; | ||||
| 	char addr[sizeof(MACSTR)]; | ||||
| 	uc_value_t *val, *cur; | ||||
| 	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); | ||||
| 	if (sta->psk_idx) | ||||
| 		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)); | ||||
|  | ||||
| 	val = wpa_ucode_call(3); | ||||
|   | ||||
| @@ -15,6 +15,7 @@ sercomm,ap72tip) | ||||
| 	;; | ||||
| sonicfi,rap7110c-341x|\ | ||||
| sonicfi,rap750e-h|\ | ||||
| sonicfi,rap750e-s|\ | ||||
| sonicfi,rap750w-311a) | ||||
| 	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" | ||||
| 		;; | ||||
| 	cig,wf189|\ | ||||
| 	cig,wf672|\ | ||||
| 	edgecore,eap105|\ | ||||
| 	sercomm,ap72tip|\ | ||||
| 	sonicfi,rap750w-311a) | ||||
| 		ucidef_set_interfaces_lan_wan "eth1" "eth0" | ||||
| 		;; | ||||
| 	sonicfi,rap7110c-341x|\ | ||||
| 	sonicfi,rap750e-h) | ||||
| 	sonicfi,rap750e-h|\) | ||||
| 	sonicfi,rap750e-s) | ||||
| 		ucidef_set_interfaces_lan_wan "" "eth0" | ||||
| 		;; | ||||
| 	cig,wf189w) | ||||
| @@ -43,21 +45,35 @@ qcom_setup_macs() | ||||
| { | ||||
|         local board="$1" | ||||
|         case $board in | ||||
| 	cig,wf189w|\ | ||||
| 	cig,wf189h|\ | ||||
|         cig,wf189w|\ | ||||
|         cig,wf189h|\ | ||||
|         cig,wf189) | ||||
| 		mtd=$(find_mtd_chardev "0:APPSBLENV") | ||||
| 		[ -z "$mtd" ] && return; | ||||
| 		mac=$(grep eth1addr= $mtd | cut -d= -f2) | ||||
|                 mtd=$(find_mtd_chardev "0:APPSBLENV") | ||||
|                 [ -z "$mtd" ] && return; | ||||
|                 mac=$(grep eth1addr= $mtd | 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) | ||||
|                 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) | ||||
|                 ;; | ||||
|         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) | ||||
|                 wan_mac=$(cat /sys/class/net/eth0/address) | ||||
| @@ -69,9 +85,13 @@ qcom_setup_macs() | ||||
|         edgecore,eap105) | ||||
|                 wan_mac=$(cat /sys/class/net/eth0/address) | ||||
|                 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,rap750e-h) | ||||
|         sonicfi,rap750e-h|\ | ||||
|         sonicfi,rap750e-s) | ||||
|                 wan_mac=$(cat /sys/class/net/eth0/address) | ||||
|                 ucidef_set_wireless_macaddr_base 2g $(macaddr_add "$wan_mac" 1) | ||||
|                 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" | ||||
| } | ||||
|  | ||||
| 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) | ||||
| case "$FIRMWARE" in | ||||
| ath12k/IPQ5332/hw1.0/caldata.bin) | ||||
| @@ -36,10 +69,14 @@ ath12k/IPQ5332/hw1.0/caldata.bin) | ||||
| 	zyxel,nwa130be) | ||||
| 		caldata_extract "0:ART" 0x1000 0x20000  | ||||
| 		;; | ||||
| 	cig,wf672) | ||||
| 		cig_ipq5322_cal | ||||
| 		;; | ||||
| 	sonicfi,rap7110c-341x) | ||||
| 		caldata_extract_mmc "0:ART" 0x1000 0xF800 | ||||
| 		;; | ||||
| 	sonicfi,rap750e-h|\ | ||||
| 	sonicfi,rap750e-s|\ | ||||
| 	sonicfi,rap750w-311a) | ||||
| 		caldata_extract "0:ART" 0x1000 0xf800 | ||||
| 		;; | ||||
| @@ -54,6 +91,9 @@ ath12k/QCN92XX/hw1.0/cal-pci-0001:01:00.0.bin) | ||||
| 	zyxel,nwa130be) | ||||
| 		caldata_extract "0:ART" 0x58800 0x2d000 | ||||
| 		;; | ||||
| 	cig,wf672) | ||||
| 		cig_qcn92xx_cal | ||||
| 		;; | ||||
| 	sonicfi,rap7110c-341x) | ||||
| 		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) | ||||
| 	case "$board" in | ||||
| 	sonicfi,rap750e-h|\ | ||||
| 	sonicfi,rap750e-s|\ | ||||
| 	sonicfi,rap750w-311a) | ||||
| 		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 | ||||
| } | ||||
|  | ||||
| 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() { | ||||
| 	local tar_file="$1" | ||||
| 	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') | ||||
| @@ -86,6 +132,8 @@ platform_do_upgrade() { | ||||
|  | ||||
| 	board=$(board_name) | ||||
| 	case $board in | ||||
| 	sercomm,ap72tip-v4|\ | ||||
| 	sercomm,ap72tip|\ | ||||
| 	cig,wf189w|\ | ||||
| 	cig,wf189h|\ | ||||
| 	cig,wf189) | ||||
| @@ -98,6 +146,9 @@ platform_do_upgrade() { | ||||
| 		fi | ||||
| 		nand_upgrade_tar "$1" | ||||
| 		;; | ||||
| 	cig,wf672) | ||||
| 		spi_nor_emmc_do_upgrade_bootconfig $1 | ||||
| 		;; | ||||
| 	edgecore,eap105) | ||||
| 		if [ "$(find_mtd_chardev rootfs)" ]; then | ||||
| 			CI_UBIPART="rootfs" | ||||
| @@ -117,14 +168,11 @@ platform_do_upgrade() { | ||||
| 		emmc_do_upgrade "$1" | ||||
| 		;; | ||||
| 	sonicfi,rap750e-h|\ | ||||
| 	sonicfi,rap750e-s|\ | ||||
| 	sonicfi,rap750w-311a) | ||||
| 		sonicfi_dualimage_check | ||||
| 		nand_upgrade_tar "$1" | ||||
| 		;; | ||||
| 	sercomm,ap72tip-v4|\ | ||||
| 	sercomm,ap72tip) | ||||
| 		nand_upgrade_tar "$1" | ||||
| 		;; | ||||
| 	zyxel,nwa130be) | ||||
| 		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"; | ||||
| }; | ||||
|  | ||||
| @@ -15,7 +15,7 @@ | ||||
| #include "ipq5332-default-memory.dtsi" | ||||
|  | ||||
| / { | ||||
| 	model = "Sercomm WiFi-7"; | ||||
| 	model = "Sercomm AP72TIP-v4"; | ||||
| 	compatible = "sercomm,ap72tip-v4", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332"; | ||||
|  | ||||
| 	aliases { | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
| #include "ipq5332-default-memory.dtsi" | ||||
|  | ||||
| / { | ||||
| 	model = "Sercomm WiFi-7"; | ||||
| 	model = "Sercomm AP72TIP"; | ||||
| 	compatible = "sercomm,ap72tip", "qcom,ipq5332-ap-mi01.6", "qcom,ipq5332"; | ||||
|  | ||||
| 	aliases { | ||||
| @@ -255,7 +255,7 @@ | ||||
| 					gpios = <&tca6416 14 GPIO_ACTIVE_HIGH>; | ||||
| 				}; | ||||
| 		}; | ||||
| /* | ||||
| 		 | ||||
| 		gpio_keys { | ||||
| 			compatible = "gpio-keys"; | ||||
| 			pinctrl-0 = <&button_pins>; | ||||
| @@ -263,11 +263,11 @@ | ||||
| 			button@1 { | ||||
| 				label = "rst"; | ||||
| 				linux,code = <KEY_RESTART>; | ||||
| 				gpios = <&tlmm 25 GPIO_ACTIVE_LOW>; | ||||
| 				gpios = <&tlmm 1 GPIO_ACTIVE_LOW>; | ||||
| 				linux,input-type = <1>; | ||||
| 				debounce-interval = <60>; | ||||
| 			}; | ||||
| 		};*/ | ||||
| 		}; | ||||
|  | ||||
| 		wsi: wsi { | ||||
| 			id = <0>; | ||||
| @@ -546,13 +546,13 @@ | ||||
| 		drive-strength = <8>; | ||||
| 		bias-pull-down; | ||||
| 	};*/ | ||||
| /* | ||||
| 	 | ||||
| 	button_pins: button-state { | ||||
| 		pins = "gpio25"; | ||||
| 		pins = "gpio1"; | ||||
| 		function = "gpio"; | ||||
| 		drive-strength = <8>; | ||||
| 		bias-pull-up; | ||||
| 	};*/ | ||||
| 	}; | ||||
|  | ||||
| 	pwm_pins: pwm-state { | ||||
| 		pins = "gpio46"; | ||||
|   | ||||
							
								
								
									
										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 | ||||
| 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 | ||||
|   DEVICE_TITLE := 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 | ||||
| endef | ||||
| 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 | ||||
|  | ||||
| $(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\}//') | ||||
| 	[ -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) | ||||
| 	mmc_dev=$(echo $(find_mmc_part "certificates") | sed 's/^.\{5\}//') | ||||
| 	[ -n "$mmc_dev" ] && mount -t squashfs /dev/$mmc_dev /certificates | ||||
| @@ -82,6 +86,8 @@ cig,wf189|\ | ||||
| cig,wf189w|\ | ||||
| cig,wf189h|\ | ||||
| cig,wf186h|\ | ||||
| cig,wf196|\ | ||||
| cig,wf188n|\ | ||||
| yuncore,ax840|\ | ||||
| yuncore,fap655) | ||||
| 	PART_NAME=rootfs_1 | ||||
|   | ||||
| @@ -4,10 +4,10 @@ PKG_NAME:=ucentral-schema | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| 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_DATE:=2025-01-27 | ||||
| PKG_SOURCE_VERSION:=9710867e1a2c775fa424fd7780ba6132eaa6fd9c | ||||
| PKG_SOURCE_VERSION:=b4cfdc6a1caa279ae8c6c42b6932620fb2aed9c1 | ||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||
| 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 | ||||
| include: | ||||
|   - ucentral-ap | ||||
|   - hostapd | ||||
| diffconfig: |   | ||||
|   # CONFIG_PACKAGE_kmod-nft-offload 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