diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..1905feee --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "recipes-kernel/kernel-modules/x8h7"] + path = recipes-kernel/kernel-modules/x8h7 + url = https://github.com/arduino/portentax8-x8h7 diff --git a/recipes-kernel/kernel-modules/x8h7 b/recipes-kernel/kernel-modules/x8h7 new file mode 160000 index 00000000..6192b26b --- /dev/null +++ b/recipes-kernel/kernel-modules/x8h7 @@ -0,0 +1 @@ +Subproject commit 6192b26b6177d6239a20556f222f2fb047dbcb78 diff --git a/recipes-kernel/kernel-modules/x8h7/COPYING b/recipes-kernel/kernel-modules/x8h7/COPYING deleted file mode 100644 index 6d45519c..00000000 --- a/recipes-kernel/kernel-modules/x8h7/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/recipes-kernel/kernel-modules/x8h7/Makefile b/recipes-kernel/kernel-modules/x8h7/Makefile deleted file mode 100644 index 887a847d..00000000 --- a/recipes-kernel/kernel-modules/x8h7/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -obj-m += x8h7_drv.o -obj-m += x8h7_adc.o -obj-m += x8h7_gpio.o -obj-m += x8h7_pwm.o -obj-m += x8h7_rtc.o -obj-m += x8h7_can.o -obj-m += x8h7_uart.o -obj-m += x8h7_ui.o -obj-m += x8h7_h7.o - -SRC := $(shell pwd) - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c - rm -f Module.markers Module.symvers modules.order - rm -rf .tmp_versions Modules.symvers diff --git a/recipes-kernel/kernel-modules/x8h7/README.md b/recipes-kernel/kernel-modules/x8h7/README.md deleted file mode 100644 index fdd99036..00000000 --- a/recipes-kernel/kernel-modules/x8h7/README.md +++ /dev/null @@ -1,29 +0,0 @@ -`kernel-modules/x8h7` -===================== -#### Build/Deploy/Install -```bash -bitbake x8h7 -adb push deploy/ipk/portenta_x8/x8h7_0.1-r1_portenta_x8.ipk /home/fio -``` -```bash -adb shell -cd /home/fio -sudo opkg install --force-reinstall --force-depends x8h7_0.1-r1_portenta_x8.ipk -``` -or -```bash -adb push ./tmp-lmp_xwayland/sysroots-components/portenta_x8/x8h7/usr/lib/modules/5.10.93-lmp-standard/extra/*.ko /home/fio -adb shell -sudo rmmod x8h7_can -sudo mount -o remount,rw /usr -sudo mv *.ko /lib/modules/5.10.93-lmp-standard/extra/ -sudo modprobe x8h7_can -``` -#### Unload/Reload -```bash -lsmod | grep x8h7_ -cd /usr/arduino/extra -sudo ./unload_modules.sh -sudo ./load_modules_pre.sh -sudo ./load_modules_post.sh -``` diff --git a/recipes-kernel/kernel-modules/x8h7/blacklist.conf b/recipes-kernel/kernel-modules/x8h7/blacklist.conf deleted file mode 100644 index d64ea950..00000000 --- a/recipes-kernel/kernel-modules/x8h7/blacklist.conf +++ /dev/null @@ -1,12 +0,0 @@ -# These modules need to be started -# after systemd service check the external -# microcontroller firmware -blacklist x8h7_adc -blacklist x8h7_can -blacklist x8h7_drv -blacklist x8h7_gpio -blacklist x8h7_h7 -blacklist x8h7_pwm -blacklist x8h7_rtc -blacklist x8h7_uart -blacklist x8h7_ui diff --git a/recipes-kernel/kernel-modules/x8h7/debug.h b/recipes-kernel/kernel-modules/x8h7/debug.h deleted file mode 100644 index 7aedc6ff..00000000 --- a/recipes-kernel/kernel-modules/x8h7/debug.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - */ -#ifndef __DEBUG_H -#define __DEBUG_H - -#ifdef DEBUG - #warning "Verbose debug messages will be activated for this module!" - #define DBG_PRINT(fmt, ...) { \ - char __ctx[7]; \ - __ctx[0] = in_irq() ? 'H': '-'; \ - __ctx[1] = in_softirq() ? 'S': '-'; \ - __ctx[2] = in_interrupt() ? 'I': '-'; \ - __ctx[3] = in_serving_softirq()? 'V': '-'; \ - __ctx[4] = in_nmi() ? 'N': '-'; \ - __ctx[5] = in_atomic() ? 'A': '-'; \ - __ctx[6] = 0; \ - printk("%s:%s:%s:"fmt, DRIVER_NAME, __ctx, __func__, ##__VA_ARGS__); \ - } - - #define DBG_ERROR(fmt, ...) { \ - char __ctx[7]; \ - __ctx[0] = in_irq() ? 'H': '-'; \ - __ctx[1] = in_softirq() ? 'S': '-'; \ - __ctx[2] = in_interrupt() ? 'I': '-'; \ - __ctx[3] = in_serving_softirq()? 'V': '-'; \ - __ctx[4] = in_nmi() ? 'N': '-'; \ - __ctx[5] = in_atomic() ? 'A': '-'; \ - __ctx[6] = 0; \ - printk("%s:%s:%s:ERROR:"fmt, DRIVER_NAME, __ctx, __func__, ##__VA_ARGS__); \ - } -#else - #define DBG_PRINT(fmt, ...) - #define DBG_ERROR(fmt, ...) -#endif - -#endif /* __DEBUG_H */ diff --git a/recipes-kernel/kernel-modules/x8h7/example.dts b/recipes-kernel/kernel-modules/x8h7/example.dts deleted file mode 100644 index aef7ff3d..00000000 --- a/recipes-kernel/kernel-modules/x8h7/example.dts +++ /dev/null @@ -1,22 +0,0 @@ - -&iomuxc { - pinctrl-names = "default"; - imx8mm { - x8h7_irq { - fsl,pins = < - MX8MM_IOMUXC_NAND_DATA02_GPIO3_IO8 0x41 - >; - }; - }; -}; - -&ecspi2 { - status = "okay"; - - x8h7: x8h7@0 { - compatible = "portenta,x8h7"; - irq = <8>; - spi_frequency = <1000000>; - status = "okay"; - }; -}; diff --git a/recipes-kernel/kernel-modules/x8h7/x8h7-priv.h b/recipes-kernel/kernel-modules/x8h7/x8h7-priv.h deleted file mode 100644 index 3efc57b4..00000000 --- a/recipes-kernel/kernel-modules/x8h7/x8h7-priv.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Portenta X8 - * X8 H7 communication protocol - */ - - -static struct spi_driver mcp251x_can_driver = { - .driver = { - .name = DEVICE_NAME, - .of_match_table = mcp251x_of_match, - .pm = &mcp251x_can_pm_ops, - }, - .id_table = mcp251x_id_table, - .probe = mcp251x_can_probe, - .remove = mcp251x_can_remove, -}; -module_spi_driver(mcp251x_can_driver); - -MODULE_AUTHOR("Chris Elston , " - "Christian Pellegrin "); -MODULE_DESCRIPTION("Microchip 251x/25625 CAN driver"); -MODULE_LICENSE("GPL v2"); diff --git a/recipes-kernel/kernel-modules/x8h7/x8h7.h b/recipes-kernel/kernel-modules/x8h7/x8h7.h deleted file mode 100644 index 25499399..00000000 --- a/recipes-kernel/kernel-modules/x8h7/x8h7.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Portenta X8H7 - */ -#ifndef __X8H7_H -#define __X8H7_H - -#define X8H7_RX_TIMEOUT (HZ/10) - -#define X8H7_PKT_SIZE 1024 - -typedef struct { - uint8_t peripheral; - uint8_t opcode; - uint16_t size; - uint8_t data[X8H7_PKT_SIZE]; -} x8h7_pkt_t; - -typedef void (*x8h7_hook_t)(void *priv, x8h7_pkt_t *pkt); - -int x8h7_pkt_send_sync(uint8_t peripheral, uint8_t opcode, uint16_t size, void *data); -int x8h7_pkt_send_defer(uint8_t peripheral, uint8_t opcode, uint16_t size, void *data); -int x8h7_pkt_send_now(void); -int x8h7_hook_set(uint8_t idx, x8h7_hook_t hook, void *priv); -int x8h7_dbg_set(void (*hook)(void*, uint8_t*, uint16_t), void *priv); -#endif /* __X8H7_H */ diff --git a/recipes-kernel/kernel-modules/x8h7/x8h7_adc.c b/recipes-kernel/kernel-modules/x8h7/x8h7_adc.c deleted file mode 100644 index 31f5cb6f..00000000 --- a/recipes-kernel/kernel-modules/x8h7/x8h7_adc.c +++ /dev/null @@ -1,194 +0,0 @@ -/** - * X8H7 ADC IIO driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "x8h7.h" - -#define DRIVER_NAME "x8h7_adc" - -// #define DEBUG -#include "debug.h" - -// Peripheral code -#define X8H7_ADC_PERIPH 0x01 -// Op code -#define X8H7_ADC_OC_CONFIGURE 0x10 -#define X8H7_ADC_OC_DATA 0x01 - -#define X8H7_ADC_NUM 8 - -struct x8h7_adc_val { - uint16_t val; - wait_queue_head_t wait; - int cnt; -}; - -struct x8h7_adc { - struct device *dev; - struct mutex lock; - struct x8h7_adc_val val[X8H7_ADC_NUM]; -}; - -#define X8H7_ADC_CHAN(_idx) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = _idx, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ -} - -static const struct iio_chan_spec x8h7_adc_iio_channels[] = { - X8H7_ADC_CHAN(0), - X8H7_ADC_CHAN(1), - X8H7_ADC_CHAN(2), - X8H7_ADC_CHAN(3), - X8H7_ADC_CHAN(4), - X8H7_ADC_CHAN(5), - X8H7_ADC_CHAN(6), - X8H7_ADC_CHAN(7), -}; - -static void x8h7_adc_hook(void *priv, x8h7_pkt_t *pkt) -{ - struct x8h7_adc *adc = (struct x8h7_adc*)priv; - uint8_t ch; - - ch = pkt->opcode - 1; - if (ch < X8H7_ADC_NUM) { - adc->val[ch].val = *((uint16_t*)pkt->data); - adc->val[ch].cnt++; - wake_up_interruptible(&adc->val[ch].wait); - } -} - -static int x8h7_adc_pkt_get(struct x8h7_adc *adc, unsigned int ch) -{ - long ret; - - ret = wait_event_interruptible_timeout(adc->val[ch].wait, - adc->val[ch].cnt != 0, - X8H7_RX_TIMEOUT); - if (!ret) { - DBG_ERROR("timeout expired"); - return -1; - } - adc->val[ch].cnt--; - return 0; -} - -static int x8h7_adc_read_chan(struct x8h7_adc *adc, unsigned int ch) -{ - x8h7_pkt_send_sync(X8H7_ADC_PERIPH, ch + 1, 0, NULL); - if (x8h7_adc_pkt_get(adc, ch) < 0) - return -ETIMEDOUT; - - return adc->val[ch].val; -} - -static int x8h7_adc_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - struct x8h7_adc *adc = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&adc->lock); - *val = x8h7_adc_read_chan(adc, chan->channel); - mutex_unlock(&adc->lock); - if (*val == -1) { - return -EIO; - } - return IIO_VAL_INT; - - case IIO_CHAN_INFO_SCALE: - *val = 1; // regulator_get_voltage(adc->vref) / 1000; - *val2 = 10; - return IIO_VAL_FRACTIONAL_LOG2; - - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - return 0; - } - - return -EINVAL; -} - -static const struct iio_info x8h7_adc_info = { - .read_raw = x8h7_adc_read_raw, -}; - -static int x8h7_adc_probe(struct platform_device *pdev) -{ - struct iio_dev *indio_dev; - struct x8h7_adc *adc; - int ret; - int i; - - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc)); - if (!indio_dev) { - return -ENOMEM; - } - - platform_set_drvdata(pdev, indio_dev); - adc = iio_priv(indio_dev); - adc->dev = &pdev->dev; - mutex_init(&adc->lock); -#if 0 - init_waitqueue_head(&adc->wait); -#else - for (i=0; ival[i].wait); - } -#endif - indio_dev->name = dev_name(&pdev->dev); - indio_dev->dev.parent = &pdev->dev; - indio_dev->info = &x8h7_adc_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = x8h7_adc_iio_channels; - indio_dev->num_channels = ARRAY_SIZE(x8h7_adc_iio_channels); - - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "unable to register device\n"); - return ret; - } - - x8h7_hook_set(X8H7_ADC_PERIPH, x8h7_adc_hook, adc); - - return 0; -} - -static int x8h7_adc_remove(struct platform_device *pdev) -{ - return 0; -} - -static const struct of_device_id x8h7_adc_match[] = { - { .compatible = "portenta,x8h7_adc" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, x8h7_adc_match); - -static struct platform_driver x8h7_adc_driver = { - .probe = x8h7_adc_probe, - .remove = x8h7_adc_remove, - .driver = { - .name = "x8h7_adc", - .of_match_table = x8h7_adc_match, - }, -}; -module_platform_driver(x8h7_adc_driver); - -MODULE_DESCRIPTION("Arduino Portenta X8 ADC driver"); -MODULE_AUTHOR("Massimiliano Agneni -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "x8h7.h" - -#define DRIVER_NAME "x8h7_can" - -/* DEBUG HANDLING */ -//#define DEBUG -#include "debug.h" -#ifdef DEBUG - #define DBG_CAN_STATE(d, s) { \ - DBG_PRINT("device %s:CAN State: %d CAN controller %s\n", d, s, can_sts(s)); \ - } -#else - #define DBG_CAN_STATE(i, s) -#endif - -/** - * Those parameters are valid for the STM32H7 CAN driver using - * CAN classic. For CAN FD different values are needed. - */ -static const struct can_bittiming_const x8h7_can_bittiming_const = { - .name = DRIVER_NAME, /* Name of the CAN controller hardware */ - .tseg1_min = 1, - .tseg1_max = 256, - .tseg2_min = 1, - .tseg2_max = 128, - .sjw_max = 128, - .brp_min = 1, - .brp_max = 512, - .brp_inc = 1, -}; - -static void x8h7_can_tx_work_handler(struct work_struct *ws); -static void x8h7_can_error_skb(struct net_device *net, int can_id, int data1); - -/** - */ -static void x8h7_can_frame_to_tx_obj(struct can_frame const *frame, union x8h7_can_frame_message *x8h7_can_msg) -{ - if (frame->can_id & CAN_EFF_FLAG) - x8h7_can_msg->field.id = CAN_EFF_FLAG | (frame->can_id & CAN_EFF_MASK); - else - x8h7_can_msg->field.id = (frame->can_id & CAN_SFF_MASK); - - x8h7_can_msg->field.len = (frame->can_dlc <= X8H7_CAN_FRAME_MAX_DATA_LEN) ? frame->can_dlc : X8H7_CAN_FRAME_MAX_DATA_LEN; - memcpy(x8h7_can_msg->field.data, frame->data, x8h7_can_msg->field.len); -} - -/** - */ -static char* can_sts(enum can_state sts) -{ - switch(sts){ - case CAN_STATE_ERROR_ACTIVE : return "is error active"; - case CAN_STATE_ERROR_WARNING: return "is error active, warning level is reached"; - case CAN_STATE_ERROR_PASSIVE: return "is error passive"; - case CAN_STATE_BUS_OFF : return "went into Bus Off"; - case CAN_STATE_STOPPED : return "is in stopped mode"; - case CAN_STATE_SLEEPING : return "is in Sleep mode"; - default : return "is unknown state"; - } -} - -/** - */ -static void x8h7_can_status(struct x8h7_can_priv *priv, u8 intf, u8 eflag) -{ - struct net_device *net = priv->net; - int can_id = 0; - int data1 = 0; - - //DBG_PRINT("\n"); - - if (intf & X8H7_CAN_STS_INT_ERR) - { - /* Handle overflow counters */ - if (eflag & X8H7_CAN_STS_FLG_RX_OVR) - { - net->stats.rx_over_errors++; - net->stats.rx_errors++; - can_id |= CAN_ERR_CRTL; - data1 |= CAN_ERR_CRTL_RX_OVERFLOW; - x8h7_can_error_skb(net, can_id, data1); - } - if (eflag & X8H7_CAN_STS_FLG_TX_OVR) - { - net->stats.tx_fifo_errors++; - net->stats.tx_errors++; - can_id |= CAN_ERR_CRTL; - data1 |= CAN_ERR_CRTL_TX_OVERFLOW; - x8h7_can_error_skb(net, can_id, data1); - } - } - - if (intf & X8H7_CAN_STS_INT_TX_COMPLETE) { - DBG_PRINT("TX COMPLETE"); - net->stats.tx_packets++; - net->stats.tx_bytes += priv->tx_len; - priv->tx_len = 0; - can_led_event(net, CAN_LED_EVENT_TX); - can_get_echo_skb(net, 0); - netif_wake_queue(net); - } - - if (intf & X8H7_CAN_STS_INT_TX_ABORT_COMPLETE) - { - DBG_PRINT("TX ABORT COMPLETE"); - } - - if (intf & X8H7_CAN_STS_INT_TX_FIFO_EMPTY) - { - DBG_PRINT("TX FIFO EMPTY"); - } -} - -/** - */ -static void x8h7_can_hook(void *arg, x8h7_pkt_t *pkt) -{ - struct x8h7_can_priv *priv = (struct x8h7_can_priv*)arg; - - switch(pkt->opcode) { - case X8H7_CAN_OC_RECV: - if (pkt->size < X8H7_CAN_HEADER_SIZE) { - DBG_ERROR("received packed is too short (%d)\n", pkt->size); - return; - } else { - struct sk_buff *skb; - struct can_frame *frame; - union x8h7_can_frame_message x8h7_can_msg; - - skb = alloc_can_skb(priv->net, &frame); - if (!skb) { - dev_err(priv->dev, "cannot allocate RX skb\n"); - priv->net->stats.rx_dropped++; - return; - } - - /* Copy header from raw byte-stream onto union. */ - memcpy(x8h7_can_msg.buf, pkt->data, X8H7_CAN_HEADER_SIZE); - - /* Extract can_id and can_dlc. Note: x8h7_can_frame_message uses the exact - * same flags for signaling extended/standard id mode or remote - * retransmit request as struct can_frame. - */ - frame->can_id = x8h7_can_msg.field.id; - frame->can_dlc = x8h7_can_msg.field.len; - memcpy(frame->data, pkt->data + X8H7_CAN_HEADER_SIZE, frame->can_dlc); - - priv->net->stats.rx_packets++; - priv->net->stats.rx_bytes += frame->can_dlc; - can_led_event(priv->net, CAN_LED_EVENT_RX); - netif_rx_ni(skb); - } - break; - case X8H7_CAN_OC_STS: - DBG_PRINT("received status %02X %02X\n", pkt->data[0], pkt->data[1]); - x8h7_can_status(priv, pkt->data[0], pkt->data[1]); - break; - } -} - -/** - */ -static void x8h7_can_clean(struct net_device *net) -{ - struct x8h7_can_priv *priv = netdev_priv(net); - - DBG_PRINT("\n"); - - net->stats.tx_errors++; - can_free_echo_skb(priv->net, 0); -} - -/** - */ -static int x8h7_can_hw_setup(struct x8h7_can_priv *priv) -{ - struct can_bittiming *bt = &priv->can.bittiming; - union x8h7_can_init_message x8h7_msg; - - DBG_PRINT("bitrate: %d, sample_point: %d, tq: %d, prop_seg: %d, phase_seg1: %d, phase_seg2: %d, sjw: %d, brp: %d, freq: %d ctrlmode: %08X\n", - bt->bitrate, - bt->sample_point, - bt->tq, - bt->prop_seg, - bt->phase_seg1, - bt->phase_seg2, - bt->sjw, - bt->brp, - priv->can.clock.freq, - priv->can.ctrlmode); - - x8h7_msg.field.baud_rate_prescaler = bt->brp; - x8h7_msg.field.time_segment_1 = bt->prop_seg + bt->phase_seg1 - bt->phase_seg2; - x8h7_msg.field.time_segment_2 = can_bit_time(bt) - x8h7_msg.field.time_segment_1 - CAN_SYNC_SEG; - x8h7_msg.field.sync_jump_width = bt->sjw; - - DBG_PRINT("baud_rate_prescaler: %d, time_segment_1: %d, time_segment_2: %d, sync_jump_width: %d\n", - x8h7_msg.field.baud_rate_prescaler, - x8h7_msg.field.time_segment_1, - x8h7_msg.field.time_segment_2, - x8h7_msg.field.sync_jump_width); - - x8h7_pkt_send_sync(priv->periph, X8H7_CAN_OC_INIT, sizeof(x8h7_msg.buf), x8h7_msg.buf); - - return 0; -} - -/** - */ -static int x8h7_can_hw_stop(struct x8h7_can_priv *priv) -{ - x8h7_pkt_send_sync(priv->periph, X8H7_CAN_OC_DEINIT, 0, NULL); - - return 0; -} - -/** - */ -static int x8h7_can_set_normal_mode(struct x8h7_can_priv *priv) -{ - DBG_PRINT("\n"); - - /* Enable interrupts */ - x8h7_hook_set(priv->periph, x8h7_can_hook, priv); - - return 0; -} - -/** - */ -static void x8h7_can_error_skb(struct net_device *net, int can_id, int data1) -{ - struct sk_buff *skb; - struct can_frame *frame; - - DBG_PRINT("\n"); - skb = alloc_can_err_skb(net, &frame); - if (skb) { - frame->can_id |= can_id; - frame->data[1] = data1; - netif_rx_ni(skb); - } else { - netdev_err(net, "cannot allocate error skb\n"); - } -} - -/** - */ -static int x8h7_can_open(struct net_device *net) -{ - struct x8h7_can_priv *priv = netdev_priv(net); - int ret; - - DBG_PRINT("\n"); - - ret = open_candev(net); - if (ret) { - DBG_ERROR("unable to set initial baudrate!\n"); - return ret; - } - - priv->tx_len = 0; - - priv->wq = alloc_workqueue("x8h7_can_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); - if (!priv->wq) { - ret = -ENOMEM; - goto out_clean; - } - INIT_WORK(&priv->work, x8h7_can_tx_work_handler); - - mutex_init(&priv->lock); - - ret = x8h7_can_hw_stop(priv); - if (ret) { - goto out_free_wq; - } - ret = x8h7_can_hw_setup(priv); - if (ret) { - goto out_free_wq; - } - ret = x8h7_can_set_normal_mode(priv); - if (ret) { - goto out_free_wq; - } - - can_led_event(net, CAN_LED_EVENT_OPEN); - - netif_wake_queue(net); - - return 0; - -out_free_wq: - destroy_workqueue(priv->wq); -out_clean: - x8h7_hook_set(priv->periph, NULL, NULL); - close_candev(net); - return ret; -} - -/** - */ -static int x8h7_can_stop(struct net_device *net) -{ - struct x8h7_can_priv *priv = netdev_priv(net); - - DBG_PRINT("\n"); - - x8h7_can_hw_stop(priv); - x8h7_can_clean(net); - - close_candev(net); - mutex_lock(&priv->lock); - x8h7_hook_set(priv->periph, NULL, NULL); - destroy_workqueue(priv->wq); - priv->wq = NULL; - - priv->can.state = CAN_STATE_STOPPED; - mutex_unlock(&priv->lock); - - can_led_event(net, CAN_LED_EVENT_STOP); - - return 0; -} - -/** - */ -static netdev_tx_t x8h7_can_start_xmit(struct sk_buff *skb, - struct net_device *net) -{ - struct x8h7_can_priv *priv = netdev_priv(net); - const struct device *dev = priv->dev; - struct can_frame *frame; - - DBG_PRINT("\n"); - - if (can_dropped_invalid_skb(net, skb)) - return NETDEV_TX_OK; - - netif_stop_queue(net); - - frame = (struct can_frame *)skb->data; - x8h7_can_frame_to_tx_obj(frame, &priv->tx_frame); - can_put_echo_skb(skb, net, 0); - queue_work(priv->wq, &priv->work); - - return NETDEV_TX_OK; -} - -/** - */ -static void x8h7_can_tx_work_handler(struct work_struct *ws) -{ - struct x8h7_can_priv *priv = container_of(ws, struct x8h7_can_priv, work); - -#ifdef DEBUG - char data_str[X8H7_CAN_FRAME_MAX_DATA_LEN * 4]; - int i; - int len; - - i = 0; len = 0; - for (i = 0; (i < priv->tx_frame.field.len) && (len < sizeof(data_str)); i++) - len += snprintf(data_str + len, sizeof(data_str) - len, " %02X", priv->tx_frame.field.data[i]); - DBG_PRINT("Send CAN frame to H7: id = %08X, len = %d, data = [%s ]\n", priv->tx_frame.field.id, priv->tx_frame.field.len, data_str); -#endif - - priv->tx_len = priv->tx_frame.field.len; - - x8h7_pkt_send_sync(priv->periph, - X8H7_CAN_OC_SEND, - X8H7_CAN_HEADER_SIZE + priv->tx_frame.field.len, /* Send 4-Byte ID, 1-Byte Length and the required number of data bytes. */ - priv->tx_frame.buf); -} - -/** - */ -static int x8h7_can_hw_do_set_bittiming(struct net_device *net) -{ - struct x8h7_can_priv *priv = netdev_priv(net); - struct can_bittiming *bt = &priv->can.bittiming; - union x8h7_can_bittiming_message x8h7_msg; - - DBG_PRINT("\n"); - - x8h7_msg.field.baud_rate_prescaler = bt->brp; - x8h7_msg.field.time_segment_1 = bt->prop_seg + bt->phase_seg1 - bt->phase_seg2; - x8h7_msg.field.time_segment_2 = can_bit_time(bt) - x8h7_msg.field.time_segment_1 - CAN_SYNC_SEG; - x8h7_msg.field.sync_jump_width = bt->sjw; - - DBG_PRINT("baud_rate_prescaler: %d, time_segment_1: %d, time_segment_2: %d, sync_jump_width: %d\n", - x8h7_msg.field.baud_rate_prescaler, - x8h7_msg.field.time_segment_1, - x8h7_msg.field.time_segment_2, - x8h7_msg.field.sync_jump_width); - - x8h7_pkt_send_sync(priv->periph, X8H7_CAN_OC_BITTIM, sizeof(x8h7_msg.buf), x8h7_msg.buf); - - return 0; -} - -/** - */ -static int x8h7_can_do_set_mode(struct net_device *net, enum can_mode mode) -{ - struct x8h7_can_priv *priv = netdev_priv(net); - DBG_PRINT("\n"); - - switch (mode) { - case CAN_MODE_START: - x8h7_can_clean(net); - priv->can.state = CAN_STATE_ERROR_ACTIVE; - break; - default: - return -EOPNOTSUPP; - } - - return 0; -} - -/** - */ -static int x8h7_can_do_get_berr_counter(const struct net_device *net, - struct can_berr_counter *bec) -{ - //@TODO: to be read from device - bec->txerr = 0; - bec->rxerr = 0; - - return 0; -} - -/** - */ -static const struct net_device_ops x8h7_can_netdev_ops = { - .ndo_open = x8h7_can_open, - .ndo_stop = x8h7_can_stop, - .ndo_start_xmit = x8h7_can_start_xmit, - //.ndo_change_mtu = can_change_mtu, -}; - -/** - */ -static int x8h7_can_hw_config_filter(struct x8h7_can_priv *priv, - uint32_t const idx, - uint32_t const id, - uint32_t const mask) -{ - union x8h7_can_filter_message x8h7_msg; - - x8h7_msg.field.idx = idx; - x8h7_msg.field.id = id; - x8h7_msg.field.mask = mask; - - DBG_PRINT("SEND idx %X, id %X, mask %X\n", idx, id, mask); - - x8h7_pkt_send_sync(priv->periph, X8H7_CAN_OC_FLT, sizeof(x8h7_msg.buf), x8h7_msg.buf); - - return 0; -} - -/** - * Standard id filter show - */ -static ssize_t x8h7_can_sf_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct x8h7_can_priv *priv = netdev_priv(to_net_dev(dev)); - int len; - int i; - - len = 0; - for (i = 0; i < X8H7_STD_FLT_MAX; i++) - { - if (priv->std_flt[i].can_mask) { - len += snprintf(buf + len, PAGE_SIZE - len, - "%02X %08X %08X\n", - i, priv->std_flt[i].can_id, priv->std_flt[i].can_mask); - } - } - return len; -} - -/** - * Standard id filter set - */ -static ssize_t x8h7_can_sf_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct x8h7_can_priv *priv = netdev_priv(to_net_dev(dev)); - uint32_t idx; - uint32_t id; - uint32_t mask; - int ret; - - ret = sscanf(buf, "%x %x %x", &idx, &id, &mask); - - if (ret != 3) { - DBG_ERROR("invalid num of params\n"); - return -EINVAL; - } - - if ((idx >= X8H7_STD_FLT_MAX) || - (id & ~0x7FF) || (mask & ~0x7FF)) { - DBG_ERROR("invalid params\n"); - return -EINVAL; - } - - ret = x8h7_can_hw_config_filter(priv, idx, id, mask); - if (ret) { - DBG_ERROR("set filter\n"); - return -EIO; - } - - priv->std_flt[idx].can_id = id; - priv->std_flt[idx].can_mask = mask; - - return count; -} - -/** - * Extended id filter show - */ -static ssize_t x8h7_can_ef_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct x8h7_can_priv *priv = netdev_priv(to_net_dev(dev)); - int len; - int i; - - len = 0; - for (i = 0; i < X8H7_EXT_FLT_MAX; i++) - { - if (priv->ext_flt[i].can_mask) { - len += snprintf(buf + len, PAGE_SIZE - len, - "%02X %08X %08X\n", - i, priv->ext_flt[i].can_id, priv->ext_flt[i].can_mask); - } - } - return len; -} - -/** - * Extended id filter set - */ -static ssize_t x8h7_can_ef_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct x8h7_can_priv *priv = netdev_priv(to_net_dev(dev)); - int ret; - uint32_t idx; - uint32_t id; - uint32_t mask; - - ret = sscanf(buf, "%x %x %x", &idx, &id, &mask); - - if (ret != 3) { - DBG_ERROR("invalid num of params\n"); - return -EINVAL; - } - - if ((idx >= X8H7_EXT_FLT_MAX) || - (id & ~0x1FFFFFFF) || (mask & ~0x1FFFFFFF)) { - DBG_ERROR("invalid params\n"); - return -EINVAL; - } - - ret = x8h7_can_hw_config_filter(priv, idx, (CAN_EFF_FLAG | id), mask); - if (ret) { - DBG_ERROR("set filter\n"); - return -EIO; - } - - priv->ext_flt[idx].can_id = id; - priv->ext_flt[idx].can_mask = mask; - - return count; -} - -/** - * Status show - */ -static ssize_t x8h7_can_sts_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct x8h7_can_priv *priv = netdev_priv(to_net_dev(dev)); - int len; - - len = snprintf(buf, PAGE_SIZE, - "status %d %s\n" - "error warning %d\n" - "error passive %d\n" - "bus off %d\n" - "tx packets %ld\n" - "tx bytes %ld\n" - "rx packets %ld\n" - "rx bytes %ld\n" - "rx over_errors %ld\n" - "rx errors %ld\n" - "rx dropped %ld\n", - priv->can.state, can_sts(priv->can.state), - priv->can.can_stats.error_warning, - priv->can.can_stats.error_passive, - priv->can.can_stats.bus_off, - priv->net->stats.tx_packets, - priv->net->stats.tx_bytes, - priv->net->stats.rx_packets, - priv->net->stats.rx_bytes, - priv->net->stats.rx_over_errors, - priv->net->stats.rx_errors, - priv->net->stats.rx_dropped); - return len; -} - -static DEVICE_ATTR(std_flt, 0644, x8h7_can_sf_show, x8h7_can_sf_store); -static DEVICE_ATTR(ext_flt, 0644, x8h7_can_ef_show, x8h7_can_ef_store); -static DEVICE_ATTR(status , 0644, x8h7_can_sts_show, NULL); - -static struct attribute *x8h7_can_sysfs_attrs[] = { - &dev_attr_std_flt.attr, - &dev_attr_ext_flt.attr, - &dev_attr_status.attr, - //.... - NULL, -}; - -static const struct attribute_group x8h7_can_sysfs_attr_group = { - .name = "x8h7can", - .attrs = (struct attribute **)x8h7_can_sysfs_attrs, -}; - -/** - */ -static int x8h7_can_probe(struct platform_device *pdev) -{ - struct net_device *net; - struct x8h7_can_priv *priv; - int err; - - u32 clock_freq = 100000000; - - DBG_PRINT("\n"); - - if (pdev->dev.of_node) { - of_property_read_u32(pdev->dev.of_node, "clock-frequency", &clock_freq); - DBG_PRINT("fdcan_clk = %d", clock_freq); - } - - net = alloc_candev(sizeof(struct x8h7_can_priv), 1); - if (!net) { - return -ENOMEM; - } - - net->netdev_ops = &x8h7_can_netdev_ops; - net->flags |= IFF_ECHO; - net->sysfs_groups[0] = &x8h7_can_sysfs_attr_group; - - priv = netdev_priv(net); - - priv->can.clock.freq = clock_freq; - priv->can.bittiming_const = &x8h7_can_bittiming_const; - priv->can.do_set_bittiming = x8h7_can_hw_do_set_bittiming; - priv->can.do_set_mode = x8h7_can_do_set_mode; - priv->can.do_get_berr_counter = x8h7_can_do_get_berr_counter; - priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | - CAN_CTRLMODE_LISTENONLY | - CAN_CTRLMODE_3_SAMPLES ; - priv->net = net; - - platform_set_drvdata(pdev, priv); - - SET_NETDEV_DEV(net, &pdev->dev); - - err = register_candev(net); - if (err) { - dev_err(&pdev->dev, "registering netdev failed\n"); - goto failed_register; - } - DBG_PRINT("net device registered %s, " - "ifindex: %d, if_port %d, dev_id: %d, dev_port %d\n", - net->name, net->ifindex, net->if_port, net->dev_id, net ->dev_port); - - devm_can_led_init(net); - - if (net->name[3] == '0') { - priv->periph = X8H7_CAN1_PERIPH; - } else { - priv->periph = X8H7_CAN2_PERIPH; - } - priv->dev = &pdev->dev; - DBG_PRINT("periph: %d DONE\n", priv->periph); - - netdev_info(net, "X8H7 CAN successfully initialized.\n"); - - return 0; - -failed_register: - DBG_ERROR("\n"); - free_candev(net); - return err; -} - -/** - */ -static int x8h7_can_remove(struct platform_device *pdev) -{ - struct x8h7_can_priv *priv = platform_get_drvdata(pdev); - struct net_device *net = priv->net; - - unregister_candev(net); - free_candev(net); - - return 0; -} - -/** - */ -static const struct of_device_id x8h7_can_of_match[] = { - { .compatible = "portenta,x8h7_can", }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, x8h7_can_of_match); - -/** - */ -static const struct platform_device_id x8h7_can_id_table[] = { - { .name = "x8h7_can", }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(platform, x8h7_can_id_table); - -/** - */ -static struct platform_driver x8h7_can_driver = { - .driver = { - .name = DRIVER_NAME, - .of_match_table = x8h7_can_of_match, - }, - .probe = x8h7_can_probe, - .remove = x8h7_can_remove, - .id_table = x8h7_can_id_table, -}; - -module_platform_driver(x8h7_can_driver); - -MODULE_AUTHOR("Massimiliano Agneni -#include -#include - -/** - * DEFINES - */ -#define X8H7_CAN1_PERIPH 0x03 -#define X8H7_CAN2_PERIPH 0x04 - -#define X8H7_CAN_OC_INIT 0x10 -#define X8H7_CAN_OC_DEINIT 0x11 -#define X8H7_CAN_OC_BITTIM 0x12 -#define X8H7_CAN_OC_SEND 0x01 -#define X8H7_CAN_OC_RECV 0x01 -#define X8H7_CAN_OC_STS 0x40 -#define X8H7_CAN_OC_FLT 0x50 - -#define X8H7_CAN_STS_INT_TX_COMPLETE 0x01 -#define X8H7_CAN_STS_INT_RX 0x02 -#define X8H7_CAN_STS_INT_ERR 0x04 -#define X8H7_CAN_STS_INT_TX_ABORT_COMPLETE 0x08 -#define X8H7_CAN_STS_INT_TX_FIFO_EMPTY 0x10 - -#define X8H7_CAN_STS_FLG_RX_OVR 0x01 // Receive Buffer Overflow -#define X8H7_CAN_STS_FLG_TX_BO 0x02 // Bus-Off -#define X8H7_CAN_STS_FLG_TX_EP 0x04 // Transmit Error-Passive -#define X8H7_CAN_STS_FLG_RX_EP 0x08 // Receive Error-Passive -#define X8H7_CAN_STS_FLG_TX_WAR 0x10 // Transmit Error Warning -#define X8H7_CAN_STS_FLG_RX_WAR 0x20 // Receive Error Warning -#define X8H7_CAN_STS_FLG_EWARN 0x40 // Error Warning -#define X8H7_CAN_STS_FLG_TX_OVR 0x80 // Transmit Buffer Overflow - -#define X8H7_CAN_HEADER_SIZE 5 -#define X8H7_CAN_FRAME_MAX_DATA_LEN 8 - -#define X8H7_STD_FLT_MAX 128 -#define X8H7_EXT_FLT_MAX 64 - -#define X8H7_TX_FIFO_SIZE 32 - -/** - * TYPEDEFS - */ -union x8h7_can_init_message -{ - struct __attribute__((packed)) - { - uint32_t baud_rate_prescaler; - uint32_t time_segment_1; - uint32_t time_segment_2; - uint32_t sync_jump_width; - } field; - uint8_t buf[sizeof(uint32_t) /* can_bitrate_Hz */ + sizeof(uint32_t) /* time_segment_1 */ + sizeof(uint32_t) /* time_segment_2 */ + sizeof(uint32_t) /* sync_jump_width */]; -}; - -union x8h7_can_bittiming_message -{ - struct __attribute__((packed)) - { - uint32_t baud_rate_prescaler; - uint32_t time_segment_1; - uint32_t time_segment_2; - uint32_t sync_jump_width; - } field; - uint8_t buf[sizeof(uint32_t) /* can_bitrate_Hz */ + sizeof(uint32_t) /* time_segment_1 */ + sizeof(uint32_t) /* time_segment_2 */ + sizeof(uint32_t) /* sync_jump_width */]; -}; - -union x8h7_can_filter_message -{ - struct __attribute__((packed)) - { - uint32_t idx; - uint32_t id; - uint32_t mask; - } field; - uint8_t buf[sizeof(uint32_t) /* idx */ + sizeof(uint32_t) /* id */ + sizeof(uint32_t) /* mask */]; -}; - -union x8h7_can_frame_message -{ - struct __attribute__((packed)) - { - uint32_t id; - uint8_t len; - uint8_t data[X8H7_CAN_FRAME_MAX_DATA_LEN]; - } field; - uint8_t buf[X8H7_CAN_HEADER_SIZE + X8H7_CAN_FRAME_MAX_DATA_LEN]; -}; - -struct x8h7_can_priv { - struct can_priv can; - struct net_device *net; - struct device *dev; - int periph; - - int tx_len; - - struct workqueue_struct *wq; - struct work_struct work; - union x8h7_can_frame_message tx_frame; - - struct can_filter std_flt[X8H7_STD_FLT_MAX]; - struct can_filter ext_flt[X8H7_EXT_FLT_MAX]; - - struct mutex lock; -}; - -#endif diff --git a/recipes-kernel/kernel-modules/x8h7/x8h7_drv.c b/recipes-kernel/kernel-modules/x8h7/x8h7_drv.c deleted file mode 100644 index f2e3b17f..00000000 --- a/recipes-kernel/kernel-modules/x8h7/x8h7_drv.c +++ /dev/null @@ -1,553 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/** - * Portenta X8 - * X8 H7 communication protocol - * How it works: this driver is a SPI bus single aggregator. - * Kernel space peripheral subdrivers (/dev/adc, /dev/pwm, etc) calls will invoke - * exported functions x8h7_pkt_enq x8h7_pkt_send x8h7_hook_set to enqueue their payload to be transmitted in x8h7_pkt_send_priv method - * Data transmission on SPI bus can be triggered by the following sources: - * a) From this module (peripheral subdrivers ioctl'ed typically) to H7 - * b) When an interrupt event from H7 is received - * - * Please check available documentation on the H7 firmware repo - * - https://github.com/arduino/portentax8-stm32h7-fw/tree/master/doc - * - * Based on: - * Simple synchronous userspace interface to SPI devices - * - * Copyright (C) 2006 SWAPP - * Andrea Paterniani - * Copyright (C) 2007 - * David Brownell (simplification, cleanup) - * Copyright (C) 2021 X8H7 - * "Massimiliano Agneni " - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "x8h7.h" - -#define DRIVER_NAME "x8h7" -#define X8H7_BUF_SIZE (64*1024) - -//#define DEBUG -#include "debug.h" - - -struct spidev_data { - struct spi_device *spi; - struct mutex lock; - u32 speed_hz; - u8 *x8h7_txb; - u16 x8h7_txl; - u8 *x8h7_rxb; - struct gpio_desc *flow_ctrl_gpio; -}; - -/*-------------------------------------------------------------------------*/ - -struct spidev_data *x8h7_spidev; - -/** - */ -typedef struct __attribute__((packed, aligned(4))) { - uint16_t size; - uint16_t checksum; -} x8h7_pkthdr_t; - -/** - */ -typedef struct __attribute__((packed, aligned(4))) { - uint8_t peripheral; - uint8_t opcode; - uint16_t size; -} x8h7_subpkt_t; - -#define X8H7_PERIPH_NUM 16 -x8h7_hook_t x8h7_hook[X8H7_PERIPH_NUM] = {}; -void *x8h7_hook_priv[X8H7_PERIPH_NUM]; - -void (*x8h7_dbg)(void*, uint8_t*, uint16_t); -void *x8h7_dbg_priv; - -/** - */ -#if defined(DEBUG) - -#define X8H7_PERIPH_ADC 0x01 -#define X8H7_PERIPH_PWM 0x02 -#define X8H7_PERIPH_FDCAN1 0x03 -#define X8H7_PERIPH_FDCAN2 0x04 -#define X8H7_PERIPH_UART 0x05 -#define X8H7_PERIPH_RTC 0x06 -#define X8H7_PERIPH_GPIO 0x07 -#define X8H7_PERIPH_H7 0x09 -#define X8H7_PERIPH_UI 0x0A - -/** - */ -char* to_peripheral_string(uint8_t peripheral) { - switch (peripheral) { - case X8H7_PERIPH_H7 : return "H7"; - case X8H7_PERIPH_ADC : return "ADC"; - case X8H7_PERIPH_PWM : return "PWM"; - case X8H7_PERIPH_FDCAN1: return "FDCAN1"; - case X8H7_PERIPH_FDCAN2: return "FDCAN2"; - case X8H7_PERIPH_UART : return "UART"; - case X8H7_PERIPH_RTC : return "RTC"; - case X8H7_PERIPH_GPIO : return "GPIO"; - case X8H7_PERIPH_UI : return "UI"; - default : return "UNKNOWN"; - } -} - -/** - */ -void pkt_dump(char *title, void *data) -{ - x8h7_pkthdr_t *hdr; - x8h7_subpkt_t *pkt; - uint8_t *ptr; - uint16_t len; - char data_str[8192]; - int data_len; - int i; - int err; - - ptr = data; - hdr = (x8h7_pkthdr_t*)ptr; - err = (hdr->size != 0) && ((hdr->size ^ 0x5555) != hdr->checksum); - printk("%s: Header size %d %04X, checksum %04X %s\n", - title, - hdr->size, hdr->size, hdr->checksum, - err ? "ERROR" : "OK"); - if (err) { - return; - } - len = hdr->size; - ptr += sizeof(x8h7_pkthdr_t); - while (len > 0) { - pkt = (x8h7_subpkt_t*)ptr; - ptr += sizeof(x8h7_subpkt_t); - - data_len = 0; - data_str[0] = 0; - for (i=0; isize; i++) { - data_len += sprintf(data_str + data_len, " %02X", ptr[i]); - } - printk("- PKT peripheral: %d %s, opcode: %d, size: %d data: %s\n", - pkt->peripheral, to_peripheral_string(pkt->peripheral), - pkt->opcode, pkt->size, data_str); - - ptr += pkt->size; - len -= (sizeof(x8h7_subpkt_t) + pkt->size); - }; -} -#else -void pkt_dump(char *title, void *data) {} -#endif - -/** - */ -int x8h7_pkt_enq(uint8_t peripheral, uint8_t opcode, uint16_t size, void *data) -{ - struct spidev_data *spidev = x8h7_spidev; - x8h7_pkthdr_t *hdr; - x8h7_subpkt_t *pkt; - uint8_t *ptr; - - ptr = spidev->x8h7_txb; - hdr = (x8h7_pkthdr_t*)ptr; - - if ((hdr->size + sizeof(x8h7_subpkt_t) + size) < X8H7_BUF_SIZE) { - ptr += sizeof(x8h7_pkthdr_t) + hdr->size; - pkt = (x8h7_subpkt_t*)ptr; - pkt->peripheral = peripheral; - pkt->opcode = opcode; - pkt->size = size; - ptr += sizeof(x8h7_subpkt_t); - if (size) { - if (!data) { - memset(ptr, 0, size); - } else { - memcpy(ptr, data, size); - } - } - hdr->size += sizeof(x8h7_subpkt_t) + size; - hdr->checksum = hdr->size ^ 0x5555; - spidev->x8h7_txl = hdr->size; - return 0; - } - - return -ENOMEM; -} - -static int x8h7_pkt_send(void); -/** - */ -int x8h7_pkt_send_sync(uint8_t peripheral, uint8_t opcode, uint16_t size, void *data) -{ - struct spidev_data *spidev = x8h7_spidev; - int ret; - - mutex_lock(&spidev->lock); - ret = x8h7_pkt_enq(peripheral, opcode, size, data); - if (ret < 0) { - printk("x8h7_pkt_enq failed with %d", ret); - mutex_unlock(&spidev->lock); - return ret; - } - ret = x8h7_pkt_send(); - if (ret < 0) { - printk("x8h7_pkt_send failed with %d", ret); - mutex_unlock(&spidev->lock); - return ret; - } - mutex_unlock(&spidev->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(x8h7_pkt_send_sync); - -/** - */ -int x8h7_pkt_send_defer(uint8_t peripheral, uint8_t opcode, uint16_t size, void *data) -{ - struct spidev_data *spidev = x8h7_spidev; - int ret; - - mutex_lock(&spidev->lock); - ret = x8h7_pkt_enq(peripheral, opcode, size, data); - if (ret < 0) { - printk("x8h7_pkt_enq failed with %d", ret); - mutex_unlock(&spidev->lock); - return ret; - } - /* No mutex unlocking here ... */ - - return ret; -} -EXPORT_SYMBOL_GPL(x8h7_pkt_send_defer); - -/** - */ -int x8h7_pkt_send_now(void) -{ - /* No mutex locking here ... */ - struct spidev_data *spidev = x8h7_spidev; - int ret; - - ret = x8h7_pkt_send(); - if (ret < 0) { - printk("x8h7_pkt_send failed with %d", ret); - mutex_unlock(&spidev->lock); - return ret; - } - mutex_unlock(&spidev->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(x8h7_pkt_send_now); - -/** - * Function to parse data coming from h7 - * and dispatch to peripheral - */ -static int pkt_parse(struct spidev_data *spidev) -{ - x8h7_pkthdr_t *hdr; - x8h7_subpkt_t *pkt; - uint8_t *ptr; - uint16_t size; - int i; - - pkt_dump("Parse", spidev->x8h7_rxb); - - ptr = spidev->x8h7_rxb; - hdr = (x8h7_pkthdr_t*)ptr; - size = hdr->size; - ptr += sizeof(x8h7_pkthdr_t); - - /* Loop to parse data from h7 and dispatch to correct peripheral */ - do { - pkt = (x8h7_subpkt_t*)ptr; - ptr += sizeof(x8h7_subpkt_t); - - i = pkt->peripheral; - if (i < X8H7_PERIPH_NUM) { - if (x8h7_hook[i]) { - x8h7_pkt_t p; - p.peripheral = pkt->peripheral; - p.opcode = pkt->opcode; - p.size = pkt->size; - if (p.size > X8H7_PKT_SIZE) { - DBG_ERROR("packet size is %d\n", pkt->size); - p.size = X8H7_PKT_SIZE; - } - memcpy(p.data, ptr, p.size); - x8h7_hook[i](x8h7_hook_priv[i], &p); - } - } - - ptr += pkt->size; - size -= (sizeof(x8h7_subpkt_t) + pkt->size); - } while (size > 0); - - return 0; -} - -/** - */ -int x8h7_spi_trx(struct spi_device *spi, - void *tx_buf, void* rx_buf, unsigned len) -{ - struct spi_transfer t = {}; - struct spi_message m; - int ret; - - t.tx_buf = tx_buf; - t.rx_buf = rx_buf; - t.len = len; - t.speed_hz = x8h7_spidev->speed_hz; - - spi_message_init(&m); - spi_message_add_tail(&t, &m); - - ret = spi_sync(spi, &m); - if (ret) { - DBG_ERROR("spi transfer failed: ret = %d\n", ret); - } - -#ifdef DEBUG - { - char data_str[1024] = {0}; - uint8_t * data_ptr = 0; - int i = 0, l = 0; - - l = 0; - data_ptr = (uint8_t *)tx_buf; - for (i = 0; (i < len) && (l < sizeof(data_str)); i++) - l += snprintf(data_str + l, sizeof(data_str) - l, " %02X", *(data_ptr + i)); - DBG_PRINT(" TX: len = %d, data = [%s ]\n", len, data_str); - - l = 0; - data_ptr = (uint8_t *)rx_buf; - for (i = 0; (i < len) && (l < sizeof(data_str)); i++) - l += snprintf(data_str + l, sizeof(data_str) - l, " %02X", *(data_ptr + i)); - DBG_PRINT(" RX: len = %d, data = [%s ]\n", len, data_str); - } -#endif - - return ret; -} - -/** - * Function to send/receive physically data over SPI, - * moreover in this function we process received data - * and dispatch to corresponding peripheral - */ -static int x8h7_pkt_send(void) -{ - struct spidev_data *spidev = x8h7_spidev; - x8h7_pkthdr_t *hdr; - int len; - - DBG_PRINT("\n"); - - /* Exchange of the packet header. */ - x8h7_spi_trx(spidev->spi, - spidev->x8h7_txb, spidev->x8h7_rxb, sizeof(x8h7_pkthdr_t)); - - hdr = (x8h7_pkthdr_t*)spidev->x8h7_rxb; - if ((hdr->size != 0) && ((hdr->size ^ 0x5555) != hdr->checksum)) { - DBG_ERROR("Out of sync %04X %04X\n", hdr->size, hdr->checksum); - return -1; - } - - len = max(hdr->size, spidev->x8h7_txl); - if (len == 0) { - DBG_ERROR("Transaction length is zero\n"); - return 0; - } - - pkt_dump("Send", spidev->x8h7_txb); - - x8h7_spi_trx(spidev->spi, - spidev->x8h7_txb + sizeof(x8h7_pkthdr_t), - spidev->x8h7_rxb + sizeof(x8h7_pkthdr_t), len); - - hdr = (x8h7_pkthdr_t*)spidev->x8h7_rxb; - // @TODO: Add control - if (hdr->size) { - if (x8h7_dbg) { - x8h7_dbg(x8h7_dbg_priv, spidev->x8h7_rxb, hdr->size); - } else { - pkt_parse(spidev); - } - } - - memset(spidev->x8h7_txb, 0, X8H7_BUF_SIZE); - memset(spidev->x8h7_rxb, 0, X8H7_BUF_SIZE); - spidev->x8h7_txl = 0; - - return 0; -} - -/** - */ -int x8h7_hook_set(uint8_t idx, x8h7_hook_t hook, void *priv) -{ - if (idx >= X8H7_PERIPH_NUM) { - return -1; - } - x8h7_hook[idx] = hook; - x8h7_hook_priv[idx] = priv; - return 0; -} -EXPORT_SYMBOL_GPL(x8h7_hook_set); - -/** - */ -int x8h7_dbg_set(void (*hook)(void*, uint8_t*, uint16_t), void *priv) -{ - x8h7_dbg = hook; - x8h7_dbg_priv = priv; - return 0; -} -EXPORT_SYMBOL_GPL(x8h7_dbg_set); - -/** - * Interrupt handler - */ -static irqreturn_t x8h7_threaded_isr(int irq, void *data) -{ - struct spidev_data *spidev = (struct spidev_data*)data; - - mutex_lock(&spidev->lock); - DBG_PRINT("Got IRQ from H7\n"); - x8h7_pkt_send(); - mutex_unlock(&spidev->lock); - - return IRQ_HANDLED; -} - -static int x8h7_probe(struct spi_device *spi) -{ - struct spidev_data *spidev; - int status; - uint32_t value; - - /* Allocate driver data */ - spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); - if (!spidev) - return -ENOMEM; - - /* Initialize the driver data */ - spidev->spi = spi; - mutex_init(&spidev->lock); - - /* Device speed */ - if (!of_property_read_u32(spi->dev.of_node, "spi-max-frequency", &value)) - spidev->speed_hz = value; - DBG_PRINT("Configuring speed_hz=%d\n", spidev->speed_hz); - - status = 0; - - if (status == 0) { - spidev->x8h7_txb = devm_kzalloc(&spi->dev, X8H7_BUF_SIZE, GFP_KERNEL); - if (!spidev->x8h7_txb) { - DBG_ERROR("X8H7 Tx buffer memory fail\n"); - status = -ENOMEM; - } - } - - if (status == 0) { - spidev->x8h7_rxb = devm_kzalloc(&spi->dev, X8H7_BUF_SIZE, GFP_KERNEL); - if (!spidev->x8h7_rxb) { - DBG_ERROR("X8H7 Rx buffer memory fail\n"); - status = -ENOMEM; - } - } - - memset(spidev->x8h7_txb, 0, X8H7_BUF_SIZE); - memset(spidev->x8h7_rxb, 0, X8H7_BUF_SIZE); - spidev->x8h7_txl = 0; - - /* Request optional flow control pin, in case it's a list the first */ - spidev->flow_ctrl_gpio = devm_gpiod_get_optional(&spi->dev, "flow-ctrl", GPIOD_IN); - if ((int)spidev->flow_ctrl_gpio < 0) { - DBG_ERROR("Cannot obtain flow-ctrl-gpio\n"); - return (int)spidev->flow_ctrl_gpio; - } - - /* Example: read flow control pin */ - if (spidev->flow_ctrl_gpio) { - value = gpiod_get_value_cansleep(spidev->flow_ctrl_gpio); - DBG_PRINT("Flow control GPIO value: %d\n", value); - } - - /* Configure interrupt request */ - if (spi->irq > 0) { - int ret; - ret = devm_request_threaded_irq(&spi->dev, spi->irq, - NULL, x8h7_threaded_isr, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "x8h7", spidev); - if (ret) { - DBG_ERROR("Failed request IRQ #%d\n", spi->irq); - status = -ENODEV; - } - DBG_PRINT("IRQ request irq %d OK\n", spi->irq); - } - - x8h7_spidev = spidev; - - if (status == 0) - spi_set_drvdata(spi, spidev); - else - kfree(spidev); - - return status; -} - -static int x8h7_remove(struct spi_device *spi) -{ - struct spidev_data *spidev = spi_get_drvdata(spi); - - /* Make sure ops on existing fds can abort cleanly */ - kfree(spidev); - - return 0; -} - -static struct spi_driver x8h7_driver = { - .driver = { - .name = "x8h7", - }, - .probe = x8h7_probe, - .remove = x8h7_remove, -}; - -module_spi_driver(x8h7_driver); - -MODULE_AUTHOR("Massimiliano Agneni "); -MODULE_DESCRIPTION("Arduino x8h7 SPI driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:x8h7"); diff --git a/recipes-kernel/kernel-modules/x8h7/x8h7_gpio.c b/recipes-kernel/kernel-modules/x8h7/x8h7_gpio.c deleted file mode 100644 index 74855bb1..00000000 --- a/recipes-kernel/kernel-modules/x8h7/x8h7_gpio.c +++ /dev/null @@ -1,664 +0,0 @@ -/** - * X8H7 GPIO driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "x8h7.h" - -#define DRIVER_NAME "x8h7_gpio" - -//#define DEBUG -#include "debug.h" - -// Peripheral code -#define X8H7_GPIO_PERIPH 0x07 -// Op code -#define X8H7_GPIO_OC_DIR 0x10 -#define X8H7_GPIO_OC_IRQ_TYPE 0x11 -#define X8H7_GPIO_OC_WR 0x20 -#define X8H7_GPIO_OC_RD 0x30 -#define X8H7_GPIO_OC_IEN 0x40 -#define X8H7_GPIO_OC_INT 0x50 -#define X8H7_GPIO_OC_IACK 0x60 - -//#define GPIO_MODE_INPUT 0x00 /*!< Input Floating Mode */ -//#define GPIO_MODE_OUTPUT_PP 0x01 /*!< Output Push Pull Mode */ -//#define GPIO_MODE_OUTPUT_OD 0x11 /*!< Output Open Drain Mode */ - -#define GPIO_MODE_INPUT 0x00 /*!< Input Floating Mode */ -#define GPIO_MODE_IN_RE 0x01 /*!< Input interrupt rising edge */ -#define GPIO_MODE_IN_FE 0x02 /*!< Input interrupt falling edge */ - -#define GPIO_MODE_OUTPUT_PP 0x01 /*!< Output Push Pull Mode */ -#define GPIO_MODE_OUTPUT_OD 0x11 /*!< Output Open Drain Mode */ - -//#define GPIO_INT_EDGE_RISING 0x1 -//#define GPIO_INT_EDGE_FALLING 0x2 -//#define GPIO_INT_MASK (GPIO_INT_EDGE_RISING | GPIO_INT_EDGE_FALLING) -//#define GPIO_INT_MASK_SIZE 2 - -#define X8H7_GPIO_NUM 34 - -struct x8h7_gpio_info { - struct device *dev; - wait_queue_head_t wait; - int rx_cnt; - int tx_cnt; - x8h7_pkt_t rx_pkt; - struct pinctrl_dev *pctldev; - struct pinctrl_desc pinctrl_desc; - struct gpio_chip gc; - uint32_t gpio_dir; - uint32_t gpio_val; - uint8_t gpio_ien; - uint8_t irq_conf; - struct irq_domain *irq; - struct mutex lock; - struct work_struct work; - struct workqueue_struct *workqueue; - uint64_t ack_irq; -}; - -// @TODO: add remaining gpios -static const struct pinctrl_pin_desc x8h7_gpio_34_pins[] = { - PINCTRL_PIN(0, "gpio0"), - PINCTRL_PIN(1, "gpio1"), - PINCTRL_PIN(2, "gpio2"), - PINCTRL_PIN(3, "gpio3"), - PINCTRL_PIN(4, "gpio4"), - PINCTRL_PIN(5, "gpio5"), - PINCTRL_PIN(6, "gpio6"), - PINCTRL_PIN(7, "gpio7"), - PINCTRL_PIN(8, "gpio8"), - PINCTRL_PIN(9, "gpio9"), - PINCTRL_PIN(10, "gpio10"), - PINCTRL_PIN(11, "gpio11"), - PINCTRL_PIN(12, "gpio12"), - PINCTRL_PIN(13, "gpio13"), - PINCTRL_PIN(14, "gpio14"), - PINCTRL_PIN(15, "gpio15"), - PINCTRL_PIN(16, "gpio16"), - PINCTRL_PIN(17, "gpio17"), - PINCTRL_PIN(18, "gpio18"), - PINCTRL_PIN(19, "gpio19"), - PINCTRL_PIN(20, "gpio20"), - PINCTRL_PIN(21, "gpio21"), - PINCTRL_PIN(22, "gpio22"), - PINCTRL_PIN(23, "gpio23"), - PINCTRL_PIN(24, "gpio24"), - PINCTRL_PIN(25, "gpio25"), - PINCTRL_PIN(26, "gpio26"), - PINCTRL_PIN(27, "gpio27"), - PINCTRL_PIN(28, "gpio28"), - PINCTRL_PIN(29, "gpio29"), - PINCTRL_PIN(30, "gpio30"), - PINCTRL_PIN(31, "gpio31"), - PINCTRL_PIN(32, "gpio32"), - PINCTRL_PIN(33, "gpio33"), -}; - -/* We can't use x8h7_pkt_send directly in x8h7_gpio_hook since it's a deadlock */ -static void x8h7_gpio_irq_ack(struct x8h7_gpio_info *inf) -{ - if(inf->workqueue) - queue_work(inf->workqueue, &inf->work); -} - -/* Worqueue for gpio_irq_ack handling */ -static void gpio_irq_ack_work_func(struct work_struct *work) -{ - struct x8h7_gpio_info *inf = container_of(work, struct x8h7_gpio_info, work); - uint8_t data[2]; - - DBG_PRINT("\n"); - data[0] = inf->ack_irq; - data[1] = 0x55; - x8h7_pkt_send_sync(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_IACK, 2, data); - return; -} - -static void x8h7_gpio_hook(void *priv, x8h7_pkt_t *pkt) -{ - struct x8h7_gpio_info *inf = (struct x8h7_gpio_info*)priv; - unsigned long irq = 0; - uint8_t hwirq = 0; - - if ((pkt->peripheral == X8H7_GPIO_PERIPH) && - (pkt->opcode == X8H7_GPIO_OC_INT) && - (pkt->size == 1)) { - if (pkt->data[0] < X8H7_GPIO_NUM) { - hwirq = pkt->data[0]; - irq = irq_linear_revmap(inf->irq, hwirq); - handle_nested_irq(irq); - DBG_PRINT("call handle_nested_irq(%d)\n", hwirq); - inf->ack_irq = hwirq; - x8h7_gpio_irq_ack(inf); - DBG_PRINT("call x8h7_gpio_irq_ack(%d)\n", inf->ack_irq); - } - } else { - memcpy(&inf->rx_pkt, pkt, sizeof(x8h7_pkt_t)); - inf->rx_cnt++; - wake_up_interruptible(&inf->wait); - } -} - -static int x8h7_gpio_pkt_get(struct x8h7_gpio_info *inf) -{ - long ret; - - ret = wait_event_interruptible_timeout(inf->wait, - inf->rx_cnt != 0, - X8H7_RX_TIMEOUT); - if (!ret) { - DBG_ERROR("timeout expired"); - return -1; - } - inf->rx_cnt--; - return 0; -} - -static int x8h7_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct x8h7_gpio_info *inf = gpiochip_get_data(chip); - uint8_t data[2]; - - DBG_PRINT("offset: %d\n", offset); - if (offset >= inf->gc.ngpio) { - DBG_ERROR("offset out of reange\n"); - return -EINVAL; - } - inf->gpio_dir &= ~(1 << offset); - - data[0] = offset; - data[1] = GPIO_MODE_INPUT; - - x8h7_pkt_send_sync(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_DIR, 2, data); - - DBG_PRINT(" dir %08X\n", inf->gpio_dir); - return 0; -} - -static int x8h7_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct x8h7_gpio_info *inf = gpiochip_get_data(chip); - uint8_t data[1]; - - DBG_PRINT("offset: %d\n", offset); - if (offset >= inf->gc.ngpio) { - DBG_ERROR("offset out of reange\n"); - return -EINVAL; - } - - data[0] = offset; - x8h7_pkt_send_sync(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_RD, 1, data); - if (x8h7_gpio_pkt_get(inf) < 0) - return -ETIMEDOUT; - - if ((inf->rx_pkt.peripheral == X8H7_GPIO_PERIPH) && - (inf->rx_pkt.opcode == X8H7_GPIO_OC_RD) && - (inf->rx_pkt.size == 2)) { - if (inf->rx_pkt.data[1]) { - inf->gpio_val |= 1 << offset; - } else { - inf->gpio_val &= ~(1 << offset); - } - } - DBG_PRINT("read %08X\n", inf->gpio_val); - return !!(inf->gpio_val & (1 << offset)); -} - -static int x8h7_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - struct x8h7_gpio_info *inf = gpiochip_get_data(chip); - uint8_t data[2]; - - DBG_PRINT("offset: %d, value: %d\n", offset, value); - if (offset >= inf->gc.ngpio) { - DBG_ERROR("offset out of reange\n"); - return -EINVAL; - } - inf->gpio_dir |= (1 << offset); - if (value) { - inf->gpio_val |= (1 << offset); - } else { - inf->gpio_val &= ~(1 << offset); - } - data[0] = offset; - data[1] = !!value; - x8h7_pkt_send_sync(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_WR, 2, data); - data[1] = GPIO_MODE_OUTPUT_PP; - x8h7_pkt_send_sync(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_DIR, 2, data); - - DBG_PRINT("dir %08X write %08X\n", inf->gpio_dir, inf->gpio_val); - return 0; -} - -static void x8h7_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct x8h7_gpio_info *inf = gpiochip_get_data(chip); - uint8_t data[2]; - - DBG_PRINT("offset: %d, value: %d\n", offset, value); - if (offset >= inf->gc.ngpio) { - DBG_ERROR("offset out of reange\n"); - return; - } - - if (value) { - inf->gpio_val |= (1 << offset); - } else { - inf->gpio_val &= ~(1 << offset); - } - - data[0] = offset; - data[1] = !!value; - x8h7_pkt_send_sync(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_WR, 2, data); - - DBG_PRINT("write %08X\n", inf->gpio_val); -} - -static int x8h7_gpio_get_direction(struct gpio_chip *chip, unsigned offset) -{ - struct x8h7_gpio_info *inf = gpiochip_get_data(chip); - - DBG_PRINT("offset: %d\n", offset); - if (inf->gpio_dir & (1 << offset)) { - return GPIOF_DIR_OUT; - } - return GPIOF_DIR_IN; -} - - -static int x8h7_gpio_set_config(struct gpio_chip *chip, unsigned int offset, - unsigned long config) -{ -// struct x8h7_gpio_info *inf = gpiochip_get_data(chip); - uint8_t data[2]; - - DBG_PRINT("offset: %d, config: %ld\n", offset, config); - data[0] = offset; - switch (pinconf_to_config_param(config)) { - case PIN_CONFIG_DRIVE_OPEN_DRAIN: - data[1] = GPIO_MODE_OUTPUT_OD; - break; - case PIN_CONFIG_DRIVE_PUSH_PULL: - data[1] = GPIO_MODE_OUTPUT_PP; - break; - default: - return -ENOTSUPP; - } - x8h7_pkt_send_sync(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_DIR, 2, data); - - return 0; -} - -static int x8h7_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct x8h7_gpio_info *inf = gpiochip_get_data(gc); - - if (inf->irq && offset < X8H7_GPIO_NUM) { - int irq; - irq = irq_create_mapping(inf->irq, offset); - DBG_PRINT("offset %d, irq %d\n", offset, irq); - return irq; - } else { - DBG_ERROR("\n"); - return -ENXIO; - } -} - -static void x8h7_gpio_irq_unmask(struct irq_data *d) -{ - struct x8h7_gpio_info *inf = irq_data_get_irq_chip_data(d); - uint8_t data[2]; - unsigned long irq; - - irq = irqd_to_hwirq(d); - inf->gpio_ien = 1; - - // Send mask - data[0] = irq; - data[1] = inf->gpio_ien; - x8h7_pkt_send_defer(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_IEN, 2, data); - inf->tx_cnt++; - - DBG_PRINT("irq %ld, ien %02X\n", irq, inf->gpio_ien); -} - -static void x8h7_gpio_irq_mask(struct irq_data *d) -{ - struct x8h7_gpio_info *inf = irq_data_get_irq_chip_data(d); - uint8_t data[2]; - unsigned long irq; - - irq = irqd_to_hwirq(d); - inf->gpio_ien = 0; - - // Send mask - data[0] = irq; - data[1] = inf->gpio_ien; - x8h7_pkt_send_defer(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_IEN, 2, data); - inf->tx_cnt++; - - DBG_PRINT("irq %ld, ien %02X\n", irq, inf->gpio_ien); -} - -static int x8h7_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) -{ - struct x8h7_gpio_info *inf = irq_data_get_irq_chip_data(d); - uint8_t data[2]; - unsigned long irq; - - irq = irqd_to_hwirq(d); - DBG_PRINT("irq %ld flow_type %d\n", irq, flow_type); - - switch (flow_type) { - case IRQ_TYPE_EDGE_RISING: - inf->irq_conf = GPIO_MODE_IN_RE; - break; - case IRQ_TYPE_EDGE_FALLING: - inf->irq_conf = GPIO_MODE_IN_FE; - break; - case IRQ_TYPE_EDGE_BOTH: - inf->irq_conf = GPIO_MODE_IN_RE | GPIO_MODE_IN_FE; - break; - case IRQ_TYPE_LEVEL_HIGH: - DBG_ERROR("trigger on active high not supported.\n"); - return -EINVAL; - break; - case IRQ_TYPE_LEVEL_LOW: - DBG_ERROR("trigger on active low not supported.\n"); - return -EINVAL; - break; - default: - return -EINVAL; - } - - // Send interrupt type - data[0] = irq; - data[1] = inf->irq_conf; - x8h7_pkt_send_defer(X8H7_GPIO_PERIPH, X8H7_GPIO_OC_IRQ_TYPE, 2, data); - inf->tx_cnt++; - - return 0; -} - -static void x8h7_gpio_irq_bus_lock(struct irq_data *d) -{ - struct x8h7_gpio_info *inf = irq_data_get_irq_chip_data(d); - - DBG_PRINT("\n"); - mutex_lock(&inf->lock); -} - -/* This is where we actually send spi packets to sync irq data */ -static void x8h7_gpio_irq_bus_sync_unlock(struct irq_data *d) -{ - struct x8h7_gpio_info *inf = irq_data_get_irq_chip_data(d); - - DBG_PRINT("\n"); - - /* Invoke send only if there are pending events */ - if(inf->tx_cnt != 0) { - x8h7_pkt_send_now(); - inf->tx_cnt = 0; - } - mutex_unlock(&inf->lock); -} - -static struct irq_chip x8h7_gpio_irq_chip = { - .name = "x8h7_gpio-irq", - .irq_unmask = x8h7_gpio_irq_unmask, - .irq_mask = x8h7_gpio_irq_mask, - .irq_set_type = x8h7_gpio_irq_set_type, - .irq_bus_lock = x8h7_gpio_irq_bus_lock, - .irq_bus_sync_unlock = x8h7_gpio_irq_bus_sync_unlock, -}; - -static int x8h7_gpio_irq_map(struct irq_domain *h, unsigned int irq, - irq_hw_number_t hwirq) -{ - irq_set_chip_data(irq, h->host_data); - irq_set_chip_and_handler(irq, &x8h7_gpio_irq_chip, handle_edge_irq); - irq_set_nested_thread(irq, 1); - irq_set_noprobe(irq); - - return 0; -} - -static const struct irq_domain_ops x8h7_gpio_irq_ops = { - .map = x8h7_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static int x8h7_gpio_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) -{ - return 0; -} - -static const char *x8h7_gpio_pinctrl_get_group_name(struct pinctrl_dev *pctldev, - unsigned int group) -{ - return NULL; -} - -static int x8h7_gpio_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, - unsigned int group, - const unsigned int **pins, - unsigned int *num_pins) -{ - return -ENOTSUPP; -} - -static const struct pinctrl_ops x8h7_gpio_pinctrl_ops = { - .get_groups_count = x8h7_gpio_pinctrl_get_groups_count, - .get_group_name = x8h7_gpio_pinctrl_get_group_name, - .get_group_pins = x8h7_gpio_pinctrl_get_group_pins, -// @TODO: fixme map ops needed? -#if 0 -#ifdef CONFIG_OF - dt_node_to_map = pinconf_generic_dt_node_to_map_pin, - dt_free_map = pinctrl_utils_free_map, -#endif -#endif -}; - -static int x8h7_gpio_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, - unsigned long *config) -{ - struct x8h7_gpio_info *inf = pinctrl_dev_get_drvdata(pctldev); - unsigned int param = pinconf_to_config_param(*config); - int ret; - u32 arg; - - switch (param) { - case PIN_CONFIG_OUTPUT: - ret = x8h7_gpio_get_direction(&inf->gc, pin); - if (ret < 0) - return ret; - - if (ret) - return -EINVAL; - - ret = x8h7_gpio_get(&inf->gc, pin); - if (ret < 0) - return ret; - - arg = ret; - break; - - default: - DBG_ERROR("Feature not supported, param = %d", param); - return -ENOTSUPP; - } - - *config = pinconf_to_config_packed(param, arg); - - return 0; -} - -static int x8h7_gpio_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - unsigned long *configs, unsigned int num_configs) -{ - struct x8h7_gpio_info *inf = pinctrl_dev_get_drvdata(pctldev); - enum pin_config_param param; - u32 arg; - int i; - int ret; - - for (i = 0; i < num_configs; i++) { - param = pinconf_to_config_param(configs[i]); - arg = pinconf_to_config_argument(configs[i]); - - switch (param) { - case PIN_CONFIG_OUTPUT: - ret = x8h7_gpio_direction_output(&inf->gc, - pin, arg); - if (ret < 0) - return ret; - - break; - - default: - DBG_ERROR("Feature not supported, param = %d", param); - return -ENOTSUPP; - } - } /* for each config */ - - return 0; -} - -static const struct pinconf_ops x8h7_gpio_pinconf_ops = { - .pin_config_get = x8h7_gpio_pinconf_get, - .pin_config_set = x8h7_gpio_pinconf_set, - .is_generic = true, -}; - -static int x8h7_gpio_probe(struct platform_device *pdev) -{ - struct x8h7_gpio_info *inf; - struct device_node *node = pdev->dev.of_node; - int base; - int ret; - - inf = devm_kzalloc(&pdev->dev, sizeof(*inf), GFP_KERNEL); - if (!inf) { - return -ENODEV; - } - - ret = of_property_read_u32(node, "base", &base); - if (ret) { - base = 160; - DBG_ERROR("reading GPIO base from DTB failed, use default\n"); - } - - inf->dev = &pdev->dev; - init_waitqueue_head(&inf->wait); - inf->rx_cnt = 0; - inf->tx_cnt = 0; - - mutex_init(&inf->lock); - - INIT_WORK(&inf->work, gpio_irq_ack_work_func); - inf->workqueue = create_workqueue("x8h7_gpio_irq_ack_work"); - if (!inf->workqueue) { - DBG_ERROR("Failed to create work queue\n"); - ret = -ENOMEM; - } - - /* Pinctrl_desc */ - inf->pinctrl_desc.name = "x8h7_gpio-pinctrl"; - inf->pinctrl_desc.pctlops = &x8h7_gpio_pinctrl_ops; - inf->pinctrl_desc.confops = &x8h7_gpio_pinconf_ops; - inf->pinctrl_desc.pins = x8h7_gpio_34_pins; - inf->pinctrl_desc.npins = X8H7_GPIO_NUM; - inf->pinctrl_desc.owner = THIS_MODULE; - - ret = devm_pinctrl_register_and_init(inf->dev, &inf->pinctrl_desc, - inf, &inf->pctldev); - if (ret) { - DBG_ERROR("Failed to register pinctrl device\n"); - return ret; - } - - ret = pinctrl_enable(inf->pctldev); - if (ret) { - DBG_ERROR("Failed to enable pinctrl device\n"); - return ret; - } - - /* Register GPIO controller */ - inf->gc.label = "x8h7_gpio"; - inf->gc.direction_input = x8h7_gpio_direction_input; - inf->gc.get = x8h7_gpio_get; - inf->gc.direction_output = x8h7_gpio_direction_output; - inf->gc.set = x8h7_gpio_set; - inf->gc.get_direction = x8h7_gpio_get_direction; - inf->gc.set_config = x8h7_gpio_set_config; - inf->gc.to_irq = x8h7_gpio_to_irq; - inf->gc.base = base; - inf->gc.ngpio = X8H7_GPIO_NUM; - inf->gc.parent = &pdev->dev; -#ifdef CONFIG_OF_GPIO - inf->gc.of_node = pdev->dev.of_node; -#endif - - inf->irq = irq_domain_add_linear(node, X8H7_GPIO_NUM, - &x8h7_gpio_irq_ops, inf); - if (!inf->irq) { - DBG_ERROR("Failed to add irq domain\n"); - //return 0; - } - - platform_set_drvdata(pdev, inf); - - ret = devm_gpiochip_add_data(inf->dev, &inf->gc, inf); - if (ret < 0) { - DBG_ERROR("Failed to add gpio\n"); - return ret; - } - - x8h7_hook_set(X8H7_GPIO_PERIPH, x8h7_gpio_hook, inf); - - return 0; -} - -static int x8h7_gpio_remove(struct platform_device *pdev) -{ -// struct x8h7_gpio_info *inf = platform_get_drvdata(pdev); - - return 0; -} - -static const struct of_device_id x8h7_gpio_of_match[] = { - { .compatible = "portenta,x8h7_gpio"}, - { }, -}; - -static struct platform_driver x8h7_gpio_driver = { - .driver = { - .name = "x8h7_gpio", - .of_match_table = x8h7_gpio_of_match, - }, - .probe = x8h7_gpio_probe, - .remove = x8h7_gpio_remove, -}; - -module_platform_driver(x8h7_gpio_driver); - -MODULE_AUTHOR("Massimiliano Agneni -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "x8h7.h" -#include "x8h7_ioctl.h" - -#define DRIVER_NAME "x8h7_h7" - -//#define DEBUG -#include "debug.h" - -// Peripheral code -#define X8H7_H7_PERIPH 0x09 -// Op code -#define X8H7_H7_OC_FW_GET 0x10 -#define X8H7_GET_UID_REQ 0x78 -#define X8H7_GET_UID_RSP 0x78 - - -#define X8H7_H7_DATA_MAX (4096) -#define X8H7_H7_LIST_SIZE 16 -#define X8H7_H7_RX_TIMEOUT (2 * HZ) - - -struct x8h7_h7_buf { - uint8_t data[X8H7_H7_DATA_MAX]; - uint16_t len; - struct list_head list; -}; - -struct x8h7_h7_priv { - struct device *dev; - dev_t dev_num; - struct cdev cdev; - struct class *cl; - - uint32_t mode; - - wait_queue_head_t wait; - int cnt; -/* - uint8_t rx_data[X8H7_H7_DATA_MAX]; - uint16_t rx_len; -*/ - x8h7_pkt_t rx_pkt; - - int rxindex; - struct list_head rxqueue; - struct x8h7_h7_buf buf[X8H7_H7_LIST_SIZE]; -}; - -union x8h7_h7_uid_message -{ - struct __attribute__((packed)) - { - uint32_t word0; - uint32_t word1; - uint32_t word2; - } field; - uint8_t buf[sizeof(uint32_t) /* word0 */ + sizeof(uint32_t) /* word1 */ + sizeof(uint32_t) /* word2 */]; -}; - -struct x8h7_h7_priv *x8h7_h7; -/* -static void x8h7_h7_init_rx_queue(struct x8h7_h7_priv *priv) -{ - int i; - - INIT_LIST_HEAD(&priv->rxqueue); - for (i=0; ibuf[i].buf.flags = V4L2_BUF_FLAG_MAPPED; - priv->buf[i].buf.bytesused = 0; - } -} -*/ - -static void x8h7_h7_hook(void *prv, x8h7_pkt_t *pkt) -{ - struct x8h7_h7_priv *priv = (struct x8h7_h7_priv *)prv; - /* - if ((pkt->peripheral == X8H7_H7_PERIPH) && - (pkt->opcode == X8H7_H7_OC_FW_GET) && - (pkt->size >= 1)) { - // copy fw version - pkt->data[pkt->size] = 0; - DBG_PRINT("FW ver size %d %s\n", pkt->size, pkt->data); - } -*/ - memcpy(&priv->rx_pkt, pkt, sizeof(x8h7_pkt_t)); - priv->cnt++; - wake_up_interruptible(&priv->wait); -} - -static int x8h7_h7_pkt_get(struct x8h7_h7_priv *priv) -{ - long ret; - - ret = wait_event_interruptible_timeout(priv->wait, - priv->cnt != 0, - X8H7_RX_TIMEOUT); - if (!ret) { - DBG_ERROR("timeout expired"); - return -1; - } - priv->cnt--; - return 0; -} - -static void x8h7_h7_dbg(void *prv, uint8_t *data, uint16_t len) -{ - struct x8h7_h7_priv *priv = (struct x8h7_h7_priv*)prv; - - //if (priv->cnt) { - //DBG_ERROR("Receive override cnt %d\n", priv->cnt); - //} - //DBG_PRINT("Received %d bytes\n", len); -/**/ - memcpy(priv->buf[priv->rxindex].data, data, len); - priv->buf[priv->rxindex].len = len; - list_add_tail(&priv->buf[priv->rxindex].list, &priv->rxqueue); - priv->rxindex++; - if (priv->rxindex >= X8H7_H7_LIST_SIZE) { - priv->rxindex = 0; - } -/**/ -/* - memcpy(priv->rx_data, data, len); - priv->rx_len = len; -*/ - priv->cnt++; - wake_up_interruptible(&priv->wait); -} - -static int x8h7_h7_open(struct inode *inode, struct file *file) -{ -// DBG_PRINT("\n"); - return 0; -} - -static int x8h7_h7_release(struct inode *inode, struct file *file) -{ -// DBG_PRINT("\n"); - return 0; -} - -static ssize_t x8h7_h7_read(struct file *file, - char __user *buf, size_t count, loff_t *offset) -{ - struct x8h7_h7_priv *priv = x8h7_h7; - long ret; - struct x8h7_h7_buf *rxbuf; - - if ((priv->mode & X8H7_MODE_DEBUG) == 0) { - return -1; - } - ret = wait_event_interruptible_timeout(priv->wait, - priv->cnt != 0, - X8H7_H7_RX_TIMEOUT); - if (!ret) { - return -1; - } -/**/ - rxbuf = list_entry(priv->rxqueue.next, struct x8h7_h7_buf, list); - list_del(priv->rxqueue.next); - if (count > rxbuf->len) { - count = rxbuf->len; - } - if (rxbuf->len) { - rxbuf->len = 0; - //DBG_PRINT("copy to user %d bytes\n", count); - if (copy_to_user(buf, rxbuf->data, count)) { - return -EFAULT; - } - } -/**/ -/* - if (count > priv->rx_len) { - count = priv->rx_len; - } - if (priv->rx_len) { - priv->rx_len = 0; - DBG_PRINT("copy to user %d bytes\n", count); - if (copy_to_user(buf, priv->rx_data, count)) { - return -EFAULT; - } - } -*/ - priv->cnt--; - return count; -} - -static ssize_t x8h7_h7_write(struct file *file, - const char __user *buf, size_t count, loff_t *offset) -{ - /* - size_t len; - unsigned long ret; - uint8_t data[X8H7_H7_DATA_MAX]; - - if (count >= X8H7_H7_DATA_MAX) { - len = X8H7_H7_DATA_MAX; - } else { - len = count; - } - - ret = copy_from_user(data, buf, len); - if (ret) { - DBG_ERROR("Could't copy %zd bytes from the user\n", ret); - return -EFAULT; - } - - x8h7_pkt_send_sync(X8H7_H7_PERIPH, X8H7_H7_OC_DATA, len, data); - - return len; - */ - return 0; -} - -static long x8h7_h7_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct x8h7_h7_priv *priv = x8h7_h7; - u32 tmp; - x8h7_pkt_t pkt; - long retval = 0; - - DBG_PRINT("cmd %X\n", cmd); - - if (unlikely(_IOC_TYPE(cmd) != X8H7_IOCTL_MAGIC)) { - DBG_ERROR("ioctl called with wrong magic number: %d\n", _IOC_TYPE(cmd)); - return -ENOTTY; - } - - if (unlikely(_IOC_NR(cmd) > X8H7_IOCTL_MAXNR)) { - DBG_ERROR("ioctl called with wrong command number: %d\n", _IOC_NR(cmd)); - return -ENOTTY; - } - switch (cmd) { - case X8H7_IOCTL_FW_VER: - x8h7_pkt_send_sync(X8H7_H7_PERIPH, X8H7_H7_OC_FW_GET, 0, NULL); - retval = x8h7_h7_pkt_get(priv); - if (retval < 0) { - return -ETIMEDOUT; - } - if ((priv->rx_pkt.peripheral == X8H7_H7_PERIPH) && - (priv->rx_pkt.opcode == X8H7_H7_OC_FW_GET) && - (priv->rx_pkt.size >= 1)) { - - if (copy_to_user((void __user *)arg, &priv->rx_pkt, sizeof(x8h7_pkt_t))) { - DBG_ERROR("couldn't version information to user."); - return -EFAULT; - } - //return priv->rx_pkt.size; - //pkt->data[pkt->size] = 0; - //DBG_PRINT("FW ver size %d %s\n", pkt->size, pkt->data); - retval = 0; - } else { - return -EFAULT; - } - - //pkt_dump("FW Version", (void*)&x8h7_spidev->rx_pkt); - break; - case X8H7_IOCTL_MODE_SET: - retval = get_user(tmp, (u32 __user *)arg); - if (retval == 0) { - priv->mode = tmp; - DBG_PRINT("Set mode to %08X\n", priv->mode); - if (priv->mode & X8H7_MODE_DEBUG) { - x8h7_dbg_set(x8h7_h7_dbg, x8h7_h7); - } else { - x8h7_dbg_set(NULL, NULL); - } - } - break; - case X8H7_IOCTL_MODE_GET: - retval = put_user(priv->mode, (__u32 __user *)arg); - break; - case X8H7_IOCTL_PKT_SYNC_SEND: - retval = copy_from_user(&pkt, (void __user *)arg, sizeof(pkt)); - if (retval == 0) { - retval = x8h7_pkt_send_sync(pkt.peripheral, pkt.opcode, pkt.size, pkt.data); - DBG_PRINT("x8h7_pkt_send_sync(%02X, %02X, %04X, ...) return %d\n", - pkt.peripheral, pkt.opcode, pkt.size, retval); - } - break; - default: - retval = -ENOTTY; - break; - } -/* -@TODO: if needed - case X8H7_IOCTL_INT_WAIT: - case X8H7_IOCTL_PKT_INIT: -*/ - if (retval) { - DBG_ERROR("ioctl return error: %ld\n", retval); - } - return retval; -} - - -ssize_t x8h7_read_firmware_version(char * buf, size_t const buf_size) -{ - struct x8h7_h7_priv * priv = x8h7_h7; - - x8h7_pkt_send_sync(X8H7_H7_PERIPH, X8H7_H7_OC_FW_GET, 0, NULL); - if (x8h7_h7_pkt_get(priv) < 0) - return -ETIMEDOUT; - - if ((priv->rx_pkt.peripheral == X8H7_H7_PERIPH) && - (priv->rx_pkt.opcode == X8H7_H7_OC_FW_GET) && - (priv->rx_pkt.size >= 1)) { - - memcpy(buf, - &priv->rx_pkt.data, - (priv->rx_pkt.size < buf_size) ? priv->rx_pkt.size : buf_size); - } else { - return -EFAULT; - } - - return strlen(buf); -} - -/* This function allows to read the current firmware of - * from the H7 and display it by reading from a sysfs node, - * i.e. - * $ cat /sys/kernel/x8h7_firmware/version - * 0.0.2-next-15c3fee-20220303-dirty - */ -static ssize_t sysfs_show_version(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return x8h7_read_firmware_version(buf, PAGE_SIZE); -} - -ssize_t x8h7_read_chip_uid(char * buf, size_t const buf_size) -{ - struct x8h7_h7_priv * priv = x8h7_h7; - - x8h7_pkt_send_sync(X8H7_H7_PERIPH, X8H7_GET_UID_REQ, 0, NULL); - if (x8h7_h7_pkt_get(priv) < 0) - return -ETIMEDOUT; - - if ((priv->rx_pkt.peripheral == X8H7_H7_PERIPH) && - (priv->rx_pkt.opcode == X8H7_GET_UID_RSP) && - (priv->rx_pkt.size >= 1)) { - - int i, len; - union x8h7_h7_uid_message msg; - - memcpy(msg.buf, - &priv->rx_pkt.data, - (priv->rx_pkt.size < buf_size) ? priv->rx_pkt.size : sizeof(msg.buf)); - - i = 0; len = 0; - for (i = 0; (i < sizeof(msg.buf)) && (len < buf_size); i++) - { - len += snprintf(buf + len, buf_size - len, "%02X", msg.buf[i]); - } - } else { - return -EFAULT; - } - - return strlen(buf); -} - -/* This function allows to read the unique chip id of the - * H7 and display it by reading from a sysfs node, - * i.e. - * $ cat /sys/kernel/x8h7_firmware/chip_uid - * 21002C000A51313032353139 - */ -static ssize_t sysfs_show_chip_uid(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return x8h7_read_chip_uid(buf, PAGE_SIZE); -} - -struct kobject *kobj_ref_x8h7_firmware_version; -struct kobj_attribute x8h7_firmware_version_attr = __ATTR(version, 0444, sysfs_show_version, NULL); -struct kobj_attribute x8h7_chip_uid_attr = __ATTR(chip_uid, 0444, sysfs_show_chip_uid, NULL); - - struct file_operations fops = { - .open = x8h7_h7_open, - .release = x8h7_h7_release, - .read = x8h7_h7_read, - .write = x8h7_h7_write, - .unlocked_ioctl = x8h7_h7_ioctl, -}; - -static int x8h7_h7_probe(struct platform_device *pdev) -{ - struct x8h7_h7_priv *priv; -// struct device_node *node = pdev->dev.of_node; - int ret; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - return -ENODEV; - } -/* - ret = of_property_read_u32(node, "base", &base); - if (ret) { - base = 0; - DBG_ERROR("reading param from DTB failed, use default\n"); - } -*/ - x8h7_h7 = priv; - platform_set_drvdata(pdev, priv); - - /* we will get the major number dynamically this is recommended please read ldd3*/ - ret = alloc_chrdev_region(&priv->dev_num, 0, 1, DRIVER_NAME); - if (ret < 0) { - DBG_ERROR("failed to allocate major number\n"); - return ret; - } - DBG_PRINT("major number of our device is %d\n", MAJOR(priv->dev_num)); - - DBG_PRINT("Class creation\n"); - priv->cl = class_create(THIS_MODULE, DRIVER_NAME); - if (priv->cl == NULL) { - DBG_ERROR("Class creation failed\n"); - unregister_chrdev_region(priv->dev_num, 1); - return -1; - } - - DBG_PRINT("Device creation\n"); - priv->dev = device_create(priv->cl, NULL, priv->dev_num, NULL, DRIVER_NAME); - if (IS_ERR(priv->dev)) { - DBG_ERROR("Device creation failed\n"); - class_destroy(priv->cl); - unregister_chrdev_region(priv->dev_num, 1); - return -1; - } - - DBG_PRINT("Device addition\n"); - cdev_init(&priv->cdev, &fops); - if (cdev_add(&priv->cdev, priv->dev_num, 1) == -1) { - DBG_ERROR("Device addition failed\n"); - device_destroy(priv->cl, priv->dev_num); - class_destroy(priv->cl); - unregister_chrdev_region(priv->dev_num, 1); - return -1; - } - - init_waitqueue_head(&priv->wait); -/**/ - INIT_LIST_HEAD(&priv->rxqueue); - priv->rxindex = 0; -/**/ - x8h7_hook_set(X8H7_H7_PERIPH, x8h7_h7_hook, priv); - - /* Creating a sysfs entry for reading the - * firmware version of the X8H7 firmware. - */ - kobj_ref_x8h7_firmware_version = kobject_create_and_add("x8h7_firmware", kernel_kobj); - if(sysfs_create_file(kobj_ref_x8h7_firmware_version, &x8h7_firmware_version_attr.attr)){ - DBG_ERROR("Cannot create 'x8h7_firmware' sysfs file\n"); - } - /* Creating a sysfs entry for reading the - * unique chip ID of the STM32H747. - */ - if(sysfs_create_file(kobj_ref_x8h7_firmware_version, &x8h7_chip_uid_attr.attr)){ - DBG_ERROR("Cannot create 'x8h7_chip_uid' sysfs file\n"); - } - - return 0; -} - -static int x8h7_h7_remove(struct platform_device *pdev) -{ - struct x8h7_h7_priv *priv = platform_get_drvdata(pdev); - - x8h7_hook_set(X8H7_H7_PERIPH, NULL, NULL); - cdev_del(&priv->cdev); - device_destroy(priv->cl, priv->dev_num); - class_destroy(priv->cl); - unregister_chrdev_region(priv->dev_num, 1); - return 0; -} - -static const struct of_device_id x8h7_h7_of_match[] = { - { .compatible = "portenta,x8h7_h7"}, - { }, -}; - -static struct platform_driver x8h7_h7_driver = { - .driver = { - .name = "x8h7_h7", - .of_match_table = x8h7_h7_of_match, - }, - .probe = x8h7_h7_probe, - .remove = x8h7_h7_remove, -}; - -module_platform_driver(x8h7_h7_driver); - -MODULE_AUTHOR("Massimiliano Agneni -#include - -#define X8H7_MODE_DEBUG 0x00000001 - -#define X8H7_IOCTL_MAGIC 0xB5 - -#define X8H7_IOCTL_MODE_SET _IOW (X8H7_IOCTL_MAGIC, 0, uint32_t*) -#define X8H7_IOCTL_MODE_GET _IOR (X8H7_IOCTL_MAGIC, 1, uint32_t*) -#define X8H7_IOCTL_FW_VER _IOR (X8H7_IOCTL_MAGIC, 2, x8h7_pkt_t*) -#define X8H7_IOCTL_PKT_INIT _IO (X8H7_IOCTL_MAGIC, 3) -#define X8H7_IOCTL_PKT_SYNC_SEND _IOW (X8H7_IOCTL_MAGIC, 4, x8h7_pkt_t*) - -#define X8H7_IOCTL_MAXNR 4 - -#endif /* __X8H7_IOCTL_H */ diff --git a/recipes-kernel/kernel-modules/x8h7/x8h7_pwm.c b/recipes-kernel/kernel-modules/x8h7/x8h7_pwm.c deleted file mode 100644 index 1244d9a5..00000000 --- a/recipes-kernel/kernel-modules/x8h7/x8h7_pwm.c +++ /dev/null @@ -1,191 +0,0 @@ -/** - * X8H7 PWM - * driver - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "x8h7.h" - -#define DRIVER_NAME "x8h7_pwm" - -//#define DEBUG -#include "debug.h" - -// Peripheral code -#define X8H7_PWM_PERIPH 0x02 - -struct __attribute__((packed, aligned(4))) pwmPacket { - uint8_t enable : 1; - uint8_t polarity: 1; - uint32_t duty : 30; - uint32_t period : 32; -}; - -struct x8h7_pwm_chip { - struct pwm_chip chip; - struct pwmPacket pkt; - wait_queue_head_t wait; - int cnt; -}; - -#define to_x8h7_pwm_chip(_chip) container_of(_chip, struct x8h7_pwm_chip, chip) - -static int x8h7_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) -{ - struct x8h7_pwm_chip *x8h7 = to_x8h7_pwm_chip(chip); - - DBG_PRINT("duty_ns: %d, period_ns: %d\n", duty_ns, period_ns); - //@TODO: period_ns must be greater than 953 - x8h7->pkt.duty = duty_ns; - x8h7->pkt.period = period_ns; - x8h7_pkt_send_sync(X8H7_PWM_PERIPH, pwm->hwpwm, sizeof(x8h7->pkt), &x8h7->pkt); - - return 0; -} - - -static void x8h7_pwm_hook(void *priv, x8h7_pkt_t *pkt) -{ - struct x8h7_pwm_chip *pwm = (struct x8h7_pwm_chip*)priv; - uint8_t ch; - - ch = pkt->opcode & 0xF; - if (ch < 10) { - struct pwmPacket* packet = (struct pwmPacket*)(pkt->data); - pwm->pkt.duty = packet->duty; - pwm->pkt.period = packet->period; - pwm->cnt++; - wake_up_interruptible(&pwm->wait); - } -} - -static int x8h7_pwm_pkt_get(struct x8h7_pwm_chip *pwm, unsigned int timeout) -{ - long ret; - - ret = wait_event_interruptible_timeout(pwm->wait, - pwm->cnt != 0, - timeout); - if (!ret) { - DBG_ERROR("timeout expired"); - return -1; - } - pwm->cnt--; - return 0; -} - -static int x8h7_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_capture *result, unsigned long timeout) -{ - struct x8h7_pwm_chip *x8h7 = to_x8h7_pwm_chip(chip); - - //@TODO: period_ns must be greater than 953 - x8h7_pkt_send_sync(X8H7_PWM_PERIPH, pwm->hwpwm | 0x60, sizeof(x8h7->pkt), &x8h7->pkt); - - x8h7->pkt.duty = 0; - x8h7->pkt.period = 0; - - if (x8h7_pwm_pkt_get(x8h7, timeout) < 0) - return -ETIMEDOUT; - - result->duty_cycle = x8h7->pkt.duty; - result->period = x8h7->pkt.period; - - DBG_PRINT("duty_ns: %d, period_ns: %d\n", result->duty_cycle, result->period); - - return 0; -} - -static int x8h7_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct x8h7_pwm_chip *x8h7 = to_x8h7_pwm_chip(chip); - - DBG_PRINT("\n"); - x8h7->pkt.enable = 1; - x8h7_pkt_send_sync(X8H7_PWM_PERIPH, pwm->hwpwm, sizeof(x8h7->pkt), &x8h7->pkt); - - return 0; -} - -static void x8h7_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct x8h7_pwm_chip *x8h7 = to_x8h7_pwm_chip(chip); - - DBG_PRINT("\n"); - x8h7->pkt.enable = 0; - x8h7_pkt_send_sync(X8H7_PWM_PERIPH, pwm->hwpwm, sizeof(x8h7->pkt), &x8h7->pkt); -} - -static const struct pwm_ops x8h7_pwm_ops = { - .config = x8h7_pwm_config, - .enable = x8h7_pwm_enable, - .disable = x8h7_pwm_disable, - .capture = x8h7_pwm_capture, - .owner = THIS_MODULE, -}; - -static const struct of_device_id x8h7_pwm_dt_ids[] = { - { .compatible = "portenta,x8h7_pwm", }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, x8h7_pwm_dt_ids); - -static int x8h7_pwm_probe(struct platform_device *pdev) -{ - struct x8h7_pwm_chip *x8h7_pwm; - int ret; - - x8h7_pwm = devm_kzalloc(&pdev->dev, sizeof(*x8h7_pwm), GFP_KERNEL); - if (!x8h7_pwm) { - return -ENOMEM; - } - - x8h7_pwm->chip.dev = &pdev->dev; - x8h7_pwm->chip.ops = &x8h7_pwm_ops; - x8h7_pwm->chip.base = -1; - x8h7_pwm->chip.npwm = 10; - - init_waitqueue_head(&x8h7_pwm->wait); - - ret = pwmchip_add(&x8h7_pwm->chip); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add PWM chip %d\n", ret); - return ret; - } - - platform_set_drvdata(pdev, x8h7_pwm); - - x8h7_hook_set(X8H7_PWM_PERIPH, x8h7_pwm_hook, x8h7_pwm); - - return ret; -} - -static int x8h7_pwm_remove(struct platform_device *pdev) -{ - struct x8h7_pwm_chip *x8h7_pwm = platform_get_drvdata(pdev); - - return pwmchip_remove(&x8h7_pwm->chip); -} - -static struct platform_driver x8h7_pwm_driver = { - .driver = { - .name = DRIVER_NAME, - .of_match_table = of_match_ptr(x8h7_pwm_dt_ids), - }, - .probe = x8h7_pwm_probe, - .remove = x8h7_pwm_remove, -}; -module_platform_driver(x8h7_pwm_driver); - -MODULE_ALIAS("platform:x8h7-pwm"); -MODULE_AUTHOR("Massimiliano Agneni "); -MODULE_DESCRIPTION("Aeduino portenta X8 PWM driver"); -MODULE_LICENSE("GPL v2"); diff --git a/recipes-kernel/kernel-modules/x8h7/x8h7_rtc.c b/recipes-kernel/kernel-modules/x8h7/x8h7_rtc.c deleted file mode 100644 index 7cbfb037..00000000 --- a/recipes-kernel/kernel-modules/x8h7/x8h7_rtc.c +++ /dev/null @@ -1,252 +0,0 @@ -/** - * X8H7 RTC driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "x8h7.h" - -#define DRIVER_NAME "x8h7_rtc" -#define DEVICE_NAME "x8h7_rtc" - -//#define DEBUG -#include "debug.h" - -// Peripheral code -#define X8H7_RTC_PERIPH 0x06 -// Op code -#define X8H7_RTC_SET_DATE 0x01 -#define X8H7_RTC_GET_DATE 0x02 -#define X8H7_RTC_SET_ALARM 0x11 -#define X8H7_RTC_GET_ALARM 0x12 -#define X8H7_RTC_ALARM_IEN 0x13 -#define X8H7_RTC_ALARM_INT 0x14 - -struct x8h7_rtc { - struct rtc_device *rtc; - int alarm_enabled; - int alarm_pending; - wait_queue_head_t wait; - int rx_cnt; - x8h7_pkt_t rx_pkt; -}; - -static void x8h7_rtc_hook(void *priv, x8h7_pkt_t *pkt) -{ - struct x8h7_rtc *rtc = (struct x8h7_rtc*)priv; - - if ((pkt->peripheral == X8H7_RTC_PERIPH) && - (pkt->opcode == X8H7_RTC_ALARM_INT) && - (pkt->size == 1)) { - rtc->alarm_pending = 1; - rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); - } else { - memcpy(&rtc->rx_pkt, pkt, sizeof(x8h7_pkt_t)); - rtc->rx_cnt++; - wake_up_interruptible(&rtc->wait); - } -} - -static int x8h7_rtc_pkt_get(struct x8h7_rtc *rtc) -{ - long ret; - - ret = wait_event_interruptible_timeout(rtc->wait, - rtc->rx_cnt != 0, - X8H7_RX_TIMEOUT); - if (!ret) { - DBG_ERROR("timeout expired"); - return -1; - } - rtc->rx_cnt--; - return 0; -} - -static int x8h7_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - struct x8h7_rtc *rtc = dev_get_drvdata(dev); - - DBG_PRINT("\n"); - x8h7_pkt_send_sync(X8H7_RTC_PERIPH, X8H7_RTC_GET_DATE, 0, NULL); - if (x8h7_rtc_pkt_get(rtc) < 0) - return -ETIMEDOUT; - - if ((rtc->rx_pkt.peripheral == X8H7_RTC_PERIPH) && - (rtc->rx_pkt.opcode == X8H7_RTC_GET_DATE) && - (rtc->rx_pkt.size == 7)) { - tm->tm_sec = rtc->rx_pkt.data[0x00]; - tm->tm_min = rtc->rx_pkt.data[0x01]; - tm->tm_hour = rtc->rx_pkt.data[0x02]; - tm->tm_mday = rtc->rx_pkt.data[0x03]; - tm->tm_mon = rtc->rx_pkt.data[0x04]; - tm->tm_year = rtc->rx_pkt.data[0x05] + 100; - tm->tm_wday = rtc->rx_pkt.data[0x06]; - } else { - DBG_ERROR("Invalid response\n"); - } - return 0; -} - -static int x8h7_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - uint8_t data[7]; - - DBG_PRINT("%02d:%02d:%02d %d/%d/%d\n", - tm->tm_hour, tm->tm_min, tm->tm_sec, - tm->tm_year, tm->tm_mon, tm->tm_mday); - - data[0x00] = tm->tm_sec ; - data[0x01] = tm->tm_min ; - data[0x02] = tm->tm_hour; - data[0x03] = tm->tm_mday; - data[0x04] = tm->tm_mon ; - data[0x05] = tm->tm_year - 100; - data[0x06] = tm->tm_wday; - - x8h7_pkt_send_sync(X8H7_RTC_PERIPH, X8H7_RTC_SET_DATE, 7, data); - - return 0; -} - -/* -struct rtc_wkalrm { - unsigned char enabled; // 0 = alarm disabled, 1 = alarm enabled - unsigned char pending; // 0 = alarm not pending, 1 = alarm pending - struct rtc_time time; // time the alarm is set to -}; -*/ -int x8h7_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wa) -{ - struct x8h7_rtc *rtc = dev_get_drvdata(dev); - - DBG_PRINT("\n"); - - wa->enabled = rtc->alarm_enabled; - wa->pending = rtc->alarm_pending; - - x8h7_pkt_send_sync(X8H7_RTC_PERIPH, X8H7_RTC_GET_ALARM, 0, NULL); - if (x8h7_rtc_pkt_get(rtc) < 0) - return -ETIMEDOUT; - - if ((rtc->rx_pkt.peripheral == X8H7_RTC_PERIPH) && - (rtc->rx_pkt.opcode == X8H7_RTC_GET_ALARM) && - (rtc->rx_pkt.size == 7)) { - wa->time.tm_sec = rtc->rx_pkt.data[0x00]; - wa->time.tm_min = rtc->rx_pkt.data[0x01]; - wa->time.tm_hour = rtc->rx_pkt.data[0x02]; - wa->time.tm_mday = rtc->rx_pkt.data[0x03]; - wa->time.tm_mon = rtc->rx_pkt.data[0x04]; - wa->time.tm_year = rtc->rx_pkt.data[0x05] + 100; - wa->time.tm_wday = rtc->rx_pkt.data[0x06]; - } else { - DBG_ERROR("Invalid response\n"); - } - return rtc_valid_tm(&wa->time);; -} - -int x8h7_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wa) -{ - struct x8h7_rtc *rtc = dev_get_drvdata(dev); - uint8_t data[7]; - - DBG_PRINT("%02d:%02d:%02d %d/%d/%d ena %d pending %d\n", - wa->time.tm_hour, wa->time.tm_min, wa->time.tm_sec, - wa->time.tm_year, wa->time.tm_mon, wa->time.tm_mday, - wa->enabled, wa->pending); - data[0x00] = wa->time.tm_sec ; - data[0x01] = wa->time.tm_min ; - data[0x02] = wa->time.tm_hour; - data[0x03] = wa->time.tm_mday; - data[0x04] = wa->time.tm_mon ; - data[0x05] = wa->time.tm_year - 100; - data[0x06] = wa->time.tm_wday; - - x8h7_pkt_send_sync(X8H7_RTC_PERIPH, X8H7_RTC_SET_ALARM, 7, data); - - if (!wa->enabled) { - rtc->alarm_pending = 0; - } - rtc->alarm_enabled = wa->enabled; - return 0; -} - -int x8h7_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct x8h7_rtc *rtc = dev_get_drvdata(dev); - uint8_t data[1]; - - rtc->alarm_enabled = enabled; - - if (enabled) { - data[0] = RTC_AF; - } else { - data[0] = ~RTC_AF; - } - x8h7_pkt_send_sync(X8H7_RTC_PERIPH, X8H7_RTC_ALARM_IEN, 1, data); - return 0; -} - -static const struct rtc_class_ops x8h7_rtc_ops = { - .read_time = x8h7_rtc_read_time, - .set_time = x8h7_rtc_set_time, -#if 0 - .read_alarm = x8h7_rtc_read_alarm, - .set_alarm = x8h7_rtc_set_alarm, - .alarm_irq_enable = x8h7_rtc_alarm_irq_enable, -#endif -}; - -static int x8h7_rtc_probe(struct platform_device *pdev) -{ - struct x8h7_rtc *p; - int err = -ENOMEM; - - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); - if (!p) { - goto out; - } - - init_waitqueue_head(&p->wait); - - platform_set_drvdata(pdev, p); - - p->rtc = devm_rtc_device_register(&pdev->dev, DEVICE_NAME, - &x8h7_rtc_ops, THIS_MODULE); - if (IS_ERR(p->rtc)) { - err = PTR_ERR(p->rtc); - goto out; - } - - x8h7_hook_set(X8H7_RTC_PERIPH, x8h7_rtc_hook, p); - - err = 0; -out: - return err; -} - -static const struct of_device_id x8h7_rtc_dt_ids[] = { - { .compatible = "portenta,x8h7_rtc", }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, x8h7_rtc_dt_ids); - -static struct platform_driver x8h7_rtc_driver = { - .driver = { - .name = DRIVER_NAME, - .of_match_table = of_match_ptr(x8h7_rtc_dt_ids), - }, - .probe = x8h7_rtc_probe, -}; - -module_platform_driver(x8h7_rtc_driver); - -MODULE_AUTHOR("Massimiliano Agneni -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "x8h7.h" - -#define DRIVER_NAME "x8h7_uart" - -//#define DEBUG -#include "debug.h" - -#define PORT_X8H7_UART 1000 // @TODO: add this define in serial.h - - -#define X8H7_UART_BAUD_MIN 0 -#define X8H7_UART_BAUD_MAX 2000000 - -// Peripheral code -#define X8H7_UART_PERIPH 0x05 - -// Op code -#define X8H7_UART_OC_CONFIGURE 0x10 // BAUD | DATA_MODE 2 byte -#define X8H7_UART_OC_GET_LINESTATE 0x20 // 2 byte -#define X8H7_UART_OC_DATA 0x01 // variable -#define X8H7_UART_OC_STATUS 0x02 // received uart status e.g. busy state - -// byte size -#define X8H7_UART_CFG_BS_5 0x0001 -#define X8H7_UART_CFG_BS_6 0x0001 -#define X8H7_UART_CFG_BS_7 0x0001 -#define X8H7_UART_CFG_BS_8 0x0001 - -// stop bits -#define X8H7_UART_CFG_SB_1 0x0000 -#define X8H7_UART_CFG_SB_2 0x0001 - -// parity -#define X8H7_UART_CFG_PAR_N 0x0000 -#define X8H7_UART_CFG_PAR_O 0x0000 -#define X8H7_UART_CFG_PAR_E 0x0000 -#define X8H7_UART_CFG_PAR_M 0x0000 -#define X8H7_UART_CFG_PAR_S 0x0000 - -// mode -#define X8H7_UART_CFG_MODE_NORMAL 0x0000 -#define X8H7_UART_CFG_MODE_HWHS 0x0000 -#define X8H7_UART_CFG_MODE_RS485 0x0000 - -// uart control -#define X8H7_UART_CTRL_RS485 0x0001 -#define X8H7_UART_CTRL_RTS 0x0002 -#define X8H7_UART_CTRL_DTR 0x0004 -#define X8H7_UART_CTRL_DSR 0x0010 -#define X8H7_UART_CTRL_CTS 0x0020 -#define X8H7_UART_CTRL_DCD 0x0040 - -// uart status -#define X8H7_UART_STATUS_TX_EMPTY 0x01 - -enum UARTParity { - PARITY_EVEN = 0, - PARITY_ODD, - PARITY_NONE, -}; - -struct __attribute__((packed, aligned(4))) uartPacket { - uint8_t bits : 4; // LSB - uint8_t stop_bits : 2; - uint8_t parity : 2; - uint8_t flow_control: 1; - uint32_t baud : 23; // MSB -}; -// 32-9 MSB 8 7-6 5-4 3-0 LSB - -#define to_x8h7_uart_port(_port) \ - container_of(_port, struct x8h7_uart_port, port) - -/** - */ -#define X8H7_UART_MAJOR 204 -#define MINOR_START 5 - -#define X8H7_UART_NR_PORTS 1 - - -#define X8H7_UART_CFG_SEND 0x00000001 -#define X8H7_UART_TRANSMIT 0x00000002 - -/* - * This determines how often we check the modem status signals - * for any change. They generally aren't connected to an IRQ - * so we have to poll them. We also check immediately before - * filling the TX fifo in case CTS has been dropped. - */ -#define MCTRL_TIMEOUT (250*HZ/1000) - -struct x8h7_uart_port { - struct uart_port port; - struct timer_list timer; - unsigned int old_status; - - /* Low level I/O work */ - struct work_struct work; - struct workqueue_struct *workqueue; - uint32_t flags; - - struct uartPacket cfg; - - /* X8H7 */ - wait_queue_head_t wait; - int rx_cnt; - x8h7_pkt_t rx_pkt; - uint8_t status; // used to handle busy tx and other stuff -}; - -struct x8h7_uart_port x8h7_uart_ports[X8H7_UART_NR_PORTS]; - -static void x8h7_uart_stop_tx(struct uart_port *port); -static void x8h7_uart_mctrl_check(struct x8h7_uart_port *sport); -static void x8h7_uart_rx_chars(struct x8h7_uart_port *sport); -static void x8h7_uart_tx_chars(struct x8h7_uart_port *sport); - - -/** - */ -static void x8h7_uart_hook(void *priv, x8h7_pkt_t *pkt) -{ - struct x8h7_uart_port *sport = (struct x8h7_uart_port*)priv; - - memcpy(&sport->rx_pkt, pkt, sizeof(x8h7_pkt_t)); - - switch(sport->rx_pkt.opcode) { - case X8H7_UART_OC_DATA: - /* Byte or break signal received */ - x8h7_uart_rx_chars(sport); - break; - case X8H7_UART_OC_STATUS: - sport->status = sport->rx_pkt.data[0]; // @TODO: implement this on H7 side - break; - } - - sport->rx_cnt++; -} - -/** - */ -static void x8h7_uart_rx_chars(struct x8h7_uart_port *sport) -{ - unsigned int ch; - int i; - int ret; - - DBG_PRINT("size: %d\n", sport->rx_pkt.size); - for (i=0 ; irx_pkt.size; i++) { - ch = sport->rx_pkt.data[0 + i]; - ret = uart_handle_sysrq_char(&sport->port, ch); - if (!ret) { - // @TODO: fix parameters - unsigned int status = 0; - unsigned int overrun = 0; - unsigned int flg = TTY_NORMAL; - DBG_PRINT("add char '%c'\n", ch); - uart_insert_char(&sport->port, status, overrun, ch, flg); - sport->port.icount.rx++; - } - } - - //spin_unlock(&sport->port.lock); - tty_flip_buffer_push(&sport->port.state->port); - //spin_lock(&sport->port.lock); -} - -/** - */ -static void x8h7_uart_tx_chars(struct x8h7_uart_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - -#if 0 - //@TODO Xon Xoff protocol - size = 0; - - if (sport->port.x_char) { - data[size] = sport->port.x_char; - size++; - sport->port.icount.tx++; - sport->port.x_char = 0; - return; - } -#endif - /* - * Check the modem control lines before - * transmitting anything. - */ - x8h7_uart_mctrl_check(sport); - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - x8h7_uart_stop_tx(&sport->port); - return; - } - - /* - * TX while bytes available - */ - sport->flags |= X8H7_UART_TRANSMIT; - DBG_PRINT("work queue triggered\n"); - queue_work(sport->workqueue, &sport->work); -} - -/** - * Handle any change of modem status signal since we were last called. - */ -static void x8h7_uart_mctrl_check(struct x8h7_uart_port *sport) -{ - unsigned int status, changed; - - status = sport->port.ops->get_mctrl(&sport->port); - changed = status ^ sport->old_status; - - if (changed == 0) { - return; - } - sport->old_status = status; - - if (changed & TIOCM_RI) { - sport->port.icount.rng++; - } - if (changed & TIOCM_DSR) { - sport->port.icount.dsr++; - } - if (changed & TIOCM_CAR) { - uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); - } - if (changed & TIOCM_CTS) { - uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - } -} - -/** - * This is our per-port timeout handler, for checking the - * modem status signals: RI DSR CAR CTS. - */ -/*static void x8h7_uart_timeout(struct timer_list *t) -{ -}*/ - -/** - * Stop receiving - port is in process of being closed. - */ -static void x8h7_uart_stop_rx(struct uart_port *port) -{ - DBG_PRINT("No operation\n"); -} - -/** - * Return TIOCSER_TEMT when transmitter is not busy. - * @TODO: need to understand when H7 is still busy - * in trasmitting data on uart due to slower throughput in - * comparison with spi. Introduce status byte? - */ -static unsigned int x8h7_uart_tx_empty(struct uart_port *port) -{ - struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - return ((sport->flags & X8H7_UART_TRANSMIT) ? 0 : TIOCSER_TEMT); -} - -/** - */ -static void x8h7_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -//struct x8h7_uart_port *sport = (struct x8h7_uart_port *)port; - uint16_t control; - - DBG_PRINT("\n"); - control = 0; - - if (port->rs485.flags & SER_RS485_ENABLED) { - control |= X8H7_UART_CTRL_RS485; - } - if (mctrl & TIOCM_RTS) { - control |= X8H7_UART_CTRL_RTS; - } - if (mctrl & TIOCM_DTR) { - control |= X8H7_UART_CTRL_DTR; - } -//@TODO: tolto per BUG: scheduling while atomic: insmod/573/0x00000002 trovare un sistema - //x8h7_pkt_send_sync(X8H7_UART_PERIPH, X8H7_UART_OC_GET_LINESTATE, 2, &control); -} - -/** - */ -static unsigned int x8h7_uart_get_mctrl(struct uart_port *port) -{ - /* DCD and DSR are not wired and CTS/RTS is handled automatically - * so just indicate DSR and CAR asserted - * @TODO: add also TIOCM_CTS? - */ - return TIOCM_DSR | TIOCM_CAR; -} - -/** - * - */ -static void x8h7_uart_stop_tx(struct uart_port *port) -{ - DBG_PRINT("No operation\n"); -} - -/** - * - */ -static void x8h7_uart_start_tx(struct uart_port *port) -{ - struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - - DBG_PRINT("\n"); - x8h7_uart_tx_chars(sport); -} - -/** - * Control the transmission of a break signal - */ -static void x8h7_uart_break_ctl(struct uart_port *port, int break_state) -{ - struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - unsigned long flags; - - DBG_PRINT("\n"); - spin_lock_irqsave(&sport->port.lock, flags); - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -/** - * Perform initialization and enable port for reception - */ -static int x8h7_uart_startup(struct uart_port *port) -{ - //struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - - return 0; -} - -/** - * Disable the port - */ -static void x8h7_uart_shutdown(struct uart_port *port) -{ - //struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - DBG_PRINT("\n"); - /* - * Disable all interrupts - * Clear all interrupts - * Free the interrupt - */ - //destroy_workqueue(sport->workqueue); -} - -/** - * Change the port parameters - */ -static void x8h7_uart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - unsigned int baud; - - memset(&sport->cfg, 0, sizeof(sport->cfg)); - - /* byte size */ - /* - switch (termios->c_cflag & CSIZE) { - case CS5: - sport->cfg |= X8H7_UART_CFG_BS_5; - break; - case CS6: - sport->cfg |= X8H7_UART_CFG_BS_6; - break; - case CS7: - sport->cfg |= X8H7_UART_CFG_BS_7; - break; - default: - sport->cfg |= X8H7_UART_CFG_BS_8; - break; - } -*/ - switch (termios->c_cflag & CSIZE) { - case CS7: - sport->cfg.bits = 7; - break; - default: - sport->cfg.bits = 8; - break; - } - - /* stop bits */ - /*if (termios->c_cflag & CSTOPB) { - sport->cfg |= X8H7_UART_CFG_SB_2; - }*/ - if (termios->c_cflag & CSTOPB) { - sport->cfg.stop_bits = 2; - } else { - sport->cfg.stop_bits = 1; - } - - /* parity */ - /* - if (termios->c_cflag & PARENB) { - // Mark or Space parity - if (termios->c_cflag & CMSPAR) { - if (termios->c_cflag & PARODD) { - sport->cfg |= X8H7_UART_CFG_PAR_M; - } else { - sport->cfg |= X8H7_UART_CFG_PAR_S; - } - } else if (termios->c_cflag & PARODD) { - sport->cfg |= X8H7_UART_CFG_PAR_O; - } else { - sport->cfg |= X8H7_UART_CFG_PAR_E; - } - } else { - sport->cfg |= X8H7_UART_CFG_PAR_N; - } -*/ - if (termios->c_cflag & PARENB) { - if (termios->c_cflag & PARODD) { - sport->cfg.parity |= PARITY_ODD; - } else { - sport->cfg.parity |= PARITY_EVEN; - } - } else { - sport->cfg.parity = PARITY_NONE; - } - - /* baud */ - baud = uart_get_baud_rate(port, termios, old, - X8H7_UART_BAUD_MIN, X8H7_UART_BAUD_MAX); - DBG_PRINT("baud: %d\n", baud); - - sport->cfg.baud = baud; - - /* - * disable interrupts and drain transmitter - * then, disable everything - * Reset the Rx and Tx FIFOs too - */ - sport->flags |= X8H7_UART_CFG_SEND; - DBG_PRINT("work queue triggered\n"); - queue_work(sport->workqueue, &sport->work); - - //spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static const char *x8h7_uart_type(struct uart_port *port) -{ - struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - - DBG_PRINT("\n"); - return sport->port.type == PORT_X8H7_UART ? "X8H7_UART" : NULL; -} - -/** - * - */ -static int x8h7_uart_request_port(struct uart_port *port) -{ - struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - - DBG_PRINT("\n"); - x8h7_hook_set(X8H7_UART_PERIPH, x8h7_uart_hook, sport); - return 0; -} - -/** - * - */ -static void x8h7_uart_release_port(struct uart_port *port) -{ - DBG_PRINT("\n"); - x8h7_hook_set(X8H7_UART_PERIPH, NULL, NULL); -} - -/* - * Configure/autoconfigure the port. - */ -static void x8h7_uart_config_port(struct uart_port *port, int flags) -{ - struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - - DBG_PRINT("\n"); - if (flags & UART_CONFIG_TYPE && - x8h7_uart_request_port(&sport->port) == 0) { - sport->port.type = PORT_X8H7_UART; - } -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - */ -static int x8h7_uart_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - //struct x8h7_uart_port *sport = to_x8h7_uart_port(port); - //int ret = 0; - - DBG_PRINT("\n"); - /* - if (ser->type != PORT_UNKNOWN && ser->type != PORT_X8H7_UART) - ret = -EINVAL; - if (sport->port.irq != ser->irq) - ret = -EINVAL; - if (ser->io_type != SERIAL_IO_MEM) - ret = -EINVAL; - if (sport->port.uartclk / 16 != ser->baud_base) - ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) - ret = -EINVAL; - if (sport->port.iobase != ser->port) - ret = -EINVAL; - if (ser->hub6 != 0) - ret = -EINVAL; - */ - return 0; //ret; -} - -static const struct uart_ops x8h7_uart_pops = { - .tx_empty = x8h7_uart_tx_empty, - .set_mctrl = x8h7_uart_set_mctrl, - .get_mctrl = x8h7_uart_get_mctrl, - .stop_tx = x8h7_uart_stop_tx, - .start_tx = x8h7_uart_start_tx, - .stop_rx = x8h7_uart_stop_rx, - .break_ctl = x8h7_uart_break_ctl, - .startup = x8h7_uart_startup, - .shutdown = x8h7_uart_shutdown, - .set_termios = x8h7_uart_set_termios, - .type = x8h7_uart_type, - .request_port = x8h7_uart_request_port, - .release_port = x8h7_uart_release_port, - .config_port = x8h7_uart_config_port, - .verify_port = x8h7_uart_verify_port, -}; - -/** - */ -static struct uart_driver x8h7_uart = { - .owner = THIS_MODULE, - .driver_name = "ttyX", - .dev_name = "ttyX", - .major = X8H7_UART_MAJOR, - .minor = MINOR_START, - .nr = X8H7_UART_NR_PORTS, - .cons = NULL, -}; - -/** - * main workqueue for uart module - */ -static void x8h7_uart_work_func(struct work_struct *work) -{ - struct x8h7_uart_port *sport = container_of(work, struct x8h7_uart_port, work); - - DBG_PRINT("work queue start\n"); - DBG_PRINT("FLAGS %08X\n", sport->flags); - - if (sport->flags & X8H7_UART_CFG_SEND) { - sport->flags &= ~X8H7_UART_CFG_SEND; - x8h7_pkt_send_sync(X8H7_UART_PERIPH, X8H7_UART_OC_CONFIGURE, - sizeof(sport->cfg), &sport->cfg); - } - if (sport->flags & X8H7_UART_TRANSMIT) { - struct circ_buf *xmit = &sport->port.state->xmit; - uint8_t txb[X8H7_PKT_SIZE]; - uint16_t size; - - sport->flags &= ~X8H7_UART_TRANSMIT; - - while (!uart_circ_empty(xmit)) { - - for (size = 0; size < X8H7_PKT_SIZE && !uart_circ_empty(xmit); size++) { - txb[size] = xmit->buf[xmit->tail]; - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } - - //send pkt - x8h7_pkt_send_sync(X8H7_UART_PERIPH, X8H7_UART_OC_DATA, size, txb); - - sport->port.icount.tx += size; - } - //uart_circ_clear(xmit); - } - DBG_PRINT("work queue end\n"); -} - -/** - */ -static int x8h7_uart_probe(struct platform_device *pdev) -{ - int i = 0; - - init_waitqueue_head(&x8h7_uart_ports[i].wait); - - x8h7_uart_ports[i].port.type = 150; - x8h7_uart_ports[i].port.fifosize = 32; - x8h7_uart_ports[i].port.flags = 0; - x8h7_uart_ports[i].port.iotype = SERIAL_IO_PORT; - x8h7_uart_ports[i].port.iobase = 0; - x8h7_uart_ports[i].port.membase = (void __iomem *)~0; - x8h7_uart_ports[i].port.uartclk = 24*1000*1000; - x8h7_uart_ports[i].port.ops = &x8h7_uart_pops; - - x8h7_uart_ports[i].port.line = 0; - x8h7_uart_ports[i].port.dev = &pdev->dev; - x8h7_uart_ports[i].port.irq = 0; - - uart_add_one_port(&x8h7_uart, &x8h7_uart_ports[i].port); - platform_set_drvdata(pdev, &x8h7_uart_ports[i]); - x8h7_hook_set(X8H7_UART_PERIPH, x8h7_uart_hook, &x8h7_uart_ports[i]); - - INIT_WORK(&x8h7_uart_ports[i].work, x8h7_uart_work_func); - x8h7_uart_ports[i].workqueue = create_workqueue("x8h7_uart_work"); - if (!x8h7_uart_ports[i].workqueue) { - DBG_ERROR("fail to create work queue\n"); - return -ENOMEM; - } - - DBG_PRINT("probed\n"); - return 0; -} - -static int x8h7_uart_remove(struct platform_device *pdev) -{ - struct x8h7_uart_port *sport = platform_get_drvdata(pdev); - - DBG_PRINT("destroying work queue\n"); - destroy_workqueue(sport->workqueue); - if (sport) { - uart_remove_one_port(&x8h7_uart, &sport->port); - } - return 0; -} - - -static const struct of_device_id x8h7_uart_dt_ids[] = { - { .compatible = "portenta,x8h7_uart" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, x8h7_uart_dt_ids); - -static struct platform_driver x8h7_uart_driver = { - .driver = { - .name = DRIVER_NAME, - .of_match_table = x8h7_uart_dt_ids, - }, - .probe = x8h7_uart_probe, - .remove = x8h7_uart_remove, -}; - -static int __init x8h7_uart_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: X8H7 UART driver\n"); - - ret = uart_register_driver(&x8h7_uart); - if (ret == 0) { - ret = platform_driver_register(&x8h7_uart_driver); - if (ret) { - uart_unregister_driver(&x8h7_uart); - } - } - return ret; -} - -static void __exit x8h7_uart_exit(void) -{ - platform_driver_unregister(&x8h7_uart_driver); - uart_unregister_driver(&x8h7_uart); -} - -module_init(x8h7_uart_init); -module_exit(x8h7_uart_exit); - -MODULE_AUTHOR("Massimiliano Agneni -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "x8h7.h" - -#define DRIVER_NAME "x8h7_ui" - -//#define DEBUG -#include "debug.h" - -// Peripheral code -#define X8H7_UI_PERIPH 0x0A -// Op code -#define X8H7_UI_OC_DATA 0x01 - -#define X8H7_UI_DATA_MAX (1 * 1024) - -struct x8h7_ui_priv { - struct device *dev; - dev_t dev_num; - struct cdev cdev; - struct class *cl; - - uint8_t rx_data[X8H7_UI_DATA_MAX]; - uint16_t rx_len; -}; - -static DECLARE_WAIT_QUEUE_HEAD(wq); - -struct x8h7_ui_priv *x8h7_ui; - -static void x8h7_ui_hook(void *prv, x8h7_pkt_t *pkt) -{ - struct x8h7_ui_priv *priv = (struct x8h7_ui_priv*)prv; - - //DBG_PRINT("received %d bytes\n", pkt->size); - if (priv->rx_len + pkt->size > X8H7_UI_DATA_MAX) { - goto wake_read; - } - - memcpy(&priv->rx_data[priv->rx_len], pkt->data, pkt->size); - priv->rx_len += pkt->size; - -wake_read: - wake_up_interruptible(&wq); -} - -static int x8h7_ui_open(struct inode *inode, struct file *file) -{ -// DBG_PRINT("\n"); - return 0; -} - -static int x8h7_ui_release(struct inode *inode, struct file *file) -{ -// DBG_PRINT("\n"); - return 0; -} - -/* -static long x8h7_ui_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - DBG_PRINT("\n"); - return 0; -} -*/ - -static ssize_t x8h7_ui_read(struct file *file, - char __user *buf, size_t count, loff_t *offset) -{ - struct x8h7_ui_priv *priv = x8h7_ui; - ssize_t ret; - - // call this only in case of O_BLOCK - wait_event_interruptible(wq, priv->rx_len != 0); - - *offset = 0; - //DBG_PRINT("cpoy to user %d bytes\n", count); - ret = simple_read_from_buffer(buf, count, offset, priv->rx_data, priv->rx_len); - priv->rx_len = 0; - - return ret; -} - -static ssize_t x8h7_ui_write(struct file *file, - const char __user *buf, size_t count, loff_t *offset) -{ - size_t len; - unsigned long ret; - uint8_t data[X8H7_UI_DATA_MAX]; - - if (count >= X8H7_UI_DATA_MAX) { - len = X8H7_UI_DATA_MAX; - } else { - len = count; - } - - ret = copy_from_user(data, buf, len); - if (ret) { - DBG_ERROR("Could't copy %zd bytes from the user\n", ret); - return -EFAULT; - } - - x8h7_pkt_send_sync(X8H7_UI_PERIPH, X8H7_UI_OC_DATA, len, data); - - return len; -} - - struct file_operations fops = { - .open = x8h7_ui_open, - .release = x8h7_ui_release, - .read = x8h7_ui_read, - .write = x8h7_ui_write, -}; - -static int x8h7_ui_probe(struct platform_device *pdev) -{ - struct x8h7_ui_priv *priv; -// struct device_node *node = pdev->dev.of_node; - int ret; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - return -ENODEV; - } -/* - ret = of_property_read_u32(node, "base", &base); - if (ret) { - base = 0; - DBG_ERROR("reading param from DTB failed, use default\n"); - } -*/ - x8h7_ui = priv; - platform_set_drvdata(pdev, priv); - - /* we will get the major number dynamically this is recommended please read ldd3*/ - ret = alloc_chrdev_region(&priv->dev_num, 0, 1, DRIVER_NAME); - if (ret < 0) { - DBG_ERROR("failed to allocate major number\n"); - return ret; - } - DBG_PRINT("major number of our device is %d\n", MAJOR(priv->dev_num)); - - DBG_PRINT("Class creation\n"); - priv->cl = class_create(THIS_MODULE, DRIVER_NAME); - if (priv->cl == NULL) { - DBG_ERROR("Class creation failed\n"); - unregister_chrdev_region(priv->dev_num, 1); - return -1; - } - - DBG_PRINT("Device creation\n"); - priv->dev = device_create(priv->cl, NULL, priv->dev_num, NULL, DRIVER_NAME); - if (IS_ERR(priv->dev)) { - DBG_ERROR("Device creation failed\n"); - class_destroy(priv->cl); - unregister_chrdev_region(priv->dev_num, 1); - return -1; - } - - DBG_PRINT("Device addition\n"); - cdev_init(&priv->cdev, &fops); - if (cdev_add(&priv->cdev, priv->dev_num, 1) == -1) { - DBG_ERROR("Device addition failed\n"); - device_destroy(priv->cl, priv->dev_num); - class_destroy(priv->cl); - unregister_chrdev_region(priv->dev_num, 1); - return -1; - } - - x8h7_ui->rx_len = 0; - - x8h7_hook_set(X8H7_UI_PERIPH, x8h7_ui_hook, priv); - - return 0; -} - -static int x8h7_ui_remove(struct platform_device *pdev) -{ - struct x8h7_ui_priv *priv = platform_get_drvdata(pdev); - - x8h7_hook_set(X8H7_UI_PERIPH, NULL, NULL); - cdev_del(&priv->cdev); - device_destroy(priv->cl, priv->dev_num); - class_destroy(priv->cl); - unregister_chrdev_region(priv->dev_num, 1); - return 0; -} - -static const struct of_device_id x8h7_ui_of_match[] = { - { .compatible = "portenta,x8h7_ui"}, - { }, -}; - -static struct platform_driver x8h7_ui_driver = { - .driver = { - .name = "x8h7_ui", - .of_match_table = x8h7_ui_of_match, - }, - .probe = x8h7_ui_probe, - .remove = x8h7_ui_remove, -}; - -module_platform_driver(x8h7_ui_driver); - -MODULE_AUTHOR("Massimiliano Agneni