pax_global_header 0000666 0000000 0000000 00000000064 12703306510 0014507 g ustar 00root root 0000000 0000000 52 comment=023fb0af7f4e09caba49cdc9d2996b2e261658fe
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/ 0000775 0000000 0000000 00000000000 12703306510 0021346 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/.gitignore 0000664 0000000 0000000 00000000146 12703306510 0023337 0 ustar 00root root 0000000 0000000 bin
tmp
Debug
Release
linux
sysroots
.project
.cproject
.externalToolBuilders
.settings
.pydevproject
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/README.md 0000664 0000000 0000000 00000003622 12703306510 0022630 0 ustar 00root root 0000000 0000000 # linux-elphel
Extras (drivers, etc.) and patches for the kernel
##Downloading
Code must be located in `poky/` directory. Navigate to `poky/` and run:
```
git clone https://github.com/Elphel/linux-elphel.git
```
##Generating links and headers
Links between project tree and kernel source tree are generated by Bitbake during 'link' task when using `meta-elphel393`. Some required header files are automatically generated during the build process.
```
. ./oe-init-build-env
bitbake linux-xlnx -c clean -f
bitbake linux-xlnx -c link -f
bitbake linux-xlnx -f
```
##Importing project into Eclipse
Run Eclipse from its location directory and provide additional heap memory to it.
```
./eclipse -vmargs -Xmx4G
```
- File → Import... → General → Existing Project into Workspace
- [Next] → Select root directory → Browse → specify project location (`poky/linux-elphel/`) → [OK] → [Finish]
Project now is imported into Eclipse workspace.
- Project → Properties
- C/C++ General → Preprocessor Include Paths → Entries → GNU C → CDT User Settings
- [Add...] → Select "Preprocessor macros file" → `linux/include/generated/autoconf.h` → [OK]
- [Add...] → Select "Preprocessor macros file" → `linux/include/linux/compiler.h` → [OK]
- [Add...] → Select "Include file" → `linux/include/linux/kconfig.h` → [OK]
- C/C++ General → Indexer
- Check “Enable project specific setttings”
- Check “Enable indexer”
- Uncheck “Index source files not included in the build”
- Uncheck “Index unused headers”
- Check “Index header variants”
- Uncheck “Index source and header files opened in editor”
- Uncheck “Allow heuristic resolution of includes”
- Set size of files to be skipped >100MB (effectively disabling this feature)
- Uncheck all “Skip…” options
- [OK] to close the Advanced Settings window.
- Project → C/C++ Index → Rebuild
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/ 0000775 0000000 0000000 00000000000 12703306510 0025740 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.cproject 0000664 0000000 0000000 00000337203 12703306510 0027562 0 ustar 00root root 0000000 0000000
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.externalToolBuilders/ 0000775 0000000 0000000 00000000000 12703306510 0032170 5 ustar 00root root 0000000 0000000 bitbake compile -f [Builder].launch 0000664 0000000 0000000 00000001372 12703306510 0040444 0 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.externalToolBuilders
bitbake compile [Builder].launch 0000664 0000000 0000000 00000001552 12703306510 0040161 0 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.externalToolBuilders
bitbake deploy [Builder].launch 0000664 0000000 0000000 00000001762 12703306510 0040030 0 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.externalToolBuilders
kernel modules [Builder].launch 0000664 0000000 0000000 00000001257 12703306510 0040062 0 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.externalToolBuilders
org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder.launch 0000664 0000000 0000000 00000001361 12703306510 0046207 0 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.externalToolBuilders
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.project 0000664 0000000 0000000 00000005211 12703306510 0027406 0 ustar 00root root 0000000 0000000
linux-elphel
org.eclipse.cdt.managedbuilder.core.genmakebuilder
full,incremental,
org.eclipse.ui.externaltools.ExternalToolBuilder
full,incremental,
LaunchConfigHandle
<project>/.externalToolBuilders/org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder.launch
org.eclipse.ui.externaltools.ExternalToolBuilder
clean,
LaunchConfigHandle
<project>/.externalToolBuilders/bitbake compile -f [Builder].launch
org.eclipse.ui.externaltools.ExternalToolBuilder
full,incremental,
LaunchConfigHandle
<project>/.externalToolBuilders/bitbake compile [Builder].launch
incclean
true
org.eclipse.ui.externaltools.ExternalToolBuilder
full,incremental,
LaunchConfigHandle
<project>/.externalToolBuilders/bitbake deploy [Builder].launch
incclean
true
org.eclipse.ui.externaltools.ExternalToolBuilder
full,incremental,
LaunchConfigHandle
<project>/.externalToolBuilders/kernel modules [Builder].launch
org.eclipse.cdt.core.cnature
org.eclipse.cdt.managedbuilder.core.managedBuildNature
org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
1416246125600
26
org.eclipse.ui.ide.multiFilter
1.0-name-matches-false-false-src
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.pydevproject 0000664 0000000 0000000 00000000456 12703306510 0030464 0 ustar 00root root 0000000 0000000
Default
python 2.7
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.settings/ 0000775 0000000 0000000 00000000000 12703306510 0027656 5 ustar 00root root 0000000 0000000 language.settings.xml 0000664 0000000 0000000 00000001117 12703306510 0033743 0 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.settings
org.eclipse.cdt.codan.core.prefs 0000664 0000000 0000000 00000024130 12703306510 0035635 0 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.settings eclipse.preferences.version=1
org.eclipse.cdt.codan.checkers.errnoreturn=Warning
org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
org.eclipse.cdt.codan.checkers.errreturnvalue=Error
org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.checkers.noreturn=Error
org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false}
org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()}
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true}
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error
org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()}
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false}
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false}
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")}
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
org.eclipse.cdt.core.prefs 0000664 0000000 0000000 00000002342 12703306510 0034553 0 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/eclipse_project_setup/.settings eclipse.preferences.version=1
environment/project/cdt.managedbuild.config.gnu.cross.exe.debug.903609687/PATH/delimiter=\:
environment/project/cdt.managedbuild.config.gnu.cross.exe.debug.903609687/PATH/operation=replace
environment/project/cdt.managedbuild.config.gnu.cross.exe.debug.903609687/PATH/value=${ProjDirPath}/sysroots/x86_64-linux/usr/bin/armv7a-vfp-neon-poky-linux-gnueabi/\:/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/usr/games\:/usr/local/games\:/usr/lib/jvm/java-8-oracle/bin\:/usr/lib/jvm/java-8-oracle/db/bin\:/usr/lib/jvm/java-8-oracle/jre/bin
environment/project/cdt.managedbuild.config.gnu.cross.exe.debug.903609687/append=true
environment/project/cdt.managedbuild.config.gnu.cross.exe.debug.903609687/appendContributed=true
indexer/indexAllFiles=false
indexer/indexAllHeaderVersions=true
indexer/indexAllVersionsSpecificHeaders=
indexer/indexOnOpen=true
indexer/indexUnusedHeadersWithDefaultLang=false
indexer/indexerId=org.eclipse.cdt.core.fastIndexer
indexer/skipFilesLargerThanMB=999
indexer/skipImplicitReferences=false
indexer/skipIncludedFilesLargerThanMB=999
indexer/skipMacroReferences=false
indexer/skipReferences=false
indexer/skipTypeReferences=false
indexer/useHeuristicIncludeResolution=false
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/run_bitbake.sh 0000775 0000000 0000000 00000000330 12703306510 0024166 0 ustar 00root root 0000000 0000000 #!/bin/bash
args="$@"
while (( "$#" )); do
shift
done
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo "Launching bitbake $args"
cd $DIR/..
. ./oe-init-build-env
bitbake $args | sed -u 's@| @@'
exit 0
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/ 0000775 0000000 0000000 00000000000 12703306510 0022135 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/ 0000775 0000000 0000000 00000000000 12703306510 0023613 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/Makefile 0000664 0000000 0000000 00000011460 12703306510 0025255 0 ustar 00root root 0000000 0000000 #
# Makefile for the Linux kernel device drivers.
#
# 15 Sep 2000, Christoph Hellwig
# Rewritten to use lists instead of if-statements.
#
obj-y += irqchip/
obj-y += bus/
obj-$(CONFIG_GENERIC_PHY) += phy/
# GPIO must come after pinctrl as gpios may need to mux pins etc
obj-y += pinctrl/
obj-y += gpio/
obj-y += pwm/
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/
obj-y += video/
obj-y += idle/
# IPMI must come before ACPI in order to provide IPMI opregion support
obj-$(CONFIG_IPMI_HANDLER) += char/ipmi/
obj-$(CONFIG_ACPI) += acpi/
obj-$(CONFIG_SFI) += sfi/
# PnP must come after ACPI since it will eventually need to check if acpi
# was used and do nothing if so
obj-$(CONFIG_PNP) += pnp/
obj-y += amba/
# Many drivers will want to use DMA so this has to be made available
# really early.
obj-$(CONFIG_DMADEVICES) += dma/
# SOC specific infrastructure drivers.
obj-y += soc/
obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_XEN) += xen/
# regulators early, since some subsystems rely on them to initialize
obj-$(CONFIG_REGULATOR) += regulator/
# reset controllers early, since gpu drivers might rely on them to initialize
obj-$(CONFIG_RESET_CONTROLLER) += reset/
# tty/ comes before char/ so that the VT console is the boot-time
# default.
obj-y += tty/
obj-y += char/
# iommu/ comes before gpu as gpu are using iommu controllers
obj-$(CONFIG_IOMMU_SUPPORT) += iommu/
# gpu/ comes after char for AGP vs DRM startup and after iommu
obj-y += gpu/
obj-$(CONFIG_CONNECTOR) += connector/
# i810fb and intelfb depend on char/agp/
obj-$(CONFIG_FB_I810) += video/fbdev/i810/
obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ nfc/
obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/
obj-$(CONFIG_NUBUS) += nubus/
obj-y += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_SCSI) += scsi/
obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_TARGET_CORE) += target/
obj-$(CONFIG_MTD) += mtd/
obj-$(CONFIG_SPI) += spi/
obj-$(CONFIG_SPMI) += spmi/
obj-y += hsi/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_FUSION) += message/
obj-y += firewire/
obj-$(CONFIG_UIO) += uio/
obj-$(CONFIG_VFIO) += vfio/
obj-y += cdrom/
obj-y += auxdisplay/
obj-$(CONFIG_PCCARD) += pcmcia/
obj-$(CONFIG_DIO) += dio/
obj-$(CONFIG_SBUS) += sbus/
obj-$(CONFIG_ZORRO) += zorro/
obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_UWB) += uwb/
obj-$(CONFIG_USB_PHY) += usb/
obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/
obj-$(CONFIG_SERIO) += input/serio/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
obj-y += i2c/ media/
obj-$(CONFIG_PPS) += pps/
obj-$(CONFIG_PTP_1588_CLOCK) += ptp/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/
obj-$(CONFIG_THERMAL) += thermal/
obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_ACCESSIBILITY) += accessibility/
obj-$(CONFIG_ISDN) += isdn/
obj-$(CONFIG_EDAC) += edac/
obj-$(CONFIG_EISA) += eisa/
obj-y += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_CPU_IDLE) += cpuidle/
obj-y += mmc/
obj-$(CONFIG_MEMSTICK) += memstick/
obj-y += leds/
obj-$(CONFIG_INFINIBAND) += infiniband/
obj-$(CONFIG_SGI_SN) += sn/
obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_ARCH_SHMOBILE) += sh/
ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
obj-y += clocksource/
endif
obj-$(CONFIG_DCA) += dca/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_BCMA) += bcma/
obj-$(CONFIG_VHOST_RING) += vhost/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
obj-y += platform/
#common clk code
obj-y += clk/
obj-$(CONFIG_MAILBOX) += mailbox/
obj-$(CONFIG_HWSPINLOCK) += hwspinlock/
obj-$(CONFIG_REMOTEPROC) += remoteproc/
obj-$(CONFIG_RPMSG) += rpmsg/
# Virtualization drivers
obj-$(CONFIG_VIRT_DRIVERS) += virt/
obj-$(CONFIG_HYPERV) += hv/
obj-$(CONFIG_PM_DEVFREQ) += devfreq/
obj-$(CONFIG_EXTCON) += extcon/
obj-$(CONFIG_MEMORY) += memory/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_IPACK_BUS) += ipack/
obj-$(CONFIG_NTB) += ntb/
obj-$(CONFIG_FMC) += fmc/
obj-$(CONFIG_POWERCAP) += powercap/
obj-$(CONFIG_MCB) += mcb/
obj-$(CONFIG_RAS) += ras/
obj-$(CONFIG_THUNDERBOLT) += thunderbolt/
obj-$(CONFIG_CORESIGHT) += coresight/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_ELPHEL393) += elphel/
obj-$(CONFIG_ELPHELDRVONMICROZED) += elphel/
obj-$(CONFIG_ELPHEL393_EXTERNAL) += elphel/
obj-y += net/
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/ata/ 0000775 0000000 0000000 00000000000 12703306510 0024360 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/ata/Kconfig 0000664 0000000 0000000 00000062003 12703306510 0025664 0 ustar 00root root 0000000 0000000 #
# SATA/PATA driver configuration
#
config HAVE_PATA_PLATFORM
bool
help
This is an internal configuration node for any machine that
uses pata-platform driver to enable the relevant driver in the
configuration structure without having to submit endless patches
to update the PATA_PLATFORM entry.
menuconfig ATA
tristate "Serial ATA and Parallel ATA drivers (libata)"
depends on HAS_IOMEM
depends on BLOCK
depends on !(M32R || M68K || S390) || BROKEN
select SCSI
select GLOB
---help---
If you want to use an ATA hard disk, ATA tape drive, ATA CD-ROM or
any other ATA device under Linux, say Y and make sure that you know
the name of your ATA host adapter (the card inside your computer
that "speaks" the ATA protocol, also called ATA controller),
because you will be asked for it.
NOTE: ATA enables basic SCSI support; *however*,
'SCSI disk support', 'SCSI tape support', or
'SCSI CDROM support' may also be needed,
depending on your hardware configuration.
if ATA
config ATA_NONSTANDARD
bool
default n
config ATA_VERBOSE_ERROR
bool "Verbose ATA error reporting"
default y
help
This option adds parsing of ATA command descriptions and error bits
in libata kernel output, making it easier to interpret.
This option will enlarge the kernel by approx. 6KB. Disable it only
if kernel size is more important than ease of debugging.
If unsure, say Y.
config ATA_ACPI
bool "ATA ACPI Support"
depends on ACPI && PCI
default y
help
This option adds support for ATA-related ACPI objects.
These ACPI objects add the ability to retrieve taskfiles
from the ACPI BIOS and write them to the disk controller.
These objects may be related to performance, security,
power management, or other areas.
You can disable this at kernel boot time by using the
option libata.noacpi=1
config SATA_ZPODD
bool "SATA Zero Power Optical Disc Drive (ZPODD) support"
depends on ATA_ACPI && PM
default n
help
This option adds support for SATA Zero Power Optical Disc
Drive (ZPODD). It requires both the ODD and the platform
support, and if enabled, will automatically power on/off the
ODD when certain condition is satisfied. This does not impact
end user's experience of the ODD, only power is saved when
the ODD is not in use (i.e. no disc inside).
If unsure, say N.
config SATA_PMP
bool "SATA Port Multiplier support"
default y
help
This option adds support for SATA Port Multipliers
(the SATA version of an ethernet hub, or SAS expander).
comment "Controllers with non-SFF native interface"
config SATA_AHCI
tristate "AHCI SATA support"
depends on PCI
help
This option enables support for AHCI Serial ATA.
If unsure, say N.
config SATA_AHCI_PLATFORM
tristate "Platform AHCI SATA support"
help
This option enables support for Platform AHCI Serial ATA
controllers.
If unsure, say N.
config AHCI_DA850
tristate "DaVinci DA850 AHCI SATA support"
depends on ARCH_DAVINCI_DA850
help
This option enables support for the DaVinci DA850 SoC's
onboard AHCI SATA.
If unsure, say N.
config AHCI_ST
tristate "ST AHCI SATA support"
depends on ARCH_STI
help
This option enables support for ST AHCI SATA controller.
If unsure, say N.
config AHCI_IMX
tristate "Freescale i.MX AHCI SATA support"
depends on MFD_SYSCON && (ARCH_MXC || COMPILE_TEST)
help
This option enables support for the Freescale i.MX SoC's
onboard AHCI SATA.
If unsure, say N.
config AHCI_CEVA
tristate "Ceva AHCI SATA support"
depends on OF
help
This option enables support for the Xilinx Zynq
UltraScale+ MPSoC's onboard Ceva AHCI SATA.
If unsure, say N.
config AHCI_MVEBU
tristate "Marvell EBU AHCI SATA support"
depends on ARCH_MVEBU
help
This option enables support for the Marvebu EBU SoC's
onboard AHCI SATA.
If unsure, say N.
config AHCI_SUNXI
tristate "Allwinner sunxi AHCI SATA support"
depends on ARCH_SUNXI
help
This option enables support for the Allwinner sunxi SoC's
onboard AHCI SATA.
If unsure, say N.
config AHCI_TEGRA
tristate "NVIDIA Tegra124 AHCI SATA support"
depends on ARCH_TEGRA
help
This option enables support for the NVIDIA Tegra124 SoC's
onboard AHCI SATA.
If unsure, say N.
config AHCI_XGENE
tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support"
depends on PHY_XGENE
help
This option enables support for APM X-Gene SoC SATA host controller.
config AHCI_ELPHEL
tristate "Elphel AHCI SATA driver support for elphel393 camera series"
depends on ARM
default m if ARM
help
This option enables support for Elphel AHCI SATA controller in elphel393
series cameras.
If unsure, say N.
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
help
This option enables support for Freescale 3.0Gbps SATA controller.
It can be found on MPC837x and MPC8315.
If unsure, say N.
config SATA_INIC162X
tristate "Initio 162x SATA support (Very Experimental)"
depends on PCI
help
This option enables support for Initio 162x Serial ATA.
config SATA_ACARD_AHCI
tristate "ACard AHCI variant (ATP 8620)"
depends on PCI
help
This option enables support for Acard.
If unsure, say N.
config SATA_SIL24
tristate "Silicon Image 3124/3132 SATA support"
depends on PCI
help
This option enables support for Silicon Image 3124/3132 Serial ATA.
If unsure, say N.
config ATA_SFF
bool "ATA SFF support (for legacy IDE and PATA)"
default y
help
This option adds support for ATA controllers with SFF
compliant or similar programming interface.
SFF is the legacy IDE interface that has been around since
the dawn of time. Almost all PATA controllers have an
SFF interface. Many SATA controllers have an SFF interface
when configured into a legacy compatibility mode.
For users with exclusively modern controllers like AHCI,
Silicon Image 3124, or Marvell 6440, you may choose to
disable this unneeded SFF support.
If unsure, say Y.
if ATA_SFF
comment "SFF controllers with custom DMA interface"
config PDC_ADMA
tristate "Pacific Digital ADMA support"
depends on PCI
help
This option enables support for Pacific Digital ADMA controllers
If unsure, say N.
config PATA_OCTEON_CF
tristate "OCTEON Boot Bus Compact Flash support"
depends on CAVIUM_OCTEON_SOC
help
This option enables a polled compact flash driver for use with
compact flash cards attached to the OCTEON boot bus.
If unsure, say N.
config SATA_QSTOR
tristate "Pacific Digital SATA QStor support"
depends on PCI
help
This option enables support for Pacific Digital Serial ATA QStor.
If unsure, say N.
config SATA_SX4
tristate "Promise SATA SX4 support (Experimental)"
depends on PCI
help
This option enables support for Promise Serial ATA SX4.
If unsure, say N.
config ATA_BMDMA
bool "ATA BMDMA support"
default y
help
This option adds support for SFF ATA controllers with BMDMA
capability. BMDMA stands for bus-master DMA and is the
de facto DMA interface for SFF controllers.
If unsure, say Y.
if ATA_BMDMA
comment "SATA SFF controllers with BMDMA"
config ATA_PIIX
tristate "Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support"
depends on PCI
help
This option enables support for ICH5/6/7/8 Serial ATA
and support for PATA on the Intel ESB/ICH/PIIX3/PIIX4 series
host controllers.
If unsure, say N.
config SATA_DWC
tristate "DesignWare Cores SATA support"
depends on 460EX
help
This option enables support for the on-chip SATA controller of the
AppliedMicro processor 460EX.
If unsure, say N.
config SATA_DWC_DEBUG
bool "Debugging driver version"
depends on SATA_DWC
help
This option enables debugging output in the driver.
config SATA_DWC_VDEBUG
bool "Verbose debug output"
depends on SATA_DWC_DEBUG
help
This option enables the taskfile dumping and NCQ debugging.
config SATA_HIGHBANK
tristate "Calxeda Highbank SATA support"
depends on ARCH_HIGHBANK || COMPILE_TEST
help
This option enables support for the Calxeda Highbank SoC's
onboard SATA.
If unsure, say N.
config SATA_MV
tristate "Marvell SATA support"
depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \
ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
select GENERIC_PHY
help
This option enables support for the Marvell Serial ATA family.
Currently supports 88SX[56]0[48][01] PCI(-X) chips,
as well as the newer [67]042 PCI-X/PCIe and SOC devices.
If unsure, say N.
config SATA_NV
tristate "NVIDIA SATA support"
depends on PCI
help
This option enables support for NVIDIA Serial ATA.
If unsure, say N.
config SATA_PROMISE
tristate "Promise SATA TX2/TX4 support"
depends on PCI
help
This option enables support for Promise Serial ATA TX2/TX4.
If unsure, say N.
config SATA_RCAR
tristate "Renesas R-Car SATA support"
depends on ARCH_SHMOBILE || COMPILE_TEST
help
This option enables support for Renesas R-Car Serial ATA.
If unsure, say N.
config SATA_SIL
tristate "Silicon Image SATA support"
depends on PCI
help
This option enables support for Silicon Image Serial ATA.
If unsure, say N.
config SATA_SIS
tristate "SiS 964/965/966/180 SATA support"
depends on PCI
select PATA_SIS
help
This option enables support for SiS Serial ATA on
SiS 964/965/966/180 and Parallel ATA on SiS 180.
The PATA support for SiS 180 requires additionally to
enable the PATA_SIS driver in the config.
If unsure, say N.
config SATA_SVW
tristate "ServerWorks Frodo / Apple K2 SATA support"
depends on PCI
help
This option enables support for Broadcom/Serverworks/Apple K2
SATA support.
If unsure, say N.
config SATA_ULI
tristate "ULi Electronics SATA support"
depends on PCI
help
This option enables support for ULi Electronics SATA.
If unsure, say N.
config SATA_VIA
tristate "VIA SATA support"
depends on PCI
help
This option enables support for VIA Serial ATA.
If unsure, say N.
config SATA_VITESSE
tristate "VITESSE VSC-7174 / INTEL 31244 SATA support"
depends on PCI
help
This option enables support for Vitesse VSC7174 and Intel 31244 Serial ATA.
If unsure, say N.
comment "PATA SFF controllers with BMDMA"
config PATA_ALI
tristate "ALi PATA support"
depends on PCI
help
This option enables support for the ALi ATA interfaces
found on the many ALi chipsets.
If unsure, say N.
config PATA_AMD
tristate "AMD/NVidia PATA support"
depends on PCI
help
This option enables support for the AMD and NVidia PATA
interfaces found on the chipsets for Athlon/Athlon64.
If unsure, say N.
config PATA_ARASAN_CF
tristate "ARASAN CompactFlash PATA Controller Support"
depends on ARCH_SPEAR13XX || COMPILE_TEST
depends on DMADEVICES
select DMA_ENGINE
help
Say Y here to support the ARASAN CompactFlash PATA controller
config PATA_ARTOP
tristate "ARTOP 6210/6260 PATA support"
depends on PCI
help
This option enables support for ARTOP PATA controllers.
If unsure, say N.
config PATA_ATIIXP
tristate "ATI PATA support"
depends on PCI
help
This option enables support for the ATI ATA interfaces
found on the many ATI chipsets.
If unsure, say N.
config PATA_ATP867X
tristate "ARTOP/Acard ATP867X PATA support"
depends on PCI
help
This option enables support for ARTOP/Acard ATP867X PATA
controllers.
If unsure, say N.
config PATA_BF54X
tristate "Blackfin 54x ATAPI support"
depends on BF542 || BF548 || BF549
help
This option enables support for the built-in ATAPI controller on
Blackfin 54x family chips.
If unsure, say N.
config PATA_CMD64X
tristate "CMD64x PATA support"
depends on PCI
help
This option enables support for the CMD64x series chips
except for the CMD640.
If unsure, say N.
config PATA_CS5520
tristate "CS5510/5520 PATA support"
depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the Cyrix 5510/5520
companion chip used with the MediaGX/Geode processor family.
If unsure, say N.
config PATA_CS5530
tristate "CS5530 PATA support"
depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the Cyrix/NatSemi/AMD CS5530
companion chip used with the MediaGX/Geode processor family.
If unsure, say N.
config PATA_CS5535
tristate "CS5535 PATA support (Experimental)"
depends on PCI && X86_32
help
This option enables support for the NatSemi/AMD CS5535
companion chip used with the Geode processor family.
If unsure, say N.
config PATA_CS5536
tristate "CS5536 PATA support"
depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
help
This option enables support for the AMD CS5536
companion chip used with the Geode LX processor family.
If unsure, say N.
config PATA_CYPRESS
tristate "Cypress CY82C693 PATA support (Very Experimental)"
depends on PCI
help
This option enables support for the Cypress/Contaq CY82C693
chipset found in some Alpha systems
If unsure, say N.
config PATA_EFAR
tristate "EFAR SLC90E66 support"
depends on PCI
help
This option enables support for the EFAR SLC90E66
IDE controller found on some older machines.
If unsure, say N.
config PATA_EP93XX
tristate "Cirrus Logic EP93xx PATA support"
depends on ARCH_EP93XX
help
This option enables support for the PATA controller in
the Cirrus Logic EP9312 and EP9315 ARM CPU.
If unsure, say N.
config PATA_HPT366
tristate "HPT 366/368 PATA support"
depends on PCI
help
This option enables support for the HPT 366 and 368
PATA controllers via the new ATA layer.
If unsure, say N.
config PATA_HPT37X
tristate "HPT 370/370A/371/372/374/302 PATA support"
depends on PCI
help
This option enables support for the majority of the later HPT
PATA controllers via the new ATA layer.
If unsure, say N.
config PATA_HPT3X2N
tristate "HPT 371N/372N/302N PATA support"
depends on PCI
help
This option enables support for the N variant HPT PATA
controllers via the new ATA layer.
If unsure, say N.
config PATA_HPT3X3
tristate "HPT 343/363 PATA support"
depends on PCI
help
This option enables support for the HPT 343/363
PATA controllers via the new ATA layer
If unsure, say N.
config PATA_HPT3X3_DMA
bool "HPT 343/363 DMA support"
depends on PATA_HPT3X3
help
This option enables DMA support for the HPT343/363
controllers. Enable with care as there are still some
problems with DMA on this chipset.
config PATA_ICSIDE
tristate "Acorn ICS PATA support"
depends on ARM && ARCH_ACORN
help
On Acorn systems, say Y here if you wish to use the ICS PATA
interface card. This is not required for ICS partition support.
If you are unsure, say N to this.
config PATA_IMX
tristate "PATA support for Freescale iMX"
depends on ARCH_MXC
help
This option enables support for the PATA host available on Freescale
iMX SoCs.
If unsure, say N.
config PATA_IT8213
tristate "IT8213 PATA support (Experimental)"
depends on PCI
help
This option enables support for the ITE 821 PATA
controllers via the new ATA layer.
If unsure, say N.
config PATA_IT821X
tristate "IT8211/2 PATA support"
depends on PCI
help
This option enables support for the ITE 8211 and 8212
PATA controllers via the new ATA layer, including RAID
mode.
If unsure, say N.
config PATA_JMICRON
tristate "JMicron PATA support"
depends on PCI
help
Enable support for the JMicron IDE controller, via the new
ATA layer.
If unsure, say N.
config PATA_MACIO
tristate "Apple PowerMac/PowerBook internal 'MacIO' IDE"
depends on PPC_PMAC
help
Most IDE capable PowerMacs have IDE busses driven by a variant
of this controller which is part of the Apple chipset used on
most PowerMac models. Some models have multiple busses using
different chipsets, though generally, MacIO is one of them.
config PATA_MARVELL
tristate "Marvell PATA support via legacy mode"
depends on PCI
help
This option enables limited support for the Marvell 88SE61xx ATA
controllers. If you wish to use only the SATA ports then select
the AHCI driver alone. If you wish to the use the PATA port or
both SATA and PATA include this driver.
If unsure, say N.
config PATA_MPC52xx
tristate "Freescale MPC52xx SoC internal IDE"
depends on PPC_MPC52xx && PPC_BESTCOMM
select PPC_BESTCOMM_ATA
help
This option enables support for integrated IDE controller
of the Freescale MPC52xx SoC.
If unsure, say N.
config PATA_NETCELL
tristate "NETCELL Revolution RAID support"
depends on PCI
help
This option enables support for the Netcell Revolution RAID
PATA controller.
If unsure, say N.
config PATA_NINJA32
tristate "Ninja32/Delkin Cardbus ATA support"
depends on PCI
help
This option enables support for the Ninja32, Delkin and
possibly other brands of Cardbus ATA adapter
If unsure, say N.
config PATA_NS87415
tristate "Nat Semi NS87415 PATA support"
depends on PCI
help
This option enables support for the National Semiconductor
NS87415 PCI-IDE controller.
If unsure, say N.
config PATA_OLDPIIX
tristate "Intel PATA old PIIX support"
depends on PCI
help
This option enables support for early PIIX PATA support.
If unsure, say N.
config PATA_OPTIDMA
tristate "OPTI FireStar PATA support (Very Experimental)"
depends on PCI
help
This option enables DMA/PIO support for the later OPTi
controllers found on some old motherboards and in some
laptops.
If unsure, say N.
config PATA_PDC2027X
tristate "Promise PATA 2027x support"
depends on PCI
help
This option enables support for Promise PATA pdc20268 to pdc20277 host adapters.
If unsure, say N.
config PATA_PDC_OLD
tristate "Older Promise PATA controller support"
depends on PCI
help
This option enables support for the Promise 20246, 20262, 20263,
20265 and 20267 adapters.
If unsure, say N.
config PATA_RADISYS
tristate "RADISYS 82600 PATA support (Experimental)"
depends on PCI
help
This option enables support for the RADISYS 82600
PATA controllers via the new ATA layer
If unsure, say N.
config PATA_RDC
tristate "RDC PATA support"
depends on PCI
help
This option enables basic support for the later RDC PATA controllers
controllers via the new ATA layer. For the RDC 1010, you need to
enable the IT821X driver instead.
If unsure, say N.
config PATA_SC1200
tristate "SC1200 PATA support"
depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the NatSemi/AMD SC1200 SoC
companion chip used with the Geode processor family.
If unsure, say N.
config PATA_SCC
tristate "Toshiba's Cell Reference Set IDE support"
depends on PCI && PPC_CELLEB
help
This option enables support for the built-in IDE controller on
Toshiba Cell Reference Board.
If unsure, say N.
config PATA_SCH
tristate "Intel SCH PATA support"
depends on PCI
help
This option enables support for Intel SCH PATA on the Intel
SCH (US15W, US15L, UL11L) series host controllers.
If unsure, say N.
config PATA_SERVERWORKS
tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support"
depends on PCI
help
This option enables support for the Serverworks OSB4/CSB5/CSB6 and
HT1000 PATA controllers, via the new ATA layer.
If unsure, say N.
config PATA_SIL680
tristate "CMD / Silicon Image 680 PATA support"
depends on PCI
help
This option enables support for CMD / Silicon Image 680 PATA.
If unsure, say N.
config PATA_SIS
tristate "SiS PATA support"
depends on PCI
help
This option enables support for SiS PATA controllers
If unsure, say N.
config PATA_TOSHIBA
tristate "Toshiba Piccolo support (Experimental)"
depends on PCI
help
Support for the Toshiba Piccolo controllers. Currently only the
primary channel is supported by this driver.
If unsure, say N.
config PATA_TRIFLEX
tristate "Compaq Triflex PATA support"
depends on PCI
help
Enable support for the Compaq 'Triflex' IDE controller as found
on many Compaq Pentium-Pro systems, via the new ATA layer.
If unsure, say N.
config PATA_VIA
tristate "VIA PATA support"
depends on PCI
help
This option enables support for the VIA PATA interfaces
found on the many VIA chipsets.
If unsure, say N.
config PATA_PXA
tristate "PXA DMA-capable PATA support"
depends on ARCH_PXA
help
This option enables support for harddrive attached to PXA CPU's bus.
NOTE: This driver utilizes PXA DMA controller, in case your hardware
is not capable of doing MWDMA, use pata_platform instead.
If unsure, say N.
config PATA_WINBOND
tristate "Winbond SL82C105 PATA support"
depends on PCI
help
This option enables support for SL82C105 PATA devices found in the
Netwinder and some other systems
If unsure, say N.
endif # ATA_BMDMA
comment "PIO-only SFF controllers"
config PATA_AT32
tristate "Atmel AVR32 PATA support (Experimental)"
depends on AVR32 && PLATFORM_AT32AP
help
This option enables support for the IDE devices on the
Atmel AT32AP platform.
If unsure, say N.
config PATA_AT91
tristate "PATA support for AT91SAM9260"
depends on ARM && SOC_AT91SAM9
depends on !ARCH_MULTIPLATFORM
help
This option enables support for IDE devices on the Atmel AT91SAM9260 SoC.
If unsure, say N.
config PATA_CMD640_PCI
tristate "CMD640 PCI PATA support (Experimental)"
depends on PCI
help
This option enables support for the CMD640 PCI IDE
interface chip. Only the primary channel is currently
supported.
If unsure, say N.
config PATA_ISAPNP
tristate "ISA Plug and Play PATA support"
depends on ISAPNP
help
This option enables support for ISA plug & play ATA
controllers such as those found on old soundcards.
If unsure, say N.
config PATA_IXP4XX_CF
tristate "IXP4XX Compact Flash support"
depends on ARCH_IXP4XX
help
This option enables support for a Compact Flash connected on
the ixp4xx expansion bus. This driver had been written for
Loft/Avila boards in mind but can work with others.
If unsure, say N.
config PATA_MPIIX
tristate "Intel PATA MPIIX support"
depends on PCI
help
This option enables support for MPIIX PATA support.
If unsure, say N.
config PATA_NS87410
tristate "Nat Semi NS87410 PATA support"
depends on PCI
help
This option enables support for the National Semiconductor
NS87410 PCI-IDE controller.
If unsure, say N.
config PATA_OPTI
tristate "OPTI621/6215 PATA support (Very Experimental)"
depends on PCI
help
This option enables full PIO support for the early Opti ATA
controllers found on some old motherboards.
If unsure, say N.
config PATA_PALMLD
tristate "Palm LifeDrive PATA support"
depends on MACH_PALMLD
help
This option enables support for Palm LifeDrive's internal ATA
port via the new ATA layer.
If unsure, say N.
config PATA_PCMCIA
tristate "PCMCIA PATA support"
depends on PCMCIA
help
This option enables support for PCMCIA ATA interfaces, including
compact flash card adapters via the new ATA layer.
If unsure, say N.
config PATA_PLATFORM
tristate "Generic platform device PATA support"
depends on EXPERT || PPC || HAVE_PATA_PLATFORM
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems.
If unsure, say N.
config PATA_OF_PLATFORM
tristate "OpenFirmware platform device PATA support"
depends on PATA_PLATFORM && OF
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems with OpenFirmware
bindings.
If unsure, say N.
config PATA_QDI
tristate "QDI VLB PATA support"
depends on ISA
select PATA_LEGACY
help
Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
config PATA_RB532
tristate "RouterBoard 532 PATA CompactFlash support"
depends on MIKROTIK_RB532
help
This option enables support for the RouterBoard 532
PATA CompactFlash controller.
If unsure, say N.
config PATA_RZ1000
tristate "PC Tech RZ1000 PATA support"
depends on PCI
help
This option enables basic support for the PC Tech RZ1000/1
PATA controllers via the new ATA layer
If unsure, say N.
config PATA_SAMSUNG_CF
tristate "Samsung SoC PATA support"
depends on SAMSUNG_DEV_IDE
help
This option enables basic support for Samsung's S3C/S5P board
PATA controllers via the new ATA layer
If unsure, say N.
config PATA_WINBOND_VLB
tristate "Winbond W83759A VLB PATA support (Experimental)"
depends on ISA
select PATA_LEGACY
help
Support for the Winbond W83759A controller on Vesa Local Bus
systems.
comment "Generic fallback / legacy drivers"
config PATA_ACPI
tristate "ACPI firmware driver for PATA"
depends on ATA_ACPI && ATA_BMDMA
help
This option enables an ACPI method driver which drives
motherboard PATA controller interfaces through the ACPI
firmware in the BIOS. This driver can sometimes handle
otherwise unsupported hardware.
config ATA_GENERIC
tristate "Generic ATA support"
depends on PCI && ATA_BMDMA
help
This option enables support for generic BIOS configured
ATA controllers via the new ATA layer
If unsure, say N.
config PATA_LEGACY
tristate "Legacy ISA PATA support (Experimental)"
depends on (ISA || PCI)
help
This option enables support for ISA/VLB/PCI bus legacy PATA
ports and allows them to be accessed via the new ATA layer.
If unsure, say N.
endif # ATA_SFF
endif # ATA
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/ata/Makefile 0000664 0000000 0000000 00000011503 12703306510 0026020 0 ustar 00root root 0000000 0000000
obj-$(CONFIG_ATA) += libata.o
# non-SFF interface
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_ELPHEL) += ahci_elphel.o libahci.o libahci_platform.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_TEGRA) += ahci_tegra.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
obj-$(CONFIG_PATA_ARASAN_CF) += pata_arasan_cf.o
obj-$(CONFIG_PATA_OCTEON_CF) += pata_octeon_cf.o
obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o
obj-$(CONFIG_SATA_SX4) += sata_sx4.o
# SFF SATA w/ BMDMA
obj-$(CONFIG_ATA_PIIX) += ata_piix.o
obj-$(CONFIG_SATA_MV) += sata_mv.o
obj-$(CONFIG_SATA_NV) += sata_nv.o
obj-$(CONFIG_SATA_PROMISE) += sata_promise.o
obj-$(CONFIG_SATA_RCAR) += sata_rcar.o
obj-$(CONFIG_SATA_SIL) += sata_sil.o
obj-$(CONFIG_SATA_SIS) += sata_sis.o
obj-$(CONFIG_SATA_SVW) += sata_svw.o
obj-$(CONFIG_SATA_ULI) += sata_uli.o
obj-$(CONFIG_SATA_VIA) += sata_via.o
obj-$(CONFIG_SATA_VITESSE) += sata_vsc.o
# SFF PATA w/ BMDMA
obj-$(CONFIG_PATA_ALI) += pata_ali.o
obj-$(CONFIG_PATA_AMD) += pata_amd.o
obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
obj-$(CONFIG_PATA_ATP867X) += pata_atp867x.o
obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o
obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
obj-$(CONFIG_PATA_EFAR) += pata_efar.o
obj-$(CONFIG_PATA_EP93XX) += pata_ep93xx.o
obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o
obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
obj-$(CONFIG_PATA_IMX) += pata_imx.o
obj-$(CONFIG_PATA_IT8213) += pata_it8213.o
obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
obj-$(CONFIG_PATA_MACIO) += pata_macio.o
obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o
obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NINJA32) += pata_ninja32.o
obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o
obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o
obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o
obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
obj-$(CONFIG_PATA_RDC) += pata_rdc.o
obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
obj-$(CONFIG_PATA_SCH) += pata_sch.o
obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
obj-$(CONFIG_PATA_SIL680) += pata_sil680.o
obj-$(CONFIG_PATA_SIS) += pata_sis.o
obj-$(CONFIG_PATA_TOSHIBA) += pata_piccolo.o
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
obj-$(CONFIG_PATA_VIA) += pata_via.o
obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
# SFF PIO only
obj-$(CONFIG_PATA_AT32) += pata_at32.o
obj-$(CONFIG_PATA_AT91) += pata_at91.o
obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
obj-$(CONFIG_PATA_OPTI) += pata_opti.o
obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o
obj-$(CONFIG_PATA_PALMLD) += pata_palmld.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o
obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o
obj-$(CONFIG_PATA_PXA) += pata_pxa.o
# Should be last but two libata driver
obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
# Should be last but one libata driver
obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
# Should be last libata driver
obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
libata-y := libata-core.o libata-scsi.o libata-eh.o libata-transport.o
libata-$(CONFIG_ATA_SFF) += libata-sff.o
libata-$(CONFIG_SATA_PMP) += libata-pmp.o
libata-$(CONFIG_ATA_ACPI) += libata-acpi.o
libata-$(CONFIG_SATA_ZPODD) += libata-zpodd.o
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/ata/ahci_elphel.c 0000664 0000000 0000000 00000021651 12703306510 0026766 0 ustar 00root root 0000000 0000000 /*
* Elphel AHCI SATA platform driver for elphel393 camera
*
* Based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "ahci.h"
#define DRV_NAME "elphel-ahci"
/*
* FPGA bitstream control address and bit mask. These are used to check whether
* bitstream is loaded or not.
*/
#define BITSTREAM_CTRL_ADDR 0xf800700c
#define BITSTREAM_CTRL_BIT 0x4
/* Property names from device tree, these are specific for the controller */
#define PROP_NAME_CLB_OFFS "clb_offs"
#define PROP_NAME_FB_OFFS "fb_offs"
static struct ata_port_operations ahci_elphel_ops;
static const struct ata_port_info ahci_elphel_port_info;
static struct scsi_host_template ahci_platform_sht;
static const struct of_device_id ahci_elphel_of_match[];
static const struct attribute_group dev_attr_root_group;
static bool load_driver = false;
struct elphel_ahci_priv {
u32 clb_offs;
u32 fb_offs;
u32 base_addr;
};
static ssize_t set_load_flag(struct device *dev, struct device_attribute *attr,
const char *buff, size_t buff_sz)
{
load_driver = true;
return buff_sz;
}
static int bitstream_loaded(u32 *ptr)
{
u32 val = ioread32(ptr);
if (val & BITSTREAM_CTRL_BIT)
return 1;
else
return 0;
}
static void elphel_defer_load(struct device *dev)
{
bool check_flag = true;
u32 *ctrl_ptr = ioremap_nocache(BITSTREAM_CTRL_ADDR, 4);
dev_info(dev, "AHCI driver loading is deferred. Load bitstream and write 1 into "
"/sys/devices/soc0/amba@0/80000000.elphel-ahci/load_module to continue\n");
while (check_flag) {
if (load_driver) {
if (bitstream_loaded(ctrl_ptr)) {
check_flag = false;
} else {
dev_err(dev, "FPGA bitstream is not loaded or bitstream "
"does not contain AHCI controller\n");
load_driver = false;
}
} else {
msleep(1000);
}
}
load_driver = false;
iounmap(ctrl_ptr);
}
// What about port_stop and freeing/unmapping ?
// Or at least check if it is re-started and memory is already allocated/mapped
static int elphel_port_start(struct ata_port *ap)
{
void *mem;
dma_addr_t mem_dma;
struct device *dev = ap->host->dev;
struct ahci_port_priv *pp;
struct ahci_host_priv *hpriv = ap->host->private_data;
const struct elphel_ahci_priv *dpriv = hpriv->plat_data;
dev_dbg(dev, "starting port %d", ap->port_no);
pp = devm_kzalloc(dev, sizeof(struct ahci_port_priv), GFP_KERNEL);
if (!pp)
return -ENOMEM;
mem = devm_kmalloc(dev, 0x100000, GFP_KERNEL); // AHCI_CMD_TBL_AR_SZ = 0x16000
if (!mem)
return -ENOMEM;
mem_dma = dma_map_single(dev, mem, AHCI_CMD_TBL_AR_SZ, DMA_TO_DEVICE); // maybe DMA_BIDIRECTIONAL, but currently we do not use DMA for received FISes
pp->cmd_tbl = mem;
pp->cmd_tbl_dma = mem_dma;
/*
* Set predefined addresses
*/
pp->cmd_slot = hpriv->mmio + dpriv->clb_offs;
pp->cmd_slot_dma = dpriv->base_addr + dpriv->clb_offs;
pp->rx_fis = hpriv->mmio + dpriv->fb_offs;
pp->rx_fis_dma = dpriv->base_addr + dpriv->fb_offs;
/*
* Save off initial list of interrupts to be enabled.
* This could be changed later
*/
pp->intr_mask = DEF_PORT_IRQ;
ap->private_data = pp;
return ahci_port_resume(ap);
}
static int elphel_parse_prop(const struct device_node *devn,
struct device *dev,
struct elphel_ahci_priv *dpriv)
{
int rc = 0;
const __be32 *val;
struct resource res;
if (!devn) {
dev_err(dev, "elphel-ahci device tree node is not found");
return -EINVAL;
}
val = of_get_property(devn, PROP_NAME_CLB_OFFS, NULL);
if (!val) {
dev_err(dev, "can not find clb_offs in device tree");
return -EINVAL;
}
dpriv->clb_offs = be32_to_cpup(val);
val = of_get_property(devn, PROP_NAME_FB_OFFS, NULL);
if (!val) {
dev_err(dev, "can not find fb_offs in device tree");
return -EINVAL;
}
dpriv->fb_offs = be32_to_cpup(val);
rc = of_address_to_resource((struct device_node *)devn, 0, &res);
if (rc < 0) {
dev_err(dev, "can not find address in device tree");
return -EINVAL;
}
dpriv->base_addr = (u32)res.start;
return 0;
}
static int elphel_drv_probe(struct platform_device *pdev)
{
int ret;
struct ahci_host_priv *hpriv;
struct elphel_ahci_priv *dpriv;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
unsigned int reg_val;
if (&dev->kobj) {
ret = sysfs_create_group(&dev->kobj, &dev_attr_root_group);
if (ret < 0)
return ret;
}
elphel_defer_load(dev);
dev_info(&pdev->dev, "probing Elphel AHCI driver");
dpriv = devm_kzalloc(dev, sizeof(struct elphel_ahci_priv), GFP_KERNEL);
if (!dpriv)
return -ENOMEM;
match = of_match_device(ahci_elphel_of_match, &pdev->dev);
if (!match)
return -EINVAL;
ret = elphel_parse_prop(dev->of_node, dev, dpriv);
if (ret != 0)
return ret;
hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
return PTR_ERR(hpriv);
hpriv->plat_data = dpriv;
ret = ahci_platform_init_host(pdev, hpriv, &ahci_elphel_port_info,
&ahci_platform_sht);
if (ret) {
dev_err(dev, "can not initialize platform host");
ahci_platform_disable_resources(hpriv);
return ret;
}
return 0;
}
static int elphel_drv_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "removing Elphel AHCI driver");
sysfs_remove_group(&pdev->dev.kobj, &dev_attr_root_group);
ata_platform_remove_one(pdev);
return 0;
}
static void elphel_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct ahci_port_priv *pp = ap->private_data;
int is_atapi = ata_is_atapi(qc->tf.protocol);
void *cmd_tbl;
u32 opts;
const u32 cmd_fis_len = 5; /* five dwords */
unsigned int n_elem;
struct scatterlist *sg;
struct ahci_sg *ahci_sg;
/* There is only one slot in controller thus we need to change tag*/
qc->tag = 0;
/*
* Fill in command table information. First, the header,
* a SATA Register - Host to Device command FIS.
*/
dma_sync_single_for_cpu(&qc->dev->tdev, pp->cmd_tbl_dma,
AHCI_CMD_TBL_AR_SZ, DMA_TO_DEVICE);
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
if (is_atapi) {
memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
}
/*
* Next, the S/G list.
*/
n_elem = 0;
ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
if (qc->flags & ATA_QCFLAG_DMAMAP) {
for_each_sg(qc->sg, sg, qc->n_elem, n_elem) {
dma_addr_t addr = sg_dma_address(sg);
u32 sg_len = sg_dma_len(sg);
ahci_sg[n_elem].addr = cpu_to_le32(addr & 0xffffffff);
ahci_sg[n_elem].addr_hi = cpu_to_le32((addr >> 16) >> 16);
ahci_sg[n_elem].flags_size = cpu_to_le32(sg_len - 1);
}
}
/*
* Fill in command slot information.
*/
opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
if (qc->tf.flags & ATA_TFLAG_WRITE)
opts |= AHCI_CMD_WRITE;
if (is_atapi)
opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
ahci_fill_cmd_slot(pp, qc->tag, opts);
dma_sync_single_for_device(&qc->dev->tdev, pp->cmd_tbl_dma,
AHCI_CMD_TBL_AR_SZ, DMA_TO_DEVICE);
}
static DEVICE_ATTR(load_module, S_IWUSR | S_IWGRP, NULL, set_load_flag);
static struct attribute *root_dev_attrs[] = {
&dev_attr_load_module.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
.attrs = root_dev_attrs,
.name = NULL,
};
static struct ata_port_operations ahci_elphel_ops = {
.inherits = &ahci_ops,
.port_start = elphel_port_start,
.qc_prep = elphel_qc_prep,
};
static const struct ata_port_info ahci_elphel_port_info = {
AHCI_HFLAGS(AHCI_HFLAG_NO_NCQ),
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_elphel_ops,
};
static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
.can_queue = 1,
.sg_tablesize = AHCI_MAX_SG,
.dma_boundary = AHCI_DMA_BOUNDARY,
.shost_attrs = ahci_shost_attrs,
.sdev_attrs = ahci_sdev_attrs,
};
static const struct of_device_id ahci_elphel_of_match[] = {
{ .compatible = "elphel,elphel-ahci", },
{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, ahci_elphel_of_match);
static struct platform_driver ahci_elphel_driver = {
.probe = elphel_drv_probe,
.remove = elphel_drv_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = ahci_elphel_of_match,
},
};
module_platform_driver(ahci_elphel_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Elphel, Inc.");
MODULE_DESCRIPTION("Elphel AHCI SATA platform driver for elphel393 camera");
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/clk/ 0000775 0000000 0000000 00000000000 12703306510 0024364 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/clk/clk-si5338.c 0000664 0000000 0000000 00000550572 12703306510 0026253 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : si5338.c
*! DESCRIPTION: control of the Silicon Laboratories SI5338 clock generator
*! Copyright (C) 2013 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! 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 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*/
#define DEBUG /* should be before linux/module.h - enables dev_dbg at boot in this file (needs "debug" in bootarg)*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#undef GENERATE_EXTRA
#define DRV_VERSION "1.0"
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
#define REG5338_PAGE 255
#define REG5338_PAGE_MASK 1
#define REG5338_DEV_CONFIG2 2
#define REG5338_DEV_CONFIG2_MASK 0x3f
#define REG5338_DEV_CONFIG2_VAL 38 /* last 2 digits of part number */
#define LAST_REG 347
#define FVCOMIN 2200000000LL
#define FVCOMAX 2840000000LL
#define INFREQMIN 5000000LL
#define INFREQMAX 710000000LL
#define INFREQDIV 40000000LL /* divide input frequency if above */
#define SPREAD_RATE_MIN 31500 /* 31.5 KHz */
#define SPREAD_RATE_MAX 63000 /* 63 KHz */
#define SPREAD_AMP_MIN 10 /* 0.1% */
#define SPREAD_AMP_MAX 500 /* 5.0% */
#define SPREAD_AMP_DENOM 10000 /* 0.01% amplitude step */
#define SPREAD_RATE_DFLT 31500 /* 31.5 KHz */
#define SPREAD_AMP_DFLT 50 /* 0.5% */
#define MSINT_MIN 8 /* not considering 4,6 */
#define MSINT_MAX 567
#define INIT_TIMEOUT 1000 /* reads of the I2C status register (1 cycle ~ 0.1 ms) */
#define AWE_IN_MUX 0x1d18
#define AWE_IN_MUX1 0x1c1c
#define AWE_FB_MUX 0x1e18
#define AWE_FB_MUX1 0x1c20
#define AWE_XTAL_FREQ 0x1c03
#define AWE_PFD_REF 0x1de0
#define AWE_PFD_FB 0x1ee0
#define AWE_P1DIV 0x1d07
#define AWE_P2DIV 0x1e07
#define AWE_DRV0_PDN 0x1f01
#define AWE_MS0_PDN 0x1f02
#define AWE_R0DIV 0x1f1c
#define AWE_R0DIV_IN 0x1fe0
#define AWE_DRV1_PDN 0x2001
#define AWE_MS1_PDN 0x2002
#define AWE_R1DIV 0x201c
#define AWE_R1DIV_IN 0x20e0
#define AWE_DRV2_PDN 0x2101
#define AWE_MS2_PDN 0x2102
#define AWE_R2DIV 0x211c
#define AWE_R2DIV_IN 0x21e0
#define AWE_DRV3_PDN 0x2201
#define AWE_MS3_PDN 0x2202
#define AWE_R3DIV 0x221c
#define AWE_R3DIV_IN 0x22e0
#define AWE_DRV0_VDDO 0x2303
#define AWE_DRV1_VDDO 0x230c
#define AWE_DRV2_VDDO 0x2330
#define AWE_DRV3_VDDO 0x23c0
#define AWE_DRV0_FMT 0x2407
#define AWE_DRV0_INV 0x2418
#define AWE_DRV1_FMT 0x2507
#define AWE_DRV1_INV 0x2518
#define AWE_DRV2_FMT 0x2607
#define AWE_DRV2_INV 0x2618
#define AWE_DRV3_FMT 0x2707
#define AWE_DRV3_INV 0x2718
#define AWE_DRV0_TRIM 0x281f
#define AWE_DRV1_TRIM_A 0x28e0
#define AWE_DRV1_TRIM_B 0x2903
#define AWE_DRV2_TRIM 0x297c
#define AWE_DRV3_TRIM 0x2a1f
#define AWE_FCAL_OVRD_07_00 0x2dff
#define AWE_FCAL_OVRD_15_08 0x2eff
#define AWE_FCAL_OVRD_17_15 0x2f03
#define AWE_REG47_72 0x2ffc
#define AWE_PFD_EXTFB 0x3080
#define AWE_PLL_KPHI 0x307f
#define AWE_FCAL_OVRD_EN 0x3180
#define AWE_VCO_GAIN 0x3170
#define AWE_RSEL 0x310c
#define AWE_BWSEL 0x3103
#define AWE_VCO_GAIN_RSEL_BWSEL 0x317f
#define AWE_PLL_EN 0x32c0
#define AWE_MSCAL 0x323f
#define AWE_MS3_HS 0x3380
#define AWE_MS2_HS 0x3340
#define AWE_MS1_HS 0x3320
#define AWE_MS0_HS 0x3310
#define AWE_MS_PEC 0x3307
#define AWE_MS0_FIDCT 0x3460
#define AWE_MS0_FIDDIS 0x3410
#define AWE_MS0_SSMODE 0x340C
#define AWE_MS0_PHIDCT 0x3403
#define AWE_MS0_P1_07_00 0x35ff
#define AWE_MS0_P1_15_08 0x36ff
#define AWE_MS0_P1_17_16 0x3703
#define AWE_MS0_P2_05_00 0x37fc
#define AWE_MS0_P2_13_06 0x38ff
#define AWE_MS0_P2_21_14 0x39ff
#define AWE_MS0_P2_29_22 0x3aff
#define AWE_MS0_P3_07_00 0x3bff
#define AWE_MS0_P3_15_08 0x3cff
#define AWE_MS0_P3_23_16 0x3dff
#define AWE_MS0_P3_29_24 0x3e3f
#define AWE_MS1_FIDCT 0x3f60
#define AWE_MS1_FIDDIS 0x3f10
#define AWE_MS1_SSMODE 0x3f0C
#define AWE_MS1_PHIDCT 0x3f03
#define AWE_MS1_P1_07_00 0x40ff
#define AWE_MS1_P1_15_08 0x41ff
#define AWE_MS1_P1_17_16 0x4203
#define AWE_MS1_P2_05_00 0x42fc
#define AWE_MS1_P2_13_06 0x43ff
#define AWE_MS1_P2_21_14 0x44ff
#define AWE_MS1_P2_29_22 0x45ff
#define AWE_MS1_P3_07_00 0x46ff
#define AWE_MS1_P3_15_08 0x47ff
#define AWE_MS1_P3_23_16 0x48ff
#define AWE_MS1_P3_29_24 0x493f
#define AWE_MS2_FRCTL 0x4a60 /* different name? */
#define AWE_MS2_FIDDIS 0x4a10
#define AWE_MS2_SSMODE 0x4a0C
#define AWE_MS2_PHIDCT 0x4a03
#define AWE_MS2_P1_07_00 0x4bff
#define AWE_MS2_P1_15_08 0x4cff
#define AWE_MS2_P1_17_16 0x4d03
#define AWE_MS2_P2_05_00 0x4dfc
#define AWE_MS2_P2_13_06 0x4eff
#define AWE_MS2_P2_21_14 0x4fff
#define AWE_MS2_P2_29_22 0x50ff
#define AWE_MS2_P3_07_00 0x51ff
#define AWE_MS2_P3_15_08 0x52ff
#define AWE_MS2_P3_23_16 0x53ff
#define AWE_MS2_P3_29_24 0x543f
#define AWE_MS3_FIDCT 0x5560
#define AWE_MS3_FIDDIS 0x5510
#define AWE_MS3_SSMODE 0x550C
#define AWE_MS3_PHIDCT 0x5503
#define AWE_MS3_P1_07_00 0x56ff
#define AWE_MS3_P1_15_08 0x57ff
#define AWE_MS3_P1_17_16 0x5803
#define AWE_MS3_P2_05_00 0x58fc
#define AWE_MS3_P2_13_06 0x59ff
#define AWE_MS3_P2_21_14 0x5aff
#define AWE_MS3_P2_29_22 0x5bff
#define AWE_MS3_P3_07_00 0x5cff
#define AWE_MS3_P3_15_08 0x5dff
#define AWE_MS3_P3_23_16 0x5eff
#define AWE_MS3_P3_29_24 0x5f3f
#define AWE_MSN_P1_07_00 0x61ff
#define AWE_MSN_P1_15_08 0x62ff
#define AWE_MSN_P1_17_16 0x6303
#define AWE_MSN_P2_05_00 0x63fc
#define AWE_MSN_P2_13_06 0x64ff
#define AWE_MSN_P2_21_14 0x65ff
#define AWE_MSN_P2_29_22 0x66ff
#define AWE_MSN_P3_07_00 0x67ff
#define AWE_MSN_P3_15_08 0x68ff
#define AWE_MSN_P3_23_16 0x69ff
#define AWE_MSN_P3_29_24 0x6a3f
#define AWE_OUT0_DIS_STATE 0x6ec0
#define AWE_OUT1_DIS_STATE 0x72c0
#define AWE_OUT2_DIS_STATE 0x76c0
#define AWE_OUT3_DIS_STATE 0x7ac0
#define AWE_STATUS 0xdaff
#define AWE_STATUS_PLL_LOL 0xda10
#define AWE_STATUS_PLL_LOS_FDBK 0xda08
#define AWE_STATUS_PLL_LOS_CLKIN 0xda04
#define AWE_STATUS_PLL_SYS_CAL 0xda01
#define AWE_MS_RESET 0xe204
#define AWE_OUT0_DIS 0xe601
#define AWE_OUT1_DIS 0xe602
#define AWE_OUT2_DIS 0xe604
#define AWE_OUT3_DIS 0xe608
#define AWE_OUT_ALL_DIS 0xe610
#define AWE_FCAL_07_00 0xebff
#define AWE_FCAL_15_08 0xecff
#define AWE_FCAL_17_16 0xed03
#define AWE_DIS_LOS 0xf180
#define AWE_REG241 0xf1ff
#define AWE_SOFT_RESET 0xf602
#define AWE_MS0_SSUPP2_07_00 0x11fff
#define AWE_MS0_SSUPP2_14_08 0x1207f
#define AWE_MS0_SSUPP3_07_00 0x121ff /* set them to 0 - default==1 */
#define AWE_MS0_SSUPP3_14_08 0x1227f
#define AWE_MS0_SSUPP1_07_00 0x123ff
#define AWE_MS0_SSUPP1_11_08 0x1240f
#define AWE_MS0_SSUDP1_03_00 0x124f0
#define AWE_MS0_SSUDP1_11_04 0x125ff
#define AWE_MS0_SSDNP2_07_00 0x126ff
#define AWE_MS0_SSDNP2_14_08 0x1277f
#define AWE_MS0_SSDNP3_07_00 0x128ff
#define AWE_MS0_SSDNP3_14_08 0x1297f
#define AWE_MS0_SSDNP1_07_00 0x12aff
#define AWE_MS0_SSDNP1_11_08 0x12b0f
#define AWE_MS1_SSUPP2_07_00 0x12fff
#define AWE_MS1_SSUPP2_14_08 0x1307f
#define AWE_MS1_SSUPP3_07_00 0x131ff
#define AWE_MS1_SSUPP3_14_08 0x1327f
#define AWE_MS1_SSUPP1_07_00 0x133ff
#define AWE_MS1_SSUPP1_11_08 0x1340f
#define AWE_MS1_SSUDP1_03_00 0x134f0
#define AWE_MS1_SSUDP1_11_04 0x135ff
#define AWE_MS1_SSDNP2_07_00 0x136ff
#define AWE_MS1_SSDNP2_14_08 0x1377f
#define AWE_MS1_SSDNP3_07_00 0x138ff
#define AWE_MS1_SSDNP3_14_08 0x1397f
#define AWE_MS1_SSDNP1_07_00 0x13aff
#define AWE_MS1_SSDNP1_11_08 0x13b0f
#define AWE_MS2_SSUPP2_07_00 0x13fff
#define AWE_MS2_SSUPP2_14_08 0x1407f
#define AWE_MS2_SSUPP3_07_00 0x141ff
#define AWE_MS2_SSUPP3_14_08 0x1427f
#define AWE_MS2_SSUPP1_07_00 0x143ff
#define AWE_MS2_SSUPP1_11_08 0x1440f
#define AWE_MS2_SSUDP1_03_00 0x144f0
#define AWE_MS2_SSUDP1_11_04 0x145ff
#define AWE_MS2_SSDNP2_07_00 0x146ff
#define AWE_MS2_SSDNP2_14_08 0x1477f
#define AWE_MS2_SSDNP3_07_00 0x148ff
#define AWE_MS2_SSDNP3_14_08 0x1497f
#define AWE_MS2_SSDNP1_07_00 0x14aff
#define AWE_MS2_SSDNP1_11_08 0x14b0f
#define AWE_MS3_SSUPP2_07_00 0x14fff
#define AWE_MS3_SSUPP2_14_08 0x1507f
#define AWE_MS3_SSUPP3_07_00 0x151ff
#define AWE_MS3_SSUPP3_14_08 0x1527f
#define AWE_MS3_SSUPP1_07_00 0x153ff
#define AWE_MS3_SSUPP1_11_08 0x1540f
#define AWE_MS3_SSUDP1_03_00 0x154f0
#define AWE_MS3_SSUDP1_11_04 0x155ff
#define AWE_MS3_SSDNP2_07_00 0x156ff
#define AWE_MS3_SSDNP2_14_08 0x1577f
#define AWE_MS3_SSDNP3_07_00 0x158ff
#define AWE_MS3_SSDNP3_14_08 0x1597f
#define AWE_MS3_SSDNP1_07_00 0x15aff
#define AWE_MS3_SSDNP1_11_08 0x15b0f
#define AWE_MISC_47 0x2ffc /* write 0x5 */
#define AWE_MISC_106 0x6a80 /* write 0x1 */
#define AWE_MISC_116 0x7480 /* write 0x1 */
#define AWE_MISC_42 0x2a20 /* write 0x1 */
#define AWE_MISC_06A 0x06e0 /* write 0x0 */
#define AWE_MISC_06B 0x0602 /* write 0x0 */
#define AWE_MISC_28 0x1cc0 /* write 0x0 */
#define CACHE_INIT 1
#define CACHE_VOLAT 2
struct si5338_cache_t {
u8 flags;
u8 data;
};
struct si5338_data_t {
u64 input_frequency12;
u64 input_frequency3;
u64 input_frequency4;
u64 input_frequency56;
u32 ss_on_freq_change; /* 0 - disable SS when frequency is changed, 1 - update SS. +2 reset MS after starting SS*/
u32 spread_spectrum_rate[4]; /* in Hz */
u32 spread_spectrum_amp[4]; /* in 0.01% */
// u64 pll_frequency;
int reg_addr; /* used for raw register r/w */
int last_page; /* value of last page accessed (bit 0 of register 255) */
struct mutex lock;
struct si5338_cache_t cache[LAST_REG+1];
};
struct si5338_drv_t {
const char * description;
u8 fmt;
u8 vdd;
u8 trim;
u8 invert; /* bits [1:0} data, [3:2] - don't care ([3]==1 - [1] - any, [2]==1 - [0] - any */
};
static struct i2c_device_id si5338_id[] = {
{ "si5338", 0 },
{ }
};
static const struct si5338_drv_t drv_configs []={
{"3V3_CMOS_A+", 0x1,0x0,0x17,0x8}, /* bX0 */
{"3V3_CMOS_A-", 0x1,0x0,0x17,0x9}, /* bX1 */
{"3V3_CMOS_B+", 0x2,0x0,0x17,0x4}, /* b0X */
{"3V3_CMOS_B-", 0x2,0x0,0x17,0x6}, /* b1X */
{"3V3_CMOS_A+B+",0x3,0x0,0x17,0x8},
{"3V3_CMOS_A-B+",0x3,0x0,0x17,0x9},
{"3V3_CMOS_A+B-",0x3,0x0,0x17,0x4},
{"3V3_CMOS_A-B-",0x3,0x0,0x17,0x6},
{"2V5_CMOS_A+", 0x1,0x1,0x13,0x8},
{"2V5_CMOS_A-", 0x1,0x1,0x13,0x9},
{"2V5_CMOS_B+", 0x2,0x1,0x13,0x4},
{"2V5_CMOS_B-", 0x2,0x1,0x13,0x6},
{"2V5_CMOS_A+B+",0x3,0x1,0x13,0x8},
{"2V5_CMOS_A-B+",0x3,0x1,0x13,0x9},
{"2V5_CMOS_A+B-",0x3,0x1,0x13,0x4},
{"2V5_CMOS_A-B-",0x3,0x1,0x13,0x6},
{"1V8_CMOS_A+", 0x1,0x2,0x15,0x8},
{"1V8_CMOS_A-", 0x1,0x2,0x15,0x9},
{"1V8_CMOS_B+", 0x2,0x2,0x15,0x4},
{"1V8_CMOS_B-", 0x2,0x2,0x15,0x6},
{"1V8_CMOS_A+B+",0x3,0x2,0x15,0x8},
{"1V8_CMOS_A-B+",0x3,0x2,0x15,0x9},
{"1V8_CMOS_A+B-",0x3,0x2,0x15,0x4},
{"1V8_CMOS_A-B-",0x3,0x2,0x15,0x6},
{"1V5_HSTL_A+", 0x1,0x3,0x1f,0x8},
{"1V5_HSTL_A-", 0x1,0x3,0x1f,0x9},
{"1V5_HSTL_B+", 0x2,0x3,0x1f,0x4},
{"1V5_HSTL_B-", 0x2,0x3,0x1f,0x6},
{"1V5_HSTL_A+B+",0x3,0x3,0x1f,0x8},
{"1V5_HSTL_A-B+",0x3,0x3,0x1f,0x9},
{"1V5_HSTL_A+B-",0x3,0x3,0x1f,0x4},
{"1V5_HSTL_A-B-",0x3,0x3,0x1f,0x6},
{"3V3_SSTL_A+", 0x1,0x0,0x04,0x8},
{"3V3_SSTL_A-", 0x1,0x0,0x04,0x9},
{"3V3_SSTL_B+", 0x2,0x0,0x04,0x4},
{"3V3_SSTL_B-", 0x2,0x0,0x04,0x6},
{"3V3_SSTL_A+B+",0x3,0x0,0x04,0x8},
{"3V3_SSTL_A-B+",0x3,0x0,0x04,0x9},
{"3V3_SSTL_A+B-",0x3,0x0,0x04,0x5},
{"3V3_SSTL_A-B-",0x3,0x0,0x04,0x6},
{"2V5_SSTL_A+", 0x1,0x1,0x0d,0x8},
{"2V5_SSTL_A-", 0x1,0x1,0x0d,0x9},
{"2V5_SSTL_B+", 0x2,0x1,0x0d,0x4},
{"2V5_SSTL_B-", 0x2,0x1,0x0d,0x6},
{"2V5_SSTL_A+B+",0x3,0x1,0x0d,0x8},
{"2V5_SSTL_A-B+",0x3,0x1,0x0d,0x9},
{"2V5_SSTL_A+B-",0x3,0x1,0x0d,0x5},
{"2V5_SSTL_A-B-",0x3,0x1,0x0d,0x6},
{"1V8_SSTL_A+", 0x1,0x2,0x17,0x8},
{"1V8_SSTL_A-", 0x1,0x2,0x17,0x9},
{"1V8_SSTL_B+", 0x2,0x2,0x17,0x4},
{"1V8_SSTL_B-", 0x2,0x2,0x17,0x6},
{"1V8_SSTL_A+B+",0x3,0x2,0x17,0x8},
{"1V8_SSTL_A-B+",0x3,0x2,0x17,0x9},
{"1V8_SSTL_A+B-",0x3,0x2,0x17,0x4},
{"1V8_SSTL_A-B-",0x3,0x2,0x17,0x6},
{"3V3_LVPECL", 0x4,0x0,0x0f,0xc},
{"2V5_LVPECL", 0x4,0x1,0x10,0xc},
{"3V3_LVDS", 0x6,0x0,0x03,0xc},
{"2V5_LVDS", 0x6,0x1,0x04,0xc},
{"1V8_LVDS", 0x6,0x2,0x04,0xc},
{NULL, 0x0,0x0,0x0,0x0},
};
static const char *out_dis_states[]= {"dis_hi-z","dis_low","dis_high","dis_always_on", NULL};
static const char *out_en_states[]= {"output_en","output_dis", NULL};
static const char *out_pwr_states[]= {"output_power_up","output_power_down", NULL};
static const char *ms_pwr_states[]= {"ms_power_up","ms_power_down", NULL};
static const int volatile_registers[]={AWE_STATUS, AWE_SOFT_RESET, AWE_FCAL_07_00, AWE_FCAL_15_08, AWE_FCAL_17_16, -1};
static const char *out_names[]={"output0","output1","output2","output3","outputs", NULL};
static const char *in_freq_names[]={"in_frequency12", "in_frequency3", "in_frequency4", "in_frequency56", "in_frequency12xo", NULL};
static const char *pll_setup_names[]={"pll_freq_fract", "pll_freq_int", "pll_by_out_fract", "pll_by_out_int", NULL};
static const char *out_freq_setup_names[]={
"out0_freq_fract", "out1_freq_fract", "out2_freq_fract", "out3_freq_fract",
"out0_freq_int", "out1_freq_int", "out2_freq_int", "out3_freq_int", NULL};
static u32 awe_msx_ssup[4][3][3]=
{{{AWE_MS0_SSUPP1_07_00,AWE_MS0_SSUPP1_11_08,0},
{AWE_MS0_SSUPP2_07_00,AWE_MS0_SSUPP2_14_08,0},
{AWE_MS0_SSUPP3_07_00,AWE_MS0_SSUPP3_14_08,0}},
{{AWE_MS1_SSUPP1_07_00,AWE_MS1_SSUPP1_11_08,0},
{AWE_MS1_SSUPP2_07_00,AWE_MS1_SSUPP2_14_08,0},
{AWE_MS1_SSUPP3_07_00,AWE_MS1_SSUPP3_14_08,0}},
{{AWE_MS2_SSUPP1_07_00,AWE_MS2_SSUPP1_11_08,0},
{AWE_MS2_SSUPP2_07_00,AWE_MS2_SSUPP2_14_08,0},
{AWE_MS2_SSUPP3_07_00,AWE_MS2_SSUPP3_14_08,0}},
{{AWE_MS3_SSUPP1_07_00,AWE_MS3_SSUPP1_11_08,0},
{AWE_MS3_SSUPP2_07_00,AWE_MS3_SSUPP2_14_08,0},
{AWE_MS3_SSUPP3_07_00,AWE_MS3_SSUPP3_14_08,0}}};
static u32 awe_msx_ssdn[4][3][3]=
{{{AWE_MS0_SSDNP1_07_00,AWE_MS0_SSDNP1_11_08,0},
{AWE_MS0_SSDNP2_07_00,AWE_MS0_SSDNP2_14_08,0},
{AWE_MS0_SSDNP3_07_00,AWE_MS0_SSDNP3_14_08,0}},
{{AWE_MS1_SSDNP1_07_00,AWE_MS1_SSDNP1_11_08,0},
{AWE_MS1_SSDNP2_07_00,AWE_MS1_SSDNP2_14_08,0},
{AWE_MS1_SSDNP3_07_00,AWE_MS1_SSDNP3_14_08,0}},
{{AWE_MS2_SSDNP1_07_00,AWE_MS2_SSDNP1_11_08,0},
{AWE_MS2_SSDNP2_07_00,AWE_MS2_SSDNP2_14_08,0},
{AWE_MS2_SSDNP3_07_00,AWE_MS2_SSDNP3_14_08,0}},
{{AWE_MS3_SSDNP1_07_00,AWE_MS3_SSDNP1_11_08,0},
{AWE_MS3_SSDNP2_07_00,AWE_MS3_SSDNP2_14_08,0},
{AWE_MS3_SSDNP3_07_00,AWE_MS3_SSDNP3_14_08,0}}};
static u32 awe_msx_ssud[4][3]=
{{AWE_MS0_SSUDP1_03_00,AWE_MS0_SSUDP1_11_04,0},
{AWE_MS1_SSUDP1_03_00,AWE_MS1_SSUDP1_11_04,0},
{AWE_MS2_SSUDP1_03_00,AWE_MS2_SSUDP1_11_04,0},
{AWE_MS3_SSUDP1_03_00,AWE_MS3_SSUDP1_11_04,0}};
static const u32 awe_rdiv_in[]= {AWE_R0DIV_IN, AWE_R1DIV_IN, AWE_R2DIV_IN, AWE_R3DIV_IN};
static const u32 awe_rdiv_k[]= {AWE_R0DIV, AWE_R1DIV, AWE_R2DIV, AWE_R3DIV};
static const u32 awe_drv_fmt[]= {AWE_DRV0_FMT, AWE_DRV1_FMT, AWE_DRV2_FMT, AWE_DRV3_FMT};
static const u32 awe_drv_vddo[]= {AWE_DRV0_VDDO, AWE_DRV1_VDDO, AWE_DRV2_VDDO, AWE_DRV3_VDDO};
static const u32 awe_drv_trim[][4]= {{AWE_DRV0_TRIM,0,0}, {AWE_DRV1_TRIM_A,AWE_DRV1_TRIM_B,0},{AWE_DRV2_TRIM,0,0},{AWE_DRV3_TRIM,0,0}};
static const u32 awe_drv_powerdown[]={AWE_DRV0_PDN, AWE_DRV1_PDN, AWE_DRV2_PDN, AWE_DRV3_PDN};
static const u32 awe_drv_disable[]= {AWE_OUT0_DIS, AWE_OUT1_DIS, AWE_OUT2_DIS, AWE_OUT3_DIS, AWE_OUT_ALL_DIS};
static const u32 awe_drv_dis_state[]={AWE_OUT0_DIS_STATE, AWE_OUT1_DIS_STATE, AWE_OUT2_DIS_STATE, AWE_OUT3_DIS_STATE};
static const u32 awe_drv_invert[]= {AWE_DRV0_INV, AWE_DRV1_INV, AWE_DRV2_INV, AWE_DRV3_INV};
static const u32 awe_drv_inv[]= {AWE_DRV0_INV, AWE_DRV1_INV, AWE_DRV2_INV, AWE_DRV3_INV};
static const u32 awe_ms_hs[]= {AWE_MS0_HS, AWE_MS1_HS, AWE_MS2_HS, AWE_MS3_HS};
static const u32 awe_ms_ssmode[]= {AWE_MS0_SSMODE,AWE_MS1_SSMODE,AWE_MS2_SSMODE,AWE_MS3_SSMODE};
/* (register_address << 8) | mask - created from SiLabs output */
static const u32 register_masks[]= {
0x61d,0x1b80,0x1cff,0x1dff,0x1eff,0x1fff,0x20ff,0x21ff,
0x22ff,0x23ff,0x241f,0x251f,0x261f,0x271f,0x28ff,0x297f,
0x2a3f,0x2dff,0x2eff,0x2f3f,0x30ff,0x31ff,0x32ff,0x33ff,
0x34ff,0x35ff,0x36ff,0x37ff,0x38ff,0x39ff,0x3aff,0x3bff,
0x3cff,0x3dff,0x3e3f,0x3fff,0x40ff,0x41ff,0x42ff,0x43ff,
0x44ff,0x45ff,0x46ff,0x47ff,0x48ff,0x493f,0x4aff,0x4bff,
0x4cff,0x4dff,0x4eff,0x4fff,0x50ff,0x51ff,0x52ff,0x53ff,
0x543f,0x55ff,0x56ff,0x57ff,0x58ff,0x59ff,0x5aff,0x5bff,
0x5cff,0x5dff,0x5eff,0x5f3f,0x61ff,0x62ff,0x63ff,0x64ff,
0x65ff,0x66ff,0x67ff,0x68ff,0x69ff,0x6abf,0x6bff,0x6cff,
0x6dff,0x6eff,0x6fff,0x70ff,0x71ff,0x72ff,0x73ff,0x74ff,
0x75ff,0x76ff,0x77ff,0x78ff,0x79ff,0x7aff,0x7bff,0x7cff,
0x7dff,0x7eff,0x7fff,0x80ff,0x810f,0x820f,0x83ff,0x84ff,
0x85ff,0x86ff,0x87ff,0x88ff,0x89ff,0x8aff,0x8bff,0x8cff,
0x8dff,0x8eff,0x8fff,0x90ff,0x98ff,0x99ff,0x9aff,0x9bff,
0x9cff,0x9dff,0x9e0f,0x9f0f,0xa0ff,0xa1ff,0xa2ff,0xa3ff,
0xa4ff,0xa5ff,0xa6ff,0xa7ff,0xa8ff,0xa9ff,0xaaff,0xabff,
0xacff,0xadff,0xaeff,0xafff,0xb0ff,0xb1ff,0xb2ff,0xb3ff,
0xb4ff,0xb50f,0xb6ff,0xb7ff,0xb8ff,0xb9ff,0xbaff,0xbbff,
0xbcff,0xbdff,0xbeff,0xbfff,0xc0ff,0xc1ff,0xc2ff,0xc3ff,
0xc4ff,0xc5ff,0xc6ff,0xc7ff,0xc8ff,0xc9ff,0xcaff,0xcb0f,
0xccff,0xcdff,0xceff,0xcfff,0xd0ff,0xd1ff,0xd2ff,0xd3ff,
0xd4ff,0xd5ff,0xd6ff,0xd7ff,0xd8ff,0xd9ff,0xf202,0x11fff,
0x120ff,0x121ff,0x122ff,0x123ff,0x124ff,0x125ff,0x126ff,0x127ff,
0x128ff,0x129ff,0x12aff,0x12b0f,0x12fff,0x130ff,0x131ff,0x132ff,
0x133ff,0x134ff,0x135ff,0x136ff,0x137ff,0x138ff,0x139ff,0x13aff,
0x13b0f,0x13fff,0x140ff,0x141ff,0x142ff,0x143ff,0x144ff,0x145ff,
0x146ff,0x147ff,0x148ff,0x149ff,0x14aff,0x14b0f,0x14fff,0x150ff,
0x151ff,0x152ff,0x153ff,0x154ff,0x155ff,0x156ff,0x157ff,0x158ff,
0x159ff,0x15aff,0x15b0f};
//AWE_MS0_SSMODE
static const u8 out_div_values[]={1,2,4,8,16,32};
static void si5338_init_of(struct i2c_client *client);
static int get_chn_from_name(const char * name);
static ssize_t invalidate_cache_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_data_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_address_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_data_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_all_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_help_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
//static ssize_t input_xtal_freq_show (struct device *dev, struct device_attribute *attr, char *buf);
//static ssize_t input_xtal_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_xtal_freq_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_frequency12_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_frequency3_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_frequency4_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_frequency56_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_frequency12_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_frequency12xo_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_frequency3_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_frequency4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_frequency56_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_p12_div_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_p12_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_mux_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_mux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_mux_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t fb_mux_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t fb_mux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t fb_mux_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_pfd_ref_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_pfd_ref_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_pfd_ref_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t fb_external_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t fb_external_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_pfd_fb_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t in_pfd_fb_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t in_pfd_fb_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t pll_ref_frequency_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t pll_fb_frequency_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t ms_p123_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t ms_p123_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t ms_abc_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t ms_abc_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t ms_pwr_states_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t ms_pwr_states_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static int set_ms_pwr_states(struct device *dev, const char * name, int chn);
static int get_ms_powerup_state(struct device *dev, char * buf, int chn);
static ssize_t ms_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t ss_change_freq_mode_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t ss_change_freq_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t ss_vals_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t ss_vals_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t ss_regs_hex_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t ss_regs_hex_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t pre_init_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t post_init_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t pll_freq_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t pll_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t ms_freq_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t ms_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t out_source_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t out_source_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t out_source_txt_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t out_source_freq_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t out_div_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t out_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t out_div_by_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t out_freq_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t out_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t out_pwr_states_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t out_pwr_states_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static int set_out_pwr_states(struct device *dev, const char * name, int chn);
static int get_powerup_state(struct device *dev, char * buf, int chn);
static ssize_t out_en_states_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t out_en_states_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static int set_out_en_states(struct device *dev, const char * name, int chn);
static int get_enabled_state(struct device *dev, char * buf, int chn);
static ssize_t out_dis_states_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t out_dis_states_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static int set_out_dis_states(struct device *dev, const char * name, int chn);
static int get_disabled_state(struct device *dev, char * buf, int chn);
#ifdef GENERATE_EXTRA
static ssize_t drv_powerdown_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_powerdown_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t drv_disable_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_disable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t drv_disabled_state_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_disabled_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t drv_invert_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t drv_invert_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_type_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_type_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t drv_type_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_vdd_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_vdd_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t drv_vdd_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_trim_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t drv_auto_trim_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t drv_trim_any_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t drv_txt_show (struct device *dev, struct device_attribute *attr, char *buf);
static int update_drv_trim(struct i2c_client *client, int novtt, int chn); /* no Vtt - CMOS, no termination, where it matters */
static char * get_drv_txt(struct i2c_client *client, int chn);
#endif
static int make_config_out (struct device *dev);
static ssize_t status_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_description_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_route_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_route_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static int get_output_description (struct device *dev, char * buf, int chn);
static int get_out_frequency_txt(struct device *dev, char *buf, int chn);
static ssize_t output_config_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static int configure_output_driver(struct device *dev, const char * name, int chn);
static int remove_common_factor(u64 * num_denom);
static int _verify_output_channel(struct i2c_client *client,int chn);
static int get_ss_vals(struct device *dev, char * buf, int chn);
static int get_ss_state(struct i2c_client *client, int chn);
static int set_ss_state(struct i2c_client *client, int state, int chn);
static int get_ss_down_rate(struct i2c_client *client, int chn);
static int get_ss_down_amplitude(struct i2c_client *client, int chn);
static int store_ss_down_parameters(struct i2c_client *client, u32 rate, u32 amp, int chn);
static int set_ss_down(struct i2c_client *client, int chn);
static int ss_pre_freq_change(struct i2c_client *client, int chn);
static int ss_post_freq_change(struct i2c_client *client, int chn);
static int calc_ss_down_to_regs(struct i2c_client *client, u32 * up_regs, u32 * down_regs, u32 * updown_reg, int chn);
static int get_ss_regs(struct i2c_client *client, u32 * up_regs, u32 * down_regs, u32 * updown_reg, int chn);
static int set_ss_regs(struct i2c_client *client, u32 * up_regs, u32 * down_regs, u32 * updown_reg, int chn);
static int disable_spread_spectrum(struct i2c_client *client,int chn);
static int enable_spread_spectrum(struct i2c_client *client,int chn);
static int get_drv_powerdown(struct i2c_client *client, int chn);
static int set_drv_powerdown(struct i2c_client *client, int typ, int chn);
static int get_drv_disable(struct i2c_client *client, int chn);
static int set_drv_disable(struct i2c_client *client, int typ, int chn);
static int get_drv_disabled_state(struct i2c_client *client, int chn);
static int set_drv_disabled_state(struct i2c_client *client, int typ, int chn);
static int get_drv_invert(struct i2c_client *client, int chn);
static int set_drv_invert(struct i2c_client *client, int typ, int chn);
static int get_drv_type(struct i2c_client *client, int chn);
static int set_drv_type(struct i2c_client *client, int typ, int chn);
static int get_drv_vdd(struct i2c_client *client, int chn);
static int set_drv_vdd(struct i2c_client *client, int vdd, int chn);
static int get_drv_trim(struct i2c_client *client, int chn);
static int set_drv_trim_any(struct i2c_client *client, int trim, int chn);
static int set_out_div(struct i2c_client *client, int div, int chn); /*chn =0..3 */
static int get_out_div(struct i2c_client *client, int chn); /*chn =0..3 */
static int set_out_div_by_frequency(struct i2c_client *client, u64* out_freq, int chn); /*chn =0..3 */
static int get_out_frequency(struct i2c_client *client, u64* out_freq, int chn); /*chn =0..3 */
static int get_out_source(struct i2c_client *client, int chn);
static int set_out_source(struct i2c_client *client, int chn, int src);
static int get_out_ms(struct i2c_client *client, int chn);
static int get_out_route(struct i2c_client *client, char* buf, int chn);
static int set_out_route(struct i2c_client *client, const char* route, int chn);
static int set_out_frequency_and_route (struct i2c_client *client, u64 *out_freq, int chn, int int_div);
static s64 get_output_src_frequency(struct i2c_client *client, u64 *out_freq, int chn);
static int pre_init(struct i2c_client *client, int clear_all);
static int post_init(struct i2c_client *client, int timeout); /*1 in timeout ~ 0.1ms - i2c read register */
static int reset_ms(struct i2c_client *client, int wait_cycles);
static int get_status(struct i2c_client *client);
static int power_up_down_needed_ms(struct i2c_client *client);
static int disable_output(struct i2c_client *client, int chn);
static int disable_pll_in_fb_mux(struct i2c_client *client); /* to be explicitly enabled if needed */
static int set_pll_paremeters(struct i2c_client *client);
static int is_set_up(struct i2c_client *client);
static int set_misc_registers(struct i2c_client *client);
static int get_ms_powerdown(struct i2c_client *client, int chn);
static int set_ms_powerdown(struct i2c_client *client, int typ, int chn);
static int ms_to_p123(u64* ms,u32 * p123);
static int p123_to_ms(u64* ms,u32 * p123);
static int get_ms_p123(struct i2c_client *client,u32 * p123, int chn); /* chn 0,1,2,3,4 (4 - msn) */
static int set_ms_p123(struct i2c_client *client,u32 * p123, int chn); /* chn 0,1,2,3,4 (4 - msn) */
static int set_pll_freq(struct i2c_client *client, u64 *vco_freq, int int_div);
static int get_pll_freq(struct i2c_client *client,u64 * pll_freq);
static int set_pll_freq_by_out(struct i2c_client *client, u64 *out_freq, int int_msn_div);
static int get_pll_ms_freq(struct i2c_client *client, u64 *out_freq, int chn);
static int set_pll_ms_by_out(struct i2c_client *client, u64 *out_freq, int chn, int int_div);
static s64 get_pll_in_frequency(struct i2c_client *client);
static s64 get_pll_fb_frequency(struct i2c_client *client);
static s64 get_p1div_in_frequency(struct i2c_client *client);
static s64 get_p2div_in_frequency(struct i2c_client *client);
static int set_in_mux(struct i2c_client *client, int data);
static int get_in_mux(struct i2c_client *client);
static int set_fb_mux(struct i2c_client *client, int data);
static int get_fb_mux(struct i2c_client *client);
static int set_in_pdiv(struct i2c_client *client, int div, int chn); /*chn =0,1 */
static int get_in_pdiv(struct i2c_client *client, int chn); /*chn =0,1 */
static int set_in_pfd_ref_fb(struct i2c_client *client, u8 val, int chn); /*chn =0 - ref, 1 - fb*/
static int get_in_pfd_ref_fb(struct i2c_client *client, int chn); /*chn =0,1 */
static int set_fb_external(struct i2c_client *client, u8 val);
static int get_fb_external(struct i2c_client *client);
static int set_in_frequency(struct i2c_client *client, u64 frequency,int src); /* 0 - 12, 1 - 3, 2 - 4, 3 - 5,6, 4 - 12 XO */
static u64 get_in_frequency(struct i2c_client *client,int src);
static s64 read_multireg64 (struct i2c_client *client, const u32 * awe);
static int write_multireg64 (struct i2c_client *client, u64 data, const u32 * awe);
static int read_field (struct i2c_client *client, u32 awe);
static int write_field (struct i2c_client *client, u8 data, u32 awe);
static int write_adwe(struct i2c_client *client, u32 adwe);
static int write_reg(struct i2c_client *client, u16 reg, u8 val, u8 mask);
static int read_reg(struct i2c_client *client, u16 reg);
static void invalidate_cache(struct i2c_client *client);
/* raw access to i2c registers, need to set address (9 bits) first, then r/w data */
static DEVICE_ATTR(invalidate_cache, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, invalidate_cache_store);
static DEVICE_ATTR(address, SYSFS_PERMISSIONS, raw_address_show, raw_address_store);
static DEVICE_ATTR(data, SYSFS_PERMISSIONS, raw_data_show, raw_data_store);
static DEVICE_ATTR(hex_address, SYSFS_PERMISSIONS, raw_hex_address_show,raw_hex_address_store);
static DEVICE_ATTR(hex_data, SYSFS_PERMISSIONS, raw_hex_data_show, raw_hex_data_store);
static DEVICE_ATTR(hex_all, SYSFS_PERMISSIONS & SYSFS_READONLY, raw_hex_all_show, NULL);
static DEVICE_ATTR(hex_adwe, SYSFS_PERMISSIONS, raw_hex_adwe_show, raw_hex_adwe_store);
static DEVICE_ATTR(hex_adwe_help, SYSFS_PERMISSIONS & SYSFS_READONLY, raw_hex_adwe_help_show, NULL);
static struct attribute *raw_dev_attrs[] = {
&dev_attr_invalidate_cache.attr,
&dev_attr_address.attr,
&dev_attr_data.attr,
&dev_attr_hex_address.attr,
&dev_attr_hex_data.attr,
&dev_attr_hex_all.attr,
&dev_attr_hex_adwe.attr,
&dev_attr_hex_adwe_help.attr,
NULL
};
static const struct attribute_group dev_attr_raw_group = {
.attrs = raw_dev_attrs,
.name = "raw",
};
//static DEVICE_ATTR(xtal_freq, SYSFS_PERMISSIONS, input_xtal_freq_show, input_xtal_freq_store);
static DEVICE_ATTR(xtal_freq_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, input_xtal_freq_txt_show, NULL);
static DEVICE_ATTR(in_frequency12, SYSFS_PERMISSIONS, in_frequency12_show, in_frequency12_store);
static DEVICE_ATTR(in_frequency12xo, SYSFS_PERMISSIONS, in_frequency12_show, in_frequency12xo_store);
static DEVICE_ATTR(in_frequency3, SYSFS_PERMISSIONS, in_frequency3_show, in_frequency3_store);
static DEVICE_ATTR(in_frequency4, SYSFS_PERMISSIONS, in_frequency4_show, in_frequency4_store);
static DEVICE_ATTR(in_frequency56, SYSFS_PERMISSIONS, in_frequency56_show, in_frequency56_store);
static DEVICE_ATTR(in_p1_div, SYSFS_PERMISSIONS, in_p12_div_show, in_p12_div_store);
static DEVICE_ATTR(in_p2_div, SYSFS_PERMISSIONS, in_p12_div_show, in_p12_div_store);
static DEVICE_ATTR(in_mux, SYSFS_PERMISSIONS, in_mux_show, in_mux_store);
static DEVICE_ATTR(in_mux_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, in_mux_txt_show, NULL);
static DEVICE_ATTR(fb_mux, SYSFS_PERMISSIONS, fb_mux_show, fb_mux_store);
static DEVICE_ATTR(fb_mux_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, fb_mux_txt_show, NULL);
static DEVICE_ATTR(in_pfd_ref, SYSFS_PERMISSIONS, in_pfd_ref_show, in_pfd_ref_store);
static DEVICE_ATTR(in_pfd_ref_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, in_pfd_ref_txt_show, NULL);
static DEVICE_ATTR(in_pfd_fb, SYSFS_PERMISSIONS, in_pfd_fb_show, in_pfd_fb_store);
static DEVICE_ATTR(in_pfd_fb_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, in_pfd_fb_txt_show, NULL);
static DEVICE_ATTR(pll_ref_frequency,SYSFS_PERMISSIONS & SYSFS_READONLY, pll_ref_frequency_show, NULL);
static DEVICE_ATTR(pll_fb_frequency, SYSFS_PERMISSIONS & SYSFS_READONLY, pll_fb_frequency_show, NULL);
static DEVICE_ATTR(fb_external, SYSFS_PERMISSIONS, fb_external_show, fb_external_store);
static struct attribute *input_dev_attrs[] = {
// &dev_attr_xtal_freq.attr,
&dev_attr_xtal_freq_txt.attr,
&dev_attr_in_frequency12.attr,
&dev_attr_in_frequency12xo.attr,
&dev_attr_in_frequency3.attr,
&dev_attr_in_frequency4.attr,
&dev_attr_in_frequency56.attr,
&dev_attr_in_p1_div.attr,
&dev_attr_in_p2_div.attr,
&dev_attr_in_mux.attr,
&dev_attr_in_mux_txt.attr,
&dev_attr_fb_mux.attr,
&dev_attr_fb_mux_txt.attr,
&dev_attr_in_pfd_ref.attr,
&dev_attr_in_pfd_ref_txt.attr,
&dev_attr_in_pfd_fb.attr,
&dev_attr_in_pfd_fb_txt.attr,
&dev_attr_pll_ref_frequency.attr,
&dev_attr_pll_fb_frequency.attr,
&dev_attr_fb_external.attr,
NULL
};
static const struct attribute_group dev_attr_input_group = {
.attrs = input_dev_attrs,
.name = "input",
};
/* has to have/not have '_fract' in the name */
static DEVICE_ATTR(ms0_freq_fract,SYSFS_PERMISSIONS, ms_freq_show, ms_freq_store);
static DEVICE_ATTR(ms0_freq_int, SYSFS_PERMISSIONS, ms_freq_show, ms_freq_store);
static DEVICE_ATTR(ms1_freq_fract,SYSFS_PERMISSIONS, ms_freq_show, ms_freq_store);
static DEVICE_ATTR(ms1_freq_int, SYSFS_PERMISSIONS, ms_freq_show, ms_freq_store);
static DEVICE_ATTR(ms2_freq_fract,SYSFS_PERMISSIONS, ms_freq_show, ms_freq_store);
static DEVICE_ATTR(ms2_freq_int, SYSFS_PERMISSIONS, ms_freq_show, ms_freq_store);
static DEVICE_ATTR(ms3_freq_fract,SYSFS_PERMISSIONS, ms_freq_show, ms_freq_store);
static DEVICE_ATTR(ms3_freq_int, SYSFS_PERMISSIONS, ms_freq_show, ms_freq_store);
static DEVICE_ATTR(ms0_p123, SYSFS_PERMISSIONS, ms_p123_show, ms_p123_store);
static DEVICE_ATTR(ms0_abc, SYSFS_PERMISSIONS, ms_abc_show, ms_abc_store);
static DEVICE_ATTR(ms1_p123, SYSFS_PERMISSIONS, ms_p123_show, ms_p123_store);
static DEVICE_ATTR(ms1_abc, SYSFS_PERMISSIONS, ms_abc_show, ms_abc_store);
static DEVICE_ATTR(ms2_p123, SYSFS_PERMISSIONS, ms_p123_show, ms_p123_store);
static DEVICE_ATTR(ms2_abc, SYSFS_PERMISSIONS, ms_abc_show, ms_abc_store);
static DEVICE_ATTR(ms3_p123, SYSFS_PERMISSIONS, ms_p123_show, ms_p123_store);
static DEVICE_ATTR(ms3_abc, SYSFS_PERMISSIONS, ms_abc_show, ms_abc_store);
static DEVICE_ATTR(msn_p123, SYSFS_PERMISSIONS, ms_p123_show, ms_p123_store);
static DEVICE_ATTR(msn_abc, SYSFS_PERMISSIONS, ms_abc_show, ms_abc_store);
static DEVICE_ATTR(ms_power_down, SYSFS_PERMISSIONS, ms_pwr_states_show, ms_pwr_states_store);
static DEVICE_ATTR(ms_power_up, SYSFS_PERMISSIONS, ms_pwr_states_show, ms_pwr_states_store);
static DEVICE_ATTR(ms_reset, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, ms_reset_store);
static struct attribute *multisynth_attrs[] = {
&dev_attr_ms0_freq_fract.attr,
&dev_attr_ms0_freq_int.attr,
&dev_attr_ms1_freq_fract.attr,
&dev_attr_ms1_freq_int.attr,
&dev_attr_ms2_freq_fract.attr,
&dev_attr_ms2_freq_int.attr,
&dev_attr_ms3_freq_fract.attr,
&dev_attr_ms3_freq_int.attr,
&dev_attr_ms0_p123.attr,
&dev_attr_ms0_abc.attr,
&dev_attr_ms1_p123.attr,
&dev_attr_ms1_abc.attr,
&dev_attr_ms2_p123.attr,
&dev_attr_ms2_abc.attr,
&dev_attr_ms3_p123.attr,
&dev_attr_ms3_abc.attr,
&dev_attr_msn_p123.attr,
&dev_attr_msn_abc.attr,
&dev_attr_ms_power_down.attr,
&dev_attr_ms_power_up.attr,
&dev_attr_ms_reset.attr,
NULL
};
static const struct attribute_group dev_attr_multisynth_group = {
.attrs = multisynth_attrs,
.name = "multiSynth",
};
/* Spread spectrum group */
static DEVICE_ATTR(ss_change_freq_mode, SYSFS_PERMISSIONS, ss_change_freq_mode_show, ss_change_freq_mode_store);
static DEVICE_ATTR(ss0_values, SYSFS_PERMISSIONS, ss_vals_show, ss_vals_store);
static DEVICE_ATTR(ss1_values, SYSFS_PERMISSIONS, ss_vals_show, ss_vals_store);
static DEVICE_ATTR(ss2_values, SYSFS_PERMISSIONS, ss_vals_show, ss_vals_store);
static DEVICE_ATTR(ss3_values, SYSFS_PERMISSIONS, ss_vals_show, ss_vals_store);
static DEVICE_ATTR(ss0_regs_hex, SYSFS_PERMISSIONS, ss_regs_hex_show, ss_regs_hex_store);
static DEVICE_ATTR(ss1_regs_hex, SYSFS_PERMISSIONS, ss_regs_hex_show, ss_regs_hex_store);
static DEVICE_ATTR(ss2_regs_hex, SYSFS_PERMISSIONS, ss_regs_hex_show, ss_regs_hex_store);
static DEVICE_ATTR(ss3_regs_hex, SYSFS_PERMISSIONS, ss_regs_hex_show, ss_regs_hex_store);
static struct attribute *spread_spectrum_attrs[] = {
&dev_attr_ss_change_freq_mode.attr,
&dev_attr_ss0_values.attr,
&dev_attr_ss1_values.attr,
&dev_attr_ss2_values.attr,
&dev_attr_ss3_values.attr,
&dev_attr_ss0_regs_hex.attr,
&dev_attr_ss1_regs_hex.attr,
&dev_attr_ss2_regs_hex.attr,
&dev_attr_ss3_regs_hex.attr,
&dev_attr_ms_reset.attr,
NULL
};
static const struct attribute_group dev_attr_spread_spectrum_group = {
.attrs = spread_spectrum_attrs,
.name = "spread_spectrum",
};
static DEVICE_ATTR(pre_init, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, pre_init_store);
static DEVICE_ATTR(pre_init_clear, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, pre_init_store);
static DEVICE_ATTR(post_init, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, post_init_store);
static DEVICE_ATTR(pll_freq_fract, SYSFS_PERMISSIONS, pll_freq_show, pll_freq_store);
static DEVICE_ATTR(pll_freq_int, SYSFS_PERMISSIONS, pll_freq_show, pll_freq_store);
static DEVICE_ATTR(pll_by_out_fract,SYSFS_PERMISSIONS, pll_freq_show, pll_freq_store);
static DEVICE_ATTR(pll_by_out_int, SYSFS_PERMISSIONS, pll_freq_show, pll_freq_store);
static struct attribute *pll_dev_attrs[] = {
/* &dev_attr_pre_init.attr,
&dev_attr_pre_init_clear.attr,
&dev_attr_post_init.attr, */
&dev_attr_pll_ref_frequency.attr,
&dev_attr_pll_freq_fract.attr,
&dev_attr_pll_freq_int.attr,
&dev_attr_pll_by_out_fract.attr,
&dev_attr_pll_by_out_int.attr,
NULL
};
static const struct attribute_group dev_attr_pll_group = {
.attrs = pll_dev_attrs,
.name = "pll",
};
static DEVICE_ATTR(out0_source, SYSFS_PERMISSIONS, out_source_show, out_source_store);
static DEVICE_ATTR(out0_source_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, out_source_txt_show, NULL);
static DEVICE_ATTR(out1_source, SYSFS_PERMISSIONS, out_source_show, out_source_store);
static DEVICE_ATTR(out1_source_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, out_source_txt_show, NULL);
static DEVICE_ATTR(out2_source, SYSFS_PERMISSIONS, out_source_show, out_source_store);
static DEVICE_ATTR(out2_source_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, out_source_txt_show, NULL);
static DEVICE_ATTR(out3_source, SYSFS_PERMISSIONS, out_source_show, out_source_store);
static DEVICE_ATTR(out3_source_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, out_source_txt_show, NULL);
static DEVICE_ATTR(out0_source_freq,SYSFS_PERMISSIONS & SYSFS_READONLY, out_source_freq_show, NULL);
static DEVICE_ATTR(out1_source_freq,SYSFS_PERMISSIONS & SYSFS_READONLY, out_source_freq_show, NULL);
static DEVICE_ATTR(out2_source_freq,SYSFS_PERMISSIONS & SYSFS_READONLY, out_source_freq_show, NULL);
static DEVICE_ATTR(out3_source_freq,SYSFS_PERMISSIONS & SYSFS_READONLY, out_source_freq_show, NULL);
static DEVICE_ATTR(out0_div, SYSFS_PERMISSIONS, out_div_show, out_div_store);
static DEVICE_ATTR(out1_div, SYSFS_PERMISSIONS, out_div_show, out_div_store);
static DEVICE_ATTR(out2_div, SYSFS_PERMISSIONS, out_div_show, out_div_store);
static DEVICE_ATTR(out3_div, SYSFS_PERMISSIONS, out_div_show, out_div_store);
static DEVICE_ATTR(out0_div_by_freq,SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, out_div_by_freq_store);
static DEVICE_ATTR(out0_freq_int, SYSFS_PERMISSIONS, out_freq_show, out_freq_store);
static DEVICE_ATTR(out0_freq_fract, SYSFS_PERMISSIONS, out_freq_show, out_freq_store);
static DEVICE_ATTR(out1_div_by_freq,SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, out_div_by_freq_store);
static DEVICE_ATTR(out1_freq_int, SYSFS_PERMISSIONS, out_freq_show, out_freq_store);
static DEVICE_ATTR(out1_freq_fract, SYSFS_PERMISSIONS, out_freq_show, out_freq_store);
static DEVICE_ATTR(out2_div_by_freq,SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, out_div_by_freq_store);
static DEVICE_ATTR(out2_freq_int, SYSFS_PERMISSIONS, out_freq_show, out_freq_store);
static DEVICE_ATTR(out2_freq_fract, SYSFS_PERMISSIONS, out_freq_show, out_freq_store);
static DEVICE_ATTR(out3_div_by_freq,SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, out_div_by_freq_store);
static DEVICE_ATTR(out3_freq_int, SYSFS_PERMISSIONS, out_freq_show, out_freq_store);
static DEVICE_ATTR(out3_freq_fract, SYSFS_PERMISSIONS, out_freq_show, out_freq_store);
static DEVICE_ATTR(out0_route, SYSFS_PERMISSIONS, output_route_show, output_route_store);
static DEVICE_ATTR(out1_route, SYSFS_PERMISSIONS, output_route_show, output_route_store);
static DEVICE_ATTR(out2_route, SYSFS_PERMISSIONS, output_route_show, output_route_store);
static DEVICE_ATTR(out3_route, SYSFS_PERMISSIONS, output_route_show, output_route_store);
//output_route_show
static struct attribute *output_dev_attrs[] = {
&dev_attr_out0_source.attr,
&dev_attr_out0_source_txt.attr,
&dev_attr_out1_source.attr,
&dev_attr_out1_source_txt.attr,
&dev_attr_out2_source.attr,
&dev_attr_out2_source_txt.attr,
&dev_attr_out3_source.attr,
&dev_attr_out3_source_txt.attr,
&dev_attr_out0_source_freq.attr,
&dev_attr_out1_source_freq.attr,
&dev_attr_out2_source_freq.attr,
&dev_attr_out3_source_freq.attr,
&dev_attr_out0_div.attr,
&dev_attr_out1_div.attr,
&dev_attr_out2_div.attr,
&dev_attr_out3_div.attr,
&dev_attr_out0_div_by_freq.attr,
&dev_attr_out1_div_by_freq.attr,
&dev_attr_out2_div_by_freq.attr,
&dev_attr_out3_div_by_freq.attr,
&dev_attr_out0_freq_int.attr,
&dev_attr_out1_freq_int.attr,
&dev_attr_out2_freq_int.attr,
&dev_attr_out3_freq_int.attr,
&dev_attr_out0_freq_fract.attr,
&dev_attr_out1_freq_fract.attr,
&dev_attr_out2_freq_fract.attr,
&dev_attr_out3_freq_fract.attr,
&dev_attr_out0_route.attr,
&dev_attr_out1_route.attr,
&dev_attr_out2_route.attr,
&dev_attr_out3_route.attr,
NULL
};
static const struct attribute_group dev_attr_output_group = {
.attrs = output_dev_attrs,
.name = "output_clocks",
};
/* output drivers */
/* NOTE: state of the outputs changes with clock only, changing "dis_low" to "dis_high" does not work when disabled.
* Going through "dis_always_on" works
*/
#ifdef GENERATE_EXTRA
static DEVICE_ATTR(drv0_powerdown, SYSFS_PERMISSIONS, drv_powerdown_show, drv_powerdown_store);
static DEVICE_ATTR(drv1_powerdown, SYSFS_PERMISSIONS, drv_powerdown_show, drv_powerdown_store);
static DEVICE_ATTR(drv2_powerdown, SYSFS_PERMISSIONS, drv_powerdown_show, drv_powerdown_store);
static DEVICE_ATTR(drv3_powerdown, SYSFS_PERMISSIONS, drv_powerdown_show, drv_powerdown_store);
static DEVICE_ATTR(drv0_disable, SYSFS_PERMISSIONS, drv_disable_show, drv_disable_store);
static DEVICE_ATTR(drv1_disable, SYSFS_PERMISSIONS, drv_disable_show, drv_disable_store);
static DEVICE_ATTR(drv2_disable, SYSFS_PERMISSIONS, drv_disable_show, drv_disable_store);
static DEVICE_ATTR(drv3_disable, SYSFS_PERMISSIONS, drv_disable_show, drv_disable_store);
static DEVICE_ATTR(drv0_disabled_state,SYSFS_PERMISSIONS, drv_disabled_state_show, drv_disabled_state_store);
static DEVICE_ATTR(drv1_disabled_state,SYSFS_PERMISSIONS, drv_disabled_state_show, drv_disabled_state_store);
static DEVICE_ATTR(drv2_disabled_state,SYSFS_PERMISSIONS, drv_disabled_state_show, drv_disabled_state_store);
static DEVICE_ATTR(drv3_disabled_state,SYSFS_PERMISSIONS, drv_disabled_state_show, drv_disabled_state_store);
static DEVICE_ATTR(drv0_invert, SYSFS_PERMISSIONS, drv_invert_show, drv_invert_store);
static DEVICE_ATTR(drv1_invert, SYSFS_PERMISSIONS, drv_invert_show, drv_invert_store);
static DEVICE_ATTR(drv2_invert, SYSFS_PERMISSIONS, drv_invert_show, drv_invert_store);
static DEVICE_ATTR(drv3_invert, SYSFS_PERMISSIONS, drv_invert_show, drv_invert_store);
static DEVICE_ATTR(drv0_invert_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_invert_txt_show, NULL);
static DEVICE_ATTR(drv1_invert_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_invert_txt_show, NULL);
static DEVICE_ATTR(drv2_invert_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_invert_txt_show, NULL);
static DEVICE_ATTR(drv3_invert_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_invert_txt_show, NULL);
static DEVICE_ATTR(drv0_type, SYSFS_PERMISSIONS, drv_type_show, drv_type_store);
static DEVICE_ATTR(drv1_type, SYSFS_PERMISSIONS, drv_type_show, drv_type_store);
static DEVICE_ATTR(drv2_type, SYSFS_PERMISSIONS, drv_type_show, drv_type_store);
static DEVICE_ATTR(drv3_type, SYSFS_PERMISSIONS, drv_type_show, drv_type_store);
static DEVICE_ATTR(drv0_type_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_type_txt_show, NULL);
static DEVICE_ATTR(drv1_type_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_type_txt_show, NULL);
static DEVICE_ATTR(drv2_type_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_type_txt_show, NULL);
static DEVICE_ATTR(drv3_type_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_type_txt_show, NULL);
static DEVICE_ATTR(drv0_vdd, SYSFS_PERMISSIONS, drv_vdd_show, drv_vdd_store);
static DEVICE_ATTR(drv1_vdd, SYSFS_PERMISSIONS, drv_vdd_show, drv_vdd_store);
static DEVICE_ATTR(drv2_vdd, SYSFS_PERMISSIONS, drv_vdd_show, drv_vdd_store);
static DEVICE_ATTR(drv3_vdd, SYSFS_PERMISSIONS, drv_vdd_show, drv_vdd_store);
static DEVICE_ATTR(drv0_vdd_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_vdd_txt_show, NULL);
static DEVICE_ATTR(drv1_vdd_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_vdd_txt_show, NULL);
static DEVICE_ATTR(drv2_vdd_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_vdd_txt_show, NULL);
static DEVICE_ATTR(drv3_vdd_txt, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_vdd_txt_show, NULL);
static DEVICE_ATTR(drv0_trim, SYSFS_PERMISSIONS, drv_trim_show, drv_trim_any_store);
static DEVICE_ATTR(drv1_trim, SYSFS_PERMISSIONS, drv_trim_show, drv_trim_any_store);
static DEVICE_ATTR(drv2_trim, SYSFS_PERMISSIONS, drv_trim_show, drv_trim_any_store);
static DEVICE_ATTR(drv3_trim, SYSFS_PERMISSIONS, drv_trim_show, drv_trim_any_store);
static DEVICE_ATTR(drv0_auto_trim, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, drv_auto_trim_store);
static DEVICE_ATTR(drv1_auto_trim, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, drv_auto_trim_store);
static DEVICE_ATTR(drv2_auto_trim, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, drv_auto_trim_store);
static DEVICE_ATTR(drv3_auto_trim, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, drv_auto_trim_store);
static DEVICE_ATTR(drv0_description, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_txt_show, NULL);
static DEVICE_ATTR(drv1_description, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_txt_show, NULL);
static DEVICE_ATTR(drv2_description, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_txt_show, NULL);
static DEVICE_ATTR(drv3_description, SYSFS_PERMISSIONS & SYSFS_READONLY, drv_txt_show, NULL);
static struct attribute *output_extra_dev_attrs[] = {
&dev_attr_drv0_powerdown.attr,
&dev_attr_drv1_powerdown.attr,
&dev_attr_drv2_powerdown.attr,
&dev_attr_drv3_powerdown.attr,
&dev_attr_drv0_disable.attr,
&dev_attr_drv1_disable.attr,
&dev_attr_drv2_disable.attr,
&dev_attr_drv3_disable.attr,
&dev_attr_drv0_disabled_state.attr,
&dev_attr_drv1_disabled_state.attr,
&dev_attr_drv2_disabled_state.attr,
&dev_attr_drv3_disabled_state.attr,
&dev_attr_drv0_invert.attr,
&dev_attr_drv1_invert.attr,
&dev_attr_drv2_invert.attr,
&dev_attr_drv3_invert.attr,
&dev_attr_drv0_invert_txt.attr,
&dev_attr_drv1_invert_txt.attr,
&dev_attr_drv2_invert_txt.attr,
&dev_attr_drv3_invert_txt.attr,
&dev_attr_drv0_type.attr,
&dev_attr_drv1_type.attr,
&dev_attr_drv2_type.attr,
&dev_attr_drv3_type.attr,
&dev_attr_drv0_type_txt.attr,
&dev_attr_drv1_type_txt.attr,
&dev_attr_drv2_type_txt.attr,
&dev_attr_drv3_type_txt.attr,
&dev_attr_drv0_vdd.attr,
&dev_attr_drv1_vdd.attr,
&dev_attr_drv2_vdd.attr,
&dev_attr_drv3_vdd.attr,
&dev_attr_drv0_vdd_txt.attr,
&dev_attr_drv1_vdd_txt.attr,
&dev_attr_drv2_vdd_txt.attr,
&dev_attr_drv3_vdd_txt.attr,
&dev_attr_drv0_trim.attr,
&dev_attr_drv1_trim.attr,
&dev_attr_drv2_trim.attr,
&dev_attr_drv3_trim.attr,
&dev_attr_drv0_auto_trim.attr,
&dev_attr_drv1_auto_trim.attr,
&dev_attr_drv2_auto_trim.attr,
&dev_attr_drv3_auto_trim.attr,
&dev_attr_drv0_description.attr,
&dev_attr_drv1_description.attr,
&dev_attr_drv2_description.attr,
&dev_attr_drv3_description.attr,
NULL
};
static const struct attribute_group dev_attr_output_extra_group = {
.attrs = output_extra_dev_attrs,
.name = "output_extra",
};
#endif
/* root directory */
static DEVICE_ATTR(outputs, SYSFS_PERMISSIONS & SYSFS_READONLY, output_description_show, NULL);
static DEVICE_ATTR(status, SYSFS_PERMISSIONS & SYSFS_READONLY, status_show, NULL);
static struct attribute *root_dev_attrs[] = {
&dev_attr_pre_init.attr,
&dev_attr_pre_init_clear.attr,
&dev_attr_post_init.attr,
&dev_attr_outputs.attr,
&dev_attr_status.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
.attrs = root_dev_attrs,
.name = NULL,
};
static int get_chn_from_name(const char * name)
{
char * cp = strpbrk(name,"0123456789");
return (cp)?(cp[0]-'0'):-1;
}
static int make_config_out(struct device *dev)
{
int retval=-1;
int index,iout,num_types,num_files;
struct attribute **pattrs; /* array of pointers to attibutes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
for (num_types=0;drv_configs[num_types].description;num_types++);
num_files=num_types;
for (iout=0;out_dis_states[iout];iout++) num_files++;
for (iout=0;out_en_states[iout];iout++) num_files++;
for (iout=0;out_pwr_states[iout];iout++) num_files++;
for (iout=0;out_names[iout];iout++) num_files++;
pattrs = devm_kzalloc(dev,(num_files+1)*sizeof(pattrs[0]), GFP_KERNEL);
if (!pattrs) return -ENOMEM;
dev_attrs = devm_kzalloc(dev, num_files*sizeof(dev_attrs[0]), GFP_KERNEL);
if (!dev_attrs) return -ENOMEM;
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
if (!attr_group) return -ENOMEM;
memset(dev_attrs, 0, num_files*sizeof(dev_attrs[0]));
memset(attr_group, 0, sizeof(*attr_group));
for (index=0;indexname = "output_drivers";
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
index=0;
while ((*attr_group).attrs[index]){
dev_dbg(dev,"attr=%s\n",attr_group->attrs[index]->name);
index++;
}
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static ssize_t status_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int status;
struct i2c_client *client = to_i2c_client(dev);
if (((status=get_status(client)))<0) return status;
return sprintf(buf,"0x%x input clock: %s, feedback clock: %s, PLL lock: %s, calibration: %s\n",
status,(status & 0x4)?"LOST":"OK",(status & 0x8)?"LOST":"OK",(status & 0x10)?"LOST":"OK",(status & 0x10)?"IN PROGRESS":"DONE");
}
static ssize_t output_description_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int i,i1,rc,len=0,show_number,ms;
struct i2c_client *client = to_i2c_client(dev);
for (i=0; out_names[i]; i++) if (strcmp(attr->attr.name,out_names[i]) == 0) break;
if (!out_names[i]) return -EINVAL;
if (i==4) { /* all outputs */
i=0;
i1=4;
show_number=1;
} else {
i1=i+1;
show_number=0;
}
for (;i= 0){
rc=sprintf(buf,", ");
buf+=rc;
len+=rc;
if (((rc=get_ms_powerup_state(dev, buf,i)))<0) return rc;
buf+=rc;
len+=rc;
}
rc=sprintf(buf,", disabled state: ");
buf+=rc;
len+=rc;
if (((rc=get_disabled_state(dev, buf,i)))<0) return rc;
buf+=rc;
len+=rc;
rc=sprintf(buf,", ");
buf+=rc;
len+=rc;
if (((rc=get_powerup_state(dev, buf,i)))<0) return rc;
buf+=rc;
len+=rc;
rc=sprintf(buf,", ");
buf+=rc;
len+=rc;
if (((rc=get_enabled_state(dev, buf,i)))<0) return rc;
buf+=rc;
len+=rc;
/* show spread spectum settings */
rc=sprintf(buf,", ");
buf+=rc;
len+=rc;
if (((rc=get_ss_vals(dev, buf, i)))<0) return rc;
buf+=rc;
len+=rc;
rc=sprintf(buf,"\n");
buf+=rc;
len+=rc;
}
return len;
}
static ssize_t output_route_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn,rc,len=0;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name);
if (((rc=get_out_route(client, buf,chn)))<0) return rc;
buf+=rc;
len+=rc;
rc=sprintf(buf,"\n");
buf+=rc;
len+=rc;
return len;
}
static ssize_t output_route_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, rc;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name);
if (((rc=set_out_route(client, buf, chn)))<0) return rc;
return count;
}
//static void invalidate_cache(struct i2c_client *client)
static int get_output_description (struct device *dev, char * buf, int chn)
{
int drv_type, drv_vdd, drv_trim, drv_invert,i;
struct i2c_client *client = to_i2c_client(dev);
if (((i=_verify_output_channel(client,chn)))<0) return i;
if (((drv_type= get_drv_type (client, chn)))<0) return drv_type;
if (((drv_vdd= get_drv_vdd (client, chn)))<0) return drv_vdd;
if (((drv_trim= get_drv_trim (client, chn)))<0) return drv_trim;
if (((drv_invert=get_drv_invert (client, chn)))<0) return drv_invert;
for (i=0; drv_configs[i].description; i++) {
if ((drv_configs[i].fmt==drv_type) &&
(drv_configs[i].vdd==drv_vdd) &&
(drv_configs[i].trim==drv_trim) &&
((drv_invert |(drv_configs[i].invert>>2)) == ((drv_configs[i].invert & 3) | (drv_configs[i].invert>>2)))){
return sprintf (buf,drv_configs[i].description);
}
}
return sprintf (buf,"Invalid output configuration: type = %d, vdd=%d, trim=%d, invert=%d",drv_type,drv_vdd,drv_trim,drv_invert);
}
static int get_out_frequency_txt(struct device *dev, char *buf, int chn)
{
int rc;
u64 out_freq[3];
struct i2c_client *client = to_i2c_client(dev);
if (((rc=get_out_frequency(client, out_freq, chn)))<0) return sprintf (buf,"Not set");
if (out_freq[1]==0) return sprintf(buf, "%lld Hz",out_freq[0]);
return sprintf(buf, "%lld-%lld/%lld Hz",out_freq[0],out_freq[1],out_freq[2]);
}
static ssize_t output_config_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn, i, rc;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
for (i=0; drv_configs[i].description; i++) if (strcmp(attr->attr.name,drv_configs[i].description) == 0) {
break;
}
if (!drv_configs[i].description) return -EINVAL; /* filename does not exist - BUG */
for (chn=0;chn<4;chn++){
if (((rc=get_drv_type (client, chn)))<0) return rc;
if (rc!=drv_configs[i].fmt) continue;
if (((rc=get_drv_vdd (client, chn)))<0) return rc;
if (rc!=drv_configs[i].vdd) continue;
if (((rc=get_drv_trim (client, chn)))<0) return rc;
if (rc!=drv_configs[i].trim) continue;
if (((rc=get_drv_invert (client, chn)))<0) return rc;
if (rc!= (drv_configs[i].invert & 3)) continue;
buf+=sprintf(buf," %d",chn);
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t output_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, num_bytes,rc;
while ((rc=sscanf(buf, "%d%n", &chn,&num_bytes))){
dev_dbg(dev,"buf=%s rc==%d chn=%d num_bytes=%d", buf, rc,chn,num_bytes);
buf+=num_bytes;
if (((rc=configure_output_driver(dev, attr->attr.name, chn)))<0) return rc;
}
return count;
}
static int configure_output_driver(struct device *dev, const char * name, int chn)
{
int i,rc;
struct i2c_client *client = to_i2c_client(dev);
dev_dbg(dev,"name=%s chn=%d", name,chn);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
for (i=0; drv_configs[i].description; i++) if (strcmp(name,drv_configs[i].description) == 0) {
if (((rc=set_drv_type (client, drv_configs[i].fmt, chn)))<0) return rc;
if (((rc=set_drv_vdd (client, drv_configs[i].vdd, chn)))<0) return rc;
if (((rc=set_drv_trim_any(client, drv_configs[i].trim, chn)))<0) return rc;
if (((rc=set_drv_invert (client, drv_configs[i].invert&3, chn)))<0) return rc;
return 0;
}
return -EINVAL;
}
static int si5338_sysfs_register(struct device *dev)
{
int retval=0;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval;
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_raw_group)))<0) return retval;
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_input_group)))<0) return retval;
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_multisynth_group)))<0) return retval;
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_pll_group)))<0) return retval;
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_output_group)))<0) return retval;
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_spread_spectrum_group)))<0) return retval;
#ifdef GENERATE_EXTRA
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_output_extra_group)))<0) return retval;
#endif
if (((retval = make_config_out (dev)))<0) return retval;
}
return retval;
}
static ssize_t invalidate_cache_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
invalidate_cache(client);
return count;
}
static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct si5338_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%d\n",clientdata->reg_addr);
}
static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct si5338_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%du", &clientdata->reg_addr);
return count;
}
static ssize_t raw_data_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct si5338_data_t *clientdata= i2c_get_clientdata(client);
int data= read_reg(client, clientdata->reg_addr);
return sprintf(buf, "%d\n",data);
}
static ssize_t raw_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct si5338_data_t *clientdata= i2c_get_clientdata(client);
int data;
sscanf(buf, "%du", &data);
write_reg(client, clientdata->reg_addr, data, 0xff); /* write all register, it is up to user to do R-mod-W */
return count;
}
static ssize_t raw_hex_address_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct si5338_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "0x%03x\n",clientdata->reg_addr);
}
static ssize_t raw_hex_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct si5338_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%x", &clientdata->reg_addr);
return count;
}
static ssize_t raw_hex_data_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct si5338_data_t *clientdata= i2c_get_clientdata(client);
int data= read_reg(client, clientdata->reg_addr);
return sprintf(buf, "0x%02x\n",data);
}
static ssize_t raw_hex_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct si5338_data_t *clientdata= i2c_get_clientdata(client);
int data;
sscanf(buf, "%x", &data);
write_reg(client, clientdata->reg_addr, data, 0xff); /* write all register, it is up to user to do R-mod-W */
return count;
}
static ssize_t raw_hex_all_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int low_addr=0,reg,data,rc,len=0, count=PAGE_SIZE;
struct i2c_client *client = to_i2c_client(dev);
// struct si5338_data_t *clientdata= i2c_get_clientdata(client);
for (reg=low_addr;reg<=LAST_REG;reg++) if (count>10){
if ((reg & 0xf) ==0){
rc=sprintf(buf, "%03x: ",reg);
buf+=rc;
len+=rc;
count-=rc;
}
data= read_reg(client, reg); //ignore errors
if (data<0) rc=sprintf(buf, "??");
else rc=sprintf(buf, "%02x",data);
buf+=rc;
len+=rc;
count-=rc;
if (((reg & 0xf) == 0xf) || (reg==LAST_REG)){
rc=sprintf(buf, "\n");
} else {
rc=sprintf(buf, " ");
}
buf+=rc;
len+=rc;
count-=rc;
}
return len;
}
static ssize_t raw_hex_adwe_help_show (struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Setting one/multiple registers with masks in the form [0x]AAADDWW, where AAA is register address\n" \
"DD - data byte and WW - write enable bits ( 1 - write, 0 - keep old)\n" \
"When read, provides current register data that can be used in device tree.\n");
}
//static const u32 register_masks[]= {
static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int i,data;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
for (i=0;i>8)))<0) return data;
buf+=sprintf(buf," 0x%x",((register_masks[i] & 0x1ff00)<<8) | (register_masks[i] & 0xff) | ((data & 0xff)<<8));
if (((i+1) & 0x7)==0) buf+=sprintf(buf,"\n");
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
/*
* accepts single or multiple data, each [0x]AAADDWW - AAA - register address, DD - data byte, WW - write enable mask (1 - write, 0 - keep).
* Ignores any other characters, so same format as in dts with hex data is OK
*/
static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
const char hex_digits[]="0123456789abcdefABCDEF";
struct i2c_client *client = to_i2c_client(dev);
struct si5338_data_t *clientdata= i2c_get_clientdata(client);
int adwe,rc=0;
int left=count,num_bytes;
const char * cp;
mutex_lock(&clientdata->lock);
while ((left>0) && ((cp=strpbrk(buf,hex_digits))) && cp[0]){
left -= (cp-buf);
buf = cp;
dev_dbg(dev,"left=%d", left);
sscanf(buf, "%x%n", &adwe,&num_bytes);
left-=num_bytes;
buf+=num_bytes;
dev_dbg(dev,"left=%d num_bytes=%d, adwe=0x%08x", left,num_bytes,adwe);
if (((rc=write_adwe(client, adwe)))<0) {
mutex_unlock(&clientdata->lock);
return rc;
}
}
mutex_unlock(&clientdata->lock);
return count;
}
static ssize_t input_xtal_freq_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
{
const char *txt[]= {"8MHz..11Mhz", "11MHz..19Mhz", "19MHz..26Mhz", "26MHz..30Mhz"};
struct i2c_client *client = to_i2c_client(dev);
int data= read_field (client, AWE_XTAL_FREQ);
return sprintf(buf, "%s\n",(data>=0)?txt[data]:"error");
}
static ssize_t in_frequency12_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
s64 freq= get_in_frequency (client,0);
if (freq<0) return -EINVAL;
return sprintf(buf, "%lld\n",freq);
}
static ssize_t in_frequency3_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
s64 freq= get_in_frequency (client,1);
if (freq<0) return -EINVAL;
return sprintf(buf, "%lld\n",freq);
}
static ssize_t in_frequency4_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
s64 freq= get_in_frequency (client,2);
if (freq<0) return -EINVAL;
return sprintf(buf, "%lld\n",freq);
}
static ssize_t in_frequency56_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
s64 freq= get_in_frequency (client,3);
if (freq<0) return -EINVAL;
return sprintf(buf, "%lld\n",freq);
}
static ssize_t in_frequency12_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
u64 freq;
struct i2c_client *client = to_i2c_client(dev);
sscanf(buf, "%lld", &freq);
if (((rc=set_in_frequency (client, freq,0)))<0) return rc;
return count;
}
static ssize_t in_frequency12xo_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
u64 freq;
struct i2c_client *client = to_i2c_client(dev);
sscanf(buf, "%lld", &freq);
if (((rc=set_in_frequency (client, freq,4)))<0) return rc;
return count;
}
static ssize_t in_frequency3_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
u64 freq;
struct i2c_client *client = to_i2c_client(dev);
sscanf(buf, "%lld", &freq);
if (((rc=set_in_frequency (client, freq,1)))<0) return rc;
return count;
}
static ssize_t in_frequency4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
u64 freq;
struct i2c_client *client = to_i2c_client(dev);
sscanf(buf, "%lld", &freq);
if (((rc=set_in_frequency (client, freq,2)))<0) return rc;
return count;
}
static ssize_t in_frequency56_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
u64 freq;
struct i2c_client *client = to_i2c_client(dev);
sscanf(buf, "%lld", &freq);
if (((rc=set_in_frequency (client, freq,3)))<0) return rc;
return count;
}
static ssize_t in_p12_div_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int div, chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name)+1;
if (((div=get_in_pdiv(client,chn)))<0) return div;
return sprintf(buf, "%d\n",div);
}
static ssize_t in_p12_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int div,rc,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name)+1;
sscanf(buf, "%d", &div);
if (((rc=set_in_pdiv(client, div,chn)))<0) return rc;
return count;
}
static ssize_t in_mux_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data;
struct i2c_client *client = to_i2c_client(dev);
if (((data=get_in_mux(client)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t in_mux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int data,rc;
sscanf(buf, "%d", &data);
if (((rc=set_in_mux(client, data)))<0) return rc;
return count;
}
static ssize_t in_mux_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
{
const char *mux_txt[]={"IN1/IN2(diff)","IN3(single ended)","IN1/IN2(xtal)"};
int data;
struct i2c_client *client = to_i2c_client(dev);
if (((data=get_in_mux(client)))<0) return data;
return sprintf(buf, "%s\n",mux_txt[data]);
}
static ssize_t fb_mux_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data;
struct i2c_client *client = to_i2c_client(dev);
if (((data=get_fb_mux(client)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t fb_mux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int data,rc;
sscanf(buf, "%d", &data);
if (((rc=set_fb_mux(client, data)))<0) return rc;
return count;
}
static ssize_t fb_mux_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
{
const char *mux_fb_txt[]={"IN5/IN6(diff)","IN4(single ended)","No clock"};
int data;
struct i2c_client *client = to_i2c_client(dev);
if (((data=get_fb_mux(client)))<0) return data;
return sprintf(buf, "%s\n",mux_fb_txt[data]);
}
static ssize_t in_pfd_ref_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data;
struct i2c_client *client = to_i2c_client(dev);
if (((data=get_in_pfd_ref_fb(client,0)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t in_pfd_ref_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int data,rc;
sscanf(buf, "%d", &data);
if (((rc=set_in_pfd_ref_fb(client, data,0)))<0) return rc;
return count;
}
static ssize_t in_pfd_ref_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
{
const char *pfd_ref_txt[]={"p1div_in(refclk)","p2div_in(fbclk)","p1div_out(refclk)","p2div_out(fbclk)","xoclk","noclk"};
int data;
struct i2c_client *client = to_i2c_client(dev);
if (((data=get_in_pfd_ref_fb(client,0)))<0) return data;
return sprintf(buf, "%s\n",pfd_ref_txt[data]);
}
static ssize_t fb_external_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data;
struct i2c_client *client = to_i2c_client(dev);
if (((data= get_fb_external(client)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t fb_external_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int data,rc;
sscanf(buf, "%d", &data);
if (((rc=set_fb_external(client, data)))<0) return rc;
return count;
}
static ssize_t in_pfd_fb_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data;
struct i2c_client *client = to_i2c_client(dev);
if (((data=get_in_pfd_ref_fb(client,1)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t in_pfd_fb_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int data,rc;
sscanf(buf, "%d", &data);
if (((rc=set_in_pfd_ref_fb(client, data,1)))<0) return rc;
return count;
}
static ssize_t in_pfd_fb_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
{
const char *pfd_fb_txt[]={"p2div_in(fbclk)","p1div_in(refclk)","p2div_out(fbclk)","p1div_out(refclk)","reserved","noclk"};
int data;
struct i2c_client *client = to_i2c_client(dev);
if (((data=get_in_pfd_ref_fb(client,1)))<0) return data;
return sprintf(buf, "%s\n",pfd_fb_txt[data]);
}
static ssize_t pll_ref_frequency_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
s64 pll_in_freq= get_pll_in_frequency(client);
if (pll_in_freq<0) return (int) pll_in_freq;
return sprintf(buf, "%lld\n",pll_in_freq);
}
static ssize_t pll_fb_frequency_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
s64 pll_fb_freq= get_pll_fb_frequency(client);
if (pll_fb_freq<0) return (int) pll_fb_freq;
return sprintf(buf, "%lld\n",pll_fb_freq);
}
static ssize_t ms_p123_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,chn;
u32 p123[3];
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (attr->attr.name[2]=='n') chn=4; /* exception for msn */
if (((rc=get_ms_p123(client,p123, chn)))<0) return rc;
// return sprintf(buf, "%ld %ld %ld\n",p123[0],p123[1],p123[2]);
return sprintf(buf, "%u %u %u\n",p123[0],p123[1],p123[2]);
}
static ssize_t ms_p123_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,chn;
u32 p123[3];
int num_items;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (attr->attr.name[2]=='n') chn=4; /* exception for msn */
num_items=sscanf(buf, "%u %u %u", &p123[0], &p123[1], &p123[2]);
if (num_items<3){
p123[1]=0;
p123[2]=1;
}
if (((rc=set_ms_p123(client,p123, chn)))<0) return rc;
if (chn<4){
if (((rc=disable_spread_spectrum(client,chn)))<0) return rc;
}
return count;
}
static ssize_t ms_abc_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,chn;
u32 p123[3];
u64 ms[3];
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (chn<0) chn=4; /* exception for msn - should have no digits*/
if (((rc=get_ms_p123(client,p123, chn)))<0) return rc;
p123_to_ms(ms,p123);
return sprintf(buf, "%lld %lld %lld\n",ms[0],ms[1],ms[2]);
}
static ssize_t ms_abc_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,chn;
u32 p123[3];
u64 ms[3];
int num_items;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (chn<0) chn=4; /* exception for msn - should have no digits*/
num_items=sscanf(buf, "%lld %lld %lld", &ms[0], &ms[1], &ms[2]);
if (num_items<3){
ms[1]=0;
ms[2]=1;
} else {
remove_common_factor(&ms[1]);
}
ms_to_p123(ms,p123);
if (((rc=set_ms_p123(client,p123, chn)))<0) return rc;
if (chn<4){
if (((rc=disable_spread_spectrum(client,chn)))<0) return rc;
}
return count;
}
static ssize_t ms_pwr_states_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn, i;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
for (chn=0;chn<4;chn++){
for (i=0; ms_pwr_states[i]; i++) if (strcmp(attr->attr.name,ms_pwr_states[i]) == 0) {
if (i== get_ms_powerdown(client, chn)){
buf+=sprintf(buf," %d",chn);
break;
}
}
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t ms_pwr_states_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, num_bytes,rc;
while ((rc=sscanf(buf, "%d%n", &chn,&num_bytes))){
dev_dbg(dev,"buf=%s rc==%d chn=%d num_bytes=%d", buf, rc,chn,num_bytes);
buf+=num_bytes;
if (((rc=set_ms_pwr_states(dev, attr->attr.name, chn)))<0) return rc;
}
return count;
}
static int set_ms_pwr_states(struct device *dev, const char * name, int chn)
{
int i,rc;
struct i2c_client *client = to_i2c_client(dev);
dev_dbg(dev,"name=%s chn=%d", name,chn);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
for (i=0; ms_pwr_states[i]; i++) if (strcmp(name,ms_pwr_states[i]) == 0) {
if (((rc=set_ms_powerdown(client, i, chn)))<0) return rc;
return 0;
}
return -EINVAL;
}
static int get_ms_powerup_state(struct device *dev, char * buf, int chn)
{
int index;
struct i2c_client *client = to_i2c_client(dev);
if (((index=get_ms_powerdown(client,chn)))<0) return index;
return sprintf (buf,ms_pwr_states[index]);
}
static ssize_t ms_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
reset_ms(client, 10);
return count;
}
static ssize_t ss_change_freq_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int mode;
struct i2c_client *client = to_i2c_client(dev);
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
mode=clientdata->ss_on_freq_change;
switch (mode) {
case 0: return sprintf(buf, "%d - turn spread spectrum off on frequency change\n",mode);
case 1: return sprintf(buf, "%d - recalculate spread spectrum on frequency change, do not reset MS\n",mode);
case 2: return sprintf(buf, "%d - turn spread spectrum off on frequency change, reset MS when SS is turned on\n",mode);
case 3: return sprintf(buf, "%d - recalculate spread spectrum on frequency change, do not reset MS\n",mode);
default: return sprintf(buf, "%d - invalid mode\n",mode);
}
}
static ssize_t ss_change_freq_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int num_items, mode;
struct i2c_client *client = to_i2c_client(dev);
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
num_items=sscanf(buf, "%d", &mode);
if (num_items && (mode>=0) && (mode<=3)){
clientdata->ss_on_freq_change=mode;
return count;
}
return -EINVAL;
}
static ssize_t ss_vals_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn,len;
if (((chn=get_chn_from_name(attr->attr.name)))<0) return chn;
if (((len= get_ss_vals(dev, buf, chn)))<0) return len;
sprintf (buf+len,"\n");
return len+1;
}
static ssize_t ss_vals_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, rc, state, num_items;
u32 rate,amp;
struct i2c_client *client = to_i2c_client(dev);
if (((chn=get_chn_from_name(attr->attr.name)))<0) return chn;
/* get current values */
if (((state= get_ss_state(client, chn)))<0) return state;
if (((rate= get_ss_down_rate(client, chn)))<0) return rate;
if (((amp= get_ss_down_amplitude(client, chn)))<0) return amp;
num_items=sscanf(buf, "%d %d %d", &state, &, &rate);
if (num_items>1){
if (((rc= store_ss_down_parameters(client, rate, amp, chn)))<0) return rc;
}
if (num_items>0){
if (state) {
/* calculate and set SS registers */
if (((rc=set_ss_down(client, chn)))<0) return rc;
/* enable SS, optionally reset MS */
if (((rc=enable_spread_spectrum(client, chn)))<0) return rc;
} else {
if (((rc=disable_spread_spectrum(client, chn)))<0) return rc;
}
}
return count;
}
static ssize_t ss_regs_hex_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn, rc;
u32 regs[7];
u32 *updown_reg, *up_regs, *down_regs;
struct i2c_client *client = to_i2c_client(dev);
updown_reg=®s[0];
down_regs=®s[1];
up_regs=®s[4];
if (((chn=get_chn_from_name(attr->attr.name)))<0) return chn;
if (((rc= get_ss_regs(client, up_regs, down_regs, updown_reg, chn)))<0) return rc;
return sprintf(buf, "updown_par=0x%x down_pars=0x%x 0x%x 0x%x up_pars= 0x%x 0x%x 0x%x\n",
regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6]);
}
static ssize_t ss_regs_hex_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, rc, num_items;
u32 regs[7];
u32 *updown_reg, *up_regs, *down_regs;
struct i2c_client *client = to_i2c_client(dev);
updown_reg=®s[0];
down_regs=®s[1];
up_regs=®s[4];
if (((chn=get_chn_from_name(attr->attr.name)))<0) return chn;
if (((rc= get_ss_regs(client, up_regs, down_regs, updown_reg, chn)))<0) return rc;
num_items=sscanf(buf, "%x %x %x %x %x %x %x", ®s[0], ®s[1], ®s[2], ®s[3], ®s[4], ®s[5], ®s[6]);
if (num_items>0){
if (num_items<5) up_regs=NULL;
if (num_items<2) down_regs=NULL;
if (((rc= set_ss_regs(client, up_regs, down_regs, updown_reg, chn)))<0) return rc;
}
return count;
}
static ssize_t pre_init_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,clear_all;
struct i2c_client *client = to_i2c_client(dev);
clear_all=strstr(attr->attr.name,"clear")?1:0;
if (((rc=pre_init(client,clear_all)))<0) return rc;
return count;
}
static ssize_t post_init_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int rc,timeout=0;
sscanf(buf, "%d", &timeout);
if (timeout <=0) timeout=INIT_TIMEOUT;
if (((rc=post_init(client,timeout)))<0) return rc;
return count;
}
static ssize_t pll_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int rc;
u64 pll_freq[3];
struct i2c_client *client = to_i2c_client(dev);
if (((rc=get_pll_freq(client,pll_freq)))<0) return rc;
return sprintf(buf, "%lld %lld %lld\n",pll_freq[0],pll_freq[1],pll_freq[2]);
}
static ssize_t pll_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int rc,int_div,by_out;
u64 freq[3];
int num_items;
int_div=(strstr(attr->attr.name,"_fract"))?0:1; /* if filename contains '_fract' - 0, not - 1 */
by_out=(strstr(attr->attr.name,"_by_out"))?1:0; /* if filename contains '_by_out' - 1, not - 0 */
num_items=sscanf(buf, "%lld %lld %lld", &freq[0], &freq[1], &freq[2]);
if (num_items<3){
freq[1]=0;
freq[2]=1;
}
if (by_out) {
if (((rc=set_pll_freq_by_out(client, freq, int_div)))<0) return rc;
} else {
if (((rc=set_pll_freq (client, freq, int_div)))<0) return rc;
}
if (((rc=set_pll_paremeters(client)))<0) return rc;
/* if (((rc=set_misc_registers(client)))<0) return rc;*/ /* moved to pre_init() */
return count;
}
static ssize_t ms_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,chn;
u64 ms_freq[3];
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((rc=get_pll_ms_freq(client, ms_freq, chn)))<0) return rc;
return sprintf(buf, "%lld %lld %lld\n",ms_freq[0],ms_freq[1],ms_freq[2]);
}
static ssize_t ms_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,chn,int_div;
u64 freq[3];
int num_items;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
int_div=(strstr(attr->attr.name,"_fract"))?0:1; /* if includes 'fract' - 0, not - 1 */
num_items=sscanf(buf, "%lld %lld %lld", &freq[0], &freq[1], &freq[2]);
if (num_items<3){
freq[1]=0;
freq[2]=1;
}
if (((rc=set_pll_ms_by_out(client, freq, chn, int_div)))<0) return rc;
return count;
}
/* -----------Output section--------------------------- */
static ssize_t out_source_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int out_src,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((out_src=get_out_source(client, chn)))<0) return out_src;
return sprintf(buf, "%d\n",out_src);
}
static ssize_t out_source_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int rc,chn;
int out_src;
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &out_src);
if (((rc=set_out_source(client, chn, out_src)))<0) return rc;
return count;
}
static ssize_t out_source_txt_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int out_src,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((out_src=get_out_source(client, chn)))<0) return out_src;
switch (out_src){
case 0: return sprintf(buf, "p2div_in\n");
case 1: return sprintf(buf, "p1div_in\n");
case 2: return sprintf(buf, "p2div_out\n");
case 3: return sprintf(buf, "p1div_out\n");
case 4: return sprintf(buf, "xoclk\n");
case 5: return sprintf(buf, "MS0\n");
case 6: return sprintf(buf, "MS%d\n",chn);
case 7: return sprintf(buf, "No clock\n");
}
return -EINVAL;
}
static ssize_t out_source_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,chn;
u64 out_source_freq[3];
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((rc=get_output_src_frequency(client, out_source_freq, chn)))<0) return rc;
return sprintf(buf, "%lld %lld %lld\n",out_source_freq[0],out_source_freq[1],out_source_freq[2]);
}
static ssize_t out_div_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int div,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((div=get_out_div(client,chn)))<0) return div;
return sprintf(buf, "%d\n",div);
}
static ssize_t out_div_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int div,rc,chn;
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &div);
if (((rc=set_out_div(client, div,chn)))<0) return rc;
return count;
}
static ssize_t out_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,chn;
u64 out_freq[3];
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((rc=get_out_frequency(client, out_freq, chn)))<0) return rc;
return sprintf(buf, "%lld %lld %lld\n",out_freq[0],out_freq[1],out_freq[2]);
}
static ssize_t out_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,int_div,chn;
u64 freq[3];
int num_items;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
int_div=(strstr(attr->attr.name,"_fract"))?0:1; /* if filename contains '_fract' - 0, not - 1 */
num_items=sscanf(buf, "%lld %lld %lld", &freq[0], &freq[1], &freq[2]);
if (num_items<3){
freq[1]=0;
freq[2]=1;
}
if (((rc=set_out_frequency_and_route (client, freq, chn, int_div)))<0) return rc;
return count;
}
static ssize_t out_div_by_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int rc,chn;
u64 freq[3];
int num_items;
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
num_items=sscanf(buf, "%lld %lld %lld", &freq[0], &freq[1], &freq[2]);
if (num_items<3){
freq[1]=0;
freq[2]=1;
}
if (((rc=set_out_div_by_frequency(client, freq, chn)))<0) return rc;
return count;
}
static ssize_t out_pwr_states_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn, i;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
for (chn=0;chn<4;chn++){
for (i=0; out_pwr_states[i]; i++) if (strcmp(attr->attr.name,out_pwr_states[i]) == 0) {
if (i== get_drv_powerdown(client, chn)){
buf+=sprintf(buf," %d",chn);
break;
}
}
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t out_pwr_states_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, num_bytes,rc;
while ((rc=sscanf(buf, "%d%n", &chn,&num_bytes))){
dev_dbg(dev,"buf=%s rc==%d chn=%d num_bytes=%d", buf, rc,chn,num_bytes);
buf+=num_bytes;
if (((rc=set_out_pwr_states(dev, attr->attr.name, chn)))<0) return rc;
}
return count;
}
static int set_out_pwr_states(struct device *dev, const char * name, int chn)
{
int i,rc;
struct i2c_client *client = to_i2c_client(dev);
dev_dbg(dev,"name=%s chn=%d", name,chn);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
for (i=0; out_pwr_states[i]; i++) if (strcmp(name,out_pwr_states[i]) == 0) {
if (((rc=set_drv_powerdown(client, i, chn)))<0) return rc;
return 0;
}
return -EINVAL;
}
static int get_powerup_state(struct device *dev, char * buf, int chn)
{
int index;
struct i2c_client *client = to_i2c_client(dev);
if (((index=get_drv_powerdown(client,chn)))<0) return index;
return sprintf (buf,out_pwr_states[index]);
}
static ssize_t out_en_states_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn, i;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
for (chn=0;chn<4;chn++){
for (i=0; out_en_states[i]; i++) if (strcmp(attr->attr.name,out_en_states[i]) == 0) {
if (i== get_drv_disable(client, chn)){
buf+=sprintf(buf," %d",chn);
break;
}
}
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t out_en_states_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, num_bytes,rc;
while ((rc=sscanf(buf, "%d%n", &chn,&num_bytes))){
dev_dbg(dev,"buf=%s rc==%d chn=%d num_bytes=%d", buf, rc,chn,num_bytes);
buf+=num_bytes;
if (((rc=set_out_en_states(dev, attr->attr.name, chn)))<0) return rc;
}
return count;
}
static int set_out_en_states(struct device *dev, const char * name, int chn)
{
int i,rc;
struct i2c_client *client = to_i2c_client(dev);
dev_dbg(dev,"name=%s chn=%d", name,chn);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
for (i=0; out_en_states[i]; i++) if (strcmp(name,out_en_states[i]) == 0) {
if (((rc=set_drv_disable(client, i, chn)))<0) return rc;
return 0;
}
return -EINVAL;
}
static int get_enabled_state(struct device *dev, char * buf, int chn)
{
int index;
struct i2c_client *client = to_i2c_client(dev);
if (((index=get_drv_disable(client,chn)))<0) return index;
return sprintf (buf,out_en_states[index]);
}
static ssize_t out_dis_states_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn, i;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
for (chn=0;chn<4;chn++){
for (i=0; out_dis_states[i]; i++) if (strcmp(attr->attr.name,out_dis_states[i]) == 0) {
if (i== get_drv_disabled_state(client, chn)){
buf+=sprintf(buf," %d",chn);
break;
}
}
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t out_dis_states_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, num_bytes,rc;
while ((rc=sscanf(buf, "%d%n", &chn,&num_bytes))){
dev_dbg(dev,"buf=%s rc==%d chn=%d num_bytes=%d", buf, rc,chn,num_bytes);
buf+=num_bytes;
if (((rc=set_out_dis_states(dev, attr->attr.name, chn)))<0) return rc;
}
return count;
}
static int set_out_dis_states(struct device *dev, const char * name, int chn)
{
int i,rc;
struct i2c_client *client = to_i2c_client(dev);
dev_dbg(dev,"name=%s chn=%d", name,chn);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
for (i=0; out_dis_states[i]; i++) if (strcmp(name,out_dis_states[i]) == 0) {
if (((rc=set_drv_disabled_state(client, i, chn)))<0) return rc;
return 0;
}
return -EINVAL;
}
static int get_disabled_state(struct device *dev, char * buf, int chn)
{
int index;
struct i2c_client *client = to_i2c_client(dev);
if (((index=get_drv_disabled_state(client,chn)))<0) return index;
return sprintf (buf,out_dis_states[index]);
}
#ifdef GENERATE_EXTRA
static ssize_t drv_powerdown_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_powerdown(client,chn)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t drv_powerdown_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int data,rc,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &data);
if (((rc=set_drv_powerdown(client, data, chn)))<0) return rc;
return count;
}
static ssize_t drv_disable_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_disable(client,chn)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t drv_disable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int data,rc,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &data);
if (((rc=set_drv_disable(client, data, chn)))<0) return rc;
return count;
}
static ssize_t drv_disabled_state_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_disabled_state(client,chn)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t drv_disabled_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int data,rc,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &data);
if (((rc=set_drv_disabled_state(client, data, chn)))<0) return rc;
return count;
}
static ssize_t drv_invert_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_invert(client,chn)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t drv_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int data,rc,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &data);
if (((rc=set_drv_invert(client, data, chn)))<0) return rc;
return count;
}
static ssize_t drv_invert_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_invert(client,chn)))<0) return data;
switch (data) {
case 0:return sprintf(buf, "No inversion\n");
case 1:return sprintf(buf, "Invert A only (CMOS/SSTL,HSTL)\n");
case 2:return sprintf(buf, "Invert B only (CMOS/SSTL,HSTL)\n");
case 3:return sprintf(buf, "Invert both A and B (CMOS/SSTL,HSTL)\n");
}
return 0; /* never */
}
static ssize_t drv_type_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_type(client,chn)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t drv_type_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int data,rc,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &data);
if (((rc=set_drv_type(client, data, chn)))<0) return rc;
return count;
}
static ssize_t drv_type_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_type(client,chn)))<0) return data;
switch (data) {
case 0:return sprintf(buf, "reserved\n");
case 1:return sprintf(buf, "CMOS/SSTL/HSTL A enabled, B disabled\n");
case 2:return sprintf(buf, "CMOS/SSTL/HSTL A disabled, A enabled\n");
case 3:return sprintf(buf, "CMOS/SSTL/HSTL A enabled, B enabled\n");
case 4:return sprintf(buf, "LVPECL\n");
case 5:return sprintf(buf, "LVDS\n");
case 6:return sprintf(buf, "CML\n");
case 7:return sprintf(buf, "HCSL\n");
}
return 0; /* never */
}
static ssize_t drv_vdd_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_vdd(client,chn)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t drv_vdd_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int data,rc,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &data);
if (((rc=set_drv_vdd(client, data, chn)))<0) return rc;
return count;
}
static ssize_t drv_vdd_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_vdd(client,chn)))<0) return data;
switch (data) {
case 0:return sprintf(buf, "3.3V\n");
case 1:return sprintf(buf, "2.5V\n");
case 2:return sprintf(buf, "1.8V\n");
case 3:return sprintf(buf, "1.5V\n");
}
return 0; /* never */
}
static ssize_t drv_trim_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int data,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_trim(client,chn)))<0) return data;
return sprintf(buf, "%d\n",data);
}
static ssize_t drv_auto_trim_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int data,rc,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &data);
if (((rc=update_drv_trim(client, data, chn)))<0) return rc;
return count;
}
static ssize_t drv_trim_any_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int data,rc,chn;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
sscanf(buf, "%d", &data);
if (((rc=set_drv_trim_any(client, data, chn)))<0) return rc;
return count;
}
static ssize_t drv_txt_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int chn;
char * data;
struct i2c_client *client = to_i2c_client(dev);
chn=get_chn_from_name(attr->attr.name); /* uses first digit in the name */
if (((data=get_drv_txt(client,chn)))==NULL) return -EINVAL;
return sprintf(buf, "%s\n",data);
}
/* uses out_type and out_vddo */
static int update_drv_trim(struct i2c_client *client, int novtt, int chn) /* no Vtt - CMOS, no termination, where it matters */
{
int rc;
int out_type, out_vdd,trim=-1;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if (((out_type=get_drv_type(client,chn)))<0) return out_type;
if (((out_vdd=get_drv_vdd(client,chn)))<0) return out_vdd;
switch (out_type) {
case 1:
case 2:
case 3:
switch (out_vdd){
case 0:trim=novtt?0x17:0x04; break;
case 1:trim=novtt?0x13:0x0d; break;
case 2:trim=novtt?0x17:0x15; break;
case 3:trim=0x1f; break;
}
break;
case 4:
switch (out_vdd){
case 0:trim=0x0f; break;
case 1:trim=0x10; break;
}
break;
case 5:
switch (out_vdd){
case 0:trim=0x08; break;
case 1:trim=0x09; break;
}
break;
case 6:
switch (out_vdd){
case 0:trim=0x03; break;
case 1:
case 2:trim=0x04; break;
}
break;
case 7:
switch (out_vdd){
case 0:
case 1:
case 2:trim=0x07; break;
}
break;
}
if (trim<0){
dev_err(&client->dev, "Invalid combination of output type (%d) and voltage (%d)\n",out_type,out_vdd);
return - EINVAL;
}
return write_multireg64(client, trim, awe_drv_trim[chn]);
}
/* uses out_type, out_vddo and out_trim */
static char * get_drv_txt(struct i2c_client *client, int chn)
{
int rc;
int out_type, out_vdd,out_trim=-1;
if (((rc=_verify_output_channel(client,chn)))<0) return NULL;
if (((out_type=get_drv_type(client,chn)))<0) return NULL;
if (((out_vdd=get_drv_vdd(client,chn)))<0) return NULL;
if (((out_vdd=get_drv_trim(client,chn)))<0) return NULL;
switch (out_type) {
case 1:
switch (out_vdd){
case 0:return (out_trim & 0x10)?"3.3V CMOS, A & B":"3.3V SSTL, A only";
case 1:return (out_trim & 0x10)?"2.5V CMOS, A & B":"2.5V SSTL, A only";
case 2:return (out_trim & 0x02)?"1.8V SSTL, A & B":"1.8V CMOS, A only";
case 3:return "1.5V HSTL, A only";
}
break;
case 2:
switch (out_vdd){
case 0:return (out_trim & 0x10)?"3.3V CMOS, A & B":"3.3V SSTL, B only";
case 1:return (out_trim & 0x10)?"2.5V CMOS, A & B":"2.5V SSTL, B only";
case 2:return (out_trim & 0x02)?"1.8V SSTL, A & B":"1.8V CMOS, B only";
case 3:return "1.5V HSTL, B only";
}
break;
case 3:
switch (out_vdd){
case 0:return (out_trim & 0x10)?"3.3V CMOS, A & B":"3.3V SSTL, A & B";
case 1:return (out_trim & 0x10)?"2.5V CMOS, A & B":"2.5V SSTL, A & B";
case 2:return (out_trim & 0x02)?"1.8V SSTL, A & B":"1.8V CMOS, A & B";
case 3:return "1.5V HSTL, A & B";
}
break;
case 4:
switch (out_vdd){
case 0:return "3.3V LVPECL";
case 1:return "2.5V LVPECL";
}
break;
case 5:
switch (out_vdd){
case 0:return "3.3V CML";
case 1:return "2.5V CML";
}
break;
case 6:
switch (out_vdd){
case 0:return "3.3V LVDS";
case 1:return "2.5V LVDS";
case 2:return "1.8V LVDS";
}
break;
case 7:
switch (out_vdd){
case 0:return "3.3V HCSL";
case 1:return "2.5V HCSL";
case 2:return "1.8V HCSL";
}
break;
}
dev_err(&client->dev, "Invalid combination of output type (%d) and voltage (%d)\n",out_type,out_vdd);
switch (out_vdd){
case 0:return "3.3V - invalid type";
case 1:return "2.5V - invalid type";
case 2:return "1.8V - invalid type";
case 3:return "1.5V - invalid type";
}
return NULL; /* never */
}
#endif
/* -----------Output section--------------------------- */
static int remove_common_factor(u64 * num_denom)
{
u64 a,b,r;
if (num_denom[1]==0) return -1; /* zero denominator */
if (num_denom[0]==0) {
num_denom[1]=1;
return 1;
}
a=max(num_denom[0],num_denom[1]);
b=min(num_denom[0],num_denom[1]);
r=b;
while (r>1) {
r=a-b*div64_u64(a,b);
if (r==0){
num_denom[0]=div64_u64(num_denom[0],b);
num_denom[1]=div64_u64(num_denom[1],b);
return 1;
}
a=b;
b=r;
}
return 0; /* nothing done */
}
static int _verify_output_channel(struct i2c_client *client,int chn)
{
if ((chn<0) || (chn>3)){
dev_err(&client->dev, "Invalid output channel: %d (only 0..3 are allowed)\n",chn);
return - EINVAL;
}
return 0;
}
static int get_ss_vals(struct device *dev, char * buf, int chn)
{
int state;
u32 rate,amp;
struct i2c_client *client = to_i2c_client(dev);
if (((state= get_ss_state(client, chn)))<0) return state;
if (((amp= get_ss_down_amplitude(client, chn)))<0) return amp;
if (((rate= get_ss_down_rate(client, chn)))<0) return rate;
return sprintf(buf, "Spread spectrum is %s, down amplitude= %d ( *0.01%%), spread rate= %d Hz", state?"ON":"OFF", amp, rate);
}
static int get_ss_state(struct i2c_client *client, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return read_field(client, awe_ms_ssmode[chn]);
}
static int set_ss_state(struct i2c_client *client, int state, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return write_field(client, state , awe_ms_ssmode[chn]);
}
static int get_ss_down_rate(struct i2c_client *client, int chn)
{
int rc;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return clientdata->spread_spectrum_rate[chn]; /* in Hz */
}
static int get_ss_down_amplitude(struct i2c_client *client, int chn)
{
int rc;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return clientdata->spread_spectrum_amp[chn];
}
/* store required parameters - they will be needed to recalculate SS registers after MS frequency change */
static int store_ss_down_parameters(struct i2c_client *client, u32 rate, u32 amp, int chn) /* chn 0,1,2,3 */
{
int rc;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if ((rate < SPREAD_RATE_MIN) || (rate > SPREAD_RATE_MAX)){
dev_err(&client->dev, "Invalid spread spectrum rate %u - should be in [%u,%u]Hz\n",rate,SPREAD_RATE_MIN,SPREAD_AMP_MAX);
return - EINVAL;
}
if ((amp < SPREAD_AMP_MIN) || (amp > SPREAD_AMP_MAX)){
dev_err(&client->dev, "Invalid spread spectrum amplitude %u - should be in [%u,%u] (*0.01%%)\n",amp,SPREAD_AMP_MIN,SPREAD_AMP_MAX);
return - EINVAL;
}
clientdata->spread_spectrum_rate[chn]=rate; /* in Hz */
clientdata->spread_spectrum_amp[chn]=amp; /* in 0.01% */
return 0;
}
/* recalculate and set SS registers, disable SS if invalid */
static int set_ss_down(struct i2c_client *client, int chn) /* chn 0,1,2,3 */
{
int rc;
u32 ssud,ssup[3],ssdn[3];
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
/* calculate spread spectrum registers */
if (((rc=calc_ss_down_to_regs(client, ssup, ssdn, &ssud, chn)))<0) return rc;
if (rc!=0){
return disable_spread_spectrum(client,chn); /* SS parameters were never set*/
}
/* set spread spectrum registers */
if (((rc=set_ss_regs(client, ssup, ssdn, &ssud, chn)))<0) return rc;
#if 0
/* enable spread spectrum mode */
if (((rc=enable_spread_spectrum(client, chn)))<0) return rc;
#endif
return 0;
}
static int ss_pre_freq_change(struct i2c_client *client, int chn) /* chn 0,1,2,3 */
{
int rc;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if ((clientdata->ss_on_freq_change & 1)==0) {
dev_dbg(&client->dev, "Disabling spread spectrum before changing MS%d divider",chn);
if (((rc=disable_spread_spectrum(client, chn)))<0) return rc;
}
return 0;
}
static int ss_post_freq_change(struct i2c_client *client, int chn) /* chn 0,1,2,3 */
{
int rc, ss_state;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if (((ss_state=get_ss_state(client,chn)))<0) return ss_state;
if (ss_state){
/* recalculate and set SS registers */
dev_dbg(&client->dev, "Recalculating spread spectrum after changing MS%d divider",chn);
if (((rc=set_ss_down(client,chn)))<0) return rc;
if (clientdata->ss_on_freq_change & 2) {
reset_ms(client, 10);
}
}
return 0;
}
static int calc_ss_down_to_regs(struct i2c_client *client, u32 * up_regs, u32 * down_regs, u32 * updown_reg, int chn) /* chn 0,1,2,3 */
{
int rc;
u32 ssud;
u64 ms_freq, xy[2];
u32 p123[3];
u64 ms[3];
u32 rate, amp;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
rate=clientdata->spread_spectrum_rate[chn]; /* in Hz */
amp=clientdata->spread_spectrum_amp[chn]; /* in 0.01% */
dev_dbg(&client->dev,"rate=%d, amp=%d\n",rate,amp);
if ((rate==0) || (amp==0)) return 1; /* Should disable SS */
if ((rate < SPREAD_RATE_MIN) || (rate > SPREAD_RATE_MAX)){
dev_err(&client->dev, "*Invalid spread spectrum rate %u - should be in [%u,%u]Hz\n",rate,SPREAD_RATE_MIN,SPREAD_AMP_MAX);
return - EINVAL;
}
if ((amp < SPREAD_AMP_MIN) || (amp > SPREAD_AMP_MAX)){
dev_err(&client->dev, "*Invalid spread spectrum amplitude %u - should be in [%u,%u] (*0.01%%)\n",amp,SPREAD_AMP_MIN,SPREAD_AMP_MAX);
return - EINVAL;
}
if (((rc=get_pll_ms_freq(client, &ms_freq, chn)))<0) return rc;
if (ms_freq==0){
dev_err(&client->dev, "MS%d frequency is not set, can not apply spread spectrum\n",chn);
return - EINVAL;
}
if (((rc=get_ms_p123(client,p123, chn)))<0) return rc;
p123_to_ms(ms,p123);
ssud=(u32) div64_u64(ms_freq,rate << 2);
if (updown_reg) updown_reg[0]= ssud;
if (down_regs){
xy[0]=6400000000LL*amp*(ms[0]*ms[2]+ms[1]);
xy[0]=div64_u64(xy[0],ms[2]);
xy[1]= 100000000LL*(10000-amp)*ssud;
dev_dbg(&client->dev,"x=0x%llx, y=0x%llx,\n",xy[0],xy[1]);
remove_common_factor(xy);
dev_dbg(&client->dev,"x=0x%llx, y=0x%llx,\n",xy[0],xy[1]);
down_regs[0]= (u32) div64_u64(xy[0],xy[1]);
down_regs[2]= (u32)xy[1];
down_regs[1]= (u32)xy[0] - down_regs[2]*down_regs[0];
}
if (up_regs){
up_regs[0]=0;
up_regs[1]=1;
up_regs[2]=0;
}
dev_dbg(&client->dev,"updown=0x%x, down[0]=0x%x, down[1]=0x%x, down[2]=0x%x, up[0]=0x%x, up[1]=0x%x, up[2]=0x%x\n",
updown_reg[0],down_regs[0],down_regs[1],down_regs[2],up_regs[0],up_regs[1],up_regs[2]);
return 0;
}
static int get_ss_regs(struct i2c_client *client, u32 * up_regs, u32 * down_regs, u32 * updown_reg, int chn) /* chn 0,1,2,3 */
{
int i;
s64 rc;
if (((rc=_verify_output_channel(client,chn)))<0) return (int) rc;
if (up_regs) for (i=0;i<3;i++){
if (((rc=read_multireg64 (client, awe_msx_ssup[chn][i])))<0) return (int) rc;
up_regs[i]= (u32) rc;
}
if (down_regs) for (i=0;i<3;i++){
if (((rc=read_multireg64 (client, awe_msx_ssdn[chn][i])))<0) return (int) rc;
down_regs[i]= (u32) rc;
}
if (updown_reg) {
if (((updown_reg[0]=read_multireg64 (client, awe_msx_ssud[chn])))<0) return (int) updown_reg[0];
}
return 0;
}
static int set_ss_regs(struct i2c_client *client, u32 * up_regs, u32 * down_regs, u32 * updown_reg, int chn) /* chn 0,1,2,3, */
{
int i,rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if (up_regs){
dev_dbg(&client->dev,"up[0]=0x%x, up[1]=0x%x, up[2]=0x%x\n",up_regs[0],up_regs[1],up_regs[2]);
for (i=0;i<3;i++){
if (((rc=write_multireg64 (client, (u64) up_regs[i], awe_msx_ssup[chn][i])))<0) return rc;
}
}
if (down_regs) {
dev_dbg(&client->dev,"down[0]=0x%x, down[1]=0x%x, down[2]=0x%x\n",down_regs[0],down_regs[1],down_regs[2]);
for (i=0;i<3;i++){
if (((rc=write_multireg64 (client, (u64) down_regs[i], awe_msx_ssdn[chn][i])))<0) return rc;
}
}
if (updown_reg) {
dev_dbg(&client->dev,"updown=0x%x\n",updown_reg[0]);
if (((rc=write_multireg64 (client, (u64) updown_reg[0], awe_msx_ssud[chn])))<0) return rc;
}
return 0;
}
static int disable_spread_spectrum(struct i2c_client *client,int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
/* disable spread spectrum - only this register was changed to 0 from default 1 */
if (((rc=write_multireg64(client, 0 , awe_msx_ssup[chn][2])))<0) return rc;
if (((rc=set_ss_state(client, 0, chn)))<0) return rc;
return 0;
}
static int enable_spread_spectrum(struct i2c_client *client,int chn)
{
int rc;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if (((rc=set_ss_state(client, 1, chn)))<0) return rc;
if (clientdata->ss_on_freq_change & 2) {
if (((rc=reset_ms(client, 10)))<0) return rc; /* 10 - wait cycles */
}
return 0;
}
static int get_drv_powerdown(struct i2c_client *client, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return read_field (client, awe_drv_powerdown[chn]);
}
static int set_drv_powerdown(struct i2c_client *client, int typ, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if (typ) typ=1;
return write_field (client, (u8) typ, awe_drv_powerdown[chn]);
}
static int get_drv_disable(struct i2c_client *client, int chn)
{
int rc;
if ((chn!=4) && (((rc=_verify_output_channel(client,chn)))<0)) return rc;
return read_field (client, awe_drv_disable[chn]);
}
static int set_drv_disable(struct i2c_client *client, int typ, int chn)
{
int rc;
if ((chn!=4) && (((rc=_verify_output_channel(client,chn)))<0)) return rc;
if (typ) typ=1;
return write_field (client, (u8) typ, awe_drv_disable[chn]);
}
static int get_drv_disabled_state(struct i2c_client *client, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return read_field (client, awe_drv_dis_state[chn]);
}
static int set_drv_disabled_state(struct i2c_client *client, int typ, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if ((typ<0) || (typ>3)){
dev_err(&client->dev, "Invalid disabled state %d. Only 0..3 are supported\n",typ);
return - EINVAL;
}
return write_field (client, (u8) typ, awe_drv_dis_state[chn]);
}
static int get_drv_invert(struct i2c_client *client, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return read_field (client, awe_drv_invert[chn]);
}
static int set_drv_invert(struct i2c_client *client, int typ, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if ((typ<0) || (typ>3)){
dev_err(&client->dev, "Invalid invert drivers %d. Only 0..3 are supported\n",typ);
return - EINVAL;
}
return write_field (client, (u8) typ, awe_drv_invert[chn]);
}
static int get_drv_type(struct i2c_client *client, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return read_field (client, awe_drv_fmt[chn]);
}
static int set_drv_type(struct i2c_client *client, int typ, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if ((typ<0) || (typ>7)){
dev_err(&client->dev, "Invalid output type %d. Only 0..7 are supported\n",typ);
return - EINVAL;
}
return write_field (client, (u8) typ, awe_drv_fmt[chn]);
}
static int get_drv_vdd(struct i2c_client *client, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return read_field (client, awe_drv_vddo[chn]);
}
static int set_drv_vdd(struct i2c_client *client, int vdd, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if ((vdd<0) || (vdd>7)){
dev_err(&client->dev, "Invalid output type %d. Only 0..3 are supported\n",vdd);
return - EINVAL;
}
return write_field (client, (u8) vdd, awe_drv_vddo[chn]);
}
static int get_drv_trim(struct i2c_client *client, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return (int) read_multireg64 (client, awe_drv_trim[chn]);
}
static int set_drv_trim_any(struct i2c_client *client, int trim, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if ((trim<0) || (trim>31)){
dev_err(&client->dev, "Invalid output type %d. Only 0..31 are supported\n",trim);
return - EINVAL;
}
return write_multireg64(client, trim, awe_drv_trim[chn]);
}
static int set_out_div(struct i2c_client *client, int div, int chn) /*chn =0..3 */
{
int rc;
u8 val;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
for (val=0;valdev, "Invalid value for output divider: %d\n",div);
return - EINVAL;
}
static int get_out_div(struct i2c_client *client, int chn) /*chn =0..3 */
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if (((rc=read_field(client, awe_rdiv_k[chn])))<0) return rc;
if (rc>=ARRAY_SIZE(out_div_values)){
dev_err(&client->dev, "Invalid value for output divider: %d\n",rc);
return - EINVAL;
}
return out_div_values[rc];
}
static int set_out_div_by_frequency(struct i2c_client *client, u64* out_freq, int chn) /*chn =0..3 */
{
int rc,i,idiv;
u64 out_src_freq[3],div, div15, out_src_num,out_src_denom,out_num,out_denom;
if (((rc=get_output_src_frequency(client, out_src_freq, chn)))<0) return rc;
out_src_num=out_src_freq[0]*out_src_freq[2]+out_src_freq[1];
out_src_denom=out_src_freq[2];
out_num=out_freq[0]*out_freq[2]+out_freq[1];
out_denom=out_freq[2];
if (out_num==0){
dev_err(&client->dev, "Zero output frequency for channel: %d\n",chn);
return - EINVAL;
}
while ((out_src_denom>0x1000) || (((out_src_denom | out_src_num) &1)==0)){
out_src_denom>>=1;
out_src_num>>= 1;
}
while ((out_denom>0x1000) || (((out_denom | out_num) &1)==0)){
out_denom>>=1;
out_num>>= 1;
}
dev_dbg(&client->dev, "out_src_num=%lld, out_src_denom=%lld, out_num=%lld, out_denom=%lld, \n",
out_src_num, out_src_denom, out_num, out_denom);
out_src_num*=out_denom;
out_src_denom*=out_num;
div=div64_u64(out_src_num + (out_src_denom>>1), out_src_denom);
div15=div+(div>>1);
dev_dbg(&client->dev, "out_src_num*out_denom=%lld, out_src_denom*out_num=%lld, div=%lld, div15=%lld \n",
out_src_num, out_src_denom, div, div15);
if ((div15<1) || (div15>=64)) {
dev_err(&client->dev, "Output divider (%d) out of 1..32 range for output %d \n",(int) div,chn);
return - EINVAL;
}
idiv=(int) div15;
for (i=5;i>=0;i--) if ((1<7)){
dev_err(&client->dev, "Invalid source %d. Only 0...7 are supported\n",src);
return - EINVAL;
}
return write_field (client, (u8) src, awe_rdiv_in[chn]);
}
static int get_out_ms(struct i2c_client *client, int chn)
{
int rc,out_src;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if (((out_src=get_out_source(client, chn)))<0) return out_src;
switch (out_src){
case 5: return 0;
case 6: return chn;
}
return -1;
}
/* Examples:
* "IN12:2:4"
* "XO:1:1"
* "MS0:16"
* "NO"
*/
static int get_out_route(struct i2c_client *client, char* buf, int chn)
{
int rc;
int out_src,div1=-1,div2=-1,src_group, src;
const int in_numbers[]={12,3,4,56};
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if (((out_src=get_out_source(client, chn)))<0) return out_src;
if (((div2=get_out_div(client,chn)))<0) return div2; /* 1/2/4/8/16/32 */
switch (out_src){
case 0: /* p2div in */
case 2: /* p2div out */
if (out_src & 2) {
if (((div1=get_in_pdiv(client,1)))<0) return div1; /* 1/2/4/8/16/32 */
} else div1=1;
if (((src=get_fb_mux(client)))<0) return src;
src_group=0;
src=(src)?2:3; /* mod src: 0 - IN56, 1 - IN4 */
break;
case 1: /* p1div in */
case 3: /* p1div out */
if (out_src & 2) {
if (((div1=get_in_pdiv(client,0)))<0) return div1; /* 1/2/4/8/16/32 */
} else div1=1;
if (((src=get_in_mux(client)))<0) return src;
if (src==2){
src_group=1;
src=0;
} else {
src_group=0; /* keep src: 0 - IN12, 1 - IN3 */
}
break;
case 4: src_group=1; div1=1; break;
case 5: src_group=2; src=0; break;
case 6: src_group=2; src=chn; break;
case 7: src_group=3; break;
}
dev_dbg(&client->dev, "out_src=%d, src_group=%d, src=%d, div1=%d, div2=%d\n",out_src,src_group,src,div1,div2);
switch (src_group) {
case 0: return sprintf(buf,"IN%d:%d:%d",in_numbers[src],div1,div2);
case 1: return sprintf(buf,"XO:%d:%d",div1,div2);
case 2: return sprintf(buf,"MS%d:%d",src,div2);
case 3: return sprintf(buf,"No clock");
}
return 0;
}
static int set_out_route(struct i2c_client *client, const char* route, int chn)
{
int src_group, src, div1, div2, out_src, mux1=-1,mux2=-1;
const char *cp=route;
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
/* parse string */
if ((strncasecmp(cp,"in",2)==0)) {
cp+=2;
if ((strncmp(cp,"12",2)==0)) {
cp+=2;
src=0;
} else if ((strncmp(cp,"3", 1)==0)) {
cp+=1;
src=1;
} else if ((strncmp(cp,"4", 1)==0)) {
cp+=1;
src=2;
} else if ((strncmp(cp,"56",2)==0)){
cp+=2;
src=3;
} else return -EINVAL; /* invalid input number(s) */
src_group=0;
} else if ((strncasecmp(cp,"xo",2)==0)) {
cp+=2;
src_group=1;
src=0;
} else if ((strncasecmp(cp,"ms",2)==0)) {
cp+=2;
src=cp[0]-'0';
cp++;
if ((src!=0) && (src!=chn)){
return -EINVAL; /* invalid MS channel */
}
src_group=2;
div1=-1;
} else if ((strncasecmp(cp,"no",2)==0)) {
cp+=2;
src_group=3;
} else return -EINVAL;
/* for IN and XO - find input divisor */
if (src_group<2){
if ((cp[0]=='/') || (cp[0]==':')){
cp++;
if ((strncmp(cp,"32",2)==0)) {
div1=5;
cp++;
} else if ((strncmp(cp,"16",2)==0)) {
div1=4;
cp++;
} else if ((strncmp(cp,"8",1)==0)) div1=3;
else if ((strncmp(cp,"4",1)==0)) div1=2;
else if ((strncmp(cp,"2",1)==0)) div1=1;
else if ((strncmp(cp,"1",1)==0)) div1=0;
else return -EINVAL;
cp++;
} else return -EINVAL; /* divisor expected */
}
/* get output divisor */
if (src_group<3){ /* not 'no clock' */
if ((cp[0]=='/') || (cp[0]==':')){
cp++;
if ((strncmp(cp,"32",2)==0)) {
div2=5;
cp++;
} else if ((strncmp(cp,"16",2)==0)) {
div2=4;
cp++;
} else if ((strncmp(cp,"8",1)==0)) div2=3;
else if ((strncmp(cp,"4",1)==0)) div2=2;
else if ((strncmp(cp,"2",1)==0)) div2=1;
else if ((strncmp(cp,"1",1)==0)) div2=0;
else return -EINVAL;
cp++;
} else return -EINVAL; /* divisor expected */
/* apply output divisor*/
if (((rc==set_out_div(client, 1<1)?0:1; /* p2div_in / p1div_in */
} else {
out_src=(src>1)?2:3; /* p2div_out / p1div_out */
if (src_group==1){ /* xo, but with division */
mux1=2;
} else {
switch (src){
case 0: mux1=0; break; /* in1/in2 */
case 1: mux1=1; break; /* in3 */
case 2: mux2=1; break; /* in4 */
case 3: mux2=0; break; /* in5/in6 */
}
}
}
}
dev_dbg(&client->dev, "src_group=%d, src=%d, div1=%d, div2=%d, mux1=%d,mux2=%d, out_src=%d \n",src_group, src, div1, div2, mux1,mux2,out_src);
if (((rc==set_out_source(client, chn,out_src)))<0) return rc;
if (div1>0){ /* only set p1div/p2div if needed */
if (((rc==set_in_pdiv(client, 1<=0){
if (((rc==set_in_mux(client, mux1)))<0) return rc; /* set input mux if it is used */
}
if (mux2>=0){
if (((rc==set_fb_mux(client, mux2)))<0) return rc; /* set fb mux if it is used */
}
return 0;
}
static int set_out_frequency_and_route (struct i2c_client *client, u64 *out_freq, int chn, int int_div)
{
/* using MS with the same number as the output, enabling power to that MS */
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
/* setup MSn division */
if (((rc=set_pll_ms_by_out(client, out_freq, chn, int_div)))<0) return rc;
/* enable power for selected MS */
if (((rc=set_ms_powerdown(client, 0, chn)))<0) return rc;
/* route MSn to the output (6 - use 'own' MS) */
if (((rc=set_out_source(client, chn, 6)))<0) return rc;
/* setup output (R) division - by 1/2/4/8/16/32 */
if (((rc=set_out_div_by_frequency(client, out_freq, chn)))<0) return rc;
/* enable power for selected output */
if (((rc=set_drv_powerdown(client, 0, chn)))<0) return rc;
/* Note: output is not enabled ! Should it be not powered up too?*/
return 0; /* all done */
}
static s64 get_output_src_frequency(struct i2c_client *client, u64 *out_freq, int chn)
{
int mux;
int div=1,rc=0;
s64 freq[3]={0,0,1};
if (((mux=get_out_source(client,chn)))<0) return mux;
switch (mux){
case 0:
freq[0]= get_p2div_in_frequency(client);
break;
case 1:
freq[0]= get_p1div_in_frequency(client);
break;
case 2:
freq[0]= get_p2div_in_frequency(client);
div=get_in_pdiv(client,1);
break;
case 3:
freq[0]= get_p1div_in_frequency(client);
div=get_in_pdiv(client,0);
break;
case 4:
freq[0]= get_in_frequency (client,0); /* IN1/IN2, xtal */
break;
case 5:
rc=get_pll_ms_freq(client, freq, 0); /* MS0 output */
break;
case 6:
rc=get_pll_ms_freq(client, freq, chn); /* MS output */
break;
case 7:
freq[0]= 0; /* No clock */
break;
default:
dev_err(&client->dev, "Invalid value for output source mux %d\n",mux);
return - EINVAL;
}
if (rc<0) return rc;
if (freq[0]<0) return freq[0];
if (div<0) return div;
out_freq[1]=freq[0]*freq[2]+freq[1];
out_freq[2]=freq[2]*div;
out_freq[0]=div64_u64(out_freq[1],out_freq[2]);
out_freq[1]-=out_freq[0]*out_freq[2];
if (out_freq[1]==0) out_freq[2]=1;
remove_common_factor(&out_freq[1]);
return 0;
}
/* -----------PLL section--------------------------- */
static u32 awe_fcal[]= {AWE_FCAL_07_00, AWE_FCAL_15_08, AWE_FCAL_17_16, 0};
static u32 awe_fcal_ovrd[]={AWE_FCAL_OVRD_07_00, AWE_FCAL_OVRD_15_08, AWE_FCAL_OVRD_17_15, 0};
static int pre_init(struct i2c_client *client, int clear_all)
{
int rc,chn;
if (((rc=set_misc_registers(client)))<0) return rc; /* setup miscelalneous registers */
if (((rc=write_field(client, 1, AWE_OUT_ALL_DIS )))<0) return rc; /* disable all outputs */
if (((rc=write_field(client, 1, AWE_DIS_LOS )))<0) return rc; /* pause LOL */
if (clear_all){ /* clears outputs pll input/fb muxes to be set later */
/* extra */
for (chn=0;chn<4;chn++){
if (((rc=disable_output(client, chn)))<0) return rc;
}
/* to be explicitly enabled if needed */
if (((rc=disable_pll_in_fb_mux(client)))<0) return rc;
}
return 0;
}
static int post_init(struct i2c_client *client, int timeout) /*1 in timeout ~ 0.1ms - i2c read register */
{
int rc,i,in_src, fb_src,ext_fb,check_los=0;
s64 fcal;
/* validate input clock status */
if (((in_src=get_in_pfd_ref_fb(client,0)))<0) return in_src;
switch (in_src){
case 0:
case 2:
case 4:
check_los |= AWE_STATUS_PLL_LOS_CLKIN; break;
case 1:
case 3:
check_los |= AWE_STATUS_PLL_LOS_FDBK; break;
}
if (((ext_fb=read_field(client,AWE_PFD_EXTFB)))<0) return ext_fb;
if (ext_fb){
if (((fb_src=get_in_pfd_ref_fb(client,1)))<0) return fb_src;
switch (in_src){
case 1:
case 3:
check_los |= AWE_STATUS_PLL_LOS_CLKIN; break;
case 0:
case 2:
check_los |= AWE_STATUS_PLL_LOS_FDBK; break;
}
}
check_los &= 0xf;
for (i=0;i=timeout){
dev_err(&client->dev, "Timeout waiting for input clocks, status=0x%x, mask=0x%x\n",rc, check_los);
return -EPIPE;
}
dev_dbg(&client->dev, "Validated input clocks, t=%d cycles (timeout= %d cycles), status =0x%x, mask=0x%x\n",
i, timeout, rc, check_los);
if (((rc=write_field(client, 0, AWE_FCAL_OVRD_EN )))<0) return rc; /* Configure PLL for locking, set FCAL_OVRD_EN=0 */
write_field(client, 1, AWE_SOFT_RESET ); /* Configure PLL for locking, set SOFT_RESET=1 (ignore i2c error) */
for (i=0;i<250;i++) get_status(client); /* wait 25 ms */
if (((rc=write_field(client, 0x65, AWE_REG241 )))<0) return rc; /* re-enable LOL, set reg 241=0x65 */
check_los |= AWE_STATUS_PLL_LOL | AWE_STATUS_PLL_SYS_CAL;
check_los &= 0xf;
for (i=0;i=timeout){
dev_err(&client->dev, "Timeout waiting for PLL lock, status=0x%x, mask=0x%x\n",rc, check_los);
return -EPIPE;
}
dev_dbg(&client->dev, "Validated PLL locked, t=%d cycles (timeout= %d cycles), status =0x%x, mask=0x%x\n",
i, timeout, rc, check_los);
/* copy FCAL values to active registers */
if (((fcal=read_multireg64 (client, awe_fcal)))<0) return (int) fcal;
if (((rc= write_multireg64(client, fcal, awe_fcal_ovrd)))<0) return rc;
dev_dbg(&client->dev, "Copied FCAL data 0x%llx\n", fcal);
if (((rc=write_field(client, 5, AWE_REG47_72 )))<0) return rc; /* set 47[7:2] to 000101b */
if (((rc=write_field(client, 1, AWE_FCAL_OVRD_EN )))<0) return rc; /* SET PLL to use FCAL values, set FCAL_OVRD_EN=1 */
/* only needed if using down-spread. Won't hurt to do anyway */
if (((rc=reset_ms(client, 10)))<0) return rc;
if (((rc=write_field(client, 0, AWE_OUT_ALL_DIS )))<0) return rc; /* enable all (enabled individually) outputs */
write_field(client, 0, AWE_SOFT_RESET ); /* Not documented - what to do with the soft reset bit - clearing */
if (((rc=power_up_down_needed_ms(client)))<0) return rc;
return 0;
}
static int reset_ms(struct i2c_client *client, int wait_cycles)
{
int i,rc;
dev_dbg(&client->dev, "Resetting MS dividers");
if (((rc=write_field(client, 1, AWE_MS_RESET )))<0) return rc; /* SET MS RESET=1 */
for (i=0;i=15){
K=925;
rsel=0;
bwsel=0;
} else if (fpfd_mhz>=8){
K=325;
rsel=1;
bwsel=1;
} else {
K=185;
rsel=3;
bwsel=2;
}
if (fvco_mhz>2425){
Q=3;
vco_gain=0;
} else {
Q=4;
vco_gain=1;
}
kphi_num= K*2500LL*2500LL*2500LL;
kphi_denom=533LL*Q*fpfd_mhz*fvco_mhz*fvco_mhz;
pll_kphi=(int) div64_u64(kphi_num + (kphi_denom>>1),kphi_denom);
if ((pll_kphi<1) || (pll_kphi>127)) {
dev_err(&client->dev, "Calculated PLL_KPHI does not fit 1<=%d<=127\n",pll_kphi);
if (pll_kphi<1) pll_kphi=1;
else if (pll_kphi>127) pll_kphi=127;
}
mscal = (int) div64_u64(2067000-667*fvco_mhz+50000,100000ll);
if ((mscal<0) || (mscal>63)) {
dev_err(&client->dev, "Calculated MSCAL does not fit 0<=%d<=63\n",mscal);
if (mscal<0) mscal=0;
else if (mscal>63) mscal=63;
}
ms_pec = 7;
dev_dbg(&client->dev, "Calculated values: PLL_KPHI=%d K=%lld RSEL=%d BWSEL=%d VCO_GAIN=%d MSCAL=%d MS_PEC=%d\n",
pll_kphi, K, rsel, bwsel, vco_gain, mscal, ms_pec);
/* setting actual registers */
if (((rc=write_field(client, (u8) pll_kphi, AWE_PLL_KPHI)))<0) return rc;
if (((rc=write_field(client, (u8) (((vco_gain & 7)<<4) | ((rsel & 3)<<2) | (bwsel & 3)),
AWE_VCO_GAIN_RSEL_BWSEL)))<0) return rc;
if (((rc=write_field(client, (u8) mscal, AWE_MSCAL )))<0) return rc;
if (((rc=write_field(client, (u8) ms_pec, AWE_MS_PEC)))<0) return rc;
if (((rc=write_field(client, 3, AWE_PLL_EN)))<0) return rc; /* enable PLL */
return 0;
}
/* verify the chip is initilaized - returns 0 if power-up state, 5 if initialized, -1 if i2c register can not be read */
static int is_set_up(struct i2c_client *client)
{
return read_field(client, AWE_MISC_47 );
}
static int set_misc_registers(struct i2c_client *client)
{
/* ST52238 Reference Manual R1.2 p.28 */
int rc;
if (((rc=write_field(client, 0x5, AWE_MISC_47 )))<0) return rc;
if (((rc=write_field(client, 0x1, AWE_MISC_106 )))<0) return rc;
if (((rc=write_field(client, 0x1, AWE_MISC_116 )))<0) return rc;
if (((rc=write_field(client, 0x1, AWE_MISC_42 )))<0) return rc;
if (((rc=write_field(client, 0x0, AWE_MISC_06A )))<0) return rc;
if (((rc=write_field(client, 0x0, AWE_MISC_06B )))<0) return rc;
if (((rc=write_field(client, 0x0, AWE_MISC_28 )))<0) return rc;
return 0;
}
/* -----------MultiSynth section--------------------------- */
static u32 awe_msx[5][3][5]=
{{{AWE_MS0_P1_07_00, AWE_MS0_P1_15_08, AWE_MS0_P1_17_16, 0, 0},
{AWE_MS0_P2_05_00, AWE_MS0_P2_13_06, AWE_MS0_P2_21_14, AWE_MS0_P2_29_22, 0},
{AWE_MS0_P3_07_00, AWE_MS0_P3_15_08, AWE_MS0_P3_23_16, AWE_MS0_P3_29_24, 0}},
{{AWE_MS1_P1_07_00, AWE_MS1_P1_15_08, AWE_MS1_P1_17_16, 0, 0},
{AWE_MS1_P2_05_00, AWE_MS1_P2_13_06, AWE_MS1_P2_21_14, AWE_MS1_P2_29_22, 0},
{AWE_MS1_P3_07_00, AWE_MS1_P3_15_08, AWE_MS1_P3_23_16, AWE_MS1_P3_29_24, 0}},
{{AWE_MS2_P1_07_00, AWE_MS2_P1_15_08, AWE_MS2_P1_17_16, 0, 0},
{AWE_MS2_P2_05_00, AWE_MS2_P2_13_06, AWE_MS2_P2_21_14, AWE_MS2_P2_29_22, 0},
{AWE_MS2_P3_07_00, AWE_MS2_P3_15_08, AWE_MS2_P3_23_16, AWE_MS2_P3_29_24, 0}},
{{AWE_MS3_P1_07_00, AWE_MS3_P1_15_08, AWE_MS3_P1_17_16, 0, 0},
{AWE_MS3_P2_05_00, AWE_MS3_P2_13_06, AWE_MS3_P2_21_14, AWE_MS3_P2_29_22, 0},
{AWE_MS3_P3_07_00, AWE_MS3_P3_15_08, AWE_MS3_P3_23_16, AWE_MS3_P3_29_24, 0}},
{{AWE_MSN_P1_07_00, AWE_MSN_P1_15_08, AWE_MSN_P1_17_16, 0, 0},
{AWE_MSN_P2_05_00, AWE_MSN_P2_13_06, AWE_MSN_P2_21_14, AWE_MSN_P2_29_22, 0},
{AWE_MSN_P3_07_00, AWE_MSN_P3_15_08, AWE_MSN_P3_23_16, AWE_MSN_P3_29_24, 0}}};
static const u32 awe_ms_powerdown[]={AWE_MS0_PDN, AWE_MS1_PDN, AWE_MS2_PDN, AWE_MS3_PDN};
static int get_ms_powerdown(struct i2c_client *client, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
return read_field (client, awe_ms_powerdown[chn]);
}
static int set_ms_powerdown(struct i2c_client *client, int typ, int chn)
{
int rc;
if (((rc=_verify_output_channel(client,chn)))<0) return rc;
if (typ) typ=1;
return write_field (client, (u8) typ, awe_ms_powerdown[chn]);
}
static int ms_to_p123(u64* ms,u32 * p123)
{
/*
* a=ms[0],b=ms[1],c=ms[2] ms~=a+b/c
* p1=floor(((a*c+b)*128)/c -512)
* p2=mod((b*128),c)
* p3=c
*/
u64 d;
u64 ms_denom=ms[2], ms_num=ms[1], ms_int=ms[0];
while ((ms_denom >= (1<<30))| (((ms_denom | ms_num) &1) == 0)) {
ms_denom >>= 1;
ms_num >>= 1;
}
if ((ms_num==0) || (ms_denom==0)){
ms_denom = 1;
ms_num = 0;
}
d= (ms_int * ms_denom + ms_num)<<7;
p123[0]= (u32) (div64_u64(d,ms_denom) -512);
d=div64_u64((ms_num<<7),ms_denom);
p123[1]= (u32) ((ms_num<<7)-d*ms_denom);
p123[2]=ms_denom;
pr_debug("ms[]=%llu + %llu/%llu Hz, ms_int=%llu, ms_num=%llu, ms_denom=%llu p123=%u %u %u\n",
ms[0],ms[1],ms[2],ms_int,ms_num,ms_denom,p123[0],p123[1],p123[2]);
return 0;
}
static int p123_to_ms(u64* ms,u32 * p123)
{
/* a=ms[0],b=ms[1],c=ms[2] ms~=a+b/c
* p1=floor(((a*c+b)*128)/c -512)
* p2=mod((b*128),c)
* p3=c
* ---
* b*128=k*c +p2; k<128, p2>7
* a= (p1+512)>>7=(p1>>7)+4
*
*/
ms[2]=p123[2]; /* c= p3 */
ms[1]=(ms[2]*(p123[0] & 0x7f) + p123[1]) >>7; /* b= (c*(p1 & 0x7f) + p2) >>7 */
ms[0]=(p123[0]>>7)+4; /* a= (p1>>7)+4 */
pr_debug("ms[]=%llu + %llu/%llu, p123=%u %u %u\n",
ms[0],ms[1],ms[2],p123[0],p123[1],p123[2]);
return 0;
}
static int get_ms_p123(struct i2c_client *client,u32 * p123, int chn) /* chn 0,1,2,3,4 (4 - msn) */
{
int i;
s64 rc;
if ((chn<0) || (chn>4)){
dev_err(&client->dev, "Invalid channel %d. Only 0,1,2,3 and 4 (for MSN) are supported\n",chn);
return - EINVAL;
}
for (i=0;i<3;i++){
if (((rc=read_multireg64 (client, awe_msx[chn][i])))<0) return (int) rc;
p123[i]= (u32) rc;
}
return 0;
}
static int set_ms_p123(struct i2c_client *client,u32 * p123, int chn) /* chn 0,1,2,3,4 (4 - msn) */
{
int i,rc,hs;
if ((chn<0) || (chn>4)){
dev_err(&client->dev, "Invalid channel %d. Only 0,1,2,3 and 4 (for MSN) are supported\n",chn);
return - EINVAL;
}
/* high speed bit programming */
if (p123[0]<512){ /* div less than 8 */
if (p123[0]<128) p123[0]=0;
else p123[0]=256;
p123[1]=0;
p123[2]=1;
dev_dbg(&client->dev, "Using high speed divisor option on ms%d",chn);
} else hs=0;
if (((rc=write_field(client, hs, awe_ms_hs[chn])))<0) return rc;
/* optionally disable spread spectrum before changing frequency */
if (chn<4){
if (((rc=ss_pre_freq_change(client, chn)))<0) return rc;
}
for (i=0;i<3;i++){
if (((rc=write_multireg64(client, (u64) p123[i], awe_msx[chn][i])))<0) return rc;
}
/* optionally enable spread spectrum after changing frequency, reset MS */
if (chn<4){
if (((rc=ss_post_freq_change(client, chn)))<0) return rc;
}
return 0;
}
/* Setting PLL frequency in 3 ways:
* 1 - specified directly, allow fractional MSN
* 2 - specified directly, integer MSN
* 3 - specified by output frequency, allow fractional MSN (use PPL frequency closest to the middle)
* 4 - specified by output frequency, integer MSN
*/
static int set_pll_freq(struct i2c_client *client, u64 *vco_freq, int int_div)
{
s64 pll_in_freq, pll_in_freq_scaled,pll_out_freq_scaled,d;
u32 msn_p123[3];
u64 msn[]={0,0,1};
s64 vco_int=vco_freq[0],vco_num=vco_freq[1],vco_denom=vco_freq[2];
if ((vco_num==0) || (vco_denom==0)){
vco_num=0;
vco_denom=1;
}
if (vco_num>=vco_denom){ /* normalize */
d=div64_u64(vco_num,vco_denom);
vco_int+=d;
vco_num-=d*vco_denom;
}
if (vco_int < FVCOMIN){
dev_err(&client->dev, "Specified PLL frequency is too low: %llu < %llu\n",vco_int, FVCOMIN);
return - EINVAL;
}
if (vco_int > FVCOMAX){
dev_err(&client->dev, "Specified PLL frequency is too high: %llu > %llu\n",vco_int, FVCOMAX);
return - EINVAL;
}
pll_in_freq=get_pll_in_frequency(client);
if (pll_in_freq<0) return (int) pll_in_freq;
pll_in_freq_scaled=pll_in_freq*vco_denom;
// pll_out_freq_scaled=pll_out_freq*vco_denom;
pll_out_freq_scaled=vco_int*vco_denom+vco_num;
msn[0]=div64_u64(pll_out_freq_scaled,pll_in_freq_scaled);
msn[1]=pll_out_freq_scaled-pll_in_freq_scaled*msn[0];
msn[2]=pll_in_freq_scaled;
while (msn[2] >= (1<<30)) { /* trim */
msn[2] >>= 1;
msn[1] >>= 1;
}
if (msn[0] < MSINT_MIN){
dev_err(&client->dev, "Calculated MSN ratio is too low: %llu < %u\n",msn[0], MSINT_MIN);
return - EINVAL;
}
if (msn[0] > MSINT_MAX){
dev_err(&client->dev, "Calculated MSN ratio is too high: %llu > %u\n",msn[0], MSINT_MAX);
return - EINVAL;
}
if (int_div){
if (msn[1]>=(msn[2]>>1)) msn[0]++; // round
msn[1] = 0;
msn[2] = 1;
} else {
remove_common_factor(&msn[1]);
}
ms_to_p123(msn, msn_p123);
return set_ms_p123(client,msn_p123, 4); // MSN
}
/* normalizes output */
static int get_pll_freq(struct i2c_client *client,u64 * pll_freq)
{
int rc;
s64 pll_in_freq;
u32 p123[3];
pll_in_freq=get_pll_in_frequency(client);
if (pll_in_freq<=0) return (int) pll_in_freq; // return 0 if in frequency==0
if (((rc=get_ms_p123(client,p123,4)))<0) return rc; /* channel4 - MSN */
p123_to_ms(pll_freq,p123);
if (pll_freq[2]<=0) return -EINVAL; /* 0 denominator */
pll_freq[1] =(pll_freq[0]*pll_freq[2]+pll_freq[1])*pll_in_freq;
pll_freq[0] =div64_u64(pll_freq[1],pll_freq[2]);
pll_freq[1]-=pll_freq[0]*pll_freq[2];
if (pll_freq[1]==0){
pll_freq[2]=1;
} else {
remove_common_factor(&pll_freq[1]);
}
return 0;
}
/*
* Calculate pll output frequency to match specified output frequency
* out_freq as int,num,denom
*/
static int set_pll_freq_by_out(struct i2c_client *client, u64 *out_freq, int int_msn_div)
{
/* use r-divider if the output frequency is too low (less than 5 MHz) */
u64 out_int=out_freq[0],out_num=out_freq[1],out_denom=out_freq[2],
pll_out_freq[3], scaled_max,scaled_min,d;
s64 pll_freq_scaled, out_freq_scaled,err,best_err=-1,center_scaled,center_diff,best_center_diff,
out_div,pll_in_freq,in_div,best_in_div, pll_in_freq_scaled,synth_out_scaled;
int r_div=1;
if (out_denom==0){
dev_err(&client->dev, "denominator should not be 0 in %lld+%lld/%lld\n",
out_int,out_num,out_denom);
return -EINVAL;
}
out_freq_scaled=out_denom*out_int+out_num;
scaled_max=(FVCOMAX/MSINT_MAX)*out_denom;
while ((r_div < 32) && (out_freq_scaleddev, "Specified output frequency is too low: %lld < %lld\n",
out_freq[0], FVCOMAX/MSINT_MAX/32);
return -EINVAL;
}
dev_dbg(&client->dev, "Output divider by %u, Output frequency before divider: %llu+%llu/%llu Hz\n",
r_div, div64_u64(out_freq_scaled,out_denom),
out_freq_scaled-out_denom*div64_u64(out_freq_scaled,out_denom),out_denom);
scaled_max=FVCOMAX*out_denom;
scaled_min=FVCOMIN*out_denom;
if (int_msn_div==0){
out_div=div64_u64( ((FVCOMAX+FVCOMIN)/2)*out_denom+(out_freq_scaled>>1),out_freq_scaled);
dev_dbg(&client->dev, "out_div=%llu out_freq_scaled=%llu out_denom= %llu scaled_max=%llu scaled_min=%lld\n",
out_div, out_freq_scaled, out_denom,scaled_max, scaled_min);
if ((out_div==7) || (out_div==5) || (out_div==3)){
if (out_freq_scaled*(out_div+1)4) && (out_freq_scaled*(out_div-1)>scaled_min)){
out_div--;
} else {
out_div=0;
}
}
dev_dbg(&client->dev, "modified out_div=%lld\n", out_div);
if ((out_div<4) || (out_div > MSINT_MAX) ||
(out_freq_scaled*out_div < scaled_min) ||
(out_freq_scaled*out_div > scaled_max)){
dev_err(&client->dev, "Can not find suitable divisor for output frequency %lld+%lld/%lld Hz\n",
div64_u64(out_freq_scaled,out_denom),
out_freq_scaled-out_denom*div64_u64(out_freq_scaled,out_denom),out_denom);
return -EINVAL;
}
pll_out_freq[0]=div64_u64(out_freq_scaled*out_div,out_denom);
pll_out_freq[1]=(out_freq_scaled*out_div)-pll_out_freq[0]*out_denom;
pll_out_freq[2]=out_denom;
dev_dbg(&client->dev, "PLL output divider by %llu, pll frequency: %llu+%llu/%llu Hz\n",
out_div,pll_out_freq[0],pll_out_freq[1],pll_out_freq[2]);
return set_pll_freq(client, pll_out_freq, 0);
} else { /* if (int_msn_div==0), find the best pair of integer coefficients, try closest to the center, if possible */
pll_in_freq=get_pll_in_frequency(client);
pll_in_freq_scaled=pll_in_freq*out_denom;
center_scaled=((FVCOMAX+FVCOMIN)>>1)*out_denom;
if (pll_in_freq<0) return (int) pll_in_freq;
best_in_div=0;
for (out_div=4;out_div<=MSINT_MAX;out_div++) if ((out_div!=5) && (out_div!=7)){
pll_freq_scaled=out_freq_scaled*out_div; /* here scaled by denominator */
if ((pll_freq_scaled>=scaled_min) && (pll_freq_scaled<=scaled_max)) {
in_div=div64_u64(pll_freq_scaled+(pll_in_freq_scaled>>1),pll_in_freq_scaled); // round
d=pll_in_freq_scaled*in_div; /* actual pll frequency scaled by out_denom */
synth_out_scaled=div64_u64(d + (out_div>>1),out_div);
center_diff=d-center_scaled;
if (center_diff<0) center_diff=-center_diff;
err=synth_out_scaled-out_freq_scaled;
if (err<0) err=-err;
if ((best_in_div==0) || (err < best_err) || ((err == best_err) && (center_diffdev, "synth_out_scaled: %lld center_scaled: %lld out_freq_scaled:%lld err: %lld (%lld) center_diff:%lld(%lld)\n",
synth_out_scaled, center_scaled, out_freq_scaled,err,best_err,center_diff,best_center_diff);
best_err=err;
best_in_div=in_div;
best_center_diff=center_diff;
}
}
}
if (best_in_div==0){
dev_err(&client->dev, "Failed to find suitable integer coefficients for pll input %lld Hz\n",
pll_in_freq);
}
pll_out_freq[0]=div64_u64(pll_in_freq_scaled*best_in_div,out_denom);
pll_out_freq[1]=(pll_in_freq_scaled*best_in_div)-pll_out_freq[0]*out_denom;
pll_out_freq[2]=out_denom;
dev_dbg(&client->dev, "PLL output frequency: %llu+%llu/%llu Hz, MS input divider: %lld, MS output divider: %lld\n",
pll_out_freq[0],pll_out_freq[1],pll_out_freq[2], best_in_div, out_div);
return set_pll_freq(client, pll_out_freq, 1); /* integer result */
}
}
static int get_pll_ms_freq(struct i2c_client *client, u64 *out_freq, int chn)
{
int rc;
u64 pll_out_freq[3], ms[3], pll_freq_scaled, ms_scaled;
u32 p123[3];
if (((rc=get_pll_freq(client,pll_out_freq)))<0) return rc;
/* trim PLL frequency fraction */
while (pll_out_freq[2]>=0x1000){
pll_out_freq[1] >>= 1;
pll_out_freq[2] >>= 1;
}
pll_freq_scaled=pll_out_freq[0]*pll_out_freq[2]+pll_out_freq[1];
if (((rc=get_ms_p123(client,p123, chn)))<0) return rc; /* includes invalid chn */
p123_to_ms(ms,p123);
/* trim MS divisor fraction */
while (ms[2]>=0x1000){
ms[1] >>= 1;
ms[2] >>= 1;
}
ms_scaled=ms[0]*ms[2]+ms[1];
out_freq[1]=pll_freq_scaled*ms[2];
out_freq[2]=ms_scaled*pll_out_freq[2];
if (out_freq[2]==0){
out_freq[0]=0;
out_freq[1]=0;
out_freq[2]=1;
} else {
out_freq[0]=div64_u64(out_freq[1],out_freq[2]);
out_freq[1]-=out_freq[0]*out_freq[2];
remove_common_factor(&out_freq[1]);
}
dev_dbg(&client->dev, "MS%d output frequency: %llu+%llu/%llu Hz\n",chn,out_freq[0],out_freq[1],out_freq[2]);
return 0;
}
/*
* Adjust MultiSynth divisor (MS0..MS3) for specified output frequency
* MSN, input frequency should be already set
* out_freq as int,num,denom
*/
static int set_pll_ms_by_out(struct i2c_client *client, u64 *out_freq, int chn, int int_div)
{
/* use r-divider if the output frequency is too low (less than 5 MHz) */
u64 out_int=out_freq[0],out_num=out_freq[1],out_denom=out_freq[2],
pll_out_freq[3],d;
s64 pll_freq_scaled, out_freq_scaled;
u64 ms[3];
u32 p123[3];
int r_div=1,rc;
if (out_denom==0){
dev_err(&client->dev, "denominator should not be 0 in %lld+%lld/%lld\n",
out_int,out_num,out_denom);
return -EINVAL;
}
if (out_num>=out_denom){ /* normalize */
d=div64_u64(out_num,out_denom);
out_int+=d;
out_num-=d*out_denom;
}
if (out_num==0){
out_denom=1;
}
if (out_int<(FVCOMAX/MSINT_MAX)){
while ((r_div < 32) && (out_int<(FVCOMAX/MSINT_MAX))){
out_int<<=1;
out_num<<=1;
r_div<<=1;
if (out_num>out_denom) {
out_int++;
out_num-=out_denom;
}
}
if (out_int<(FVCOMAX/MSINT_MAX)){
dev_err(&client->dev, "Specified output frequency is too low: %lld < %lld\n",
out_freq[0], FVCOMAX/MSINT_MAX/32);
return -EINVAL;
}
}
dev_dbg(&client->dev, "Output divider by %u, Output frequency before divider: %llu+%llu/%llu Hz\n",
r_div,out_int, out_num,out_denom);
/* trim output frequency fraction */
while (out_denom>=0x1000){
out_num >>= 1;
out_denom >>= 1;
}
out_freq_scaled=out_int*out_denom+out_num;
if (((rc=get_pll_freq(client,pll_out_freq)))<0) return rc;
/* trim PLL frequency fraction */
while (pll_out_freq[2]>=0x1000){
pll_out_freq[1] >>= 1;
pll_out_freq[2] >>= 1;
}
pll_freq_scaled=pll_out_freq[0]*pll_out_freq[2]+pll_out_freq[1];
ms[1]=pll_freq_scaled*out_denom;
ms[2]=out_freq_scaled*pll_out_freq[2];
ms[0]=div64_u64(ms[1],ms[2]);
ms[1]-=ms[0]*ms[2];
if (int_div){
if (ms[1]>(ms[2]>>1)) ms[0]++;
ms[1]=0;
ms[2]=1;
} else {
remove_common_factor(&ms[1]);
}
dev_dbg(&client->dev, "MS%d divider: %llu+%llu/%llu\n",chn,ms[0],ms[1],ms[2]);
/* set up registers */
ms_to_p123(ms,p123);
if (((rc=set_ms_p123(client,p123, chn)))<0) return rc;
if (((rc=disable_spread_spectrum(client,chn)))<0) return rc;
return 0;
}
/* ----------- Input section ----------------- */
static s64 get_pll_in_frequency(struct i2c_client *client)
{
int mux;
int div=1;
s64 freq;
if (((mux=get_in_pfd_ref_fb(client,0)))<0) return mux;
switch (mux){
case 0:
freq= get_p1div_in_frequency(client);
break;
case 1:
freq= get_p2div_in_frequency(client);
break;
case 2:
freq= get_p1div_in_frequency(client);
div=get_in_pdiv(client,0);
break;
case 3:
freq= get_p2div_in_frequency(client);
div=get_in_pdiv(client,1);
break;
case 4:
freq= get_in_frequency (client,0); /* IN1/IN2, xtal */
break;
case 5:
freq= 0; /* No clock */
break;
default:
dev_err(&client->dev, "Invalid value for PLL input multiplexer %d\n",mux);
return - EINVAL;
}
if (freq<0) return freq;
if (div<0) return div;
/* TODO - make it fractional? */
return div64_u64(freq,div);
}
static s64 get_pll_fb_frequency(struct i2c_client *client)
{
int mux;
int div=1;
s64 freq;
if (((mux=get_in_pfd_ref_fb(client,1)))<0) return mux;
switch (mux){
case 0:
freq= get_p2div_in_frequency(client);
break;
case 1:
freq= get_p1div_in_frequency(client);
break;
case 2:
freq= get_p2div_in_frequency(client);
div=get_in_pdiv(client,1);
break;
case 3:
freq= get_p1div_in_frequency(client);
div=get_in_pdiv(client,0);
break;
/* case 4: */
case 5:
freq= 0; /* No clock */
break;
default:
dev_err(&client->dev, "Invalid value for PLL feedback multiplexer %d\n",mux);
return - EINVAL;
}
if (freq<0) return freq;
if (div<0) return div;
/* TODO - make it fractional? */
return div64_u64(freq,div);
}
static s64 get_p1div_in_frequency(struct i2c_client *client)
{
int mux;
if (((mux= get_in_mux(client)))<0) return mux;
switch (mux){
case 0: return get_in_frequency (client,0); /* IN1/IN2 */
case 1: return get_in_frequency (client,1); /* IN3 */
case 2: return get_in_frequency (client,0); /* IN1/IN2 - xtal*/
default:
dev_err(&client->dev, "Invalid value for input multiplexer %d\n",mux);
return - EINVAL;
}
}
static s64 get_p2div_in_frequency(struct i2c_client *client)
{
int mux;
if (((mux= get_fb_mux(client)))<0) return mux;
switch (mux){
case 0: return get_in_frequency (client,3); /* IN5/IN6 */
case 1: return get_in_frequency (client,1); /* IN4 */
case 2: return 0; /* no clock */
default:
dev_err(&client->dev, "Invalid value for input multiplexer %d\n",mux);
return - EINVAL;
}
}
static int set_in_mux(struct i2c_client *client, int data)
{
int data1,rc;
switch (data) {
case 0: data1=0; break;
case 1: data1=2; break;
case 2: data1=5; break;
default:
dev_err(&client->dev, "Invalid value for input multiplexer %d\n",data);
return - EINVAL;
}
if (((rc=write_field (client, data, AWE_IN_MUX )))<0) return rc;
if (((rc=write_field (client, data1, AWE_IN_MUX1)))<0) return rc;
return 0;
}
static int get_in_mux(struct i2c_client *client)
{
return read_field(client,AWE_IN_MUX );
}
static int set_fb_mux(struct i2c_client *client, int data)
{
int data1,rc;
switch (data) {
case 0: data1=0; break;
case 1: data1=1; break;
case 2: data1=0; break;
default:
dev_err(&client->dev, "Invalid value for feedback multiplexer %d\n",data);
return - EINVAL;
}
if (((rc=write_field (client, data, AWE_FB_MUX )))<0) return rc;
if (((rc=write_field (client, data1, AWE_FB_MUX1)))<0) return rc;
return 0;
}
static int get_fb_mux(struct i2c_client *client)
{
return read_field(client,AWE_FB_MUX );
}
static const u8 in_div_values[]={1,2,4,8,16,32};
static int set_in_pdiv(struct i2c_client *client, int div, int chn) /*chn =0,1 */
{
int rc;
u8 val;
for (val=0;valdev, "Invalid value for input divider: %d\n",div);
return - EINVAL;
}
static int get_in_pdiv(struct i2c_client *client, int chn) /*chn =0,1 */
{
int rc;
if (((rc=read_field(client, chn?AWE_P2DIV:AWE_P1DIV )))<0) return rc;
if (rc>=ARRAY_SIZE(in_div_values)){
dev_err(&client->dev, "Invalid value for input divider: %d\n",rc);
return - EINVAL;
}
return in_div_values[rc];
}
static int set_in_pfd_ref_fb(struct i2c_client *client, u8 val, int chn) /*chn =0 - ref, 1 - fb*/
{
int rc;
if (val>5) {
dev_err(&client->dev, "Invalid value for input pfd selector: %d\n", (int) val);
return - EINVAL;
}
if (((rc=write_field (client, val, chn?AWE_PFD_FB:AWE_PFD_REF )))<0) return rc;
return 0;
}
static int get_in_pfd_ref_fb(struct i2c_client *client, int chn) /*chn =0,1 */
{
return read_field(client, chn?AWE_PFD_FB:AWE_PFD_REF );
}
static int set_fb_external(struct i2c_client *client, u8 val)
{
int rc;
if (((rc=write_field (client, val?1:0, AWE_PFD_EXTFB)))<0) return rc;
return 0;
}
static int get_fb_external(struct i2c_client *client)
{
return read_field(client,AWE_PFD_EXTFB);
}
static int set_in_frequency(struct i2c_client *client, u64 frequency,int src) /* 0 - 12, 1 - 3, 2 - 4, 3 - 5,6, 4 - 12XO */
{
int xtal_mode,rc,idiv;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (frequency < INFREQMIN){
dev_err(&client->dev, "Input frequency too low: %llu < %llu\n",frequency, INFREQMIN);
return - EINVAL;
}
if (frequency > INFREQMAX){
dev_err(&client->dev, "Input frequency too high: %llu > %llu\n",frequency, INFREQMAX);
return - EINVAL;
}
for (idiv=0;idiv<5;idiv++) if ((frequency >> idiv) <= INFREQDIV) break;
switch (src){
case 4: /* set xtal mode */
xtal_mode=0;
if (frequency>11000000ll) xtal_mode=1;
if (frequency>19000000ll) xtal_mode=2;
if (frequency>26000000ll) xtal_mode=3;
if (((rc=write_field (client, xtal_mode, AWE_XTAL_FREQ)))<0) return rc;
if (((rc=set_in_mux(client, 2)))<0) return rc; /* in mux to XO */
if (((rc=set_in_pfd_ref_fb(client, 4, 0)))<0) return rc; /* set pfd reference to XO - may use 0 (p1div_in also? )*/
clientdata->input_frequency12=frequency;
break;
case 0:
if (((rc=set_in_mux(client, 0)))<0) return rc; /* in mux to IN12 */
if (idiv==0){
if (((rc=set_in_pfd_ref_fb(client, 0, 0)))<0) return rc; /* set pfd reference to p1div_in */
} else {
if (((rc=set_in_pfd_ref_fb(client, 2, 0)))<0) return rc; /* set pfd reference to p1div_out */
if (((rc=set_in_pdiv(client, 1<input_frequency12=frequency;
break;
case 1:
if (((rc=set_in_mux(client, 1)))<0) return rc; /* in mux to IN3 */
if (idiv==0){
if (((rc=set_in_pfd_ref_fb(client, 0, 0)))<0) return rc; /* set pfd reference to p1div_in */
} else {
if (((rc=set_in_pfd_ref_fb(client, 2, 0)))<0) return rc; /* set pfd reference to p1div_out */
if (((rc=set_in_pdiv(client, 1<input_frequency3=frequency;
break;
case 2:
if (((rc=set_fb_mux(client, 1)))<0) return rc; /* fb mux to IN4 */
if (idiv==0){
if (((rc=set_in_pfd_ref_fb(client, 1, 0)))<0) return rc; /* set pfd reference to p2div_in */
} else {
if (((rc=set_in_pfd_ref_fb(client, 3, 0)))<0) return rc; /* set pfd reference to p2div_out */
if (((rc=set_in_pdiv(client, 1<input_frequency4=frequency;
break;
case 3:
if (((rc=set_fb_mux(client, 0)))<0) return rc; /* fb mux to IN5/6 */
if (idiv==0){
if (((rc=set_in_pfd_ref_fb(client, 1, 0)))<0) return rc; /* set pfd reference to p2div_in */
} else {
if (((rc=set_in_pfd_ref_fb(client, 3, 0)))<0) return rc; /* set pfd reference to p2div_out */
if (((rc=set_in_pdiv(client, 1<input_frequency56=frequency;
break;
default:
dev_err(&client->dev, "Invalid source %d only 0 (IN1/2), 1 (IN3), 2 (IN4), 3 (IN4/IN5) and 4 (IN1/2, XO) are supported\n",src);
return - EINVAL;
}
return 0;
}
static u64 get_in_frequency(struct i2c_client *client, int src)
{
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
switch (src){
case 0: return clientdata->input_frequency12;
case 1: return clientdata->input_frequency3;
case 2: return clientdata->input_frequency4;
case 3: return clientdata->input_frequency56;
default:
dev_err(&client->dev, "Invalid source %d only 0 (IN1/2), 1 (IN3), 2 (IN4) and 3 (IN4/IN5) are supported\n",src);
return - EINVAL;
}
}
/* ----------- General ----------------- */
static s64 read_multireg64 (struct i2c_client *client, const u32 * awe)
{
int i,nshift,nbits, full_shift=0;
u8 mask;
u16 reg;
s64 data=0, rc;
for (i=0;awe[i]!=0;i++){
reg=awe[i]>>8;
mask=awe[i]&0xff;
if (mask!=0){
nshift=0;
nbits=1;
while (((1<>= nshift;
rc <<= full_shift;
data |= rc;
full_shift+=nbits;
}
}
return data;
}
static int write_multireg64 (struct i2c_client *client, u64 data, const u32 * awe)
{
int i,rc,nshift,nbits;
u8 mask,reg_data;
u16 reg;
for (i=0;awe[i]!=0;i++){
reg=awe[i]>>8;
mask=awe[i]&0xff;
if (mask!=0){
nshift=0;
nbits=1;
while (((1<>= nbits;
if (((rc=write_reg(client, reg, reg_data, mask)))<0) return rc;
}
}
return 0;
}
static int read_field (struct i2c_client *client, u32 awe)
{
int rc,nshift;
u8 mask;
u16 reg;
reg=awe>>8;
mask=awe&0xff;
if (mask!=0){
nshift=0;
while (((1<> nshift;
}
return 0;
}
static int write_field (struct i2c_client *client, u8 data, u32 awe)
{
int rc,nshift;
u8 mask,reg_data;
u16 reg;
reg=awe>>8;
mask=awe&0xff;
if (mask!=0){
nshift=0;
while (((1<>8) & 0xff;
u16 reg= (adwe>>16) & (0xff | (REG5338_PAGE_MASK << 8)); /* 0x1ff */
return write_reg(client, reg, data, we);
}
static int _write_single_reg(struct i2c_client *client, u8 reg, u8 val)
{
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
int ireg=reg;
dev_dbg(&client->dev,"device write: slave=0x%x, reg=0x%x, val=0x%x\n", (int) (client->addr),reg,val);
if (clientdata) {
if (reg==REG5338_PAGE) {
// dev_dbg(&client->dev,"changing page: new=0x%x, was=0x%x\n",val & REG5338_PAGE_MASK,clientdata->last_page);
clientdata->last_page=val & REG5338_PAGE_MASK;
} else {
ireg |=(clientdata->last_page)<<8;
}
if (ireg<=LAST_REG){
clientdata->cache[ireg].data= val;
clientdata->cache[ireg].flags |= CACHE_INIT;
}
}
return i2c_smbus_write_byte_data(client, reg, val);
}
static int write_reg(struct i2c_client *client, u16 reg, u8 val, u8 mask)
{
int rc,page;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (mask==0) return 0;
dev_dbg(&client->dev,"reg=0x%x, val=0x%x, mask=0x%x\n", (int) reg, (int) val, (int) mask);
if (mask !=0xff){
if (((rc=read_reg(client, reg)))<0) return rc; /* full register including page */
val=((val ^ rc) & mask)^ rc;
if ((val==rc) && !(clientdata->cache[reg].flags & CACHE_VOLAT)) {
dev_dbg(&client->dev,"No change and not volatile -> no write\n");
return 0;
}
}
page=(reg >> 8) & REG5338_PAGE_MASK;
if (page != (clientdata->last_page)) { /* set page if needed */
if (((rc=_write_single_reg(client, REG5338_PAGE, page)))<0) return rc;
}
return _write_single_reg(client, reg & 0xff, val);
}
static int read_reg(struct i2c_client *client, u16 reg)
{
int rc,page;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
if (clientdata && (reg<=LAST_REG) && (clientdata->cache[reg].flags & CACHE_INIT) && !(clientdata->cache[reg].flags & CACHE_VOLAT)){
dev_dbg(&client->dev,"Using cached register: reg=0x%x -> 0x%x\n",reg,(int) clientdata->cache[reg].data);
return clientdata->cache[reg].data;
}
page=(reg >> 8) & REG5338_PAGE_MASK;
// dev_dbg(&client->dev,"reading i2c device : slave=0x%x, reg=0x%x page=0x%x, last_page=0x%x\n",(int) (client->addr),reg,page,clientdata->last_page);
if (clientdata && (reg!=REG5338_PAGE) && (page != clientdata->last_page)) { /* set page if needed */
if (((rc=_write_single_reg(client, REG5338_PAGE, page)))<0) return rc;
}
rc= i2c_smbus_read_byte_data(client, reg & 0xff);
dev_dbg(&client->dev,"reading i2c device : slave=0x%x, reg=0x%x -> 0x%x\n",(int) (client->addr),reg,rc);
if (rc<0) return rc;
if (clientdata && (reg==REG5338_PAGE)) {
clientdata->last_page= rc & REG5338_PAGE_MASK;
}
if (clientdata && (reg<=LAST_REG)){
clientdata->cache[reg].data= (u8) rc;
clientdata->cache[reg].flags |= CACHE_INIT;
}
return rc;
}
static void si5338_init_of(struct i2c_client *client)
{
// struct device *dev=&client->dev;
const __be32 * config_data;
const char * init_type_string;
int init_type=0; /* 0 - none, 1 - always, 2 - if not running (TODO) */
struct device_node *node = client->dev.of_node;
int len,i,n;
u16 page_reg;
char buf[40];
u64 freq[3];
u32 rate,amp;
struct si5338_setup_data {
u8 page;
u8 reg;
u8 data;
u8 mask;
};
struct si5338_setup_data setup_data;
__be32 * setup_data_be32= (__be32 *) &setup_data;
if (node) {
init_type_string = of_get_property(client->dev.of_node, "si5338,init", &len);
if (init_type_string){
if (strcmp(init_type_string,"always")==0) init_type=1;
else if (strcmp(init_type_string,"if off")==0) init_type=2;
else {
dev_err(&client->dev,"Unrecognized si5338 initialization type '%s'. Only 'always' and 'if off' are permitted\n",init_type_string);
}
}
switch (init_type){
case 2:
// static int is_set_up(struct i2c_client *client);
i=is_set_up(client);
if (i<0){
dev_err(&client->dev,"Error reading i2c register, aborting initialization\n");
return;
} else if (i>0){
init_type=0;
dev_dbg(&client->dev,"Skipping conditional initialization (some driver variables will not be initialized)\n");
return;
}
init_type=1;
/* falling to initialization */
case 1:
pre_init(client,1); // clear outputs and muxes - they will be programmed later
break;
}
config_data = of_get_property(client->dev.of_node, "si5338,configuration_data", &len);
if (config_data){
len /= sizeof(*config_data);
dev_dbg(&client->dev,"Read %d values\n",len);
dev_dbg(&client->dev,"Found %d items in 'si5338,configuration_data' in the Device Tree\n",len);
for (i=0;idev,"page_reg=0x%03x, data=0x%02x, mask=0x%02x \n",
(int) page_reg,(int)setup_data.data,(int)setup_data.mask);
if (write_reg(client, page_reg, setup_data.data, setup_data.mask)<0) return;
}
}
/* input section */
/* setting input frequency here divides (if needed) and feeds it to the PLL reference. Other variants can use raw register writes */
for (n=0;in_freq_names[n];n++){
sprintf(buf,"si5338,%s",in_freq_names[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
dev_dbg(&client->dev,"Found '%s', value = %d (0x%x)\n",buf,(int)(be32_to_cpup(config_data)),(int)(be32_to_cpup(config_data)));
if (set_in_frequency(client, be32_to_cpup(config_data),n)<0) return; /* 32 bits are sufficient here */
}
}
/* setting PLL for the most important output frequency, sets analog parameters accordingly. Assumes input frequency set above */
for (n=0;pll_setup_names[n];n++){
sprintf(buf,"si5338,%s",pll_setup_names[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
len /= sizeof(*config_data);
freq[0]=be32_to_cpup(config_data);
if (len<3){
freq[1]=0;
freq[2]=1;
} else {
freq[1]=be32_to_cpup(&config_data[1]);
freq[2]=be32_to_cpup(&config_data[2]);
}
dev_dbg(&client->dev,"Found '%s', value = %lld+(%lld/%lld)\n",buf,freq[0],freq[1],freq[2]);
if (n & 2){ /* by output */
if (set_pll_freq_by_out(client, freq, n & 1)<0) return;
} else { /* directly set PLL frequency */
if (set_pll_freq (client, freq, n & 1)<0) return;
}
if (set_pll_paremeters(client)<0) return;
/* if (set_misc_registers(client)<0) return; */ /* moved to pre_init() */
}
}
/* setting MSn dividers (same channel as output), powering them up, setting output dividers and routing outputs */
for (n=0;out_freq_setup_names[n];n++){
sprintf(buf,"si5338,%s",out_freq_setup_names[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
len /= sizeof(*config_data);
freq[0]=be32_to_cpup(config_data);
if (len<3){
freq[1]=0;
freq[2]=1;
} else {
freq[1]=be32_to_cpup(&config_data[1]);
freq[2]=be32_to_cpup(&config_data[2]);
}
dev_dbg(&client->dev,"Found '%s', value = %lld+(%lld/%lld)\n",buf,freq[0],freq[1],freq[2]);
if (set_out_frequency_and_route(client, freq, n&3, n>>2)<0) return;
}
}
/* configure output driver standard */
for (n=0;drv_configs[n].description;n++){
sprintf(buf,"si5338,%s",drv_configs[n].description);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (configure_output_driver(&client->dev, drv_configs[n].description, setup_data.mask)<0) return;
}
}
}
/* configure disabled state of the output(s) */
for (n=0;out_dis_states[n];n++){
sprintf(buf,"si5338,%s",out_dis_states[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (set_drv_disable(client, n, setup_data.mask)<0) return;
}
}
}
/* configure powerdown state of the output(s) */
for (n=0;out_pwr_states[n];n++){
sprintf(buf,"si5338,%s",out_pwr_states[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (set_drv_powerdown(client, n, setup_data.mask)<0) return;
}
}
}
/* configure output enable state of the output(s) */
for (n=0;out_en_states[n];n++){
sprintf(buf,"si5338,%s",out_en_states[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (set_drv_disable(client, n, setup_data.mask)<0) return;
}
}
}
/* setting spread spectrum parameters */
for (n=0;n<4;n++){
sprintf(buf,"si5338,spread_spectrum_%d",n);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
len /= sizeof(*config_data);
rate=get_ss_down_rate(client, n);
amp= get_ss_down_amplitude(client, n);
if (len>1) amp = be32_to_cpup(&config_data[1]);
if (len>2) rate = be32_to_cpup(&config_data[2]);
if (store_ss_down_parameters(client, rate, amp, n)==0){
dev_dbg(&client->dev,"Set spread spectrum parameters for MS%d, amplitude=%d (*0.01%%), rate=%d Hz, %s\n",
n,amp,rate,config_data[0]?"ON":"OFF");
} else {
dev_err(&client->dev,"Failed to set spread spectrum parameters for MS%d, amplitude=%d (*0.01%%), rate=%d Hz, %s\n",
n,amp,rate,config_data[0]?"ON":"OFF");
continue;
}
if (config_data[0]){ /* enable SS */
if ((set_ss_down(client, n)==0) && /* calculate and set SS registers */
(set_ss_state(client, 1, n)==0)){ // enable SS. Not using enable_spread_spectrum() as we'll reset MS later anyway
dev_dbg(&client->dev,"Spread spectrum enabled for MS%d\n",n);
} else {
dev_err(&client->dev,"Fail to enable spread spectrum for MS%d\n",n);
}
}
}
}
} else {
dev_info(&client->dev,"Device tree data not found for %s\n",client->name);
}
if (init_type){
if (post_init(client,INIT_TIMEOUT)<0) dev_err(&client->dev,"SI5338 initialization failed\n");
else dev_info(&client->dev,"SI5338 initialized\n");
}
}
static void invalidate_cache(struct i2c_client *client)
{
int i;
struct si5338_data_t *clientdata = i2c_get_clientdata(client);
for (i=0;i<=LAST_REG;i++){
clientdata->cache[i].flags&= ~CACHE_INIT;
}
}
static int si5338_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int i,rc=0;
struct si5338_data_t *clientdata = NULL;
/* initialize i2c ... */
//#define REG5338_DEV_CONFIG2 2
//#define REG5338_DEV_CONFIG2_MASK 0x3f
//#define REG5338_DEV_CONFIG2_VAL 38 /* last 2 digits of part number */
if (((rc=_write_single_reg(client, REG5338_PAGE,0)))<0) return rc; // did not respond
if (((rc=read_reg(client, REG5338_DEV_CONFIG2)))<0) return rc; // did not respond
if ((rc & REG5338_DEV_CONFIG2_MASK)!= REG5338_DEV_CONFIG2_VAL){
dev_err(&client->dev,
"Chip returned unexpected value from reg %d: %d, expected %d. It is not %s\n",
REG5338_DEV_CONFIG2,rc, REG5338_DEV_CONFIG2_VAL,id->name);
return -EIO;
}
dev_info(&client->dev,
"Chip %s is found, driver version %s\n", id->name, DRV_VERSION);
clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata), GFP_KERNEL);
for (i=0;i<=LAST_REG;i++){
clientdata->cache[i].flags=0;
clientdata->cache[i].data=0;
}
for (i=0;volatile_registers[i]>=0;i++){
clientdata->cache[volatile_registers[i]>>8].flags |= CACHE_VOLAT;
}
//volatile_registers[]
i2c_set_clientdata(client, clientdata);
if (((rc=read_reg(client, REG5338_PAGE)))<0) return rc; // will set clientdata->last_page
si5338_sysfs_register(&client->dev);
mutex_init(&clientdata->lock);
clientdata->input_frequency12=0;
clientdata->input_frequency3=0;
clientdata->input_frequency4=0;
clientdata->input_frequency56=0;
clientdata->ss_on_freq_change=0; /* 0 - disable SS when frequency is changed, 1 - update SS. +2 reset MS after starting SS*/
for (i=0;i<4;i++){
clientdata->spread_spectrum_rate[i]=SPREAD_RATE_DFLT; /* 31.5 KHz */
clientdata->spread_spectrum_amp[i]=SPREAD_AMP_DFLT; /* 0.5% */
}
si5338_init_of(client);
return 0;
}
static int si5338_i2c_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_driver si5338_i2c_driver = {
.driver = {
.name = "si5338",
.owner = THIS_MODULE,
},
.probe = si5338_i2c_probe,
.remove = si5338_i2c_remove,
.id_table = si5338_id,
};
module_i2c_driver(si5338_i2c_driver);
MODULE_DEVICE_TABLE(i2c, si5338_id);
MODULE_AUTHOR("Andrey Filippov ");
MODULE_DESCRIPTION("SI5338 I2C bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:si5338");
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/ 0000775 0000000 0000000 00000000000 12703306510 0025064 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/Kconfig 0000664 0000000 0000000 00000002272 12703306510 0026372 0 ustar 00root root 0000000 0000000 #
# Elphel devices
#
menu "Elphel devices"
config ELPHEL393
tristate "Support Elphel 10393 board voltage regulator, DMA memory allocator"
# add more
# depends on I2C && SYSFS
help
Say Y here if you have a Elphel board 10393.
config ELPHELDRVONMICROZED
tristate "Provide only Elphel features which are compatible with Microzed"
help
Say Y here if you debug Elphel camera code on Microzed board.
config ELPHEL393_INIT
bool
default y
help
If unsure, say Y.
config ELPHEL393_EXTERNAL
tristate "Compile some Elphel drivers as external modules"
default m
help
If unsure, say Y.
endmenu
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/Makefile 0000664 0000000 0000000 00000001732 12703306510 0026527 0 ustar 00root root 0000000 0000000 #
# Makefile for Elphel specific devices.
#
obj-$(CONFIG_ELPHEL393) += elphel393-pwr.o
obj-$(CONFIG_ELPHEL393) += elphel393-mem.o
obj-$(CONFIG_ELPHELDRVONMICROZED) += elphel393-mem.o
obj-$(CONFIG_ELPHEL393_INIT) += elphel393-init.o
obj-$(CONFIG_ELPHEL393) += x393.o
obj-$(CONFIG_ELPHEL393) += sensor_i2c.o
obj-$(CONFIG_ELPHEL393) += fpgajtag353.o
#fpgajtag-y := fpgajtag353.o x393.o
#obj-$(CONFIG_ELPHEL393_EXTERNAL) += fpgajtag.o linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/elphel393-init.c 0000664 0000000 0000000 00000027417 12703306510 0027714 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : elphel393-init.c
*! DESCRIPTION: * Unlock rootfs NAND flash partition
*! * Read MAC and other useful info from NAND flash OTP area
*! and put to sysfs
*!
*! E-mail: oleg@elphel.com, support-list@elphel.com
*!
*! Copyright (C) 2016 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! 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 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*!****************************************************************************/
#define DRV_NAME "elphel393-init"
#define pr_fmt(fmt) DRV_NAME": " fmt
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* from elphel393-mem.c */
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
#define NAND_FLASH_OTP_PAGE_OFFSET 0*2048
/*
* Read and parse bootargs parameter in the device tree
* This driver is run in the last place - at least after NAND driver is probed
*/
static struct mtd_info *mtd;
//surprise size
static char *bootargs;
//known size
static char boardinfo[2048];
static char serial[13];
static char revision[8];
/*
static int __init elphel393_early_initialize(void){
struct device_node *node;
struct property *newproperty;
u8 *macaddr;
pr_info("VERY EARLY CALL TO UPDATE DEVICE TREE");
node = of_find_node_by_name(NULL, "ps7-ethernet");
if (!node){
pr_err("Device tree node 'ps7-ethernet' not found.");
return -ENODEV;
}
newproperty = kzalloc(sizeof(*newproperty) + 6, GFP_KERNEL);
if (!newproperty)
return -ENOMEM;
newproperty->value = newproperty + 1;
newproperty->length = 6;
newproperty->name = kstrdup("local-mac-address", GFP_KERNEL);
if (!newproperty->name) {
kfree(newproperty);
return -ENOMEM;
}
macaddr = newproperty->value;
macaddr[0] = 0x02;
macaddr[1] = 0x03;
macaddr[2] = 0x04;
macaddr[3] = 0x05;
macaddr[4] = 0x06;
macaddr[5] = 0x07;
of_update_property(node,newproperty);
return 0;
}
*/
static int __init elphel393_init_init (void)
{
struct device_node *node;
node = of_find_node_by_name(NULL, "chosen");
//just throw an error
if (!node){
pr_err("Device tree node 'chosen' not found.");
return -ENODEV;
}
of_property_read_string(node, "bootargs", &bootargs);
if (bootargs!=NULL) {
pr_debug("bootargs line from device tree is %s",bootargs);
}
return 0;
}
static void __exit elphel393_init_exit(void)
{
printk("Exit\n");
}
// SYSFS
static ssize_t get_bootargs(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%s\n",bootargs);
}
static ssize_t get_boardinfo(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%s\n",boardinfo);
}
static ssize_t get_revision(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%s\n",revision);
}
static ssize_t get_serial(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%s\n",serial);
}
static int get_factory_info(void);
static ssize_t set_boardinfo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int ret;
size_t retlen;
char wbuf[2048];
if (IS_ERR(mtd)){
pr_err("Get MTD device error, code:%d\n",-(u32)mtd);
return -ENODEV;
}
memset(wbuf,0xff,2048);
//too much of a trouble to read from flash again
if(!strnstr(boardinfo,"",sizeof(boardinfo))){
pr_info("Factory Info record is clean.\n");
pr_info("Data to be written: %s",buf);
// I got some buf, unknown size- should be limited to 2048? ok
if (strlen(buf)>2048) {
pr_err("Data > 2KiB. Abort.\n");
return -EFBIG;
}
// Not too strict check, just look for opening tags.
if(!strnstr(buf,"",2048)||!strnstr(buf,"",2048)||!strnstr(buf,"",2048)){
pr_err("Bad data format\n");
return -EINVAL;
}
//copy to buf
strncpy(wbuf,buf,strlen(buf));
//pr_info("BUFFER: %s\n",wbuf);
ret = mtd_write_user_prot_reg(mtd, NAND_FLASH_OTP_PAGE_OFFSET, 2048, &retlen, wbuf);
if (ret){
pr_err("Flash page write, code %d",ret);
return ret;
}
pr_info("Data is successfully written and cannot be overwritten anymore\n");
get_factory_info();
}else{
pr_err("Factory Info record (serial='%s' revision='%s') can not be overwritten\n",serial,revision);
return -EPERM;
}
return count;
}
static DEVICE_ATTR(bootargs , SYSFS_PERMISSIONS & SYSFS_READONLY, get_bootargs , NULL);
static DEVICE_ATTR(boardinfo , SYSFS_PERMISSIONS , get_boardinfo, set_boardinfo);
static DEVICE_ATTR(revision , SYSFS_PERMISSIONS & SYSFS_READONLY, get_revision , NULL);
static DEVICE_ATTR(serial , SYSFS_PERMISSIONS & SYSFS_READONLY, get_serial , NULL);
static struct attribute *root_dev_attrs[] = {
&dev_attr_bootargs.attr,
&dev_attr_boardinfo.attr,
&dev_attr_revision.attr,
&dev_attr_serial.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
.attrs = root_dev_attrs,
.name = NULL,
};
static int elphel393_init_sysfs_register(struct platform_device *pdev)
{
int retval=0;
struct device *dev = &pdev->dev;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval;
}
return retval;
}
static int elphel393_init_probe(struct platform_device *pdev)
{
char *bootargs_copy;
char *token;
char *token_copy;
char *param;
char *value;
//mtd device number to unlock
u8 devnum= 0;
u8 unlock= 0;
pr_debug("Probing\n");
//copy bootargs string
bootargs_copy = kstrdup(bootargs,GFP_KERNEL);
//find out which partition to unlock if any
//parse bootargs
do {
token = strsep(&bootargs_copy," ");
if (token) {
//if '=' is found - split by '='
token_copy = token;
if (strchr(token_copy,'=')){
if (!strcmp(token_copy,"rootfstype=ubifs")){
unlock=1;
}
param = strsep(&token_copy,"=");
//if "ubi.mtd" then get the partition number and unlock /dev/mtdN - if not found then don't care
if (!strcmp(param,"ubi.mtd")){
value = strsep(&token_copy,",");
if (kstrtou8(value,10,&devnum)){
pr_err("Partition number str to u8 conversion.");
}
}
}
}
} while (token);
kfree(bootargs_copy);
// unlock /dev/mtdN partition
// if there's no need to unlock, get /dev/mtd0
if (devnum>=0){
mtd = get_mtd_device(NULL,devnum);
if (IS_ERR(mtd)){
pr_err("Get MTD device error, code:%d\n",-(u32)mtd);
return -ENODEV;
}
if (unlock){
mtd_unlock(mtd,0,mtd->size);
pr_info("/dev/mtd%d: unlocked",devnum);
}
}
// read boardinfo record
// * device number is not important
// * no need to unlock
// page size
BUG_ON(mtd->writesize > 2048);
get_factory_info();
elphel393_init_sysfs_register(pdev);
return 0;
}
static int get_factory_info(void){
char regvalh[]="0000";
char regvall[]="00000000";
u16 hwaddrh0, hwaddrh1;
u32 hwaddrl0, hwaddrl1;
size_t retlen;
//size of nand flash page
char kbuf[2048];
size_t size = mtd->writesize;
int ret;
char *ps,*pe;
struct device_node *node;
struct property *newproperty;
u32 *mac32; // = (u32*) mac_address;
u8 *macaddr;
u8 block_factory_mac = 0;
node = of_find_node_by_name(NULL, "ps7-ethernet");
if (!node){
pr_err("Device tree node 'ps7-ethernet' not found.");
return -ENODEV;
}
// check if MAC address was overridden in u-boot
mac32 = (u32 *) of_get_mac_address(node);
hwaddrl0 = cpu_to_le32(mac32[0]);
hwaddrh0 = cpu_to_le16(mac32[1]);
if ((hwaddrh0!=0x0000)||(hwaddrl0!=0x10640E00)){
block_factory_mac = 1;
}
ret = mtd_read_user_prot_reg(mtd, NAND_FLASH_OTP_PAGE_OFFSET, size, &retlen, kbuf);
if (ret){
pr_err("Flash page read, code %d",ret);
return ret;
}
pr_debug("buf: %s\n",kbuf);
// do whatever we like with the kbuf
// search for ""
// expecting to find it somewhere...
if(strnstr(kbuf,"",size)){
//...right in the beginning or error
ps = strnstr(kbuf,"",size);
pe = strnstr(kbuf,"",size);
strncpy(serial,ps+sizeof("")-1,pe-ps-(sizeof("")-1));
strncpy(regvalh,serial,4);
strncpy(regvall,serial+4,8);
//there is kstrtou64 but it doesn't work?
kstrtou16(regvalh,16,&hwaddrh1);
kstrtou32(regvall,16,&hwaddrl1);
pr_debug("MAC from flash: %02x:%02x:%02x:%02x:%02x:%02x\n",
(hwaddrl1 & 0xff), ((hwaddrl1 >> 8) & 0xff),
((hwaddrl1 >> 16) & 0xff), (hwaddrl1 >> 24),
(hwaddrh1 & 0xff), (hwaddrh1 >> 8));
newproperty = kzalloc(sizeof(*newproperty) + 6, GFP_KERNEL);
if (!newproperty)
return -ENOMEM;
newproperty->value = newproperty + 1;
newproperty->length = 6;
newproperty->name = kstrdup("local-mac-address", GFP_KERNEL);
if (!newproperty->name) {
kfree(newproperty);
return -ENOMEM;
}
macaddr = newproperty->value;
macaddr[0] = (hwaddrh1 >> 8) & 0xff;
macaddr[1] = hwaddrh1 & 0xff;
macaddr[2] = (hwaddrl1 >> 24) & 0xff;
macaddr[3] = (hwaddrl1 >> 16) & 0xff;
macaddr[4] = (hwaddrl1 >> 8) & 0xff;
macaddr[5] = hwaddrl1 & 0xff;
if (!block_factory_mac)
of_update_property(node,newproperty);
else
pr_info("Factory MAC: %02x:%02x:%02x:%02x:%02x:%02x, u-boot overridden MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
(hwaddrl1 & 0xff),((hwaddrl1 >> 8) & 0xff),((hwaddrl1 >> 16) & 0xff),(hwaddrl1 >> 24),(hwaddrh1 & 0xff),(hwaddrh1 >> 8),
(hwaddrl0 & 0xff),((hwaddrl0 >> 8) & 0xff),((hwaddrl0 >> 16) & 0xff),(hwaddrl0 >> 24),(hwaddrh0 & 0xff),(hwaddrh0 >> 8));
mac32 = (u32 *) of_get_mac_address(node);
hwaddrl1 = cpu_to_le32(mac32[0]);
hwaddrh1 = cpu_to_le16(mac32[1]);
pr_debug("new MAC from device tree: %02x:%02x:%02x:%02x:%02x:%02x\n",
(hwaddrl1 & 0xff), ((hwaddrl1 >> 8) & 0xff),
((hwaddrl1 >> 16) & 0xff), (hwaddrl1 >> 24),
(hwaddrh1 & 0xff), (hwaddrh1 >> 8));
//write hwaddr to zynq reg
//kstrtou16(serial,16,®valh);
//serial
ps = strnstr(kbuf,"",size);
pe = strnstr(kbuf,"",size);
strncpy(revision,ps+sizeof("")-1,pe-ps-(sizeof("")-1));
ps = strnstr(kbuf,"",size);
pe = strnstr(kbuf,"",size);
strncpy(boardinfo,ps,pe-ps+(sizeof("")-1));
}
return 0;
}
static int elphel393_init_remove(struct platform_device *pdev)
{
pr_info("Remove");
return 0;
}
static struct of_device_id elphel393_init_of_match[] = {
{ .compatible = "elphel,elphel393-init-1.00", },
{ /* end of table */}
};
MODULE_DEVICE_TABLE(of, elphel393_init_of_match);
static struct platform_driver elphel393_initialize = {
.probe = elphel393_init_probe,
.remove = elphel393_init_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = elphel393_init_of_match,
.pm = NULL, /* power management */
},
};
//early_initcall(elphel393_early_initialize);
module_platform_driver(elphel393_initialize);
module_init(elphel393_init_init);
module_exit(elphel393_init_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Elphel, Inc.");
MODULE_DESCRIPTION("Unlock rootfs flash partition and read/write board info: serial and revision");
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/elphel393-mem.c 0000664 0000000 0000000 00000041353 12703306510 0027522 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : elphel393-mem.c
*! DESCRIPTION: Reserve large memory range at boot time (when it is available)
*! to use as a circular video buffer
*! Copyright (C) 2015 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! 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 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*!****************************************************************************/
#define DRV_NAME "elphel393-mem"
#define pr_fmt(fmt) DRV_NAME": " fmt
#include
#include
#include
#include
#include // kmalloc
#include // vmalloc
#include // __get_free_pages
#include
#include
#include
#include
#include
#include
#include
#include
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
static ssize_t get_paddr(struct device *dev, struct device_attribute *attr, char *buf);
static struct elphel_buf_t _elphel_buf = {
// Coherent DMA buffer
.vaddr = NULL,
.paddr = 0,
.size = 0,
// Host to device stream DMA buffer
.h2d_vaddr = NULL,
.h2d_paddr = 0,
.h2d_size = 1024, // TODO: add to DT, learn how to allocate more
// Device to host stream DMA buffer
.d2h_vaddr = NULL,
.d2h_paddr = 0,
.d2h_size = 1024,
// Bidirectional stream DMA buffer
.bidir_vaddr = NULL,
.bidir_paddr = 0,
.bidir_size = 1024
};
struct elphel_buf_t *pElphel_buf; // static can not be extern
EXPORT_SYMBOL_GPL(pElphel_buf);
static int __init elphelmem_init(void)
{
struct device_node *node;
const __be32 *bufsize_be;
pElphel_buf = &_elphel_buf;
node = of_find_node_by_name(NULL, "elphel393-mem");
if (!node)
{
pr_err("DMA buffer allocation ERROR: No device tree node found\n");
return -ENODEV;
}
bufsize_be = (__be32 *)of_get_property(node, "memsize", NULL);
_elphel_buf.size = be32_to_cpup(bufsize_be);
/*
// Coherent DMA buffer
void *vaddr;
dma_addr_t paddr;
ssize_t size;
// Host to device stream DMA buffer
void *h2d_vaddr;
dma_addr_t h2d_paddr;
ssize_t h2d_size;
// Device to host stream DMA buffer
void *d2h_vaddr;
dma_addr_t d2h_paddr;
ssize_t d2h_size;
// Bidirectional stream DMA buffer
void *bidir_vaddr;
dma_addr_t bidir_paddr;
ssize_t bidir_size;
_elphel_buf.vaddr = dma_alloc_coherent(NULL,(_elphel_buf.size*PAGE_SIZE),&(_elphel_buf.paddr),GFP_KERNEL);
if(_elphel_buf.paddr)
{
printk("Allocated %u pages for DMA at address 0x%x\n", (u32)_elphel_buf.size, (u32)_elphel_buf.paddr);
}
else printk("ERROR allocating memory buffer");
http://linuxkernelhacker.blogspot.com/2014/07/arm-dma-mapping-explained.html
*/
// Alternative way to allocate memory for DMA
// allocate continuous virtual memory range
// _elphel_buf.vaddr = kmalloc((_elphel_buf.size*PAGE_SIZE) ,GFP_KERNEL);
_elphel_buf.vaddr = dma_alloc_coherent(NULL,(_elphel_buf.size*PAGE_SIZE),&(_elphel_buf.paddr),GFP_KERNEL);
if(_elphel_buf.vaddr) {
pr_info("Allocated %u pages for DMA at address 0x%x\n", (u32)_elphel_buf.size, (u32)_elphel_buf.paddr);
} else {
pr_err("ERROR allocating coherent DMA memory buffer\n");
}
_elphel_buf.h2d_vaddr = kzalloc((_elphel_buf.h2d_size*PAGE_SIZE) ,GFP_KERNEL);
if (!_elphel_buf.h2d_vaddr){
_elphel_buf.h2d_size = 0;
pr_err("ERROR allocating H2D DMA memory buffer\n");
}
_elphel_buf.d2h_vaddr = kzalloc((_elphel_buf.d2h_size*PAGE_SIZE) ,GFP_KERNEL);
if (!_elphel_buf.d2h_vaddr){
_elphel_buf.d2h_size = 0;
pr_err("ERROR allocating D2H DMA memory buffer\n");
}
_elphel_buf.bidir_vaddr = kzalloc((_elphel_buf.bidir_size*PAGE_SIZE) ,GFP_KERNEL);
if (!_elphel_buf.bidir_vaddr){
_elphel_buf.bidir_size = 0;
pr_err("ERROR allocating Bidirectional DMA memory buffer\n");
}
pr_info("Coherent buffer vaddr: 0x%08X\n",(u32) pElphel_buf -> vaddr);
pr_info("Coherent buffer paddr: 0x%08X\n",(u32) pElphel_buf -> paddr);
pr_info("Coherent buffer length: 0x%08X\n",(u32) pElphel_buf -> size * PAGE_SIZE);
return 0;
}
/*
dma_addr_t
dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction direction)
*/
static void __exit elphelmem_exit(void)
{
pr_info("DMA buffer disabled\n");
}
// SYSFS
static ssize_t get_paddr(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%x\n", (u32)_elphel_buf.paddr);
}
static ssize_t get_size(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%u\n", _elphel_buf.size);
}
static ssize_t get_paddr_h2d(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%x\n", (u32)_elphel_buf.h2d_paddr);
}
static ssize_t get_size_h2d(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%u\n", _elphel_buf.h2d_size);
}
static ssize_t get_paddr_d2h(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%x\n", (u32)_elphel_buf.d2h_paddr);
}
static ssize_t get_size_d2h(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%u\n", _elphel_buf.d2h_size);
}
static ssize_t get_paddr_bidir(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%x\n", (u32)_elphel_buf.bidir_paddr);
}
static ssize_t get_size_bidir(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%u\n", _elphel_buf.bidir_size);
}
/*
static ssize_t get_cache(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Write into this file to flush L1/L2 caches to memory.\n");
}
static ssize_t flush_cache(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
__cpuc_flush_kern_all();
outer_flush_all();
return count;
}
*/
static ssize_t sync_for_cpu_h2d(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
dma_addr_t paddr;
size_t len;
int num_items;
num_items=sscanf(buf, "%u %u", &paddr, &len);
if (num_items<2) {
paddr = _elphel_buf.h2d_paddr;
len = _elphel_buf.h2d_size * PAGE_SIZE;
}
printk("\naddr=0x%08x, size = 0x%08x\n", paddr, len);
dma_sync_single_for_cpu(dev, paddr, len, DMA_TO_DEVICE);
return count;
}
static ssize_t sync_for_device_h2d(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
dma_addr_t paddr;
size_t len;
int num_items;
num_items=sscanf(buf, "%u %u", &paddr, &len);
if (num_items<2) {
paddr = _elphel_buf.h2d_paddr;
len = _elphel_buf.h2d_size * PAGE_SIZE;
}
pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len);
dma_sync_single_for_device(dev, paddr, len, DMA_TO_DEVICE);
return count;
}
static ssize_t sync_for_cpu_d2h(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
dma_addr_t paddr;
size_t len;
int num_items;
num_items=sscanf(buf, "%u %u", &paddr, &len);
if (num_items<2) {
paddr = _elphel_buf.d2h_paddr;
len = _elphel_buf.d2h_size * PAGE_SIZE;
}
pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len);
dma_sync_single_for_cpu(dev, paddr, len, DMA_FROM_DEVICE);
return count;
}
static ssize_t sync_for_device_d2h(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
dma_addr_t paddr;
size_t len;
int num_items;
num_items=sscanf(buf, "%u %u", &paddr, &len);
if (num_items<2) {
paddr = _elphel_buf.d2h_paddr;
len = _elphel_buf.d2h_size * PAGE_SIZE;
}
pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len);
dma_sync_single_for_device(dev, paddr, len, DMA_FROM_DEVICE);
return count;
}
static ssize_t sync_for_cpu_bidir(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
dma_addr_t paddr;
size_t len;
int num_items;
num_items=sscanf(buf, "%u %u", &paddr, &len);
if (num_items<2) {
paddr = _elphel_buf.bidir_paddr;
len = _elphel_buf.bidir_size * PAGE_SIZE;
}
pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len);
dma_sync_single_for_cpu(dev, paddr, len, DMA_BIDIRECTIONAL);
return count;
}
static ssize_t sync_for_device_bidir(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
dma_addr_t paddr;
size_t len;
int num_items;
num_items=sscanf(buf, "%u %u", &paddr, &len);
if (num_items<2) {
paddr = _elphel_buf.bidir_paddr;
len = _elphel_buf.bidir_size * PAGE_SIZE;
}
pr_info("\naddr=0x%08x, size = 0x%08x\n", paddr, len);
dma_sync_single_for_device(dev, paddr, len, DMA_BIDIRECTIONAL);
return count;
}
static ssize_t get_sync_for_device_h2d(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Write address/length pair into this file to hand this region of the host to device DMA buffer to device (after CPU writes).\n");
}
static ssize_t get_sync_for_cpu_h2d(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Write address/length pair into this file to hand this region of the host to device DMA buffer to CPU (before CPU reads).\n");
}
static ssize_t get_sync_for_device_d2h(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Write address/length pair into this file to hand this region of the device to host DMA buffer to device (after CPU writes).\n");
}
static ssize_t get_sync_for_cpu_d2h(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Write address/length pair into this file to hand this region of the device to host DMA buffer to CPU (before CPU reads).\n");
}
static ssize_t get_sync_for_device_bidir(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Write address/length pair into this file to hand this region of the bidirectional DMA buffer to device (after CPU writes).\n");
}
static ssize_t get_sync_for_cpu_bidir(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Write address/length pair into this file to hand this region of the bidirectional DMA buffer to CPU (before CPU reads).\n");
}
static DEVICE_ATTR(buffer_address, SYSFS_PERMISSIONS & SYSFS_READONLY, get_paddr, NULL);
static DEVICE_ATTR(buffer_pages, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size, NULL);
static DEVICE_ATTR(buffer_address_h2d, SYSFS_PERMISSIONS & SYSFS_READONLY, get_paddr_h2d, NULL);
static DEVICE_ATTR(buffer_pages_h2d, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size_h2d, NULL);
static DEVICE_ATTR(buffer_address_d2h, SYSFS_PERMISSIONS & SYSFS_READONLY, get_paddr_d2h, NULL);
static DEVICE_ATTR(buffer_pages_d2h, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size_d2h, NULL);
static DEVICE_ATTR(buffer_address_bidir, SYSFS_PERMISSIONS & SYSFS_READONLY, get_paddr_bidir, NULL);
static DEVICE_ATTR(buffer_pages_bidir, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size_bidir, NULL);
//static DEVICE_ATTR(buffer_flush, SYSFS_PERMISSIONS, get_cache, flush_cache);
static DEVICE_ATTR(sync_for_cpu_h2d, SYSFS_PERMISSIONS, get_sync_for_cpu_h2d, sync_for_cpu_h2d);
static DEVICE_ATTR(sync_for_device_h2d, SYSFS_PERMISSIONS, get_sync_for_device_h2d, sync_for_device_h2d);
static DEVICE_ATTR(sync_for_cpu_d2h, SYSFS_PERMISSIONS, get_sync_for_cpu_d2h, sync_for_cpu_d2h);
static DEVICE_ATTR(sync_for_device_d2h, SYSFS_PERMISSIONS, get_sync_for_device_d2h, sync_for_device_d2h);
static DEVICE_ATTR(sync_for_cpu_bidir, SYSFS_PERMISSIONS, get_sync_for_cpu_bidir, sync_for_cpu_bidir);
static DEVICE_ATTR(sync_for_device_bidir, SYSFS_PERMISSIONS, get_sync_for_device_bidir, sync_for_device_bidir);
static struct attribute *root_dev_attrs[] = {
&dev_attr_buffer_address.attr,
&dev_attr_buffer_pages.attr,
&dev_attr_buffer_address_h2d.attr,
&dev_attr_buffer_pages_h2d.attr,
&dev_attr_buffer_address_d2h.attr,
&dev_attr_buffer_pages_d2h.attr,
&dev_attr_buffer_address_bidir.attr,
&dev_attr_buffer_pages_bidir.attr,
// &dev_attr_buffer_flush.attr,
&dev_attr_sync_for_cpu_h2d.attr,
&dev_attr_sync_for_device_h2d.attr,
&dev_attr_sync_for_cpu_d2h.attr,
&dev_attr_sync_for_device_d2h.attr,
&dev_attr_sync_for_cpu_bidir.attr,
&dev_attr_sync_for_device_bidir.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
.attrs = root_dev_attrs,
.name = NULL,
};
static int elphel393_mem_sysfs_register(struct platform_device *pdev)
{
int retval=0;
struct device *dev = &pdev->dev;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval;
}
return retval;
}
static int elphel393_mem_probe(struct platform_device *pdev)
{
elphel393_mem_sysfs_register(pdev);
pr_info("Probing elphel393-mem\n");
if (_elphel_buf.h2d_vaddr){
// mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back
pElphel_buf->h2d_paddr = dma_map_single(&pdev->dev, _elphel_buf.h2d_vaddr, (_elphel_buf.h2d_size*PAGE_SIZE), DMA_TO_DEVICE);
if (!pElphel_buf->h2d_paddr){
pr_err("ERROR in dma_map_single() for bidirectional buffer\n");
return 0;
}
// printk("H2D DMA buffer location:\t\t0x%08X\n", pElphel_buf->h2d_paddr);
}
if (_elphel_buf.d2h_vaddr){
// mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back
pElphel_buf->d2h_paddr = dma_map_single(&pdev->dev, _elphel_buf.d2h_vaddr, (_elphel_buf.d2h_size*PAGE_SIZE), DMA_FROM_DEVICE);
if (!pElphel_buf->d2h_paddr){
pr_err("ERROR in dma_map_single() for bidirectional buffer\n");
return 0;
}
// printk("D2H DMA buffer location:\t\t0x%08X\n", pElphel_buf->d2h_paddr);
}
if (_elphel_buf.bidir_vaddr){
// mapped as DMA_BIDIRECTIONAL, each time will be synchronized when passing control from soft to hard and back
pElphel_buf->bidir_paddr = dma_map_single(&pdev->dev, _elphel_buf.bidir_vaddr, (_elphel_buf.bidir_size*PAGE_SIZE), DMA_BIDIRECTIONAL);
if (!pElphel_buf->bidir_paddr){
pr_err("ERROR in dma_map_single() for bidirectional buffer\n");
return 0;
}
// printk("Bidirectional DMA buffer location:\t0x%08X\n", pElphel_buf->bidir_paddr);
}
printk("H2D stream buffer vaddr: 0x%08X\n",(u32) pElphel_buf -> h2d_vaddr);
printk("H2D stream buffer paddr: 0x%08X\n",(u32) pElphel_buf -> h2d_paddr);
printk("H2D stream buffer length: 0x%08X\n",(u32) pElphel_buf -> h2d_size * PAGE_SIZE);
printk("D2H stream buffer vaddr: 0x%08X\n",(u32) pElphel_buf -> d2h_vaddr);
printk("D2H stream buffer paddr: 0x%08X\n",(u32) pElphel_buf -> d2h_paddr);
printk("D2H stream buffer length: 0x%08X\n",(u32) pElphel_buf -> d2h_size * PAGE_SIZE);
printk("Bidirectional stream buffer vaddr: 0x%08X\n",(u32) pElphel_buf -> bidir_vaddr);
printk("Bidirectional stream buffer paddr: 0x%08X\n",(u32) pElphel_buf -> bidir_paddr);
printk("Bidirectional stream buffer length: 0x%08X\n",(u32) pElphel_buf -> bidir_size * PAGE_SIZE);
return 0;
}
static int elphel393_mem_remove(struct platform_device *pdev)
{
pr_info("Removing elphel393-mem");
return 0;
}
static struct of_device_id elphel393_mem_of_match[] = {
{ .compatible = "elphel,elphel393-mem-1.00", },
{ /* end of table */}
};
MODULE_DEVICE_TABLE(of, elphel393_pwr_of_match);
static struct platform_driver elphel393_mem = {
.probe = elphel393_mem_probe,
.remove = elphel393_mem_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = elphel393_mem_of_match,
.pm = NULL, /* power management */
},
};
module_platform_driver(elphel393_mem);
module_init(elphelmem_init);
module_exit(elphelmem_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Elphel, Inc.");
MODULE_DESCRIPTION("Reserve a large chunk of contiguous memory at boot");
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/elphel393-pwr.c 0000664 0000000 0000000 00000130717 12703306510 0027557 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : elphel393-pwr.c
*! DESCRIPTION: power supplies control on Elphel 10393 board
*! Copyright (C) 2013 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! 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 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*/
#undef DEBUG /* should be before linux/module.h - enables dev_dbg at boot in this file */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DRIVER_DESCRIPTION "Elphel 10393 power supply control"
#define DRIVER_VERSION "1.00"
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
#define GPIO_CHIP1_ADDR 0x20
#define GPIO_CHIP2_ADDR 0x21
#define LTC3589_ADDR 0x34
/* TODO: set resistors in device tree to accommodate different revisions ( elphel393_pwr,vp15_r1 = <357000>)*/
#define VP15_R1 357000
#define VP15_R2 287000
#define VCC_SENS01_R1 787000
#define VCC_SENS01_R2 287000
#define VCC_SENS23_R1 787000
#define VCC_SENS23_R2 287000
#define VP5_R1 523000
#define VP5_R2 100000
#define VLDO18_R1 357000
#define VLDO18_R2 287000
#define PINSTRAPPED_OVEN 1
#define REF_FIXED_TENTH_MV 8000
#define REF_VAR_0_TENTH_MV 3625
#define REF_VAR_STEP_TENTH_MV 125
#define DEAFULT_TIMEOUT 300 /* number of retries testing pgood before giving up */
struct pwr_gpio_t {
const char * label;
int pin;
int dir; /* direction: 0 - in, 1 - out*/
int out_val; /* output value */
};
struct elphel393_pwr_data_t {
int chip_i2c_addr[3];
struct device * ltc3489_dev;
struct pwr_gpio_t pwr_gpio [16];
int simulate; /* do not perform actual i2c writes */
struct mutex lock;
int pgoot_timeout;
int pinstrapped_oven;
};
struct voltage_reg_t {
const char * name;
int r1; /* resistor in ohms, if <=0 - r2 is voltage in mv */
int r2; /* resistor in ohms, if r1<=0 - voltage in mv */
int awe_ref; /* 0 - no control, -1 - margining VP10, -2 - margining VP18 */
int awe_en; /* 0 - no control, negative - -1-gpio_index */
int awe_pgood; /* 0 - no status , negative - -1-gpio_index */
int mask_pgood; /* 1 - temporarily disable pgood when turning on/changing voltage */
int awe_slew;
};
static struct voltage_reg_t voltage_reg[]={
{
.name="vp15",
.r1=VP15_R1,
.r2=VP15_R2,
.awe_ref=LTC3589_AWE_B1DTV1_REF,
.awe_en=0,
.awe_pgood=LTC3589_AWE_PGSTAT_SD1,
.mask_pgood=1,
.awe_slew=LTC3589_AWE_VCCR_SLEW_SD1
},
{
.name="vcc_sens01",
.r1=VCC_SENS01_R1,
.r2=VCC_SENS01_R2,
.awe_ref=LTC3589_AWE_B2DTV1_REF,
.awe_en=LTC3589_AWE_OVEN_EN_SD2,
.awe_pgood=LTC3589_AWE_PGSTAT_SD2,
.mask_pgood=1,
.awe_slew=LTC3589_AWE_VCCR_SLEW_SD2
},
{
.name="vcc_sens23",
.r1=VCC_SENS23_R1,
.r2=VCC_SENS23_R2,
.awe_ref=LTC3589_AWE_B3DTV1_REF,
.awe_en=LTC3589_AWE_OVEN_EN_SD3,
.awe_pgood=LTC3589_AWE_PGSTAT_SD3,
.mask_pgood=1,
.awe_slew=LTC3589_AWE_VCCR_SLEW_SD3
},
{
.name="vp5",
.r1=VP5_R1,
.r2=VP5_R2,
.awe_ref=0,
.awe_en=LTC3589_AWE_OVEN_EN_BB,
.awe_pgood=LTC3589_AWE_PGSTAT_BB,
.mask_pgood=1,
.awe_slew=0
},
{
.name="vldo18",
.r1=VLDO18_R1,
.r2=VLDO18_R2,
.awe_ref=0,
.awe_en= 0,
.awe_pgood=LTC3589_AWE_PGSTAT_LDO1,
.mask_pgood=1,
.awe_slew=0
},
{
.name="vp33sens01",
.r1=-1,
.r2=33000,
.awe_ref=0,
.awe_en= -7, /* SENSPWREN0 */
.awe_pgood=0,
.mask_pgood=1,
.awe_slew=0
},
{
.name="vp33sens23",
.r1=-1,
.r2=33000,
.awe_ref=0,
.awe_en= -8, /* SENSPWREN1 */
.awe_pgood=0,
.mask_pgood=1,
.awe_slew=0
},
{
.name="mmtavcc10",
.r1=-1,
.r2=10000,
.awe_ref=0,
.awe_en= 0,
.awe_pgood=-15, /* MGTAVTTGOOD */
.mask_pgood=1,
.awe_slew=0
},
{
.name="mmtavtt12",
.r1=-1,
.r2=12000,
.awe_ref=0,
.awe_en= 0,
.awe_pgood=-15, /* MGTAVTTGOOD */
.mask_pgood=1,
.awe_slew=0
},
{
.name="vp10",
.r1=-1,
.r2=10000,
.awe_ref=-1,
.awe_en= 0,
.awe_pgood=-16, /* PGOOD18 */
.mask_pgood=1,
.awe_slew=0
},
{
.name="vp18",
.r1=-1,
.r2=18000,
.awe_ref=-2,
.awe_en= 0,
.awe_pgood=-16, /* PGOOD18 */
.mask_pgood=1,
.awe_slew=0
},
};
static struct pwr_gpio_t pwr_gpio[16]={
/* 0x20: */
{"PWR_MGB1", 0, 0, 0}, /* 1.8V margining magnitude (0 - 5%, 1 - 10%, float - 15%) */
{"PWR_MG1", 1, 0, 0}, /* 1.8V margining enable 0 - negative margining, 1 - positive margining, float - no margining */
{"PWR_MGB0", 2, 0, 0}, /* 1.0V margining magnitude (0 - 5%, 1 - 10%, float - 15%) */
{"PWR_MG0", 3, 0, 0}, /* 1.0V margining enable 0 - negative margining, 1 - positive margining, float - no margining */
{"PWR_FQ0", 4, 0, 0}, /* float - nominal frequency (should float for SS), 0 - 0.67 nominal frequency, 1 - 1.5 nominal frequency */
{"PWR_SS", 5, 0, 0}, /* Spread spectrum, 0 or float - spread spectrum disabled */
{"SENSPWREN0", 6, 0, 0}, /* 1 - enable 3.3 power to sensor connectors J6 and J7 (0 or float - disable) */
{"SENSPWREN1", 7, 0, 0}, /* 1 - enable 3.3 power to sensor connectors J8 and J9 (0 or float - disable) */
/* 0x21: */
{"NSHUTDOWN", 8, 0, 0}, /* (pulled up). 0 - shutdown, 1 normal */
{"DIS_POR", 9, 0, 0}, /* (pulled down). 0 - normal, 1 - disable POR generation on PGOOD deassertion (needed whil changing voltages) */
{ NULL, 10, 0, 0}, /* Not connected */
{ NULL, 11, 0, 0}, /* Not connected */
{ NULL, 12, 0, 0}, /* Not connected */
{ NULL, 13, 0, 0}, /* Not connected */
{"MGTAVTTGOOD",14, 0, 0}, /* (input) 1.2V linear regulator status (generated from 1.8V) */
{"PGOOD18", 15, 0, 0} /* (input). Combines other voltages, can be monitored when DIS_POR is activated */
};
static int make_group (struct device *dev, const char * name,
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf),
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count));
static ssize_t simulate_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t simulate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t outputs_all_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t configs_all_show(struct device *dev, struct device_attribute *attr, char *buf);
#if 0
static ssize_t output_state_show(struct device *dev, struct device_attribute *attr, char *buf);
#endif
static ssize_t output_en_output_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_en_output_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t outputs_pgood_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t channels_en_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t channels_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t channels_dis_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t channels_dis_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_ref_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_ref_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t pgood_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t pbad_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t enable_por_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t enable_por_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static int por_ctrl(struct device *dev, int disable_por);
static int get_and_disable_por(struct device *dev, int chn_bits, int * old_dis_por);
static int reenable_por(struct device *dev);
static int wait_all_pgood(struct device *dev);
static int list_chn_bits(char * buf, int chn_bits);
static int parse_chn_bits(const char * buf);
static int get_enabled_mask(struct device *dev);
static int set_enabled_by_mask(struct device *dev, int chn_bits, int enable);
static int slew_by_mask(struct device *dev, int chn_bits);
static int get_voltage_channel(const char * name);
static int get_gpio_index_by_name(const char * name);
static int gpio_conf_by_index(struct device *dev,int gpio_index, int dir, int val);
static int get_gpio_pwr_mgx_indices(int chn, int * indices); /* chn = 0 (VP10) or 1 (VP18) */
static int get_volt_mv(struct device *dev, int chn);
static int set_volt_mv(struct device *dev, int chn, int v_mv);
static int get_enable(struct device *dev, int chn);
static int set_enable(struct device *dev, int chn, int enable);
static int get_pgood(struct device *dev, int chn);
/*
Voltages:
VP10 (on at power up, nominal 1.0V)
VP18 (on at power up, nomianl 1.8V)
VP15 (SW1, on by pinstrap, nominal 1.5V - may be reduced to 1.35 later)
VCC_SENS01 (SW2, nominal 1.8V, max 2.8V)
VCC_SENS23 (SW3, nominal 1.8V, max 2.8V)
VP5 (nominal 5.0V, not software programmed)
VLDO18 (LDO1 - always on)
VP33SENS0 - 3.3V to sensors J6,J7
VP33SESN1 - 3.3V to sensors J8,J9
MGTAVCC10 - 1.0 V, linear from VP18 (pgood controls MGTAVTT12)
MGTAVTT12 - 1.2 V, linear from VP18 (pgood available, means both)
LTC3589 used channels : LDO1, SW1, SW2, SW3, BB
TODO: Change VCC_SENS01_R1, VCC_SENS23_R1 to 787K (now 487)
*/
/* root directory */
static DEVICE_ATTR(simulate, SYSFS_PERMISSIONS, simulate_show, simulate_store);
static DEVICE_ATTR(output_state, SYSFS_PERMISSIONS & SYSFS_READONLY, outputs_all_show, NULL);
static DEVICE_ATTR(configs, SYSFS_PERMISSIONS & SYSFS_READONLY, configs_all_show, NULL);
static DEVICE_ATTR(channels_en, SYSFS_PERMISSIONS, channels_en_show, channels_en_store);
static DEVICE_ATTR(channels_dis,SYSFS_PERMISSIONS, channels_dis_show, channels_dis_store);
static DEVICE_ATTR(power_good, SYSFS_PERMISSIONS & SYSFS_READONLY, pgood_show, NULL);
static DEVICE_ATTR(power_bad, SYSFS_PERMISSIONS & SYSFS_READONLY, pbad_show, NULL);
static DEVICE_ATTR(enable_por, SYSFS_PERMISSIONS, enable_por_show, enable_por_store);
static struct attribute *root_dev_attrs[] = {
&dev_attr_simulate.attr,
&dev_attr_output_state.attr,
&dev_attr_configs.attr,
&dev_attr_channels_en.attr,
&dev_attr_channels_dis.attr,
&dev_attr_power_good.attr,
&dev_attr_power_bad.attr,
&dev_attr_enable_por.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
.attrs = root_dev_attrs,
.name = NULL,
};
static int make_group (struct device *dev, const char * name,
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf),
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count))
{
int retval=-1;
int index;
struct attribute **pattrs; /* array of pointers to attibutes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
pattrs = devm_kzalloc(dev,(ARRAY_SIZE(voltage_reg)+1)*sizeof(pattrs[0]), GFP_KERNEL);
if (!pattrs) return -ENOMEM;
dev_attrs = devm_kzalloc(dev, ARRAY_SIZE(voltage_reg)*sizeof(dev_attrs[0]), GFP_KERNEL);
if (!dev_attrs) return -ENOMEM;
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
if (!attr_group) return -ENOMEM;
memset(dev_attrs, 0, ARRAY_SIZE(voltage_reg)*sizeof(dev_attrs[0]));
memset(attr_group, 0, sizeof(*attr_group));
for (index=0;indexname = name;
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static ssize_t simulate_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
return sprintf(buf, "%d\n",clientdata->simulate);
}
static ssize_t simulate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
sscanf(buf, "%du", &clientdata->simulate);
ltc3589_set_simulate(ltc3589_client, clientdata->simulate);
return count;
}
static ssize_t outputs_all_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn, pg;
char * cp = buf;
for (chn=0;chn0)?get_pgood(dev, chn):-1;
buf+=sprintf(buf,"%s: %s %d mV%s\n",
voltage_reg[chn].name,
get_enable(dev, chn)?"ON":"OFF",
get_volt_mv(dev, chn),
(pg==1)?", power good":((pg==0)?", power is NOT good":"")
);
}
return buf-cp;
}
static ssize_t configs_all_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn, pg;
char * cp = buf;
for (chn=0;chnattr.name);
if (chn<0) return chn;
pg=get_pgood(dev, chn);
return sprintf(buf,"%s: %s %d mV, %s\n",
voltage_reg[chn].name,
get_enable(dev, chn)?"ON":"OFF",
get_volt_mv(dev, chn),
(pg=1)?"power good":((pg==0)?"power is NOT good":"")
);
}
#endif
static ssize_t output_en_output_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn;
chn=get_voltage_channel(attr->attr.name);
if (chn<0) return chn;
return sprintf(buf,"%d\n", get_enable(dev, chn));
}
static ssize_t output_en_output_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, enable;
chn=get_voltage_channel(attr->attr.name);
if (chn<0) return chn;
sscanf(buf, "%du", &enable);
return count;
}
static ssize_t outputs_pgood_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn;
chn=get_voltage_channel(attr->attr.name);
if (chn<0) return chn;
return sprintf(buf,"%d\n", get_pgood(dev, chn));
}
static ssize_t channels_en_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn_bits;
char * cp=buf;
chn_bits=get_enabled_mask(dev);
if (chn_bits<0) return chn_bits;
buf+=list_chn_bits(buf, chn_bits);
buf+=sprintf(buf,"\n");
return buf-cp;
}
/* also slews DAC(s) if applilcable. Call after changing voltage on enabled channels */
static ssize_t channels_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn_bits,rc,old_dis_por,pre_disabled;
chn_bits=parse_chn_bits(buf);
pre_disabled=get_and_disable_por(dev, chn_bits, &old_dis_por);
if (pre_disabled<0) return pre_disabled;
rc=slew_by_mask(dev, chn_bits); /* slew if needed - before enabling, waits for slew over */
if (rc<0) return rc;
rc=set_enabled_by_mask(dev, chn_bits, 1);
if (rc<0) return rc;
if (pre_disabled && (old_dis_por==0)){
rc=reenable_por(dev); /* will wait pgood */
if (rc<0) return rc;
}
return count;
}
static ssize_t channels_dis_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn_bits;
char * cp=buf;
chn_bits=get_enabled_mask(dev);
if (chn_bits<0) return chn_bits;
chn_bits=~chn_bits;
buf+=list_chn_bits(buf, chn_bits);
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t channels_dis_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn_bits,rc;
chn_bits=parse_chn_bits(buf);
rc=set_enabled_by_mask(dev, chn_bits, 0);
if (rc<0) return rc;
return count;
}
static ssize_t output_ref_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn;
chn=get_voltage_channel(attr->attr.name);
if (chn<0) return chn;
return sprintf(buf,"%d\n",get_volt_mv(dev, chn));
}
static ssize_t output_ref_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn, v_mv;
int rc,old_dis_por,pre_disabled;
chn=get_voltage_channel(attr->attr.name);
if (chn<0) return chn;
/* if output was enabled, and pgood negation may cause POR, disable POR (later restore) */
if (get_enable(dev,chn)) pre_disabled=get_and_disable_por(dev, 1<0) pgood_bits |= (1<pwr_gpio[gpio_disable_por_index].out_val)?0:1);
}
/* When enable_por is set to 1, it first waits for PGOOD and does not enable POR on error */
static ssize_t enable_por_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int en_por,rc;
sscanf(buf, "%du", &en_por);
if (en_por) rc=reenable_por(dev); /* will wait pgood, then enable POR */
else rc=por_ctrl(dev, 1); /* disable POR */
if (rc<0) return rc;
return count;
}
int por_ctrl(struct device *dev, int disable_por)
{
int gpio_disable_por_index=get_gpio_index_by_name("DIS_POR");
if (gpio_disable_por_index<0) return gpio_disable_por_index;
return gpio_conf_by_index(dev, gpio_disable_por_index, 1, disable_por);
}
/*
* disable POR (if needed) before changing value or enabling one of the voltages
* chn_bits - 1 bit per channel
*/
static int get_and_disable_por(struct device *dev, int chn_bits, int * old_dis_por)
{
int rc,chn;
int gpio_disable_por_index;
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
gpio_disable_por_index=get_gpio_index_by_name("DIS_POR");
if (gpio_disable_por_index<0) return gpio_disable_por_index;
old_dis_por[0]=clientdata->pwr_gpio[gpio_disable_por_index].out_val;
for (chn=0;chn=ARRAY_SIZE(voltage_reg)) return 0; /* POR was not required to be disabled */
rc = gpio_conf_by_index(dev, gpio_disable_por_index, 1, 1); /* out turn on "disable_por" */
if (rc<0) return rc;
return 1; /* pgood-based POR was disabled (could already be disabled)*/
}
/* call if POR was diasabled before changing voltage (value or enabling), after waiting for pgood*/
static int reenable_por(struct device *dev)
{
int gpio_disable_por_index, rc;
gpio_disable_por_index=get_gpio_index_by_name("DIS_POR");
if (gpio_disable_por_index<0) return gpio_disable_por_index;
if (((rc=wait_all_pgood(dev)))<0) return rc;
return gpio_conf_by_index(dev, gpio_disable_por_index, 1, 0); /* out turn off "disable_por" */
}
static int wait_all_pgood(struct device *dev)
{
int ntry,chn,all_good=0;
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
for (ntry=0;ntrypgoot_timeout;ntry++){
all_good=1;
for (chn=0;chn0) && (get_pgood(dev,chn)!=1)){ /* enabled or always enabled */
all_good=0;
break;
}
}
if (all_good) break; /* all enabled channels that have pgood control are good */
}
if (!all_good) return -EAGAIN;
return 0;
}
static int list_chn_bits(char * buf, int chn_bits)
{
int chn;
char * cp=buf;
for (chn=0;chn0) en_mask|= (1<0){
awe |= voltage_reg[chn].awe_en;
}
}
awe &= 0xff; /* just WE mask */
if (awe){
dev_dbg(dev,"set_enabled_by_mask(), cumulative awe=0x%x\n",awe);
ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
oven=ltc3589_read_field (ltc3589_client, LTC3589_AWE_OVEN);
if (oven<0) return oven;
if (enable) oven |= awe;
else oven &= ~awe;
return ltc3589_write_field (ltc3589_client, oven, LTC3589_AWE_OVEN);
}
return 0;
}
static int slew_by_mask(struct device *dev, int chn_bits)
{
/* assuming all slew bits in LTC3589 to be in a single register (LTC3589_AWE_OVEN) */
int chn, slew=0,rc,ntry;
u32 adwe;
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
struct i2c_client *ltc3589_client;
ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
dev_dbg(dev,"slew_by_mask(dev,0x%x)\n",chn_bits);
for (chn=0;chn%d (slew = 0x%x)\n",adwe,rc,slew);
if (rc<0) return rc;
/* wait slew over */
for (ntry=0;ntrypgoot_timeout;ntry++){
rc=ltc3589_read_field(ltc3589_client, LTC3589_AWE_VCCR);
dev_dbg(dev,"slew_by_mask():ltc3589_read_field(ltc3589_client, 0x%x)->0x%x(%d)\n",LTC3589_AWE_VCCR,rc,rc);
if (rc<0) return rc;
if ((rc & slew) ==0 ) break;
}
if (ntry>=clientdata->pgoot_timeout) return -EAGAIN;
}
return 0;
}
/* name should either completely match, or have "_*" suffix */
static int get_voltage_channel(const char * name)
{
int i;
for (i=0;i=ARRAY_SIZE(clientdata->pwr_gpio))) return -EINVAL;
if ((clientdata->pwr_gpio[gpio_index].dir==dir) && ((clientdata->pwr_gpio[gpio_index].out_val==val) || (dir==0))){
dev_dbg(dev,"GPIO#%d(index=%d) did not change: old dir=%d, new dir=%d, old val = %d, new val=%d\n",
clientdata->pwr_gpio[gpio_index].pin,
gpio_index,
clientdata->pwr_gpio[gpio_index].dir,
dir,
clientdata->pwr_gpio[gpio_index].out_val,
val);
return 0;
}
clientdata->pwr_gpio[gpio_index].dir=dir?1:0;
clientdata->pwr_gpio[gpio_index].out_val=val?1:0;
if (clientdata->pwr_gpio[gpio_index].dir){
if (!clientdata->simulate) rc=gpio_direction_output(clientdata->pwr_gpio[gpio_index].pin, clientdata->pwr_gpio[gpio_index].out_val);
dev_dbg(dev,"gpio_direction_output(%d,%d)->%d\n",clientdata->pwr_gpio[gpio_index].pin, clientdata->pwr_gpio[gpio_index].out_val,rc);
} else {
if (!clientdata->simulate) rc=gpio_direction_input(clientdata->pwr_gpio[gpio_index].pin);
dev_dbg(dev,"gpio_direction_input(%d)->%d\n",clientdata->pwr_gpio[gpio_index].pin,rc);
}
return rc;
}
static int get_gpio_pwr_mgx_indices(int chn, int * indices) /* chn = 0 (VP10) or 1 (VP18) */
{
indices[0]=get_gpio_index_by_name(chn?"PWR_MG1": "PWR_MG0");
indices[1]=get_gpio_index_by_name(chn?"PWR_MGB1":"PWR_MGB0");
return ((indices[0]>=0) && (indices[1]>=0))?0:-EINVAL;
}
/* calculate output voltage in mV */
static int get_volt_mv(struct device *dev, int chn)
{
int v_mv,ref,rc;
int pwr_mg_indices[2];
s64 num;
struct i2c_client *ltc3589_client;
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
if (voltage_reg[chn].r1<=0) {
if (voltage_reg[chn].awe_ref<0) { /* vp10, vp18*/
rc= get_gpio_pwr_mgx_indices(-1-voltage_reg[chn].awe_ref,pwr_mg_indices); /* chn = 0 (VP10) or 1 (VP18) */
if (rc<0) return rc;
if (clientdata->pwr_gpio[pwr_mg_indices[0]].dir==0) ref=0;
else if (clientdata->pwr_gpio[pwr_mg_indices[0]].out_val) ref=1;
else ref=-1;
if (ref) {
if (clientdata->pwr_gpio[pwr_mg_indices[1]].dir==0) ref*=15;
else if (clientdata->pwr_gpio[pwr_mg_indices[1]].out_val) ref*=10;
else ref*= 5;
}
v_mv=(voltage_reg[chn].r2*(100+ref)*2+10)/2000;
} else { /* vp33sens01, vp33sens23, mmtavcc10, mmtavtt12 */
v_mv=(voltage_reg[chn].r2+5)/10;
}
} else if (voltage_reg[chn].awe_ref==0){ /* VP5, vldo18 */
#if 0
v_mv=(REF_FIXED_TENTH_MV*(voltage_reg[chn].r1+voltage_reg[chn].r2)+ 5*voltage_reg[chn].r2)/(10*voltage_reg[chn].r2);
#endif
num=((u64) REF_FIXED_TENTH_MV)* (voltage_reg[chn].r1+voltage_reg[chn].r2)+ 5*voltage_reg[chn].r2;
v_mv=(int) div64_u64(num, 10*voltage_reg[chn].r2);
dev_dbg(dev,"chn=%d REF_FIXED_TENTH_MV=%d .r1=%d .r2=%d v_mv=%d\n",chn, REF_FIXED_TENTH_MV,voltage_reg[chn].r1,voltage_reg[chn].r2,v_mv);
} else { /* vp15, vcc_sens01,vcc_sens23 */
ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
ref=ltc3589_read_field(ltc3589_client, voltage_reg[chn].awe_ref);
if (ref<0) return ref;
num=(REF_VAR_0_TENTH_MV+ REF_VAR_STEP_TENTH_MV* ref);
num=num*(voltage_reg[chn].r1+voltage_reg[chn].r2)+ 5*voltage_reg[chn].r2;
v_mv=div64_u64(num, 10*voltage_reg[chn].r2);
dev_dbg(dev,"chn=%d ref=%d .r1=%d .r2=%d v_mv=%d\n",chn, ref,voltage_reg[chn].r1,voltage_reg[chn].r2,v_mv);
}
return v_mv;
}
/* 0 - OK, <0 - error */
/* does not iclude disabling/re-enabling PoR */
static int set_volt_mv(struct device *dev, int chn, int v_mv)
{
int rc,index,d;
s64 num;
int pwr_mg_indices[2];
struct i2c_client *ltc3589_client;
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
dev_dbg(dev,"set_volt_mv(dev,%d,%d),.r1=%d\n",chn,v_mv,voltage_reg[chn].r1);
if (voltage_reg[chn].r1<=0) {
if (voltage_reg[chn].awe_ref<0) { /* vp10, vp18*/
index=(400*v_mv+voltage_reg[chn].r2)/(2*voltage_reg[chn].r2);
dev_dbg(dev,"chn=%d v_mv=%d index=%d .r1=%d .r2=%d\n",chn, v_mv, index,voltage_reg[chn].r1,voltage_reg[chn].r2);
if ((index<17) || (index>23)) {
dev_err(dev,"specified voltage for %s is not in the range %dmV to %d mV\n", voltage_reg[chn].name,
(17*voltage_reg[chn].r2)/200,(23*voltage_reg[chn].r2)/200);
return -EINVAL;
}
/* disable -> chnage -> enable (if needed) */
rc= get_gpio_pwr_mgx_indices(-1-voltage_reg[chn].awe_ref,pwr_mg_indices); /* chn = 0 (VP10) or 1 (VP18) */
if (rc<0) return rc;
rc = gpio_conf_by_index(dev,pwr_mg_indices[0], 0, 0); /* disable margining */
if (rc < 0)return rc;
if (index !=20){
/* set margining absolute value */
switch (index) {
case 17:
case 23:
rc = gpio_conf_by_index(dev,pwr_mg_indices[1], 0, 0); /* float: +/- 15% */
break;
case 18:
case 22:
rc = gpio_conf_by_index(dev,pwr_mg_indices[1], 1, 1); /* out 1: +/- 10% */
break;
case 19:
case 21:
rc = gpio_conf_by_index(dev,pwr_mg_indices[1], 1, 0); /* out 0: +/- 5% */
break;
}
if (rc < 0)return rc;
/* set margining sign */
if (index >20) rc = gpio_conf_by_index(dev,pwr_mg_indices[0], 1, 1); /* out 1: positive margining */
else rc = gpio_conf_by_index(dev,pwr_mg_indices[0], 1, 0); /* out 0: negative margining */
if (rc < 0)return rc;
}
} else { /* vp33sens01, vp33sens23, mmtavcc10, mmtavtt12 */
return -EINVAL; /* voltage not regulated */
}
} else if (voltage_reg[chn].awe_ref==0){ /* VP5, vldo18 */
return -EINVAL; /* voltage not regulated */
} else { /* vp15, vcc_sens01,vcc_sens23 */
ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
#if 0
index=((10*v_mv*voltage_reg[chn].r2) -(REF_VAR_0_TENTH_MV-REF_VAR_STEP_TENTH_MV/2)*(voltage_reg[chn].r1+voltage_reg[chn].r2))/
((voltage_reg[chn].r1+voltage_reg[chn].r2)*REF_VAR_STEP_TENTH_MV);
num=(10*v_mv*voltage_reg[chn].r2) -(REF_VAR_0_TENTH_MV-REF_VAR_STEP_TENTH_MV/2);
num*=(voltage_reg[chn].r1+voltage_reg[chn].r2);
index=div64_u64(num, (voltage_reg[chn].r1+voltage_reg[chn].r2)*REF_VAR_STEP_TENTH_MV);
#endif
num= (10LL*v_mv*voltage_reg[chn].r2) - ((s64) (voltage_reg[chn].r1+voltage_reg[chn].r2))*REF_VAR_0_TENTH_MV;
d= REF_VAR_STEP_TENTH_MV*(voltage_reg[chn].r1+voltage_reg[chn].r2);
index=div64_u64(num +(d>>1), d);
dev_dbg(dev,"chn=%d v_mv=%d index=%d .r1=%d .r2=%d\n",chn, v_mv, index,voltage_reg[chn].r1,voltage_reg[chn].r2);
dev_dbg(dev,"index=%d\n",index);
if ((index<0) || (index>31)){
dev_err(dev,"chn=%d v_mv=%d index=%d .r1=%d .r2=%d\n",chn, v_mv, index,voltage_reg[chn].r1,voltage_reg[chn].r2);
dev_err(dev,"REF_VAR_0_TENTH_MV=%d REF_VAR_STEP_TENTH_MV=%d\n",REF_VAR_0_TENTH_MV,REF_VAR_STEP_TENTH_MV);
dev_err(dev,"specified voltage for %s is not in the range %dmV to %d mV\n", voltage_reg[chn].name,
(int) div64_u64((((u64)(REF_VAR_0_TENTH_MV+REF_VAR_STEP_TENTH_MV* 0))*(voltage_reg[chn].r1+voltage_reg[chn].r2)+5*voltage_reg[chn].r2),
10*voltage_reg[chn].r2),
(int) div64_u64((((u64)(REF_VAR_0_TENTH_MV+REF_VAR_STEP_TENTH_MV*31))*(voltage_reg[chn].r1+voltage_reg[chn].r2)+5*voltage_reg[chn].r2),
10*voltage_reg[chn].r2));
return -EINVAL;
}
dev_dbg(dev,"ltc3589_client->name= %s\n", ltc3589_client->name);
rc=ltc3589_write_field(ltc3589_client, index,voltage_reg[chn].awe_ref);
if (rc<0) return rc;
}
return 0;
}
/* get output enable state */
static int get_enable(struct device *dev, int chn)
{
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
if (voltage_reg[chn].awe_en==0) {
return 2; /* always on */
} else if (voltage_reg[chn].awe_en>0){
if (clientdata->pinstrapped_oven & voltage_reg[chn].awe_en) return 1; /* pin-strapped on bit */
return ltc3589_read_field(ltc3589_client, voltage_reg[chn].awe_en);
} else {
return (clientdata->pwr_gpio[-1-voltage_reg[chn].awe_en].dir && clientdata->pwr_gpio[-1-voltage_reg[chn].awe_en].out_val)?1:0;
}
}
/* set output enable state */
static int set_enable(struct device *dev, int chn, int enable)
{
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
if (voltage_reg[chn].awe_en==0) {
return -EINVAL; /* always on, not controlled */
} else if (voltage_reg[chn].awe_en>0){
return ltc3589_write_field(ltc3589_client, enable, voltage_reg[chn].awe_en);
} else {
return gpio_conf_by_index(dev,-1-voltage_reg[chn].awe_en, 1, enable);
}
}
/* get power good state */
static int get_pgood(struct device *dev, int chn)
{
int rc;
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
if (voltage_reg[chn].awe_pgood==0) {
if (((rc=get_enable(dev,chn)))<0) return rc; /* 0 - disabled */
return 2; /* no status available */
} else if (voltage_reg[chn].awe_pgood>0){
return ltc3589_read_field(ltc3589_client, voltage_reg[chn].awe_pgood);
} else {
/* return gpio_get_value(clientdata->pwr_gpio[-1-voltage_reg[chn].awe_pgood].pin); */
return gpio_get_value_cansleep(clientdata->pwr_gpio[-1-voltage_reg[chn].awe_pgood].pin);
}
}
static int elphel393_pwr_sysfs_register(struct platform_device *pdev)
{
int retval=0;
struct device *dev = &pdev->dev;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval;
if (((retval = make_group (dev, "voltages_mv", output_ref_show, output_ref_store)))<0) return retval;
if (((retval = make_group (dev, "outputs_en", output_en_output_show, output_en_output_store)))<0) return retval;
if (((retval = make_group (dev, "outputs_pgood", outputs_pgood_show, NULL)))<0) return retval;
}
return retval;
}
static void elphel393_pwr_init_of_i2caddr(struct platform_device *pdev)
{
const __be32 * config_data;
int len,i;
struct device_node *node = pdev->dev.of_node;
struct elphel393_pwr_data_t *clientdata = platform_get_drvdata(pdev);
if (node) {
config_data = of_get_property(node, "elphel393_pwr,i2c_chips", &len);
if (config_data){
len /= sizeof(*config_data);
dev_dbg(&pdev->dev,"Found %d items in 'elphel393_pwr,i2c_chips' in the Device Tree\n",len);
if (len!= ARRAY_SIZE(clientdata->chip_i2c_addr)){
dev_err(&pdev->dev,"Got %d items in 'elphel393_pwr,i2c_chips', expected %d\n",len,ARRAY_SIZE(clientdata->chip_i2c_addr));
return;
}
for (i=0;ichip_i2c_addr[i]=be32_to_cpup(&config_data[i]);
}
}
}
static void elphel393_pwr_init_of(struct platform_device *pdev)
{
const __be32 * config_data;
const char * config_string;
char str[40];
int len,chn,pre_disabled,old_dis_por,rc,chn_bits;
struct device_node *node = pdev->dev.of_node;
struct elphel393_pwr_data_t *clientdata = platform_get_drvdata(pdev);
struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
if (node) {
/* find resistor values */
for (chn=0;chn0)){
dev_dbg(&pdev->dev,"Found %s=<%d>\n",str,be32_to_cpup(&config_data[0]));
voltage_reg[chn].r1=be32_to_cpup(&config_data[0]);
}
sprintf(str,"elphel393_pwr,%s.r2",voltage_reg[chn].name);
config_data = of_get_property(node, str, &len);
if (config_data && (len>0)){
dev_dbg(&pdev->dev,"Found %s=<%d>\n",str,be32_to_cpup(&config_data[0]));
voltage_reg[chn].r2=be32_to_cpup(&config_data[0]);
}
}
/* which channels are enabled by pin-strapping */
config_data = of_get_property(node, "elphel393_pwr,pinstrapped_oven", &len);
if (config_data && (len>0)){
dev_dbg(&pdev->dev,"Found elphel393_pwr,pinstrapped_oven=<%d>\n",be32_to_cpup(&config_data[0]));
clientdata->pinstrapped_oven=be32_to_cpup(&config_data[0]);
}
/* debug mode - simulate only, no actual power supply control */
config_data = of_get_property(node, "elphel393_pwr,simulate", &len);
if (config_data && (len>0)){
dev_dbg(&pdev->dev,"Found elphel393_pwr,simulate=<%d>\n",be32_to_cpup(&config_data[0]));
clientdata->simulate=config_data[0]?1:0;
ltc3589_set_simulate(ltc3589_client, clientdata->simulate);
}
/* disable output voltages (not likely to be needed - maybe for warm reboot) */
config_string = of_get_property(node, "elphel393_pwr,channels_disable", &len);
if (config_string){
dev_dbg(&pdev->dev,"Found elphel393_pwr,channels_disable=\"%s\"\n",config_string);
chn_bits=parse_chn_bits(config_string);
rc=set_enabled_by_mask(&pdev->dev, chn_bits, 0);
if (rc<0) return;
}
/* set output voltages (target voltages, in mV) */
for (chn=0;chn0)){
dev_dbg(&pdev->dev,"Found %s=<%d>\n",str,be32_to_cpup(&config_data[0]));
if (get_enable(&pdev->dev,chn)) pre_disabled=get_and_disable_por(&pdev->dev, 1<dev,"pre_disabled=%d\n",pre_disabled);
rc=set_volt_mv(&pdev->dev, chn,be32_to_cpup(&config_data[0]));
dev_dbg(&pdev->dev,"set_volt_mv()->%d\n",rc);
if (rc<0) return;
if (pre_disabled && (old_dis_por==0)){
rc=reenable_por(&pdev->dev); /* will wait pgood */
if (rc<0){
dev_err(&pdev->dev,"Timeout during wait for power good after chnging voltage for %s before re-enabling POR on power loss\n",\
voltage_reg[chn].name);
return;
}
}
}
}
/* enable output voltages */
config_string = of_get_property(node, "elphel393_pwr,channels_enable", &len);
if (config_string){
dev_dbg(&pdev->dev,"Found elphel393_pwr,channels_enable=\"%s\"\n",config_string);
chn_bits=parse_chn_bits(config_string);
pre_disabled=get_and_disable_por(&pdev->dev, chn_bits, &old_dis_por);
if (pre_disabled<0) return;
rc=slew_by_mask(&pdev->dev, chn_bits); /* slew if needed - before enabling, waits for slew over */
if (rc<0) {
dev_err(&pdev->dev,"Timeout during wait for slew over\n");
return;
}
rc=set_enabled_by_mask(&pdev->dev, chn_bits, 1);
if (rc<0) return;
if (pre_disabled && (old_dis_por==0)){
rc=reenable_por(&pdev->dev); /* will wait pgood */
if (rc<0) {
dev_err(&pdev->dev,"Timeout during wait for power good before re-enabling POR on power loss\n");
return;
}
}
}
}
dev_info(&pdev->dev,"elphel393_pwr configuration done\n");
}
static int device_by_i2c_addr_match(struct device *dev, void *data)
{
struct i2c_client *client = to_i2c_client(dev);
int *addr = (int *)data;
dev_dbg(dev,"addr_given=0x%02x, addr found=0x%02x\n",addr[0],(int) client->addr);
return i2c_verify_client(dev) && (client->addr==addr[0]);
}
static struct device * find_device_by_i2c_addr(int address)
{
return bus_find_device(&i2c_bus_type, NULL, &address, device_by_i2c_addr_match);
}
static int i2c_addr_gpiochip_match(struct gpio_chip *chip, void *data)
{
struct i2c_client *client = to_i2c_client(chip->dev);
int *addr = (int *)data;
dev_dbg(chip->dev,"addr_given=0x%02x, addr found=0x%02x\n",addr[0],(int) client->addr);
return i2c_verify_client(chip->dev) && (client->addr==addr[0]);
}
static int elphel393_pwr_probe(struct platform_device *pdev)
{
struct gpio_chip *chip;
// struct device * ltc3489_dev;
int i,rc;
int base[2];
struct i2c_client *ltc3589_client;
struct elphel393_pwr_data_t *clientdata = NULL;
dev_info(&pdev->dev,"Probing elphel393-pwr\n");
clientdata = devm_kzalloc(&pdev->dev, sizeof(*clientdata), GFP_KERNEL);
clientdata->pgoot_timeout=DEAFULT_TIMEOUT;
clientdata->pinstrapped_oven=PINSTRAPPED_OVEN;
clientdata->chip_i2c_addr[0]=0x20;
clientdata->chip_i2c_addr[1]=0x21;
clientdata->chip_i2c_addr[2]=0x34;
platform_set_drvdata(pdev, clientdata);
elphel393_pwr_sysfs_register(pdev);
// elphel393_pwr_init_of(pdev);
elphel393_pwr_init_of_i2caddr(pdev);
mutex_init(&clientdata->lock);
/* locate GPIO chips by i2c address */
for (i=0;i<2;i++){
chip = gpiochip_find(&clientdata->chip_i2c_addr[i], i2c_addr_gpiochip_match);
base[i]=chip->base;
dev_dbg(&pdev->dev,"Found gpio_chip with i2c_addr=0x%02x, label=%s, base=0x%x\n",clientdata->chip_i2c_addr[i],chip->label,base[i]);
}
for (i=0;ipwr_gpio[i].label=pwr_gpio[i].label;
clientdata->pwr_gpio[i].pin=base[i>>3]+(i & 7);
clientdata->pwr_gpio[i].dir=0; /* input */
clientdata->pwr_gpio[i].out_val=0;
rc=gpio_request(clientdata->pwr_gpio[i].pin, clientdata->pwr_gpio[i].label);
if (rc<0){
dev_err(&pdev->dev," Failed to get GPIO[%d] with label %s\n",clientdata->pwr_gpio[i].pin,clientdata->pwr_gpio[i].label);
return rc;
} else {
dev_dbg(&pdev->dev,"Confirmed request GPIO[%d] with label %s\n",clientdata->pwr_gpio[i].pin,clientdata->pwr_gpio[i].label);
}
}
/* find ltc3589 */
clientdata->ltc3489_dev=find_device_by_i2c_addr(LTC3589_ADDR);
if (!clientdata->ltc3489_dev){
dev_err(&pdev->dev," Failed to find LTC3489 with i2c address 0x%02x\n",LTC3589_ADDR);
return -EIO;
}
ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
dev_dbg(&pdev->dev,"Located %s with i2c address 0x%02x\n",ltc3589_client->name,LTC3589_ADDR);
dev_dbg(&pdev->dev,"LTC3589 status= 0x%02x\n",ltc3589_read_field(ltc3589_client, LTC3589_AWE_PGSTAT));
elphel393_pwr_init_of(pdev);
return 0;
}
static int elphel393_pwr_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev,"Removing elphel393-pwr");
return 0;
}
static struct of_device_id elphel393_pwr_of_match[] = {
{ .compatible = "elphel,elphel393-pwr-1.00", },
{ /* end of table */}
};
MODULE_DEVICE_TABLE(of, elphel393_pwr_of_match);
static struct platform_driver elphel393_pwr = {
.probe = elphel393_pwr_probe,
.remove = elphel393_pwr_remove,
.driver = {
.name = "elphel393-pwr",
.owner = THIS_MODULE,
.of_match_table = elphel393_pwr_of_match,
.pm = NULL, /* power management */
},
};
module_platform_driver(elphel393_pwr);
MODULE_AUTHOR("Andrey Filippov ");
MODULE_DESCRIPTION("Elphel 10393 power supply control");
MODULE_LICENSE("GPL");
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/fpgajtag353.c 0000664 0000000 0000000 00000160203 12703306510 0027250 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : fpgajtag353.c
*! DESCRIPTION: TBD
*! Copyright 2002-2007 (C) Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! 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 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*! -----------------------------------------------------------------------------**
*! $Log: fpgajtag353.c,v $
*! Revision 1.2 2011/05/20 21:36:52 elphel
*! typo fix
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.4 2008/09/22 22:55:48 elphel
*! snapshot
*!
*! Revision 1.3 2008/09/20 00:29:50 elphel
*! moved driver major/minor numbers to a single file - include/asm-cris/elphel/driver_numbers.h
*!
*! Revision 1.2 2008/09/16 00:49:31 elphel
*! snapshot
*!
*! Revision 1.2 2008/04/11 23:16:51 elphel
*! removed unneeded local_irq_disable() after local_irq_save_flags()
*!
*! Revision 1.1.1.1 2007/08/17 10:23:18 elphel
*! This is a fresh tree based on elphel353-2.10
*!
*! Revision 1.7 2007/08/17 10:23:18 spectr_rain
*! switch to GPL3 license
*!
*! Revision 1.6 2007/07/20 10:17:46 spectr_rain
*! *** empty log message ***
*!
*! Revision 1.5 2007/06/28 02:20:39 elphel
*! Slowed down sensor FPGA programming while working with long cables. Problem was different, so maybe that change may be undone.
*!
*! Revision 1.4 2007/05/21 21:23:50 elphel
*! remove compile-time warning
*!
*! Revision 1.3 2007/05/21 17:45:11 elphel
*! boundary scan support, added 359/347 detection
*!
*! Revision 1.2 2007/03/25 10:14:23 elphel
*! Accommodating 10359 board
*!
*! Revision 1.1.1.1 2007/02/23 10:11:48 elphel
*! initial import into CVS
*!
*! Revision 1.2 2005/05/10 21:08:49 elphel
*! *** empty log message ***
*!
TODO: replace static buffer (what a waste!)
I suspect "somebody" is is playing with portA during JTAG configuration.
To test that I'll use 256K static buffer, copy all the bitstream there,
disable interrupts and do the programming.
No debug with printk ...
*/
#undef DEBUG
/****************** INCLUDE FILES SECTION ***********************************/
#include
#include
#include
#include // needed?
#include
#include
#include
#include
//#include
#include
#include
#include
//#include
//#include
#include
//#include
#include
#include
//#include //defines for fpga_state fields
//#include
#include
//#include "fpgactrl.h" // extern fpga_state, defines port_csp0_addr, port_csp4_addr
//#include "x3x3.h" // FPGA registers and macros
#include "x393.h"
//#include
//#define JTAG_DISABLE_IRQ y
//#define D(x)
#define D(x) printk("%s:%d:",__FILE__,__LINE__);x
/*
port C 353:
0 - TDO (in)
1 - TDI (out)
2 - TMS (out)
3 - TCK (out)
4 - NC (was INIT (i/o) )
5 - DONE (in)
6 - RSTBTN
7 - PGM (out)
*/
#define FPGAJTAG_TDO_BIT 0
#define FPGAJTAG_TDI_BIT 1
#define FPGAJTAG_TMS_BIT 2
#define FPGAJTAG_TCK_BIT 3
#define FPGAJTAG_DONE_BIT 5
#define FPGAJTAG_RSTBTN_BIT 6
#define FPGAJTAG_PGM_BIT 7
#ifndef XC2S300E_BITSIZE
#define XC3S1000_BITSIZE 3223488
#define XC3S1200E_BITSIZE 3841189
#define XC3S1200E_BOUNDARY_SIZE 772
// #define XC3S1200E_BOUNDARY_SIZE 812
#define FJTAG_BUF_SIZE 0x77000
#define FJTAG_MAX_HEAD 0x1000
#define FJTAG_RAW_WSIZE 0x40000 // shared with bitstream buffer
#define FJTAG_RAW_RSIZE 0x30000 // shared with bitstream buffer
#define FJTAG_IDSIZE 0x40 // bits - ID and User
#endif
//#define FPGA_JTAG_DRIVER_NAME "Elphel (R) model 353 FPGA (Xilinx (R) XC3S1200E) configuration driver"
#define FPGA_JTAG_DRIVER_NAME "Elphel (R) model 393 FPGA (Xilinx (R) XC3S1200E) configuration driver"
#define FPGA_JTAG_MAXMINOR 16 // 10
#define JTAG_RAW 0 // raw JTAG access to any FPGA
#define JTAG_MAIN_FPGA 1 // main board FPGA access (10353)
#define JTAG_SENSOR_FPGA 2 // sensor board FPGA access (10347, 10359)
#define JTAG_AUX_FPGA 3 //
//#define JTAG_NCHANNELS 4
#define JTAG_NCHANNELS 16 // 4 << 2
#define JTAG_SENSOR_OFFSET 4 // Sensor ports minors start (4..7) - (2 LSB should be 0)
#define JTAG_SENSOR_CHANNELS 4 // Number of sensor ports for JTAG
#define JTAG_MODE_CLOSED 0 // JTAG channel is closed
#define JTAG_MODE_RDID 1 // JTAG channel read ID
#define JTAG_MODE_PGM 2 // JTAG channel PROGRAM
#define JTAG_MODE_BOUNDARY 3 // JTAG channel boundary scan (just opened, will become one of the 2:JTAG_MODE_SAMPLE, JTAG_MODE_EXTEST
#define JTAG_MODE_SAMPLE 4 // JTAG channel boundary scan - sample (the first operation after open is read)
#define JTAG_MODE_EXTEST 5 // JTAG channel boundary scan - EXTEST (the first operation after open is read)
#define JTAG_MODE_RAW 6 // JTAG raw command mode
// configuration and raw minors use whole buffer, ID and boundary can be opened at the same time
struct JTAG_channel_t {
int mode; // 0..5 -JTAG_MODE_CLOSED...JTAG_MODE_EXTEST
unsigned char * dbuf; // data buffer (shared, boundary mode use different parts)
int sizew; // byte size that can be written
int sizer; // byte size that can be read
int bitsw; // bit size to be written
int bitsr; // bit size to be read
int wp; // byte pointer for file write
int rp; // byte pointer for file read
int wdirty; // some data is buffered but not yet sent out in EXTEST mode
};
static unsigned char bitstream_data[FJTAG_BUF_SIZE]; // will fit bitstream and the header (if any). Also used for boundary write
//static unsigned short *raw_fifo_w= (unsigned short) &bitstream_data[0];
static unsigned char *raw_fifo_w= &bitstream_data[0];
static unsigned char *raw_fifo_r= &bitstream_data[FJTAG_RAW_WSIZE];
static struct JTAG_channel_t JTAG_channels[JTAG_NCHANNELS];
// boundary scan is read always at open. written - at close (only if there were any writes)
static int data_modified=0;
//static reg_gio_rw_pc_dout pc_dout;
#define PC_DOUT_INITIAL 0
//static int buf8i=0; // current buffer length (in bytes!)
//static int datastart=0;
//static int prev32;
//static int prev64;
//static int fpga_jtag_state=0;
// inteface functions
static const char fpga_jtag_name[] = "fpga_jtag_loader";
static int minors[FPGA_JTAG_MAXMINOR+1]; // each minor can be opened only once
//static int thisminor;
static int fpga_jtag_open (struct inode *inode, struct file *filp);
static int fpga_jtag_release(struct inode *inode, struct file *filp);
static ssize_t fpga_jtag_write (struct file * file, const char * buf, size_t count, loff_t *off);
static loff_t fpga_jtag_lseek (struct file * file, loff_t offset, int orig);
static ssize_t fpga_jtag_read (struct file * file, char * buf, size_t count, loff_t *off);
static int __init fpga_jtag_init(void);
static struct file_operations fpga_jtag_fops = {
owner: THIS_MODULE,
open: fpga_jtag_open,
release: fpga_jtag_release,
llseek: fpga_jtag_lseek,
read: fpga_jtag_read,
write: fpga_jtag_write
};
//static int sens_num = 0;
// internal functions
//loff_t fjtag_bitsize (int minor);
//loff_t fjtag_bytesize (int minor);
int JTAG_channel(int minor);
void initPortC(void);
void set_pgm_mode (int chn, int en);
void set_pgm (int chn, int pgmon);
int read_done (int chn);
int jtag_send (int chn, int tms, int len, int d);
int jtag_write_bits (int chn,
unsigned char *buf, // data to write
int len, // number of bytes to write
int check, // compare readback data with previously written, abort on mismatch
int last, // output last bit with TMS=1
int prev[2]); // if null - don't use
int JTAG_configure (int chn, unsigned char * buf, int len);
int JTAG_readID (int chn, unsigned char * buf);
int JTAG_openChannel (int chn);
int JTAG_resetChannel (int chn);
int JTAG_CAPTURE (int chn, unsigned char * buf, int len);
int JTAG_EXTEST (int chn, unsigned char * buf, int len);
void JTAG_push_raw (int b);
int JTAG_process_raw(void);
int JTAG_channel(int minor) {
if ((minor >= FPGA_SJTAG_MINOR_OFFSET) && (minor < (FPGA_SJTAG_MINOR_OFFSET + FPGA_SJTAG_CHANNELS)))
return (minor - FPGA_SJTAG_MINOR_OFFSET) + (JTAG_SENSOR_FPGA << 2);
if ((minor >= FPGA_SJTAG_BOUNDARY_OFFSET) && (minor < (FPGA_SJTAG_BOUNDARY_OFFSET + FPGA_SJTAG_CHANNELS)))
return (minor - FPGA_SJTAG_BOUNDARY_OFFSET) + (JTAG_SENSOR_FPGA << 2);
// maybe will never be used
switch (minor) {
case FPGA_JTAG_RESET_MINOR : // same as RAW
return JTAG_RAW << 2;
case FPGA_JTAG_MINOR:
case FPGA_JTAG_BOUNDARY_MINOR:
return JTAG_MAIN_FPGA << 2;
case FPGA_SJTAG_MINOR:
case FPGA_SJTAG_BOUNDARY_MINOR:
return JTAG_SENSOR_FPGA << 2;
case FPGA_AJTAG_MINOR:
case FPGA_AJTAG_BOUNDARY_MINOR:
return JTAG_AUX_FPGA << 2;
}
return 0;
}
static int raw_fifo_w_wp;
static int raw_fifo_w_rp;
static int raw_fifo_r_wp;
static int raw_fifo_r_rp;
static int raw_chn;
/*
* send raw JTAG commands. Each command consists of 2 bytes
* byte 0 - data to send through TDI, lsb aligned (if less than 8 bits - hign bits are not used
* byte 1 - 0001TNNN - send NNN?NNN:8 bits of byte 0 through TDI, keeping TDS at value of T (reads back TDO - before TCL)
* - 00100000 - select JTAG channel from byte 0 (reads back channel)
* - 00100010 - de-activate JTAG access (reads back 0)
* - 00100011 - activate JTAG access (reads back 0)
* - 00100100 - PGM off (reads back ready in bit 0)
* - 00100101 - PGM on (reads back 0xf0)
* - 1TTTTTTT - delay usec byte0+ ((byte1 &0x7f) << 8) (reads back 80)
* - 0??????? (other) - nop (reads back 0xff)
* if no channel is selected, no output is generated
void set_pgm_mode (int chn, int en);
void set_pgm (int chn, int pgmon);
*/
#define JTAG_RAW_SEND 0x10
#define JTAG_RAW_SETCHN 0x20
#define JTAG_RAW_DEACT 0x22
#define JTAG_RAW_ACT 0x23
#define JTAG_RAW_PGMOFF 0x24
#define JTAG_RAW_PGMON 0x25
#define JTAG_RAW_WAIT 0x80
void JTAG_push_raw (int b) {
raw_fifo_r[raw_fifo_r_wp++]=b;
if (raw_fifo_r_wp > FJTAG_RAW_RSIZE) raw_fifo_r_wp-=FJTAG_RAW_RSIZE;
}
// TODO: Not updated for 393. Is it needed?
int JTAG_process_raw(void) {
unsigned char b0, b1;
while (raw_fifo_w_rp != (raw_fifo_w_wp & ~1)) {
b0=raw_fifo_w[raw_fifo_w_rp++];
b1=raw_fifo_w[raw_fifo_w_rp++];
if (raw_fifo_w_rp > FJTAG_RAW_WSIZE) raw_fifo_w_rp-=FJTAG_RAW_WSIZE;
if (b1 == JTAG_RAW_SETCHN) { // set channel number
raw_chn = b0;
if (raw_chn>=JTAG_NCHANNELS) raw_chn=0; //illegal channel
JTAG_push_raw (raw_chn);
} else if (raw_chn) { // ignore commands until the JTAG channel number is specified
if ((b1 & 0xf0) == JTAG_RAW_SEND) { // send JTAG data
JTAG_push_raw (jtag_send(raw_chn, (b1 >> 3) & 1, b1 & 7, (int) b0 ));
} else if ((b1 & 0x80) == JTAG_RAW_WAIT) { // delay
/* possible bug here, udelay is used for delays less then 2 ms */
udelay(((b1 & 0x7f) <<8) + b0);
JTAG_push_raw (0x80);
} else switch (b1) {
case JTAG_RAW_DEACT:
set_pgm_mode (raw_chn, 0);
JTAG_push_raw (0x0);
break;
case JTAG_RAW_ACT:
set_pgm_mode (raw_chn, 1);
JTAG_push_raw (0x0);
break;
case JTAG_RAW_PGMOFF:
set_pgm (raw_chn, 0);
JTAG_push_raw (read_done(raw_chn));
break; // was missing for 353
case JTAG_RAW_PGMON:
set_pgm (raw_chn, 1);
JTAG_push_raw (0xf0);
break;
default:
JTAG_push_raw (0xff);
}
} else { // make output always be 1 byte for 2 bytes input
JTAG_push_raw (0xf0);
} // end of if (raw_chn) /else
} // while (raw_fifo_w_rp != (raw_fifo_w_wp & ~1))
return 0; // will think of return value later
}
//returns 0 if all channels closed
//
int JTAG_whatopen(void) {
int i,r=0;
for (i=0;ii_rdev);
int chn= JTAG_channel(p);
//reg_intr_vect_rw_mask intr_mask;
//D(printk("fpga_jtag_open: minor=%x, channel=%x, buf=%p\r\n",p,chn,bitstream_data ));
dev_dbg(NULL, "fpga_jtag_open: minor=%x, channel=%x, buf=%p\r\n",p ,chn, bitstream_data);
switch ( p ) {
case FPGA_JTAG_RESET_MINOR : // same as RAW
for (i=1; i> 3;
// JTAG_channels[chn].wp = 0;
// JTAG_channels[chn].rp = 0; // will read IDs if actually read
#ifdef TEST_DISABLE_CODE
fpga_state &= ~FPGA_STATE_LOADED; // is it still used?
fpga_state &= ~FPGA_STATE_SDRAM_INIT; // not needed
// disable camera interrupts here (while reprogramming FPGA could generate stray interrupts;
/* Disable external interrupts.. */
intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
intr_mask.ext = 0;
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
#endif /* TEST_DISABLE_CODE */
// printk ("Camera interrupts disabled\r\n");
// break;
// fall through
case (FPGA_SJTAG_MINOR_OFFSET + 0): // ugly, fix
case (FPGA_SJTAG_MINOR_OFFSET + 1):
case (FPGA_SJTAG_MINOR_OFFSET + 2):
case (FPGA_SJTAG_MINOR_OFFSET + 3):
case FPGA_SJTAG_MINOR :
case FPGA_AJTAG_MINOR :
if ( JTAG_whatopen() & 0x7e) return -EACCES; // none of the channels could be open when opening this file
JTAG_channels[chn].mode = JTAG_MODE_PGM;
JTAG_channels[chn].dbuf = &bitstream_data[0];
JTAG_channels[chn].sizew = FJTAG_BUF_SIZE;
JTAG_channels[chn].sizer = FJTAG_IDSIZE >> 3;
JTAG_channels[chn].wp = 0;
JTAG_channels[chn].rp = 0; // will read IDs if actually read
JTAG_channels[chn].bitsw = XC3S1200E_BITSIZE; // bit size to be written
JTAG_channels[chn].bitsr= FJTAG_IDSIZE;
JTAG_openChannel (chn); // configure channel access, reset JTAG and to RUN-TEST/IDLE state
break;
case (FPGA_SJTAG_BOUNDARY_OFFSET + 0):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 1):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 2):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 3):
case FPGA_JTAG_BOUNDARY_MINOR :
case FPGA_SJTAG_BOUNDARY_MINOR :
case FPGA_AJTAG_BOUNDARY_MINOR :
if ( JTAG_whatopen() & 0x46) return -EACCES; // none of the channels could be open for program/id/raw when opening this file
if ( JTAG_channels[chn].mode != JTAG_MODE_CLOSED) return -EACCES; // already open
JTAG_channels[chn].mode = JTAG_MODE_BOUNDARY;
JTAG_channels[chn].sizew = (XC3S1200E_BOUNDARY_SIZE+7) >> 3;
JTAG_channels[chn].sizer = (XC3S1200E_BOUNDARY_SIZE+7) >> 3;
JTAG_channels[chn].dbuf = &bitstream_data[JTAG_channels[chn].sizew * chn];
JTAG_channels[chn].wp = 0;
JTAG_channels[chn].rp = 0; // will read IDs if actually read
JTAG_channels[chn].bitsw = XC3S1200E_BOUNDARY_SIZE; // bit size to be written
JTAG_channels[chn].bitsr= XC3S1200E_BOUNDARY_SIZE;
JTAG_openChannel (chn); // configure channel access, reset JTAG and to RUN-TEST/IDLE state
break;
default: return -EINVAL;
}
dev_dbg(NULL, "fpga_jtag_open: chn=%x, JTAG_channels[chn].sizew=%x, JTAG_channels[chn].sizer=%x\r\n", chn, JTAG_channels[chn].sizew, JTAG_channels[chn].sizer);
dev_dbg(NULL, "fpga_jtag_open: chn=%x, JTAG_channels[chn].bitsw=%x, JTAG_channels[chn].bitsr=%x\r\n", chn, JTAG_channels[chn].bitsw, JTAG_channels[chn].bitsr);
JTAG_channels[chn].wdirty=0;
inode->i_size=JTAG_channels[chn].sizer;
minors[p]=p;
filp->private_data = &minors[p];
dev_dbg(NULL, "fpga_jtag_open: inode->i_size=%x, chn=%x\r\n", (int) inode->i_size, chn);
return 0;
}
//++++++++++++++++++++++++++++++++++++ release() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
static int fpga_jtag_release(struct inode *inode, struct file *filp) {
int res=0;
int p = MINOR(inode->i_rdev);
int chn= JTAG_channel(p);
dev_dbg(NULL, "fpga_jtag_release: p=%x,chn=%x, wp=0x%x, rp=0x%x\r\n", p, chn, JTAG_channels[chn].wp, JTAG_channels[chn].rp);
switch ( p ) {
case FPGA_JTAG_RESET_MINOR : // same as RAW - do nothing, raw code should do it on it's own
break;
case (FPGA_SJTAG_MINOR_OFFSET + 0): // ugly, fix
case (FPGA_SJTAG_MINOR_OFFSET + 1):
case (FPGA_SJTAG_MINOR_OFFSET + 2):
case (FPGA_SJTAG_MINOR_OFFSET + 3):
case FPGA_JTAG_MINOR :
case FPGA_SJTAG_MINOR :
case FPGA_AJTAG_MINOR :
if (JTAG_channels[chn].wp > 0) { // anything written?
res=JTAG_configure (chn, JTAG_channels[chn].dbuf, JTAG_channels[chn].wp);
JTAG_resetChannel (chn);
if ((res >=0) & (chn == JTAG_MAIN_FPGA)) {
// read FPGA model number/revision and OR it with current state
//fpga_state = (fpga_state & ~0xffff) | (port_csp0_addr[X313__RA__MODEL] & 0xffff);
}
} else JTAG_resetChannel (chn); /// reset initializing in any case:
//if (chn == JTAG_MAIN_FPGA) fpga_state &=~FPGA_STATE_INITIALIZED;
break;
case (FPGA_SJTAG_BOUNDARY_OFFSET + 0):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 1):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 2):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 3):
case FPGA_JTAG_BOUNDARY_MINOR :
case FPGA_SJTAG_BOUNDARY_MINOR :
case FPGA_AJTAG_BOUNDARY_MINOR :
// "dirty"? Send to JTAG
if (JTAG_channels[chn].wp >0) {
// D(printk("fpga_jtag_release(), JTAG_channels[%d].wp = 0x%x",chn,JTAG_channels[chn].wp));
JTAG_EXTEST (chn, JTAG_channels[chn].dbuf, JTAG_channels[chn].bitsw); // size in bits
}
JTAG_resetChannel (chn);
break;
default: return -EINVAL;
}
minors[p]=0;
JTAG_channels[chn].mode=JTAG_MODE_CLOSED;
//D(printk("fpga_jtag_release: done\r\n"));
dev_dbg(NULL, "fpga_jtag_release: done\r\n");
return (res<0)?res:0;
}
//++++++++++++++++++++++++++++++++++++ write() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
//for boundary scan: writing before wp+1 will start EXTEST cycle (either rollover or lseek)
static ssize_t fpga_jtag_write(struct file * file, const char * buf, size_t count, loff_t *off) {
int p = ((int *)file->private_data)[0];
int chn= JTAG_channel(p);
size_t size = JTAG_channels[chn].sizew;
dev_dbg(NULL, "fpga_jtag_write: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, wp=%lx,size=0x%x\r\n", p, chn, (long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].wp, (int) size);
switch (p) {
case FPGA_JTAG_RESET_MINOR : // same as RAW - do nothing, raw code should do it on it's own
if (count > size) count= size;
if ((raw_fifo_w_wp+count) > size) { // read tail, then roll over to the head to the total of count
if (copy_from_user(&raw_fifo_w[raw_fifo_w_wp],buf,size-raw_fifo_w_wp)) return -EFAULT; // read tail
if (copy_from_user(&raw_fifo_w[0],&buf[size-raw_fifo_w_wp],count+raw_fifo_w_wp-size)) return -EFAULT; // read head
} else {
if (copy_from_user(&raw_fifo_w[raw_fifo_w_wp],buf,count)) return -EFAULT; // read count
}
raw_fifo_w_wp+=count;
if (raw_fifo_w_wp > size) raw_fifo_w_wp -= size;
JTAG_process_raw(); // send all the received data to JTAG - will cause read fifo to get ~1/2 of the number of bytes written
break;
case (FPGA_SJTAG_MINOR_OFFSET + 0): // ugly, fix
case (FPGA_SJTAG_MINOR_OFFSET + 1):
case (FPGA_SJTAG_MINOR_OFFSET + 2):
case (FPGA_SJTAG_MINOR_OFFSET + 3):
case FPGA_JTAG_MINOR :
case FPGA_SJTAG_MINOR :
case FPGA_AJTAG_MINOR : // read configuration data to buffer
if (*off > size) return -EFAULT;
if ((*off + count) > size) count= (size - *off);
if (copy_from_user(&(JTAG_channels[chn].dbuf[*off]),buf,count)) return -EFAULT;
*off+=count;
if (*off > JTAG_channels[chn].wp) JTAG_channels[chn].wp= *off;
break;
case (FPGA_SJTAG_BOUNDARY_OFFSET + 0):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 1):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 2):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 3):
case FPGA_JTAG_BOUNDARY_MINOR :
case FPGA_SJTAG_BOUNDARY_MINOR :
case FPGA_AJTAG_BOUNDARY_MINOR :
if (*off > size) return -EFAULT;
if ((*off + count) > size) count= (size - *off);
if (*off < JTAG_channels[chn].wp) {
// D(printk("fpga_jtag_write(), JTAG_channels[%d].wp = 0x%x",chn, JTAG_channels[chn].wp));
JTAG_EXTEST (chn, JTAG_channels[chn].dbuf, JTAG_channels[chn].bitsw); // writing "before" causes EXTEST to fill in boundary scan register
JTAG_channels[chn].wdirty=0;
}
if (copy_from_user(&(JTAG_channels[chn].dbuf[*off]),buf,count)) return -EFAULT;
*off+=count;
JTAG_channels[chn].wp= *off; // before rolling over
if (*off >= size) {
*off=0; // roll over
}
JTAG_channels[chn].mode=JTAG_MODE_EXTEST; //should write the last byte before reading - or buffer data will be just lost
JTAG_channels[chn].wdirty=1;
break;
default: return -EINVAL;
}
dev_dbg(NULL, "fpga_jtag_write end: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, wp=%lx,size=0x%x\r\n", p, chn, (long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].wp, (int) size);
//D(printk("fpga_jtag_write end: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, wp=%lx,size=0x%x\r\n", p, chn, (long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].wp, (int) size));
return count;
}
//++++++++++++++++++++++++++++++++++++ read() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
ssize_t fpga_jtag_read(struct file * file, char * buf, size_t count, loff_t *off) {
int p = ((int *)file->private_data)[0];
int chn= JTAG_channel(p);
size_t size = JTAG_channels[chn].sizer;
int size_av; // available data
dev_dbg(NULL, "fpga_jtag_read: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, rp=%lx,size=0x%x\r\n", p, chn,(long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].rp, (int) size);
switch (p) {
case FPGA_JTAG_RESET_MINOR : // same as RAW - do nothing, raw code should do it on it's own
size_av=(raw_fifo_r_wp >= raw_fifo_r_rp)?(raw_fifo_r_wp - raw_fifo_r_rp):(size+raw_fifo_r_wp - raw_fifo_r_rp);
if (count > size_av) count= size_av;
if ((raw_fifo_r_rp+count) > size) { // read tail, then roll over to the head to the total of count
if (copy_to_user(buf, &raw_fifo_r[raw_fifo_r_rp],size-raw_fifo_r_rp)) return -EFAULT; // read tail
if (copy_to_user(&buf[size-raw_fifo_r_rp],&raw_fifo_r[0],count+raw_fifo_r_rp-size)) return -EFAULT; // read head
} else {
if (copy_to_user(buf,&raw_fifo_w[raw_fifo_w_wp],count)) return -EFAULT; // read count
}
raw_fifo_r_rp+=count;
if (raw_fifo_r_rp > size) raw_fifo_r_rp -= size;
break;
case (FPGA_SJTAG_MINOR_OFFSET + 0): // ugly, fix
case (FPGA_SJTAG_MINOR_OFFSET + 1):
case (FPGA_SJTAG_MINOR_OFFSET + 2):
case (FPGA_SJTAG_MINOR_OFFSET + 3):
case FPGA_JTAG_MINOR :
case FPGA_SJTAG_MINOR :
case FPGA_AJTAG_MINOR : // read configuration data to buffer
if ((JTAG_channels[chn].wp==0) && (JTAG_channels[chn].rp==0)) { // starting from read - get ID
JTAG_channels[chn].mode=JTAG_MODE_RDID;
JTAG_readID (chn, JTAG_channels[chn].dbuf);
}
if (*off > size) return -EFAULT;
if ((*off + count) > size) count= (size - *off);
dev_dbg(NULL, "fpga_jtag_read_01: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, rp=%lx,size=0x%x\r\n", p, chn, (long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].rp, (int) size);
if (copy_to_user(buf,&(JTAG_channels[chn].dbuf[*off]),count)) return -EFAULT;
*off+=count;
JTAG_channels[chn].rp= *off;
break;
case (FPGA_SJTAG_BOUNDARY_OFFSET + 0):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 1):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 2):
case (FPGA_SJTAG_BOUNDARY_OFFSET + 3):
case FPGA_JTAG_BOUNDARY_MINOR :
case FPGA_SJTAG_BOUNDARY_MINOR :
case FPGA_AJTAG_BOUNDARY_MINOR :
if ((JTAG_channels[chn].mode==JTAG_MODE_EXTEST) && (JTAG_channels[chn].wdirty || (*off < JTAG_channels[chn].rp))) {
JTAG_EXTEST (chn, JTAG_channels[chn].dbuf, JTAG_channels[chn].bitsr); // writing last byte causes EXTEST to fill in boundary scan register
JTAG_channels[chn].wdirty=0;
}
// (re)-read capture pins if it was a roll-over or the first access after open
if ((JTAG_channels[chn].mode!=JTAG_MODE_EXTEST) && ((*off < JTAG_channels[chn].rp) || (JTAG_channels[chn].mode==JTAG_MODE_BOUNDARY))) {
JTAG_CAPTURE (chn, JTAG_channels[chn].dbuf, JTAG_channels[chn].bitsr);
}
if (*off > size) return -EFAULT;
if ((*off + count) > size) count= (size - *off);
dev_dbg(NULL, "fpga_jtag_read_01: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, rp=%lx,size=0x%x\r\n", p, chn, (long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].rp, (int) size);
if (copy_to_user(buf,&(JTAG_channels[chn].dbuf[*off]),count)) return -EFAULT;
*off+=count;
JTAG_channels[chn].rp= *off; // before rolling over
if (*off >= size) {
*off=0; // roll over
}
if (JTAG_channels[chn].mode == JTAG_MODE_BOUNDARY) JTAG_channels[chn].mode=JTAG_MODE_SAMPLE; //should write the last byte before reading - or buffer data will be just lost
break;
default: return -EINVAL;
}
dev_dbg(NULL, "fpga_jtag_read_end: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, rp=%lx,size=0x%x, mode=%x\r\n", p, chn, (long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].rp, (int) size, JTAG_channels[chn].mode);
return count;
}
//++++++++++++++++++++++++++++++++++++ lseek() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
static loff_t fpga_jtag_lseek(struct file * file, loff_t offset, int orig) {
/*
* orig 0: position from begning of
* orig 1: relative from current position
* orig 2: position from last address
*/
int p = ((int *)file->private_data)[0];
int chn= JTAG_channel(p);
size_t size;
if (chn==JTAG_RAW) {
size=raw_fifo_r_wp-raw_fifo_r_rp;
if (size<0) size+=FJTAG_RAW_RSIZE;
} else size = JTAG_channels[chn].sizew;
if (JTAG_channels[chn].mode == JTAG_MODE_RDID) size = JTAG_channels[chn].sizer;
dev_dbg(NULL, "fpga_jtag_lseek, fsize= 0x%x\n", (int) size);
switch (orig) {
case 0:
file->f_pos = offset;
break;
case 1:
file->f_pos += offset;
break;
case 2:
file->f_pos = size + offset;
break;
default:
return -EINVAL;
}
/* truncate position */
if (file->f_pos < 0) {
file->f_pos = 0;
return (-EOVERFLOW);
}
if (file->f_pos > size) {
file->f_pos = size;
return (-EOVERFLOW);
}
dev_dbg(NULL,"fpga_jtag_lseek, file->f_pos= 0x%x\n", (int) file->f_pos);
return (file->f_pos);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Initialize GPIOs of the CPU to access JTAG/programming of the main FPGA
void initPortC(void) {
// connect 8 lower bits of port C to GPIO, disconnect from IOP
unsigned long tmp;
#ifdef TEST_DISABLE_CODE
reg_pinmux_rw_pc_iop pinmux_c_iop;
reg_pinmux_rw_pc_gio pinmux_c_gio;
reg_gio_rw_pc_oe pc_oe;
pinmux_c_iop= REG_RD(pinmux, regi_pinmux, rw_pc_iop);
tmp = REG_TYPE_CONV(unsigned long, reg_pinmux_rw_pc_iop, pinmux_c_iop);
tmp &= ~0xff;
pinmux_c_iop = REG_TYPE_CONV(reg_pinmux_rw_pc_iop, unsigned long, tmp);
REG_WR(pinmux, regi_pinmux, rw_pc_iop, pinmux_c_iop);
pinmux_c_gio= REG_RD(pinmux, regi_pinmux, rw_pc_gio);
tmp = REG_TYPE_CONV(unsigned long, reg_pinmux_rw_pc_gio, pinmux_c_gio);
tmp |= 0xff;
pinmux_c_gio = REG_TYPE_CONV(reg_pinmux_rw_pc_gio, unsigned long, tmp);
REG_WR(pinmux, regi_pinmux, rw_pc_gio, pinmux_c_gio);
// now set data of port C pins (static pc_dout)
pc_dout = REG_RD(gio, regi_gio, rw_pc_dout);
pc_dout.data &= ~0xff;
pc_dout.data |= PC_DOUT_INITIAL;
REG_WR(gio, regi_gio, rw_pc_dout, pc_dout);
// now set directions of port C pins
pc_oe = REG_RD(gio, regi_gio, rw_pc_oe);
pc_oe.oe &= ~( (1 << FPGAJTAG_TDO_BIT) |
(1 << FPGAJTAG_DONE_BIT) |
(1 << FPGAJTAG_RSTBTN_BIT));
pc_oe.oe |= ( (1 << FPGAJTAG_TDI_BIT) |
(1 << FPGAJTAG_TMS_BIT) |
(1 << FPGAJTAG_TCK_BIT) |
(1 << FPGAJTAG_PGM_BIT));
REG_WR(gio, regi_gio, rw_pc_oe, pc_oe);
#endif /* TEST_DISABLE_CODE */
}
inline u32 prep_sensio_status(int sens_num)
{
x393_status_sens_io_t stat;
x393_status_ctrl_t stat_ctrl;
stat_ctrl.d32 = 0;
stat = x393_sensio_status(sens_num);
stat_ctrl.seq_num = stat.seq_num + 1;
stat_ctrl.mode = 1;
set_x393_sensio_status_cntrl(stat_ctrl, sens_num);
// dev_dbg(NULL, "set seq_num = %d, chn = %d", stat_ctrl.seq_num, sens_num);
return stat_ctrl.seq_num; // Sequence number to expect (wait for) with return data
}
inline x393_status_sens_io_t wait_sensio_status(int chn, u32 seq_num) // reducing number of hardware reads
{
int i;
int ret = 0;
x393_status_sens_io_t stat;
// dev_dbg(NULL, "waiting for seq_num = %d, chn = %d", seq_num, chn);
for (i = 0; i < 10; i++) {
stat = x393_sensio_status(chn & 3); // sens_num);
if (stat.seq_num == seq_num) {
ret = -1;
if (i)
dev_dbg(NULL, "seq_num = %d received after %d wait cycles", seq_num, i);
break;
}
}
// return ret;
return stat;
}
inline u32 read_tdo(int sens_num)
{
x393_status_sens_io_t stat;
x393_status_ctrl_t stat_ctrl;
int i;
stat_ctrl.d32 = 0;
stat = x393_sensio_status(sens_num);
stat_ctrl.seq_num = stat.seq_num + 1;
stat_ctrl.mode = 1;
set_x393_sensio_status_cntrl(stat_ctrl, sens_num);
for (i = 0; i < 10; i++) {
stat = x393_sensio_status(sens_num & 3); // sens_num);
if (likely(stat.seq_num == stat_ctrl.seq_num)) {
return stat.xfpgatdo;
}
}
dev_err(NULL,"read_tdo(%d): failed to get expected seq_num in 10 cycles, expected = 0x%x, got 0x%x\n",sens_num,stat_ctrl.seq_num, stat.seq_num);
return stat.xfpgatdo;
}
// set FPGA in programming/JTAG mode (only for sensor board)
// NOP for the main board FPGA configuration
void set_pgm_mode (int chn, int en) {
u32 seq_num;
x393_sensio_jtag_t data;
dev_dbg(NULL, "set_pgm_mode (%d,%d)\n",chn,en);
switch (chn >> 2) {
case JTAG_SENSOR_FPGA:
//port_csp0_addr[X313_WA_SENSFPGA] = (en ? (3 << SFPGA_PGMEN_BIT): (SFPGA_RD_SENSPGMPIN | (2 << SFPGA_PGMEN_BIT))) | (2 << SFPGA_TCK_BIT); // turn off TCK (if not turned off already)
/* ? SFPGA_RD_SENSPGMPIN */
data.d32 = 0;
data.pgmen = (en) ? 1 : 0;
data.pgmen_set = 1;
data.tck = 0;
data.tck_set = 1;
/* check status register */
x393_sensio_jtag(data, chn & 3); // sens_num);
/* wait for status register update */
wait_sensio_status(chn & 3, prep_sensio_status(chn & 3)) ; // Not needed here
break;
}
udelay (2);
}
void set_pgm (int chn, int pgmon) {
u32 seq_num;
x393_sensio_jtag_t data;
dev_dbg(NULL, "set_pgm (%d,%d)\n",chn,pgmon);
switch (chn >> 2) {
case JTAG_MAIN_FPGA:
#ifdef TEST_DISABLE_CODE
if (pgmon) pc_dout.data &= ~0x80; // set PGM low (active)
else pc_dout.data |= 0x80; // set PGM high (inactive)
REG_WR(gio, regi_gio, rw_pc_dout, pc_dout); // extend low?
#endif /* TEST_DISABLE_CODE */
break;
case JTAG_SENSOR_FPGA:
//port_csp0_addr[X313_WA_SENSFPGA] = (2 | (pgmon & 1)) << SFPGA_PROG_BIT;
data.prog= pgmon & 1;
data.prog_set = 1;
x393_sensio_jtag(data, chn >> 2); // sens_num);
break;
case JTAG_AUX_FPGA:
break;
}
udelay (2);
}
int read_done (int chn) {
x393_status_sens_io_t stat;
x393_sensio_jtag_t data;
switch (chn >> 2) {
#ifdef TEST_DISABLE_CODE
case JTAG_MAIN_FPGA:
return ((((REG_RD(gio, regi_gio, r_pc_din)).data & 0x20)==0) ? 0 : 1 );
#endif //* TEST_DISABLE_CODE */
case JTAG_SENSOR_FPGA:
//port_csp0_addr[X313_WA_SENSFPGA] = SFPGA_RD_DONE;
//udelay (1);
//return (port_csp0_addr[X313__RA__SENSFPGA] >> SFPGA_RD_BIT) & 1 ;
stat = wait_sensio_status(chn & 3, prep_sensio_status(chn & 3)) ;
return stat.xfpgadone;
case JTAG_AUX_FPGA:
return 0;
}
return 0; // just in case
}
// send 1..8 bits through JTAG
int jtag_send (int chn, int tms, int len, int d) {
int sens_num = chn & 3;
x393_sensio_jtag_t data;
x393_status_sens_io_t stat;
u32 seq_num;
int i; //,m;
int r=0;
int d0;
i = len & 7;
if (i==0) i=8;
d &= 0xff;
d0=d;
dev_dbg(NULL, "jtag_send(0x%x, 0x%x, 0x%x, 0x%x)\r\n", chn, tms,len,d);
switch (chn >> 2) {
case JTAG_MAIN_FPGA:
#ifdef TEST_DISABLE_CODE
pc_dout.data &= ~0x0e;
pc_dout.data |= (tms & 1) << FPGAJTAG_TMS_BIT;
for (;i>0;i--){
r= (r<<1)+ ((REG_RD(gio, regi_gio, r_pc_din)).data & 1); // read TDO before TCK pulse
pc_dout.data = (pc_dout.data & ~0x0a) | (((d<<=1)>>7) & 2);
REG_WR(gio, regi_gio, rw_pc_dout, pc_dout);
pc_dout.data |= (1 << FPGAJTAG_TCK_BIT);
REG_WR(gio, regi_gio, rw_pc_dout, pc_dout);
pc_dout.data &= ~(1 << FPGAJTAG_TCK_BIT);
REG_WR(gio, regi_gio, rw_pc_dout, pc_dout);
}
#endif /* TEST_DISABLE_CODE */
break;
case JTAG_SENSOR_FPGA:
#ifdef TEST_DISABLE_CODE
port_csp0_addr[X313_WA_SENSFPGA] = SFPGA_RD_TDO;
udelay (1); // wait MUX
for (;i>0;i--){
port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0 - just a delay
port_csp0_addr[X313_WA_SENSFPGA] = ((2 | (tms & 1)) << SFPGA_TMS_BIT) |
(((((d<<=1)>>8) & 1) | 2) << SFPGA_TDI_BIT) |
(2 << SFPGA_TCK_BIT) ;
port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0 - just a delay
port_csp0_addr[X313_WA_SENSFPGA] = (3 << SFPGA_TCK_BIT); // TCK=1
r= (r<<1)+ ((port_csp0_addr[X313__RA__SENSFPGA] >> SFPGA_RD_BIT) & 1); // read TDO before TCK pulse
port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0 - just a delay
}
port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0
#endif /* TEST_DISABLE_CODE */
data.d32 = 0;
data.tck_set = 1;
data.tms_set = 1;
data.tdi_set = 1;
dev_dbg(NULL, "jtag_send(0x%x, 0x%x, 0x%x, 0x%x)\n", chn, tms,len,d);
for ( ; i > 0; i--) {
/* TCK = 0 - just a delay; is it really needed? */
data.tck = 0;
data.tms = tms & 1;
data.tdi = ((d <<= 1) >> 8) & 1;
data.tck = 0;
x393_sensio_jtag(data, sens_num);
/* repeat writel - just a delay; is it really needed? */
// x393_sensio_jtag(data, sens_num);
/* read TDO before TCK pulse */
r = (r << 1) + read_tdo(sens_num); // may to need to read twice to increase delay?
data.tck = 1;
x393_sensio_jtag(data, sens_num); // keep other signals, set TCK == 1
// x393_sensio_jtag(data, sens_num); // repeat if delay will be needed to increase length of the TCK signal
data.tck = 0;
// x393_sensio_jtag(data, sens_num);
}
x393_sensio_jtag(data, sens_num);
dev_dbg(NULL, " ---> %02x\n", r);
break;
case JTAG_AUX_FPGA:
break;
}
return r;
}
//====================================
// port_csp0_addr[X313_WA_SENSFPGA] = 0; // nop
// write data data bytes from buffer, read data, optionally compare/abort
// return: 0- OK, !=0 - readback mismatch error
// modified so it reads data in-place of the written one
// send/receive bits, raising TMS during the last one (if last==1). If number of bits are not multiple of 8, lower bits of the last byte will not be used.
int jtag_write_bits (int chn,
unsigned char *buf, // data to write
int len, // number of bytes to write
int check, // compare readback data with previously written, abort on mismatch
int last, // output last bit with TMS=1
int prev[2]) // if null - don't use
{
int sens_num = chn & 3;
int i,j;
int r=0;
int d,d0;
// u32 seq_num;
x393_status_sens_io_t stat;
x393_sensio_jtag_t data;
dev_dbg(NULL, "jtag_write_bits(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\r\n", (int) chn, (int) buf, len, check, last);
switch (chn >> 2) {
case JTAG_MAIN_FPGA: //TODO: save some cycles like for FPGA_SJTAG_MINOR
#ifdef TEST_DISABLE_CODE
for (i=0; len>0;i++) {
pc_dout.data &= ~0x0e;
d0=(d=buf[i]);
for (j=0;j<8;j++) {
//D(printk("i=%x, j=%x, len=%x, d=%x ",i,j,len,d));
if (len>0) {
r= (r<<1)+ ((REG_RD(gio, regi_gio, r_pc_din)).data & 1);
if ((len==1) && last) pc_dout.data = (pc_dout.data & ~0x0a) | (((d<<=1)>>7) & 2) | (1 << FPGAJTAG_TMS_BIT);
else pc_dout.data = (pc_dout.data & ~0x0a) | (((d<<=1)>>7) & 2);
REG_WR(gio, regi_gio, rw_pc_dout, pc_dout);
pc_dout.data |= (1 << FPGAJTAG_TCK_BIT);
REG_WR(gio, regi_gio, rw_pc_dout, pc_dout);
pc_dout.data &= ~(1 << FPGAJTAG_TCK_BIT);
REG_WR(gio, regi_gio, rw_pc_dout, pc_dout);
} else r= (r<<1);
len--;
//D(printk(", r=%x\r\n",r));
}
buf[i]=r; // read back in-place
if (check && ((r ^ (prev[1] >> 24)) & 0xff)) {
return -((r & 0xff) | ((i+1) << 8)); //readback mismatch
}
if (prev) {
// prev64= (prev64<<8) | ((prev32>>24) & 0xff);
// prev32= (prev32<<8) | (d0 & 0xff);
prev[1]= (prev[1]<<8) | ((prev[0]>>24) & 0xff);
prev[0]= (prev[0]<<8) | (d0 & 0xff);
}
}
#endif /* TEST_DISABLE_CODE */
break;
case JTAG_SENSOR_FPGA:
#ifdef TEST_DISABLE_CODE
port_csp0_addr[X313_WA_SENSFPGA] = SFPGA_RD_TDO; // just in case, it should be in that mode when calling jtag_write_bits()
udelay (1); // wait MUX
for (i=0; len>0;i++) {
d0=(d=buf[i]);
for (j=0;j<8;j++) {
port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0 - just a delay
if (len>0) {
if ((len==1) && last) port_csp0_addr[X313_WA_SENSFPGA] =
(3 << SFPGA_TMS_BIT) |
(((((d<<=1)>>8) & 1) | 2) << SFPGA_TDI_BIT) |
(2 << SFPGA_TMS_BIT) |
(2 << SFPGA_TCK_BIT) ;
else port_csp0_addr[X313_WA_SENSFPGA] =
(((((d<<=1)>>8) & 1) | 2) << SFPGA_TDI_BIT) |
(2 << SFPGA_TMS_BIT) |
(2 << SFPGA_TCK_BIT) ;
port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0 - just a delay
port_csp0_addr[X313_WA_SENSFPGA] = (3 << SFPGA_TCK_BIT); // TCK=1
// add delays here if long cable?
r= ((r<<1)+ ((port_csp0_addr[X313__RA__SENSFPGA] >> SFPGA_RD_BIT) & 1)); // read TDO before TCK pulse
port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0 - just a delay
} else r= (r<<1);
len--;
}
buf[i]=r; // read back in-place
if (check && ((r ^ (prev[1]>>24)) & 0xff)) {
return -((r & 0xff) | ((i+1) << 8)); //readback mismatch
}
if (prev) {
// prev64= (prev64<<8) | ((prev32>>24) & 0xff);
// prev32= (prev32<<8) | (d0 & 0xff);
prev[1]= (prev[1]<<8) | ((prev[0]>>24) & 0xff);
prev[0]= (prev[0]<<8) | (d0 & 0xff);
}
}
port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0
#endif /* TEST_DISABLE_CODE */
// Can be done once
data.d32 = 0;
data.tck_set = 1;
data.tms_set = 1;
data.tdi_set = 1;
for (i = 0; len > 0; i++) {
d0 = (d = buf[i]);
dev_dbg(NULL,"jtag_write_bits(), i=0x%x ", i);
for (j = 0; j < 8; j++) {
if (len > 0) {
data.tms = (len == 1 && last)? 1:0 ;
data.tdi = ((d <<= 1) >> 8) & 1;
data.tck = 0;
x393_sensio_jtag(data, sens_num);
// x393_sensio_jtag(data, sens_num); // repeat writel() if needed for delay
r = (r << 1) + read_tdo(sens_num);
data.tck = 1;
x393_sensio_jtag(data, sens_num);
// x393_sensio_jtag(data, sens_num); // remove if no delay is needed
data.tck = 0;
x393_sensio_jtag(data, sens_num);
// x393_sensio_jtag(data, sens_num);
} else {
r <<= 1;
}
len--;
}
buf[i] = r;
dev_dbg(NULL," ===> %02x\n", r);
if (check && ((r ^ (prev[1]>>24)) & 0xff)) {
return -((r & 0xff) | ((i+1) << 8)); //readback mismatch
}
if (prev) {
prev[1]= (prev[1]<<8) | ((prev[0]>>24) & 0xff);
prev[0]= (prev[0]<<8) | (d0 & 0xff);
}
}
break;
case JTAG_AUX_FPGA:
break;
}
return 0;
}
int JTAG_configure (int chn, unsigned char * buf, int len) {
int datastart, i, j ,r;
//static int prev32;
//static int prev64;
int prev[2];
#ifdef JTAG_DISABLE_IRQ
unsigned long flags;
#endif
const unsigned char sync[]={0xff,0xff,0xff,0xff,0xaa,0x99,0x55,0x66};
int skipvfy=8;
dev_dbg(NULL, "JTAG_configure: chn=%x, wp=0x%x, rp=0x%x, len=0x%x\r\n",chn, JTAG_channels[chn].wp, JTAG_channels[chn].rp, len);
// all the programming goes here...
// find sync:
datastart=-1;
for (i=0;i<(FJTAG_MAX_HEAD-8);i++) {
j=0;
while ((j<8) && (buf[i+j]==sync[j])) j++;
if (j==8) {
datastart=i;
break;
}
}
if (datastart<0) {
printk("Bitstream not found - bad file\r\n");
return -EFAULT;
}
// check for right bitstream length
if ((len-datastart)!=(XC3S1200E_BITSIZE>>3)) {
printk("Wrong bitstream size - XC3S1200E has bitstream of %d bits (%d bytes)\n",XC3S1200E_BITSIZE,XC3S1200E_BITSIZE>>3);
printk ("header size - %d, data size - %d\r\n",datastart, len-datastart);
return -EFAULT;
}
// enable programmimg mode (nop for the 10353 FPGA)
set_pgm_mode(chn, 1);
// reset device
set_pgm (chn, 1);
//udelay (1000); // needed?
mdelay(1);
set_pgm (chn, 0);
// wait INIT over - no init connected, just wait >2ms
//udelay (2500);
mdelay(3);
//*************************** NOW DISABLE INTERRUPS FOR THE WHOLE PROGRAMMING CYCLE ***********************
//D( udelay (100000);printk("JTAG_configure(): IRQ off!\r\n"); udelay (100000););
D( mdelay (100);printk("JTAG_configure(): IRQ off!\r\n"); mdelay (100););
#ifdef JTAG_DISABLE_IRQ
local_irq_save(flags);
//local_irq_disable();
#endif
// prepare JTAG
jtag_send(chn, 1, 5, 0 ); //step 1 - set Test-Logic-Reset state
jtag_send(chn, 0, 1, 0 ); //step 2 - set Run-Test-Idle state
jtag_send(chn, 1, 2, 0 ); //step 3 - set SELECT-IR state
jtag_send(chn, 0, 2, 0 ); //step 4 - set SHIFT-IR state
jtag_send(chn, 0, 5, 0xa0); //step 5 - start of CFG_IN ***NOW 6 bits ***
jtag_send(chn, 1, 1, 0 ); //step 6 - finish CFG_IN
jtag_send(chn, 1, 2, 0 ); //step 7 - set SELECT-DR state
jtag_send(chn, 0, 2, 0 ); //step 8 - set SHIFT-DR state
// write data (first 8 bytes - just fill the buffer, no readback comparison)
jtag_write_bits (chn,
&buf[datastart], // data to write
skipvfy << 3, // number of bytes to write
0, // compare readback data with previously written, abort on mismatch
0, // do not raise TMS at last bit
prev); // 64 bits storage to verify configuration transmission
if ((r=jtag_write_bits (chn,
&buf[datastart+skipvfy],
// (buf8i-(datastart+skipvfy)) << 3,
(len-(datastart+skipvfy)) << 3,
1,
1, prev))<0) {
r= -r;
i= (r>>8) -1 + (datastart+skipvfy);
r &= 0xff;
#ifdef JTAG_DISABLE_IRQ
local_irq_restore(flags);
#endif
set_pgm (chn, 1);
set_pgm (chn, 0);
// disable programmimg mode (nop for the 10353 FPGA)
set_pgm_mode(chn, 0);
printk ("**** Configuration failed at byte # %d (%x)****\n", (i-datastart),(i-datastart));
printk ("**** r= %x, prev64=%x prev32=%x****\n", r,prev[1], prev[0]);
return -EFAULT;
}
jtag_send(chn, 1, 1, 0 ); //step 11 - set UPDATE-DR state
jtag_send(chn, 1, 2, 0 ); //step 12 - set SELECT-IR state
jtag_send(chn, 0, 2, 0 ); //step 13 - set SHIFT-IR state
jtag_send(chn, 0, 5, 0x30); //step 14 - start of JSTART ***NOW 6 bits ***
jtag_send(chn, 1, 1, 0 ); //step 15 - finish JSTART
jtag_send(chn, 1, 2, 0 ); //step 16 - set SELECT-DR state
jtag_send(chn, 0, 0, 0 ); //step 17 - set SHIFT-DR , clock startup
jtag_send(chn, 0, 0, 0 ); //step 17a - (total >=12 clocks)
jtag_send(chn, 1, 2, 0 ); //step 18 - set UPDATE-DR state
jtag_send(chn, 0, 1, 0 ); //step 19 - set Run-Test-Idle state
jtag_send(chn, 0, 0, 0 ); //step 19a - only here starts the sequence - adding 17b does not help (5 - sets done, 6 - releases outputs, 7 - releases reset)
jtag_send(chn, 0, 0, 0 ); //step 19b - one more?
// ready or not - device should start now
#ifdef JTAG_DISABLE_IRQ
local_irq_restore(flags);
#endif
//*************************** END OF NO INTERRUPS ***********************
r=read_done(chn);
// disable programmimg mode (nop for the 10353 FPGA)
set_pgm_mode(chn, 0);
if (r==0) {
printk("*** FPGA did not start after configuration ***\r\n");
return -EFAULT;
}
//D( udelay (100000);printk("\nJTAG_configure() OK!\r\n"));
D( mdelay (100);printk("\nJTAG_configure() OK!\r\n"));
return 0;
} //int JTAG_configure
//=============================
//
// enable access to JTAG pins. For sensor FPGA that is not possible w/o deprogramming the chip
// leaves in Run-Test-Idle state
int JTAG_openChannel (int chn) {
dev_dbg(NULL, "JTAG_openChannel (%d)\n",chn);
// enable programmimg mode (nop for the 10353 FPGA)
set_pgm_mode(chn, 1);
// for shared JTAG/data bus we need to de-program the chip to be able to read JTAG :-(
switch (chn >> 2) {
case JTAG_SENSOR_FPGA:
// reset device
set_pgm (chn, 1);
set_pgm (chn, 0);
// wait INIT over - no init connected, just wait >2ms
//udelay (2500);
mdelay(3);
break;
}
jtag_send(chn, 1, 5, 0 ); // set Test-Logic-Reset state
jtag_send(chn, 0, 1, 0 ); // set Run-Test-Idle state
return 0;
} // int JTAG_openChannel (int chn)
//
int JTAG_resetChannel (int chn) {
dev_dbg(NULL, "JTAG_resetChannel (%d)\n",chn);
jtag_send(chn, 1, 5, 0 ); // set Test-Logic-Reset state
// disable programmimg mode (nop for the 10353 FPGA)
set_pgm_mode(chn, 0); // only for sensor FPGA
return 0;
} // int JTAG_resetChannel (int chn)
int JTAG_readID (int chn, unsigned char * buf) {
int i;
unsigned long d1,d2=0;
unsigned long * dp;
#ifdef JTAG_DISABLE_IRQ
unsigned long flags;
#endif
// read dev id, user id
//*************************** NOW DISABLE INTERRUPS FOR THE WHOLE JTAG SEQUENCE ***********************
#ifdef JTAG_DISABLE_IRQ
local_irq_save(flags);
//local_irq_disable();
#endif
// prepare JTAG
jtag_send(chn, 1, 5, 0 ); //step 1 - set Test-Logic-Reset state
jtag_send(chn, 0, 1, 0 ); //step 2 - set Run-Test-Idle state
jtag_send(chn, 1, 2, 0 ); //step 3 - set SELECT-IR state
jtag_send(chn, 0, 2, 0 ); //step 4 - set SHIFT-IR state
jtag_send(chn, 0, 5, 0x90); //step 5 - start of IDCODE
jtag_send(chn, 1, 1, 0 ); //step 6 - finish IDCODE
jtag_send(chn, 1, 2, 0 ); //step 7 - set SELECT-DR state
jtag_send(chn, 0, 2, 0 ); //step 8 - set CAPTURE-DR state
jtag_write_bits (chn,
&buf[0], // data to write
32, // number of bits to write/read
0, // don't compare readback data with previously written
1, 0) ; // raise TMS at last bit
jtag_send(chn, 1, 5, 0 ); //reset state machine to Test-Logic-Reset state
jtag_send(chn, 0, 1, 0 ); //step 2 - set Run-Test-Idle state
jtag_send(chn, 1, 2, 0 ); //step 3 - set SELECT-IR state
jtag_send(chn, 0, 2, 0 ); //step 4 - set SHIFT-IR state
jtag_send(chn, 0, 5, 0x10); //step 5 - start of USERCODE
jtag_send(chn, 1, 1, 0 ); //step 6 - finish USERCODE
jtag_send(chn, 1, 2, 0 ); //step 7 - set SELECT-DR state
jtag_send(chn, 0, 2, 0 ); //step 8 - set CAPTURE-DR state
jtag_write_bits (chn,
&buf[4], // data to write
32, // number of bits to write/read
0, // don't compare readback data with previously written
1,0) ; // raise TMS at last bit
jtag_send(chn,1, 5, 0 ); //reset state machine to Test-Logic-Reset state
#ifdef JTAG_DISABLE_IRQ
local_irq_restore(flags);
#endif
//*************************** END OF NO INTERRUPS ***********************
// swap all bits in ID and user fields
dp = (unsigned long *) &buf[0];
d1= *dp;
for (i=0;i<32;i++){
d2 = (d2 << 1) | (d1 & 1);
d1 >>= 1;
}
*dp=d2;
dp = (unsigned long *) &buf[4];
d1= *dp;
for (i=0;i<32;i++){
d2 = (d2 << 1) | (d1 & 1);
d1 >>= 1;
}
*dp=d2;
D(for (i=0; i<8;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");} );
data_modified=0; //*************************************************
return 0;
} // int JTAG_readID (int chn, unsigned char * buf)
/*
* capture all pins w/o changing functionality
* assuming Run-Test-Idle/UPDATE-DR leaving UPDATE-DR
*/
int JTAG_CAPTURE (int chn, unsigned char * buf, int len) {
int i; // only in debug
#ifdef JTAG_DISABLE_IRQ
unsigned long flags;
#endif
dev_dbg(NULL,"JTAG_CAPTURE(): buf=%p\n",buf);
//*************************** NOW DISABLE INTERRUPS FOR THE WHOLE JTAG SEQUENCE ***********************
#ifdef JTAG_DISABLE_IRQ
local_irq_save(flags);
//local_irq_disable();
#endif
// prepare JTAG
// jtag_send(chn, 1, 5, 0 ); //step 1 - set Test-Logic-Reset state
// jtag_send(chn, 0, 1, 0 ); //step 2 - set Run-Test-Idle state
jtag_send(chn, 1, 2, 0 ); //step 3 - set SELECT-IR state
jtag_send(chn, 0, 2, 0 ); //step 4 - set SHIFT-IR state
jtag_send(chn, 0, 5, 0x80); //step 5 - start of SAMPLE (which bit goes first???)
jtag_send(chn, 1, 1, 0 ); //step 6 - finish SAMPLE
jtag_send(chn, 1, 2, 0 ); //step 7 - set SELECT-DR state
jtag_send(chn, 0, 2, 0 ); //step 8 - set CAPTURE-DR state
jtag_write_bits (chn,
buf, // data to write
len, // number of bits to read
0, // don't compare readback data with previously written
1,0) ; // raise TMS at last bit
// D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");}printk ("\n"); );
// D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");}printk ("\n"); );
jtag_send(chn, 1, 1, 0 ); //step 9 - set UPDATE-DR state
// D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");}printk ("\n"); );
// jtag_send(chn,1, 5, 0 ); //reset state machine to Test-Logic-Reset state
#ifdef JTAG_DISABLE_IRQ
local_irq_restore(flags);
#endif
//*************************** END OF NO INTERRUPS ***********************
dev_dbg(NULL, "\n");
for (i=0; i<((len+7)>>3) ;i++) {
dev_dbg(NULL, "%3x ",(int) buf[i]);
if ((i & 0xf) == 0xf) dev_dbg(NULL, "\n");
}
dev_dbg(NULL, "\n");
data_modified=0;
return 0;
} // JTAG_CAPTURE (int chn, unsigned char * buf, int len) {
/*
* write new boundary registers (len should match BS register length), read pins in-place
* TAP controller is supposed to be in "UPDATE-DR" state (or RUN-TEST/IDLE after just opening this mode)
* TAP controller will be left in the same "UPDATE-DR" after the command
*/
int JTAG_EXTEST (int chn, unsigned char * buf, int len) {
#ifdef JTAG_DISABLE_IRQ
unsigned long flags;
#endif
int i; // only in debug
#ifdef JTAG_DISABLE_IRQ
local_irq_save(flags);
//local_irq_disable();
#endif
//D(printk("EXTEST: buf=%p, len=0x%x\n",buf,len));
//D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");}printk ("\n"); );
// jtag_send(chn, 1, 5, 0 ); //step 1 - set Test-Logic-Reset state
// jtag_send(chn, 0, 1, 0 ); //step 2 - set Run-Test-Idle state
jtag_send(chn, 1, 2, 0 ); //step 3 - set SELECT-IR state
jtag_send(chn, 0, 2, 0 ); //step 4 - set SHIFT-IR state
jtag_send(chn, 0, 5, 0xf0); //step 5 - start of EXTEST
jtag_send(chn, 1, 1, 0 ); //step 6 - finish EXTEST
jtag_send(chn, 1, 2, 0 ); //step 7 - set SELECT-DR state
jtag_send(chn, 0, 2, 0 ); //step 8 - set CAPTURE-DR state
jtag_write_bits (chn,
buf,
len, // number of bits to write
0, // don't compare readback data with previously written
1,0); // raise TMS at last bit
jtag_send(chn, 1, 1, 0 ); //step 9 - set UPDATE-DR state
#ifdef JTAG_DISABLE_IRQ
local_irq_restore(flags);
#endif
// D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");}printk ("\n"); );
return 0;
} //int JTAG_EXTEST (int chn, unsigned char * buf, int len)
static int __init fpga_jtag_init(void) {
int i,res;
res = register_chrdev(FPGA_JTAG_MAJOR, fpga_jtag_name, &fpga_jtag_fops);
if(res < 0) {
printk(KERN_ERR "\nfpga_jtag_init: couldn't get a major number %d.\n",FPGA_JTAG_MAJOR);
return res;
}
printk(FPGA_JTAG_DRIVER_NAME" - %d\n",FPGA_JTAG_MAJOR);
for (i=0;i<=FPGA_JTAG_MAXMINOR;i++) minors[i]=0;
initPortC();
dev_dbg(NULL, "elphel test %s: MAJOR %d", FPGA_JTAG_DRIVER_NAME, FPGA_JTAG_MAJOR);
res = init_mmio_ptr();
if (res < 0)
return -ENOMEM;
return 0;
}
static void __exit fpga_jtag_exit(void)
{
unregister_chrdev(FPGA_JTAG_MAJOR, FPGA_JTAG_DRIVER_NAME);
dev_dbg(NULL, "unregistering driver");
}
module_exit(fpga_jtag_exit);
/* this makes sure that fpga_init is called during boot */
module_init(fpga_jtag_init);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov ");
MODULE_DESCRIPTION(FPGA_JTAG_DRIVER_NAME);
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/sensor_i2c.c 0000664 0000000 0000000 00000056416 12703306510 0027312 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* FILE NAME : sensor_i2c.c
* DESCRIPTION: Interface to FPGA-based i2c sequencer for sensor ports
* Copyright 2016 (C) Elphel, Inc.
* -----------------------------------------------------------------------------*
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/****************** INCLUDE FILES SECTION ***********************************/
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
//#include
#include
//#include
#include
#include
#include
#include "x393.h"
#include "sensor_i2c.h"
//------------------
#include
#include
#include
#include
#include
#include
#include
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
#define DRV_NAME "elphel_sensor_i2c"
//------------------
#if 0
#include
/**
* alloc_chrdev_region() - register a range of char device numbers
* @dev: output parameter for first assigned number
* @baseminor: first of the requested range of minor numbers
* @count: the number of minor numbers required
* @name: the name of the associated device or driver
*
* Allocates a range of char device numbers. The major number will be
* chosen dynamically, and returned (along with the first minor number)
* in @dev. Returns zero or a negative error code.
*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name)
{
struct char_device_struct *cd;
cd = __register_chrdev_region(0, baseminor, count, name);
if (IS_ERR(cd))
return PTR_ERR(cd);
*dev = MKDEV(cd->major, cd->baseminor);
return 0;
}
#endif
// Number of channels is hard-wired to 4
static u32 free_i2c_groups[4];
static u32 free_i2c_pages [32];
static DEFINE_SPINLOCK(lock);
static u32 i2c_pages_shadow[1024]; // Mostly for debugging to analyze i2c pages allocation
static int sysfs_page[4]; // when positive - page locked for exclusive access
/* Mark all i2c pages for each channel as free */
void i2c_page_alloc_init(void){
int i;
for (i = 0; i < sizeof(free_i2c_groups)/sizeof(free_i2c_groups[0]); i++) free_i2c_groups[i] = 0xff000000;
for (i = 0; i < sizeof(free_i2c_pages)/ sizeof(free_i2c_pages[0]); i++) free_i2c_pages[i] = 0xffffffff;
for (i = 0; i < sizeof(i2c_pages_shadow)/sizeof(i2c_pages_shadow[0]); i++) i2c_pages_shadow[i] = 0;
for (i = 0; i < sizeof(sysfs_page)/sizeof(sysfs_page[0]); i++) sysfs_page[i] = -1;
}
/* Reserve i2c page (1 of 256 for a sensor port)*/
int i2c_page_alloc(int chn){
int g, b;
u32 * fb;
spin_lock(&lock);
g = __builtin_clz(free_i2c_groups[chn]);
if (unlikely(g > 7)) {
spin_unlock(&lock);
return -ENOMEM; // no free i2c pages left
}
fb = free_i2c_pages + ((chn << 3) + g);
b = __builtin_clz(*fb);
*fb &= ~ (1 << (31-b));
if (unlikely(*fb == 0)){
free_i2c_groups[chn] &= ~(1 << (31 - g));
}
spin_unlock(&lock);
return (g << 5) + b;
}
/* Free i2c page */
void i2c_page_free(int chn, int page){
int g = page >> 5;
int b = page & 0x1f;
u32 * fb = free_i2c_pages + ((chn << 3) + g);
spin_lock(&lock);
free_i2c_groups[chn] |= 1 << (31 - g);
*fb |= 1 << (31-b);
spin_unlock(&lock);
}
/* Set i2c table entry to raw data (will just overwrite tbl_mode = 2)*/
void set_sensor_i2c_raw(int chn,
int page, // index in lookup table
u32 data) { // Bit delay - number of mclk periods in 1/4 of the SCL period
x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0;
tb_addr.tbl_mode = 3;
tb_data.d32 = data;
tb_data.tbl_mode = 2; //
/* Table address and data should not interleave with others */
spin_lock(&lock);
x393_sensi2c_ctrl (tb_addr, chn);
x393_sensi2c_ctrl (tb_data, chn);
spin_unlock(&lock);
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
}
/* Set i2c table entry for write operation */
void set_sensor_i2c_wr(int chn,
int page, // index in lookup table
int sa, // slave address (7 bit)
int rah, // High byte of the i2c register address
int num_bytes, //Number of bytes to write (1..10)
int bit_delay) { // Bit delay - number of mclk periods in 1/4 of the SCL period
x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0;
tb_addr.tbl_mode = 3;
tb_data.d32 = 0;
tb_data.rah = rah;
tb_data.rnw = 0;
tb_data.sa = sa;
tb_data.nbwr = num_bytes;
tb_data.dly = bit_delay;
tb_data.tbl_mode = 2;
/* Table address and data should not interleave with others */
spin_lock(&lock);
x393_sensi2c_ctrl (tb_addr, chn);
x393_sensi2c_ctrl (tb_data, chn);
spin_unlock(&lock);
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
}
/* Set i2c table entry for read operation */
void set_sensor_i2c_rd(int chn,
int page, // index in lookup table
int two_byte_addr, // Number of address bytes (0 - one byte, 1 - two bytes)
int num_bytes, // Number of bytes to read (1..8, 0 means 8)
int bit_delay) { // Bit delay - number of mclk periods in 1/4 of the SCL period
x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0;
tb_addr.tbl_mode = 3;
tb_data.d32 = 0;
tb_data.rnw = 1;
tb_data.nabrd = two_byte_addr;
tb_data.nbrd = num_bytes;
tb_data.dly = bit_delay;
tb_data.tbl_mode = 2;
/* Table address and data should not interleave with others */
spin_lock(&lock);
x393_sensi2c_ctrl (tb_addr, chn);
x393_sensi2c_ctrl (tb_data, chn);
spin_unlock(&lock);
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
}
/*
// Write i2c command to the i2c command sequencer
// I2C command sequencer, block of 16 DWORD slots for absolute frame numbers (modulo 16) and 15 slots for relative ones
// 0 - ASAP, 1 next frame, 14 -14-th next.
// Data written depends on context:
// 1 - I2C register write: index page (MSB), 3 payload bytes. Payload bytes are used according to table and sent
// after the slave address and optional high address byte. Other bytes are sent in descending order (LSB- last).
// If less than 4 bytes are programmed in the table the high bytes (starting with the one from the table) are
// skipped.
// If more than 4 bytes are programmed in the table for the page (high byte), one or two next 32-bit words
// bypass the index table and all 4 bytes are considered payload ones. If less than 4 extra bytes are to be
// sent for such extra word, only the lower bytes are sent.
//
// 2 - I2C register read: index page, slave address (8-bit, with lower bit 0) and one or 2 address bytes (as programmed
// in the table. Slave address is always in byte 2 (bits 23:16), byte1 (high register address) is skipped if
// read address in the table is programmed to be a single-byte one
*/
/* Write one or multiple DWORDs to i2c relative (modulo16) address. Use offs = 0 for immediate (ASAP) command */
/* Length of data is determined by the page data already preset */
int write_sensor_i2c_rel (int chn,
int offs, // 4 bits
u32 * data){
x393_i2c_ctltbl_t tb_data;
int len;
int i;
tb_data.d32 = i2c_pages_shadow[(chn <<8) + (data[0] >> 24)];
if (tb_data.tbl_mode !=2) return -1;
len = (tb_data.rnw )? 1:((tb_data.nbwr + 5) >> 2); // read mode - always 1 DWORD, write - 1..3
if (len > 1) {
spin_lock(&lock);
for (i = 0; i > 24)];
if (tb_data.tbl_mode !=2) return -1;
len = (tb_data.rnw )? 1:((tb_data.nbwr + 5) >> 2); // read mode - always 1 DWORD, write - 1..3
if (len > 1) {
spin_lock(&lock);
for (i = 0; i attr.name + (strlen(attr->attr.name)-1), "%du", ®);
return reg;
}
static ssize_t get_i2c_page_alloc(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn = get_channel_from_name(attr) ;
int page;
// if (sysfs_page[chn]>=0)
// return -EBUSY;
page= i2c_page_alloc(chn);
if (page <0)
return -ENOMEM;
sysfs_page[chn] = page;
return sprintf(buf,"%d\n",page);
}
static ssize_t free_i2c_page(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn = get_channel_from_name(attr) ;
int page;
sscanf(buf, "%i", &page);
page &= 0xff;
// if (sysfs_page[chn] >= 0)
// i2c_page_free(chn, page);
// sysfs_page[chn] = -1; // free
i2c_page_free(chn, page);
return count;
}
/* Set/get page number for reading */
static ssize_t set_i2c_page_inuse(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn = get_channel_from_name(attr) ;
int page;
sscanf(buf, "%i", &page);
sysfs_page[chn] = page & 0xff;
return count;
}
static ssize_t get_i2c_page_inuse(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn = get_channel_from_name(attr) ;
return sprintf(buf,"%d\n",sysfs_page[chn]);
}
// Get i2c table data as raw data (hex)
static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn = get_channel_from_name(attr) ;
int page = sysfs_page[chn]; // currently selected page for sysfs reads
if (page < 0)
return -ENXIO; /* No such device or address */
return sprintf(buf,"0x%08x\n",i2c_pages_shadow[(chn << 8) + (page &0xff)]);
}
static ssize_t set_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn = get_channel_from_name(attr) ;
int ni, page, data;
ni = sscanf(buf, "%i %i", &page, &data);
if (ni < 2)
dev_err(dev, "Requires 2 parameters: page, data\n");
return -EINVAL;
set_sensor_i2c_raw(chn,
page & 0xff, // index in lookup table
(u32) data); // Bit delay - number of mclk periods in 1/4 of the SCL period
return count;
}
// Get/parse i2c table (hex)
static ssize_t get_i2c_tbl_human(struct device *dev, struct device_attribute *attr, char *buf)
{
x393_i2c_ctltbl_t tb_data;
int chn = get_channel_from_name(attr) ;
int page = sysfs_page[chn]; // currently selected page for sysfs reads
if (page < 0)
return -ENXIO; /* No such device or address */
tb_data.d32 = i2c_pages_shadow[(chn << 8) + (page &0xff)];
if (tb_data.rnw){
return sprintf(buf,"Read entry: chn=%d page=%d(0x%x) two_byte_addr=%d number bytes to read=%d bit_duration=%d\n",
chn, page,page, tb_data.nabrd,tb_data.nabrd,tb_data.nbrd, tb_data.dly);
} else {
return sprintf(buf,"Write entry: chn=%d page=%d(0x%x) sa=0x%02x rah=0x%02x nbw=%d bit_duration=%d\n",
chn, page,page,tb_data.sa,tb_data.rah,tb_data.nbwr, tb_data.dly);
}
}
static ssize_t set_i2c_tbl_wr_human(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn = get_channel_from_name(attr) ;
int ni, page, rah,sa7,nbwr,dly;
ni = sscanf(buf, "%i %i %i %i %i", &page, &sa7, &rah, &nbwr, &dly);
if (ni < 2)
dev_err(dev, "Requires 5 parameters: page, slave address (7 bit), high reg address byte, bytes to write (1..10), 1/4 scl period in mclk\n");
return -EINVAL;
set_sensor_i2c_wr(chn,
page & 0xff, // index in lookup table
sa7 & 0x7f, // slave address (7 bit)
rah & 0xff, // High byte of the i2c register address
nbwr & 0xf, // Number of bytes to write (1..10)
dly & 0xff); // Bit delay - number of mclk periods in 1/4 of the SCL period
return count;
}
static ssize_t set_i2c_tbl_rd_human(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn = get_channel_from_name(attr) ;
int ni, page, two_byte_addr, num_bytes,bit_delay;
ni = sscanf(buf, "%i %i %i %i %i", &page, &two_byte_addr, &num_bytes, &bit_delay);
if (ni < 2)
dev_err(dev, "Requires 4 parameters: page, two byte addr (0 - 8bit,1 - 16 bit reg. addr), number of bytes to read, bytes to write (1..10), 1/4 scl period in mclk\n");
return -EINVAL;
set_sensor_i2c_rd( chn,
page & 0xff, // index in lookup table
two_byte_addr & 1, // Number of address bytes (0 - one byte, 1 - two bytes)
num_bytes & 7, // Number of bytes to read (1..8, 0 means 8)
bit_delay & 0xff); // Bit delay - number of mclk periods in 1/4 of the SCL period
return count;
}
static ssize_t set_i2c_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn = get_channel_from_name(attr) ;
int ni, page, sa7, addr;
ni = sscanf(buf, "%i %i %i", &page, &sa7, addr);
if (ni <3)
dev_err(dev, "Requires 3 parameters: page, sa7, reg_addr\n");
return -EINVAL;
page &= 0xff;
read_sensor_i2c (chn,
page & 0xff, // page (8 bits)
sa7 & 0x7f, // 7-bit i2c slave address
addr & 0xffff); // 8/16 bit address return count;
}
// Get i2c read data from fifo
static ssize_t get_i2c_read(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn = get_channel_from_name(attr) ;
int page = sysfs_page[chn]; // currently selected page for sysfs reads
if (page < 0)
return -ENXIO; /* No such device or address */
return sprintf(buf,"%d\n",read_sensor_i2c_fifo(chn)); // <0 - not ready, 0..255 - data
}
// Get i2c read data from fifo
static ssize_t get_i2c_help(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Numeric suffix in file names selects sensor port\n"
"alloc*: read - allocate and return page, write (any data) - free page\n"
"rd_page*: read/write page number used in read operations (-1 if none)\n"
"tbl_raw*: read - raw hex table value (for current rd_page), write set page\n"
"tbl_wr*: read - decoded table entry for current rd_page, write \n"
"tbl_rd*: read - decoded table entry for current rd_page, write <2-byte addr> \n"
"tbl_rd* and tbl_wr* return same result when read. Delay is 8 bit, 250 - 200KHz SCL\n");
}
// Sysfs top
/* alloc*: read - allocate and return page, write (any data) - free page */
static DEVICE_ATTR(alloc0 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page);
static DEVICE_ATTR(alloc1 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page);
static DEVICE_ATTR(alloc2 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page);
static DEVICE_ATTR(alloc3 , SYSFS_PERMISSIONS , get_i2c_page_alloc , free_i2c_page);
/* rd_page*: read/write page number used in read operations */
static DEVICE_ATTR(rd_page0 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse);
static DEVICE_ATTR(rd_page1 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse);
static DEVICE_ATTR(rd_page2 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse);
static DEVICE_ATTR(rd_page3 , SYSFS_PERMISSIONS , get_i2c_page_inuse, set_i2c_page_inuse);
static DEVICE_ATTR(tbl_raw0 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw);
static DEVICE_ATTR(tbl_raw1 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw);
static DEVICE_ATTR(tbl_raw2 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw);
static DEVICE_ATTR(tbl_raw3 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw);
static DEVICE_ATTR(tbl_wr0 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human);
static DEVICE_ATTR(tbl_wr1 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human);
static DEVICE_ATTR(tbl_wr2 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human);
static DEVICE_ATTR(tbl_wr3 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_wr_human);
static DEVICE_ATTR(tbl_rd0 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human);
static DEVICE_ATTR(tbl_rd1 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human);
static DEVICE_ATTR(tbl_rd2 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human);
static DEVICE_ATTR(tbl_rd3 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human);
static DEVICE_ATTR(i2c_rd0 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read);
static DEVICE_ATTR(i2c_rd1 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read);
static DEVICE_ATTR(i2c_rd2 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read);
static DEVICE_ATTR(i2c_rd3 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read);
static DEVICE_ATTR(help, SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_help, NULL);
static struct attribute *root_dev_attrs[] = {
&dev_attr_alloc0.attr,
&dev_attr_alloc1.attr,
&dev_attr_alloc2.attr,
&dev_attr_alloc3.attr,
&dev_attr_rd_page0.attr,
&dev_attr_rd_page1.attr,
&dev_attr_rd_page2.attr,
&dev_attr_rd_page3.attr,
&dev_attr_tbl_raw0.attr,
&dev_attr_tbl_raw1.attr,
&dev_attr_tbl_raw2.attr,
&dev_attr_tbl_raw3.attr,
&dev_attr_tbl_wr0.attr,
&dev_attr_tbl_wr1.attr,
&dev_attr_tbl_wr2.attr,
&dev_attr_tbl_wr3.attr,
&dev_attr_tbl_rd0.attr,
&dev_attr_tbl_rd1.attr,
&dev_attr_tbl_rd2.attr,
&dev_attr_tbl_rd3.attr,
&dev_attr_i2c_rd0.attr,
&dev_attr_i2c_rd1.attr,
&dev_attr_i2c_rd2.attr,
&dev_attr_i2c_rd3.attr,
&dev_attr_help.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
.attrs = root_dev_attrs,
.name = NULL,
};
static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev)
{
int retval=0;
struct device *dev = &pdev->dev;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval;
}
return retval;
}
// =======================================
static void elphel393_sensor_i2c_init_of(struct platform_device *pdev)
{
const __be32 * config_data;
const char * config_string;
char str[40];
int len,chn,pre_disabled,old_dis_por,rc,chn_bits;
struct device_node *node = pdev->dev.of_node;
// struct elphel393_pwr_data_t *clientdata = platform_get_drvdata(pdev);
// struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
if (node) {
/*TODO: Configure some i2c devices here (slaves, formats, speeds) to be used by names*/
}
dev_info(&pdev->dev,"elphel393_sensor_i2c configuration done\n");
}
static int elphel393_sensor_i2c_probe(struct platform_device *pdev)
{
/*
struct gpio_chip *chip;
// struct device * ltc3489_dev;
int i,rc;
int base[2];
struct i2c_client *ltc3589_client;
struct elphel393_pwr_data_t *clientdata = NULL;
*/
pr_info("Probing elphel393-sensor-i2c\n");
elphel393_sens_i2c_sysfs_register(pdev);
i2c_page_alloc_init();
#if 0
clientdata = devm_kzalloc(&pdev->dev, sizeof(*clientdata), GFP_KERNEL);
#endif
elphel393_sensor_i2c_init_of(pdev);
pr_info("done probing elphel393-sensor-i2c\n");
return 0;
}
static int elphel393_sensor_i2c_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev,"Removing elphel393-sensor-i2c");
return 0;
}
static struct of_device_id elphel393_sensor_i2c_of_match[] = {
{ .compatible = "elphel,elphel393-sensor-i2c-1.00", },
{ /* end of table */}
};
MODULE_DEVICE_TABLE(of, elphel393_sensor_i2c_of_match);
static struct platform_driver elphel393_sensor_i2c = {
.probe = elphel393_sensor_i2c_probe,
.remove = elphel393_sensor_i2c_remove,
.driver = {
.name = "elphel393-sensor-i2c",
.owner = THIS_MODULE,
.of_match_table = elphel393_sensor_i2c_of_match,
.pm = NULL, /* power management */
},
};
module_platform_driver(elphel393_sensor_i2c);
MODULE_AUTHOR("Andrey Filippov ");
MODULE_DESCRIPTION("Elphel 10393 sensor ports i2c");
MODULE_LICENSE("GPL");
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/sensor_i2c.h 0000664 0000000 0000000 00000011705 12703306510 0027307 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* FILE NAME : sensor_i2c.h
* DESCRIPTION: Interface to FPGA-based i2c sequencer for sensor ports
* Copyright 2016 (C) Elphel, Inc.
* -----------------------------------------------------------------------------*
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
// I2C device description to be used with i2c sequencer
/*
typedef struct x393_i2c_device_tag{
char * name;
u8 slave7; // slave address (7-bit)
u8 address_bytes;
u8 data_bytes;
int scl_khz; // maximal SCL frequency in KHz (currently limited by 200KHz slowest)
struct x393_i2c_device_tag * next;
} x393_i2c_device_t;
*/
/* Reserve i2c page (1 of 256 for a sensor port)*/
int i2c_page_alloc(int chn);
/* Free i2c page */
void i2c_page_free(int chn, int page);
/* Set i2c table entry to raw data (will just overwrite tbl_mode = 2) */
void set_sensor_i2c_raw(int chn,
int page, // index in lookup table
u32 data); // Bit delay - number of mclk periods in 1/4 of the SCL period
/* Set i2c table entry for write operation */
void set_sensor_i2c_wr(int chn,
int page, // index in lookup table
int sa, // slave address (7 bit)
int rah, // High byte of the i2c register address
int num_bytes, //Number of bytes to write (1..10)
int bit_delay); // Bit delay - number of mclk periods in 1/4 of the SCL period
/* Set i2c table entry for read operation */
void set_sensor_i2c_rd(int chn,
int page, // index in lookup table
int two_byte_addr, // Number of address bytes (0 - one byte, 1 - two bytes)
int num_bytes, // Number of bytes to read (1..8, 0 means 8)
int bit_delay);// Bit delay - number of mclk periods in 1/4 of the SCL period
/*
// Write i2c command to the i2c command sequencer
// I2C command sequencer, block of 16 DWORD slots for absolute frame numbers (modulo 16) and 15 slots for relative ones
// 0 - ASAP, 1 next frame, 14 -14-th next.
// Data written depends on context:
// 1 - I2C register write: index page (MSB), 3 payload bytes. Payload bytes are used according to table and sent
// after the slave address and optional high address byte. Other bytes are sent in descending order (LSB- last).
// If less than 4 bytes are programmed in the table the high bytes (starting with the one from the table) are
// skipped.
// If more than 4 bytes are programmed in the table for the page (high byte), one or two next 32-bit words
// bypass the index table and all 4 bytes are considered payload ones. If less than 4 extra bytes are to be
// sent for such extra word, only the lower bytes are sent.
//
// 2 - I2C register read: index page, slave address (8-bit, with lower bit 0) and one or 2 address bytes (as programmed
// in the table. Slave address is always in byte 2 (bits 23:16), byte1 (high register address) is skipped if
// read address in the table is programmed to be a single-byte one
*/
/* Write one or multiple DWORDs to i2c relative (modulo16) address. Use offs = 0 for immediate (ASAP) command */
/* Length of data is determined by the page data already preset */
int write_sensor_i2c_rel (int chn,
int offs, // 4 bits
u32 * data);
/* Same to absolute (modulo16) address */
int write_sensor_i2c_abs (int chn,
int offs, // 4 bits
u32 * data);
/* Write sensor 16 bit (or 8 bit as programmed in the table) data in immediate mode */
void write_sensor_reg16 (int chn,
int page, // page (8 bits)
int addr, // low 8 bits
u32 data); // 16 or 8-bit data (LSB aligned)
/* Initiate sensor i2c read in immediate mode (data itself has to be read from FIFO with read_sensor_i2c_fifo)*/
void read_sensor_i2c (int chn,
int page, // page (8 bits)
int sa7, // 7-bit i2c slave address
int addr); // 8/16 bit address
/* Read next byte from the channel i2c FIFO. Return byte or -1 if no data available */
/* Sensor channel status should be in auto update mode (3) */
int read_sensor_i2c_fifo(int chn);
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/x393.c 0000664 0000000 0000000 00000166014 12703306510 0025746 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* File: x393.c
* Date: 2016-04-06
* Author: auto-generated file, see x393_export_c.py
* Description: Functions definitions to access x393 hardware registers
*******************************************************************************/
#include
#include "x393.h"
static void __iomem* mmio_ptr;
// init_mmio_ptr() should be called once before using any of the other defined functions
int init_mmio_ptr(void) {mmio_ptr = ioremap(0x40000000, 0x00003000); if (!mmio_ptr) return -1; else return 0;}
// R/W addresses to set up memory arbiter priorities. For sensors (chn = 8..11), for compressors - 12..15
void set_x393_mcntrl_arbiter_priority (x393_arbite_pri_t d, int chn){writel(d.d32, mmio_ptr + (0x0180 + 0x4 * chn));} // Set memory arbiter priority (currently r/w, may become just wo)
x393_arbite_pri_t get_x393_mcntrl_arbiter_priority (int chn) { x393_arbite_pri_t d; d.d32 = readl(mmio_ptr + (0x0180 + 0x4 * chn)); return d; }
// Enable/disable memory channels (bits in a 16-bit word). For sensors (chn = 8..11), for compressors - 12..15
void set_x393_mcntrl_chn_en (x393_mcntr_chn_en_t d){writel(d.d32, mmio_ptr + 0x01c0);} // Enable/disable memory channels (currently r/w, may become just wo)
x393_mcntr_chn_en_t get_x393_mcntrl_chn_en (void) { x393_mcntr_chn_en_t d; d.d32 = readl(mmio_ptr + 0x01c0); return d; }
void set_x393_mcntrl_dqs_dqm_patt (x393_mcntr_dqs_dqm_patt_t d){writel(d.d32, mmio_ptr + 0x0140);} // Setup DQS and DQM patterns
x393_mcntr_dqs_dqm_patt_t get_x393_mcntrl_dqs_dqm_patt (void) { x393_mcntr_dqs_dqm_patt_t d; d.d32 = readl(mmio_ptr + 0x0140); return d; }
void set_x393_mcntrl_dq_dqs_tri (x393_mcntr_dqs_dqm_tri_t d){writel(d.d32, mmio_ptr + 0x0144);} // Setup DQS and DQ on/off sequence
x393_mcntr_dqs_dqm_tri_t get_x393_mcntrl_dq_dqs_tri (void) { x393_mcntr_dqs_dqm_tri_t d; d.d32 = readl(mmio_ptr + 0x0144); return d; }
// Following enable/disable addresses can be written with any data, only addresses matter
void x393_mcntrl_dis (void) {writel(0, mmio_ptr + 0x00c0);} // Disable DDR3 memory controller
void x393_mcntrl_en (void) {writel(0, mmio_ptr + 0x00c4);} // Enable DDR3 memory controller
void x393_mcntrl_refresh_dis (void) {writel(0, mmio_ptr + 0x00c8);} // Disable DDR3 memory refresh
void x393_mcntrl_refresh_en (void) {writel(0, mmio_ptr + 0x00cc);} // Enable DDR3 memory refresh
void x393_mcntrl_sdrst_dis (void) {writel(0, mmio_ptr + 0x0098);} // Disable DDR3 memory reset
void x393_mcntrl_sdrst_en (void) {writel(0, mmio_ptr + 0x009c);} // Enable DDR3 memory reset
void x393_mcntrl_cke_dis (void) {writel(0, mmio_ptr + 0x00a0);} // Disable DDR3 memory CKE
void x393_mcntrl_cke_en (void) {writel(0, mmio_ptr + 0x00a4);} // Enable DDR3 memory CKE
void x393_mcntrl_cmda_dis (void) {writel(0, mmio_ptr + 0x0090);} // Disable DDR3 memory command/address lines
void x393_mcntrl_cmda_en (void) {writel(0, mmio_ptr + 0x0094);} // Enable DDR3 memory command/address lines
// Set DDR3 memory controller I/O delays and other timing parameters (should use individually calibrated values)
void set_x393_mcntrl_dq_odly0 (x393_dly_t d, int chn){writel(d.d32, mmio_ptr + (0x0200 + 0x4 * chn));} // Lane0 DQ output delays
x393_dly_t get_x393_mcntrl_dq_odly0 (int chn) { x393_dly_t d; d.d32 = readl(mmio_ptr + (0x0200 + 0x4 * chn)); return d; }
void set_x393_mcntrl_dq_odly1 (x393_dly_t d, int chn){writel(d.d32, mmio_ptr + (0x0280 + 0x4 * chn));} // Lane1 DQ output delays
x393_dly_t get_x393_mcntrl_dq_odly1 (int chn) { x393_dly_t d; d.d32 = readl(mmio_ptr + (0x0280 + 0x4 * chn)); return d; }
void set_x393_mcntrl_dq_idly0 (x393_dly_t d, int chn){writel(d.d32, mmio_ptr + (0x0240 + 0x4 * chn));} // Lane0 DQ input delays
x393_dly_t get_x393_mcntrl_dq_idly0 (int chn) { x393_dly_t d; d.d32 = readl(mmio_ptr + (0x0240 + 0x4 * chn)); return d; }
void set_x393_mcntrl_dq_idly1 (x393_dly_t d, int chn){writel(d.d32, mmio_ptr + (0x02c0 + 0x4 * chn));} // Lane1 DQ input delays
x393_dly_t get_x393_mcntrl_dq_idly1 (int chn) { x393_dly_t d; d.d32 = readl(mmio_ptr + (0x02c0 + 0x4 * chn)); return d; }
void set_x393_mcntrl_dqs_odly0 (x393_dly_t d) {writel(d.d32, mmio_ptr + 0x0220);} // Lane0 DQS output delay
x393_dly_t get_x393_mcntrl_dqs_odly0 (void) { x393_dly_t d; d.d32 = readl(mmio_ptr + 0x0220); return d; }
void set_x393_mcntrl_dqs_odly1 (x393_dly_t d) {writel(d.d32, mmio_ptr + 0x02a0);} // Lane1 DQS output delay
x393_dly_t get_x393_mcntrl_dqs_odly1 (void) { x393_dly_t d; d.d32 = readl(mmio_ptr + 0x02a0); return d; }
void set_x393_mcntrl_dqs_idly0 (x393_dly_t d) {writel(d.d32, mmio_ptr + 0x0260);} // Lane0 DQS input delay
x393_dly_t get_x393_mcntrl_dqs_idly0 (void) { x393_dly_t d; d.d32 = readl(mmio_ptr + 0x0260); return d; }
void set_x393_mcntrl_dqs_idly1 (x393_dly_t d) {writel(d.d32, mmio_ptr + 0x02e0);} // Lane1 DQS input delay
x393_dly_t get_x393_mcntrl_dqs_idly1 (void) { x393_dly_t d; d.d32 = readl(mmio_ptr + 0x02e0); return d; }
void set_x393_mcntrl_dm_odly0 (x393_dly_t d) {writel(d.d32, mmio_ptr + 0x0224);} // Lane0 DM output delay
x393_dly_t get_x393_mcntrl_dm_odly0 (void) { x393_dly_t d; d.d32 = readl(mmio_ptr + 0x0224); return d; }
void set_x393_mcntrl_dm_odly1 (x393_dly_t d) {writel(d.d32, mmio_ptr + 0x02a4);} // Lane1 DM output delay
x393_dly_t get_x393_mcntrl_dm_odly1 (void) { x393_dly_t d; d.d32 = readl(mmio_ptr + 0x02a4); return d; }
void set_x393_mcntrl_cmda_odly (x393_dly_t d, int chn){writel(d.d32, mmio_ptr + (0x0300 + 0x4 * chn));} // Address, bank and commands delays
x393_dly_t get_x393_mcntrl_cmda_odly (int chn) { x393_dly_t d; d.d32 = readl(mmio_ptr + (0x0300 + 0x4 * chn)); return d; }
void set_x393_mcntrl_phase (x393_dly_t d) {writel(d.d32, mmio_ptr + 0x0380);} // Clock phase
x393_dly_t get_x393_mcntrl_phase (void) { x393_dly_t d; d.d32 = readl(mmio_ptr + 0x0380); return d; }
void x393_mcntrl_dly_set (void) {writel(0, mmio_ptr + 0x0080);} // Set all pre-programmed delays
void set_x393_mcntrl_wbuf_dly (x393_wbuf_dly_t d) {writel(d.d32, mmio_ptr + 0x0148);} // Set write buffer delay
x393_wbuf_dly_t get_x393_mcntrl_wbuf_dly (void) { x393_wbuf_dly_t d; d.d32 = readl(mmio_ptr + 0x0148); return d; }
// Write-only addresses to program memory channels for sensors (chn = 0..3), memory channels 8..11
void x393_sens_mcntrl_scanline_mode (x393_mcntrl_mode_scan_t d, int chn){writel(d.d32, mmio_ptr + (0x1a00 + 0x40 * chn));} // Set mode register (write last after other channel registers are set)
void set_x393_sens_mcntrl_scanline_status_cntrl(x393_status_ctrl_t d, int chn){writel(d.d32, mmio_ptr + (0x1a04 + 0x40 * chn));} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_sens_mcntrl_scanline_status_cntrl(int chn) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + (0x1a04 + 0x40 * chn)); return d; }
void x393_sens_mcntrl_scanline_startaddr (x393_mcntrl_window_frame_sa_t d, int chn){writel(d.d32, mmio_ptr + (0x1a08 + 0x40 * chn));} // Set frame start address
void x393_sens_mcntrl_scanline_frame_size(x393_mcntrl_window_frame_sa_inc_t d, int chn){writel(d.d32, mmio_ptr + (0x1a0c + 0x40 * chn));} // Set frame size (address increment)
void x393_sens_mcntrl_scanline_frame_last(x393_mcntrl_window_last_frame_num_t d, int chn){writel(d.d32, mmio_ptr + (0x1a10 + 0x40 * chn));} // Set last frame number (number of frames in buffer minus 1)
void x393_sens_mcntrl_scanline_frame_full_width(x393_mcntrl_window_full_width_t d, int chn){writel(d.d32, mmio_ptr + (0x1a14 + 0x40 * chn));} // Set frame full(padded) width
void x393_sens_mcntrl_scanline_window_wh (x393_mcntrl_window_width_height_t d, int chn){writel(d.d32, mmio_ptr + (0x1a18 + 0x40 * chn));} // Set frame window size
void x393_sens_mcntrl_scanline_window_x0y0(x393_mcntrl_window_left_top_t d, int chn){writel(d.d32, mmio_ptr + (0x1a1c + 0x40 * chn));} // Set frame position
void x393_sens_mcntrl_scanline_startxy (x393_mcntrl_window_startx_starty_t d, int chn){writel(d.d32, mmio_ptr + (0x1a20 + 0x40 * chn));} // Set startXY register
// Write-only addresses to program memory channels for compressors (chn = 0..3), memory channels 12..15
void x393_sens_mcntrl_tiled_mode (x393_mcntrl_mode_scan_t d, int chn){writel(d.d32, mmio_ptr + (0x1b00 + 0x40 * chn));} // Set mode register (write last after other channel registers are set)
void set_x393_sens_mcntrl_tiled_status_cntrl(x393_status_ctrl_t d, int chn){writel(d.d32, mmio_ptr + (0x1b04 + 0x40 * chn));} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_sens_mcntrl_tiled_status_cntrl(int chn) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + (0x1b04 + 0x40 * chn)); return d; }
void x393_sens_mcntrl_tiled_startaddr (x393_mcntrl_window_frame_sa_t d, int chn){writel(d.d32, mmio_ptr + (0x1b08 + 0x40 * chn));} // Set frame start address
void x393_sens_mcntrl_tiled_frame_size (x393_mcntrl_window_frame_sa_inc_t d, int chn){writel(d.d32, mmio_ptr + (0x1b0c + 0x40 * chn));} // Set frame size (address increment)
void x393_sens_mcntrl_tiled_frame_last (x393_mcntrl_window_last_frame_num_t d, int chn){writel(d.d32, mmio_ptr + (0x1b10 + 0x40 * chn));} // Set last frame number (number of frames in buffer minus 1)
void x393_sens_mcntrl_tiled_frame_full_width(x393_mcntrl_window_full_width_t d, int chn){writel(d.d32, mmio_ptr + (0x1b14 + 0x40 * chn));} // Set frame full(padded) width
void x393_sens_mcntrl_tiled_window_wh (x393_mcntrl_window_width_height_t d, int chn){writel(d.d32, mmio_ptr + (0x1b18 + 0x40 * chn));} // Set frame window size
void x393_sens_mcntrl_tiled_window_x0y0 (x393_mcntrl_window_left_top_t d, int chn){writel(d.d32, mmio_ptr + (0x1b1c + 0x40 * chn));} // Set frame position
void x393_sens_mcntrl_tiled_startxy (x393_mcntrl_window_startx_starty_t d, int chn){writel(d.d32, mmio_ptr + (0x1b20 + 0x40 * chn));} // Set startXY register
void x393_sens_mcntrl_tiled_tile_whs (x393_mcntrl_window_tile_whs_t d, int chn){writel(d.d32, mmio_ptr + (0x1b24 + 0x40 * chn));} // Set tile size/step (tiled mode only)
// Write-only addresses to program memory channel for membridge, memory channel 1
void x393_membridge_scanline_mode (x393_mcntrl_mode_scan_t d){writel(d.d32, mmio_ptr + 0x0480);} // Set mode register (write last after other channel registers are set)
void set_x393_membridge_scanline_status_cntrl(x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x0484);} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_membridge_scanline_status_cntrl(void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x0484); return d; }
void x393_membridge_scanline_startaddr (x393_mcntrl_window_frame_sa_t d){writel(d.d32, mmio_ptr + 0x0488);} // Set frame start address
void x393_membridge_scanline_frame_size (x393_mcntrl_window_frame_sa_inc_t d){writel(d.d32, mmio_ptr + 0x048c);} // Set frame size (address increment)
void x393_membridge_scanline_frame_last (x393_mcntrl_window_last_frame_num_t d){writel(d.d32, mmio_ptr + 0x0490);} // Set last frame number (number of frames in buffer minus 1)
void x393_membridge_scanline_frame_full_width(x393_mcntrl_window_full_width_t d){writel(d.d32, mmio_ptr + 0x0494);} // Set frame full(padded) width
void x393_membridge_scanline_window_wh (x393_mcntrl_window_width_height_t d){writel(d.d32, mmio_ptr + 0x0498);} // Set frame window size
void x393_membridge_scanline_window_x0y0 (x393_mcntrl_window_left_top_t d){writel(d.d32, mmio_ptr + 0x049c);} // Set frame position
void x393_membridge_scanline_startxy (x393_mcntrl_window_startx_starty_t d){writel(d.d32, mmio_ptr + 0x04a0);} // Set startXY register
void x393_membridge_ctrl (x393_membridge_cmd_t d){writel(d.d32, mmio_ptr + 0x0800);} // Issue membridge command
void set_x393_membridge_status_cntrl (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x0804);} // Set membridge status control register
x393_status_ctrl_t get_x393_membridge_status_cntrl (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x0804); return d; }
void x393_membridge_lo_addr64 (u29_t d) {writel(d.d32, mmio_ptr + 0x0808);} // start address of the system memory range in QWORDs (4 LSBs==0)
void x393_membridge_size64 (u29_t d) {writel(d.d32, mmio_ptr + 0x080c);} // size of the system memory range in QWORDs (4 LSBs==0), rolls over
void x393_membridge_start64 (u29_t d) {writel(d.d32, mmio_ptr + 0x0810);} // start of transfer offset to system memory range in QWORDs (4 LSBs==0)
void x393_membridge_len64 (u29_t d) {writel(d.d32, mmio_ptr + 0x0814);} // Full length of transfer in QWORDs
void x393_membridge_width64 (u29_t d) {writel(d.d32, mmio_ptr + 0x0818);} // Frame width in QWORDs (last xfer in each line may be partial)
void x393_membridge_mode (x393_membridge_mode_t d){writel(d.d32, mmio_ptr + 0x081c);} // AXI cache mode
// Write-only addresses to PS PIO (Software generated DDR3 memory access sequences)
void x393_mcntrl_ps_en_rst (x393_ps_pio_en_rst_t d){writel(d.d32, mmio_ptr + 0x0400);} // Set PS PIO enable and reset
void x393_mcntrl_ps_cmd (x393_ps_pio_cmd_t d){writel(d.d32, mmio_ptr + 0x0404);} // Set PS PIO commands
void set_x393_mcntrl_ps_status_cntrl (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x0408);} // Set PS PIO status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_ps_status_cntrl (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x0408); return d; }
// Write-only addresses to to program status report mode for memory controller
void set_x393_mcontr_phy_status_cntrl (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x0150);} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcontr_phy_status_cntrl (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x0150); return d; }
void set_x393_mcontr_top_16bit_status_cntrl(x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x014c);} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcontr_top_16bit_status_cntrl(void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x014c); return d; }
// Write-only addresses to to program status report mode for test channels
void set_x393_mcntrl_test01_chn2_status_cntrl(x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x03d4);} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_test01_chn2_status_cntrl(void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x03d4); return d; }
void set_x393_mcntrl_test01_chn3_status_cntrl(x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x03dc);} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_test01_chn3_status_cntrl(void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x03dc); return d; }
void set_x393_mcntrl_test01_chn4_status_cntrl(x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x03e4);} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_test01_chn4_status_cntrl(void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x03e4); return d; }
// Write-only addresses for test channels commands
void x393_mcntrl_test01_chn2_mode (x393_test01_mode_t d){writel(d.d32, mmio_ptr + 0x03d0);} // Set command for test01 channel 2
void x393_mcntrl_test01_chn3_mode (x393_test01_mode_t d){writel(d.d32, mmio_ptr + 0x03d8);} // Set command for test01 channel 3
void x393_mcntrl_test01_chn4_mode (x393_test01_mode_t d){writel(d.d32, mmio_ptr + 0x03e0);} // Set command for test01 channel 4
// Read-only addresses for status information
x393_status_mcntrl_phy_t x393_mcontr_phy_status (void) { x393_status_mcntrl_phy_t d; d.d32 = readl(mmio_ptr + 0x2000); return d; } // Status register for MCNTRL PHY
x393_status_mcntrl_top_t x393_mcontr_top_status (void) { x393_status_mcntrl_top_t d; d.d32 = readl(mmio_ptr + 0x2004); return d; } // Status register for MCNTRL requests
x393_status_mcntrl_ps_t x393_mcntrl_ps_status (void) { x393_status_mcntrl_ps_t d; d.d32 = readl(mmio_ptr + 0x2008); return d; } // Status register for MCNTRL software R/W
x393_status_mcntrl_lintile_t x393_mcntrl_chn1_status (void) { x393_status_mcntrl_lintile_t d; d.d32 = readl(mmio_ptr + 0x2010); return d; } // Status register for MCNTRL CHN1 (membridge)
x393_status_mcntrl_lintile_t x393_mcntrl_chn3_status (void) { x393_status_mcntrl_lintile_t d; d.d32 = readl(mmio_ptr + 0x2018); return d; } // Status register for MCNTRL CHN3 (scanline)
x393_status_mcntrl_lintile_t x393_mcntrl_chn2_status (void) { x393_status_mcntrl_lintile_t d; d.d32 = readl(mmio_ptr + 0x2014); return d; } // Status register for MCNTRL CHN2 (tiled)
x393_status_mcntrl_lintile_t x393_mcntrl_chn4_status (void) { x393_status_mcntrl_lintile_t d; d.d32 = readl(mmio_ptr + 0x201c); return d; } // Status register for MCNTRL CHN4 (tiled)
x393_status_mcntrl_testchn_t x393_test01_chn2_status (void) { x393_status_mcntrl_testchn_t d; d.d32 = readl(mmio_ptr + 0x20f4); return d; } // Status register for test channel 2
x393_status_mcntrl_testchn_t x393_test01_chn3_status (void) { x393_status_mcntrl_testchn_t d; d.d32 = readl(mmio_ptr + 0x20f8); return d; } // Status register for test channel 3
x393_status_mcntrl_testchn_t x393_test01_chn4_status (void) { x393_status_mcntrl_testchn_t d; d.d32 = readl(mmio_ptr + 0x20fc); return d; } // Status register for test channel 4
x393_status_membridge_t x393_membridge_status (void) { x393_status_membridge_t d; d.d32 = readl(mmio_ptr + 0x20ec); return d; } // Status register for membridge
// Write-only control of the sensor channels
void x393_sens_mode (x393_sens_mode_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1000 + 0x100 * sens_num));} // Write sensor channel mode
void x393_sensi2c_ctrl (x393_i2c_ctltbl_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1008 + 0x100 * sens_num));} // Control sensor i2c, write i2c LUT
void set_x393_sensi2c_status_ctrl (x393_status_ctrl_t d, int sens_num){writel(d.d32, mmio_ptr + (0x100c + 0x100 * sens_num));} // Setup sensor i2c status report mode
x393_status_ctrl_t get_x393_sensi2c_status_ctrl (int sens_num) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + (0x100c + 0x100 * sens_num)); return d; }
void x393_sens_sync_mult (x393_sens_sync_mult_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1018 + 0x100 * sens_num));} // Configure frames combining
void x393_sens_sync_late (x393_sens_sync_late_t d, int sens_num){writel(d.d32, mmio_ptr + (0x101c + 0x100 * sens_num));} // Configure frame sync delay
void x393_sensio_ctrl (x393_sensio_ctl_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1020 + 0x100 * sens_num));} // Configure sensor I/O port
void set_x393_sensio_status_cntrl (x393_status_ctrl_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1024 + 0x100 * sens_num));} // Set status control for SENSIO module
x393_status_ctrl_t get_x393_sensio_status_cntrl (int sens_num) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + (0x1024 + 0x100 * sens_num)); return d; }
void x393_sensio_jtag (x393_sensio_jtag_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1028 + 0x100 * sens_num));} // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS)
void set_x393_sensio_width (x393_sensio_width_t d, int sens_num){writel(d.d32, mmio_ptr + (0x102c + 0x100 * sens_num));} // Set sensor line in pixels (0 - use line sync from the sensor)
x393_sensio_width_t get_x393_sensio_width (int sens_num) { x393_sensio_width_t d; d.d32 = readl(mmio_ptr + (0x102c + 0x100 * sens_num)); return d; }
void set_x393_sensio_tim0 (x393_sensio_tim0_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1030 + 0x100 * sens_num));} // Sensor port i/o timing configuration, register 0
x393_sensio_tim0_t get_x393_sensio_tim0 (int sens_num) { x393_sensio_tim0_t d; d.d32 = readl(mmio_ptr + (0x1030 + 0x100 * sens_num)); return d; }
void set_x393_sensio_tim1 (x393_sensio_tim1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1034 + 0x100 * sens_num));} // Sensor port i/o timing configuration, register 1
x393_sensio_tim1_t get_x393_sensio_tim1 (int sens_num) { x393_sensio_tim1_t d; d.d32 = readl(mmio_ptr + (0x1034 + 0x100 * sens_num)); return d; }
void set_x393_sensio_tim2 (x393_sensio_tim2_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1038 + 0x100 * sens_num));} // Sensor port i/o timing configuration, register 2
x393_sensio_tim2_t get_x393_sensio_tim2 (int sens_num) { x393_sensio_tim2_t d; d.d32 = readl(mmio_ptr + (0x1038 + 0x100 * sens_num)); return d; }
void set_x393_sensio_tim3 (x393_sensio_tim3_t d, int sens_num){writel(d.d32, mmio_ptr + (0x103c + 0x100 * sens_num));} // Sensor port i/o timing configuration, register 3
x393_sensio_tim3_t get_x393_sensio_tim3 (int sens_num) { x393_sensio_tim3_t d; d.d32 = readl(mmio_ptr + (0x103c + 0x100 * sens_num)); return d; }
// I2C command sequencer, block of 16 DWORD slots for absolute frame numbers (modulo 16) and 15 slots for relative ones
// 0 - ASAP, 1 next frame, 14 -14-th next.
// Data written depends on context:
// 1 - I2C register write: index page (MSB), 3 payload bytes. Payload bytes are used according to table and sent
// after the slave address and optional high address byte. Other bytes are sent in descending order (LSB- last).
// If less than 4 bytes are programmed in the table the high bytes (starting with the one from the table) are
// skipped.
// If more than 4 bytes are programmed in the table for the page (high byte), one or two next 32-bit words
// bypass the index table and all 4 bytes are considered payload ones. If less than 4 extra bytes are to be
// sent for such extra word, only the lower bytes are sent.
//
// 2 - I2C register read: index page, slave address (8-bit, with lower bit 0) and one or 2 address bytes (as programmed
// in the table. Slave address is always in byte 2 (bits 23:16), byte1 (high register address) is skipped if
// read address in the table is programmed to be a single-byte one
void x393_sensi2c_abs (u32 d, int sens_num, int offset){writel(d, mmio_ptr + (0x1040 + 0x40 * sens_num + 0x1 * offset));} // Write sensor i2c sequencer
void x393_sensi2c_rel (u32 d, int sens_num, int offset){writel(d, mmio_ptr + (0x1080 + 0x40 * sens_num + 0x1 * offset));} // Write sensor i2c sequencer
// Lens vignetting correction (for each sub-frame separately)
void set_x393_lens_height0_m1 (x393_lens_height_m1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10f0 + 0x100 * sens_num));} // Subframe 0 height minus 1
x393_lens_height_m1_t get_x393_lens_height0_m1 (int sens_num) { x393_lens_height_m1_t d; d.d32 = readl(mmio_ptr + (0x10f0 + 0x100 * sens_num)); return d; }
void set_x393_lens_height1_m1 (x393_lens_height_m1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10f4 + 0x100 * sens_num));} // Subframe 1 height minus 1
x393_lens_height_m1_t get_x393_lens_height1_m1 (int sens_num) { x393_lens_height_m1_t d; d.d32 = readl(mmio_ptr + (0x10f4 + 0x100 * sens_num)); return d; }
void set_x393_lens_height2_m1 (x393_lens_height_m1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10f8 + 0x100 * sens_num));} // Subframe 2 height minus 1
x393_lens_height_m1_t get_x393_lens_height2_m1 (int sens_num) { x393_lens_height_m1_t d; d.d32 = readl(mmio_ptr + (0x10f8 + 0x100 * sens_num)); return d; }
void x393_lens_corr_cnh_addr_data (x393_lens_corr_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10fc + 0x100 * sens_num));} // Combined address/data to write lens vignetting correction coefficients
// Lens vignetting coefficient addresses - use with x393_lens_corr_wo_t (X393_LENS_CORR_CNH_ADDR_DATA)
// Sensor gamma conversion control (See Python code for examples of the table data generation)
void set_x393_sens_gamma_ctrl (x393_gamma_ctl_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10e0 + 0x100 * sens_num));} // Gamma module control
x393_gamma_ctl_t get_x393_sens_gamma_ctrl (int sens_num) { x393_gamma_ctl_t d; d.d32 = readl(mmio_ptr + (0x10e0 + 0x100 * sens_num)); return d; }
void x393_sens_gamma_tbl (x393_gamma_tbl_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10e4 + 0x100 * sens_num));} // Write sensor gamma table address/data (with autoincrement)
void set_x393_sens_gamma_height01m1 (x393_gamma_height01m1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10e8 + 0x100 * sens_num));} // Gamma module subframes 0,1 heights minus 1
x393_gamma_height01m1_t get_x393_sens_gamma_height01m1 (int sens_num) { x393_gamma_height01m1_t d; d.d32 = readl(mmio_ptr + (0x10e8 + 0x100 * sens_num)); return d; }
void set_x393_sens_gamma_height2m1 (x393_gamma_height2m1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10ec + 0x100 * sens_num));} // Gamma module subframe 2 height minus 1
x393_gamma_height2m1_t get_x393_sens_gamma_height2m1 (int sens_num) { x393_gamma_height2m1_t d; d.d32 = readl(mmio_ptr + (0x10ec + 0x100 * sens_num)); return d; }
// Windows for histogram subchannels
void set_x393_histogram_lt0 (x393_hist_left_top_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10c0 + 0x100 * sens_num));} // Specify histogram 0 left/top
x393_hist_left_top_t get_x393_histogram_lt0 (int sens_num) { x393_hist_left_top_t d; d.d32 = readl(mmio_ptr + (0x10c0 + 0x100 * sens_num)); return d; }
void set_x393_histogram_wh0 (x393_hist_width_height_m1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10c4 + 0x100 * sens_num));} // Specify histogram 0 width/height
x393_hist_width_height_m1_t get_x393_histogram_wh0 (int sens_num) { x393_hist_width_height_m1_t d; d.d32 = readl(mmio_ptr + (0x10c4 + 0x100 * sens_num)); return d; }
void set_x393_histogram_lt1 (x393_hist_left_top_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10c8 + 0x100 * sens_num));} // Specify histogram 1 left/top
x393_hist_left_top_t get_x393_histogram_lt1 (int sens_num) { x393_hist_left_top_t d; d.d32 = readl(mmio_ptr + (0x10c8 + 0x100 * sens_num)); return d; }
void set_x393_histogram_wh1 (x393_hist_width_height_m1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10cc + 0x100 * sens_num));} // Specify histogram 1 width/height
x393_hist_width_height_m1_t get_x393_histogram_wh1 (int sens_num) { x393_hist_width_height_m1_t d; d.d32 = readl(mmio_ptr + (0x10cc + 0x100 * sens_num)); return d; }
void set_x393_histogram_lt2 (x393_hist_left_top_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10d0 + 0x100 * sens_num));} // Specify histogram 2 left/top
x393_hist_left_top_t get_x393_histogram_lt2 (int sens_num) { x393_hist_left_top_t d; d.d32 = readl(mmio_ptr + (0x10d0 + 0x100 * sens_num)); return d; }
void set_x393_histogram_wh2 (x393_hist_width_height_m1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10d4 + 0x100 * sens_num));} // Specify histogram 2 width/height
x393_hist_width_height_m1_t get_x393_histogram_wh2 (int sens_num) { x393_hist_width_height_m1_t d; d.d32 = readl(mmio_ptr + (0x10d4 + 0x100 * sens_num)); return d; }
void set_x393_histogram_lt3 (x393_hist_left_top_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10d8 + 0x100 * sens_num));} // Specify histogram 3 left/top
x393_hist_left_top_t get_x393_histogram_lt3 (int sens_num) { x393_hist_left_top_t d; d.d32 = readl(mmio_ptr + (0x10d8 + 0x100 * sens_num)); return d; }
void set_x393_histogram_wh3 (x393_hist_width_height_m1_t d, int sens_num){writel(d.d32, mmio_ptr + (0x10dc + 0x100 * sens_num));} // Specify histogram 3 width/height
x393_hist_width_height_m1_t get_x393_histogram_wh3 (int sens_num) { x393_hist_width_height_m1_t d; d.d32 = readl(mmio_ptr + (0x10dc + 0x100 * sens_num)); return d; }
// DMA control for the histograms. Subchannel here is 4*sensor_port+ histogram_subchannel
void set_x393_hist_saxi_mode (x393_hist_saxi_mode_t d){writel(d.d32, mmio_ptr + 0x1440);} // Histogram DMA operation mode
x393_hist_saxi_mode_t get_x393_hist_saxi_mode (void) { x393_hist_saxi_mode_t d; d.d32 = readl(mmio_ptr + 0x1440); return d; }
void set_x393_hist_saxi_addr (x393_hist_saxi_addr_t d, int subchannel){writel(d.d32, mmio_ptr + (0x1400 + 0x4 * subchannel));} // Histogram DMA addresses (in 4096 byte pages)
x393_hist_saxi_addr_t get_x393_hist_saxi_addr (int subchannel) { x393_hist_saxi_addr_t d; d.d32 = readl(mmio_ptr + (0x1400 + 0x4 * subchannel)); return d; }
// Read-only addresses for sensors status information
x393_status_sens_i2c_t x393_sensi2c_status (int sens_num) { x393_status_sens_i2c_t d; d.d32 = readl(mmio_ptr + (0x2080 + 0x8 * sens_num)); return d; } // Status of the sensors i2c
x393_status_sens_io_t x393_sensio_status (int sens_num) { x393_status_sens_io_t d; d.d32 = readl(mmio_ptr + (0x2084 + 0x8 * sens_num)); return d; } // Status of the sensor ports I/O pins
// Compressor bitfields values
// Compressor control
void x393_cmprs_control_reg (x393_cmprs_mode_t d, int cmprs_chn){writel(d.d32, mmio_ptr + (0x1800 + 0x40 * cmprs_chn));} // Program compressor channel operation mode
void set_x393_cmprs_status (x393_status_ctrl_t d, int cmprs_chn){writel(d.d32, mmio_ptr + (0x1804 + 0x40 * cmprs_chn));} // Setup compressor status report mode
x393_status_ctrl_t get_x393_cmprs_status (int cmprs_chn) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + (0x1804 + 0x40 * cmprs_chn)); return d; }
void set_x393_cmprs_format (x393_cmprs_frame_format_t d, int cmprs_chn){writel(d.d32, mmio_ptr + (0x1808 + 0x40 * cmprs_chn));} // Compressor frame format
x393_cmprs_frame_format_t get_x393_cmprs_format (int cmprs_chn) { x393_cmprs_frame_format_t d; d.d32 = readl(mmio_ptr + (0x1808 + 0x40 * cmprs_chn)); return d; }
void set_x393_cmprs_color_saturation (x393_cmprs_colorsat_t d, int cmprs_chn){writel(d.d32, mmio_ptr + (0x180c + 0x40 * cmprs_chn));} // Compressor color saturation
x393_cmprs_colorsat_t get_x393_cmprs_color_saturation (int cmprs_chn) { x393_cmprs_colorsat_t d; d.d32 = readl(mmio_ptr + (0x180c + 0x40 * cmprs_chn)); return d; }
void set_x393_cmprs_coring_mode (x393_cmprs_coring_mode_t d, int cmprs_chn){writel(d.d32, mmio_ptr + (0x1810 + 0x40 * cmprs_chn));} // Select coring mode
x393_cmprs_coring_mode_t get_x393_cmprs_coring_mode (int cmprs_chn) { x393_cmprs_coring_mode_t d; d.d32 = readl(mmio_ptr + (0x1810 + 0x40 * cmprs_chn)); return d; }
void x393_cmprs_interrupts (x393_cmprs_interrupts_t d, int cmprs_chn){writel(d.d32, mmio_ptr + (0x1814 + 0x40 * cmprs_chn));} // Compressor interrupts control (1 - clear, 2 - disable, 3 - enable)
// Compressor tables load control
// Several tables can be loaded to the compressor, there are 4 types of them:
// 0:quantization tables - 8 pairs can be loaded and switched at run time,
// 1:coring tables - 8 pairs can be loaded and switched at run time,
// 2:focusing tables - 15 tables can be loaded and switched at run time (16-th table address space
// is used to program other focusing mode parameters,
// 3:Huffman tables - 1 pair tables can be loaded
// Default tables are loaded with the bitstream file (100% quality for quantization table 0
// Loading a table requires to load address of the beginning of data, it includes table type and optional offset
// when multiple tables of the same type are used. Next the data should be written to the same register address,
// the table address is auto-incremented,
// Data for the tables 0..2 should be combined: two items into a single 32-bit DWORD (little endian), treating
// each item as a 16-bit word. The Huffman table is one item per DWORD. Address offset is calculated in DWORDs
// Compressor table types
// Compressor tables control
void x393_cmprs_tables_data (u32 d, int cmprs_chn){writel(d, mmio_ptr + (0x1818 + 0x40 * cmprs_chn));} // Compressor tables data
void x393_cmprs_tables_address (x393_cmprs_table_addr_t d, int cmprs_chn){writel(d.d32, mmio_ptr + (0x181c + 0x40 * cmprs_chn));} // Compressor tables type/address
// Compressor channel status)
x393_cmprs_status_t x393_cmprs_status (int chn) { x393_cmprs_status_t d; d.d32 = readl(mmio_ptr + (0x2040 + 0x4 * chn)); return d; } // Status of the compressor channel (incl. interrupt
u32 x393_cmprs_hifreq (int chn) { u32 d; d = readl(mmio_ptr + (0x2050 + 0x4 * chn)); return d; } // Focus helper high-frequency amount
// Compressor DMA control:
// Camera can be configured to use either 2 AXI HP channels (with 2 compressors served by each one) or to use a single AXI HP channel
// serving all 4 compressor channels through its input ports. Below afi_port (0..3) references to one of the 4 ports of each. Control
// for two AXI HP channels is implemented as separate functions. Currently only the first channel is used
void x393_afimux0_en (x393_afimux_en_t d){writel(d.d32, mmio_ptr + 0x1900);} // AFI MUX 0 global/port run/pause control
void set_x393_afimux0_rst (x393_afimux_rst_t d){writel(d.d32, mmio_ptr + 0x1904);} // AFI MUX 0 per-port resets
x393_afimux_rst_t get_x393_afimux0_rst (void) { x393_afimux_rst_t d; d.d32 = readl(mmio_ptr + 0x1904); return d; }
void x393_afimux0_report_mode (x393_afimux_report_t d){writel(d.d32, mmio_ptr + 0x1908);} // AFI MUX 0 readout pointer report mode
void set_x393_afimux0_status_control (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x1910);} // AFI MUX 0 status report mode
x393_status_ctrl_t get_x393_afimux0_status_control (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x1910); return d; }
void set_x393_afimux0_sa (x393_afimux_sa_t d, int afi_port){writel(d.d32, mmio_ptr + (0x1920 + 0x4 * afi_port));} // AFI MUX 0 DMA buffer start address in 32-byte blocks
x393_afimux_sa_t get_x393_afimux0_sa (int afi_port) { x393_afimux_sa_t d; d.d32 = readl(mmio_ptr + (0x1920 + 0x4 * afi_port)); return d; }
void set_x393_afimux0_len (x393_afimux_len_t d, int afi_port){writel(d.d32, mmio_ptr + (0x1930 + 0x4 * afi_port));} // AFI MUX 0 DMA buffer length in 32-byte blocks
x393_afimux_len_t get_x393_afimux0_len (int afi_port) { x393_afimux_len_t d; d.d32 = readl(mmio_ptr + (0x1930 + 0x4 * afi_port)); return d; }
// Same for the second AXI HP channel (not currently used)
void x393_afimux1_en (x393_afimux_en_t d){writel(d.d32, mmio_ptr + 0x1940);} // AFI MUX 1 global/port run/pause control
void set_x393_afimux1_rst (x393_afimux_rst_t d){writel(d.d32, mmio_ptr + 0x1944);} // AFI MUX 1 per-port resets
x393_afimux_rst_t get_x393_afimux1_rst (void) { x393_afimux_rst_t d; d.d32 = readl(mmio_ptr + 0x1944); return d; }
void x393_afimux1_report_mode (x393_afimux_report_t d){writel(d.d32, mmio_ptr + 0x1948);} // AFI MUX 1 readout pointer report mode
void set_x393_afimux1_status_control (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x1950);} // AFI MUX 1 status report mode
x393_status_ctrl_t get_x393_afimux1_status_control (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x1950); return d; }
void set_x393_afimux1_sa (x393_afimux_sa_t d, int afi_port){writel(d.d32, mmio_ptr + (0x1960 + 0x4 * afi_port));} // AFI MUX 1 DMA buffer start address in 32-byte blocks
x393_afimux_sa_t get_x393_afimux1_sa (int afi_port) { x393_afimux_sa_t d; d.d32 = readl(mmio_ptr + (0x1960 + 0x4 * afi_port)); return d; }
void set_x393_afimux1_len (x393_afimux_len_t d, int afi_port){writel(d.d32, mmio_ptr + (0x1970 + 0x4 * afi_port));} // AFI MUX 1 DMA buffer length in 32-byte blocks
x393_afimux_len_t get_x393_afimux1_len (int afi_port) { x393_afimux_len_t d; d.d32 = readl(mmio_ptr + (0x1970 + 0x4 * afi_port)); return d; }
// Read-only sensors status information (pointer offset and last sequence number)
x393_afimux_status_t x393_afimux0_status (int afi_port) { x393_afimux_status_t d; d.d32 = readl(mmio_ptr + (0x2060 + 0x4 * afi_port)); return d; } // Status of the AFI MUX 0 (including image pointer)
x393_afimux_status_t x393_afimux1_status (int afi_port) { x393_afimux_status_t d; d.d32 = readl(mmio_ptr + (0x2070 + 0x4 * afi_port)); return d; } // Status of the AFI MUX 1 (including image pointer)
//
// GPIO contol. Each of the 10 pins can be controlled by the software - individually or simultaneously or from any of the 3 masters (other FPGA modules)
// Currently these modules are;
// A - camsync (intercamera synchronization), uses up to 4 pins
// B - reserved (not yet used) and
// C - logger (IMU, GPS, images), uses 6 pins, including separate i2c available on extension boards
// If several enabled ports try to contol the same bit, highest priority has port C, lowest - software controlled
void x393_gpio_set_pins (x393_gpio_set_pins_t d){writel(d.d32, mmio_ptr + 0x1c00);} // State of the GPIO pins and seq. number
void set_x393_gpio_status_control (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x1c04);} // GPIO status control mode
x393_status_ctrl_t get_x393_gpio_status_control (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x1c04); return d; }
// Read-only GPIO pins state
x393_gpio_status_t x393_gpio_status (void) { x393_gpio_status_t d; d.d32 = readl(mmio_ptr + 0x20c0); return d; } // State of the GPIO pins and seq. number
// RTC control
void set_x393_rtc_usec (x393_rtc_usec_t d) {writel(d.d32, mmio_ptr + 0x1c10);} // RTC microseconds
x393_rtc_usec_t get_x393_rtc_usec (void) { x393_rtc_usec_t d; d.d32 = readl(mmio_ptr + 0x1c10); return d; }
void set_x393_rtc_sec_set (x393_rtc_sec_t d) {writel(d.d32, mmio_ptr + 0x1c14);} // RTC seconds and set clock
x393_rtc_sec_t get_x393_rtc_sec_set (void) { x393_rtc_sec_t d; d.d32 = readl(mmio_ptr + 0x1c14); return d; }
void set_x393_rtc_corr (x393_rtc_corr_t d) {writel(d.d32, mmio_ptr + 0x1c18);} // RTC correction (+/- 1/256 full scale)
x393_rtc_corr_t get_x393_rtc_corr (void) { x393_rtc_corr_t d; d.d32 = readl(mmio_ptr + 0x1c18); return d; }
void set_x393_rtc_set_status (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x1c1c);} // RTC status control mode, write makes a snapshot to be read out
x393_status_ctrl_t get_x393_rtc_set_status (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x1c1c); return d; }
// Read-only RTC state
x393_rtc_status_t x393_rtc_status (void) { x393_rtc_status_t d; d.d32 = readl(mmio_ptr + 0x20c4); return d; } // RTC status reg
x393_rtc_sec_t x393_rtc_status_sec (void) { x393_rtc_sec_t d; d.d32 = readl(mmio_ptr + 0x20c8); return d; } // RTC snapshot seconds
x393_rtc_usec_t x393_rtc_status_usec (void) { x393_rtc_usec_t d; d.d32 = readl(mmio_ptr + 0x20cc); return d; } // RTC snapshot microseconds
// CAMSYNC control
void x393_camsync_mode (x393_camsync_mode_t d){writel(d.d32, mmio_ptr + 0x1c20);} // CAMSYNC mode
void x393_camsync_trig_src (x393_camsync_io_t d){writel(d.d32, mmio_ptr + 0x1c24);} // CAMSYNC trigger source
void x393_camsync_trig_dst (x393_camsync_io_t d){writel(d.d32, mmio_ptr + 0x1c28);} // CAMSYNC trigger destination
// Trigger period has special value for small (<255) values written to this register
// d == 0 - disable (stop periodic mode)
// d == 1 - single trigger
// d == 2..255 - set output pulse / input-output serial bit duration (no start generated)
// d >= 256 - repetitive trigger
void set_x393_camsync_trig_period (u32 d) {writel(d, mmio_ptr + 0x1c2c);} // CAMSYNC trigger period
u32 get_x393_camsync_trig_period (void) { u32 d; d = readl(mmio_ptr + 0x1c2c); return d; }
void set_x393_camsync_trig_delay (u32 d, int sens_chn){writel(d, mmio_ptr + (0x1c30 + 0x4 * sens_chn));} // CAMSYNC trigger delay
u32 get_x393_camsync_trig_delay (int sens_chn) { u32 d; d = readl(mmio_ptr + (0x1c30 + 0x4 * sens_chn)); return d; }
// Command sequencer control
// Controller is programmed through 32 locations. Each registers but the control require two writes:
// First write - register address (AXI_WR_ADDR_BITS bits), second - register data (32 bits)
// Writing to the contol register (0x1f) resets the first/second counter so the next write will be "first"
// 0x0..0xf write directly to the frame number [3:0] modulo 16, except if you write to the frame
// "just missed" - in that case data will go to the current frame.
// 0x10 - write seq commands to be sent ASAP
// 0x11 - write seq commands to be sent after the next frame starts
//
// 0x1e - write seq commands to be sent after the next 14 frame start pulses
// 0x1f - control register:
// [14] - reset all FIFO (takes 32 clock pulses), also - stops seq until run command
// [13:12] - 3 - run seq, 2 - stop seq , 1,0 - no change to run state
// [1:0] - 0: NOP, 1: clear IRQ, 2 - Clear IE, 3: set IE
void x393_cmdframeseq_ctrl (x393_cmdframeseq_mode_t d, int sens_chn){writel(d.d32, mmio_ptr + (0x1e7c + 0x80 * sens_chn));} // CMDFRAMESEQ control register
void x393_cmdframeseq_abs (u32 d, int sens_chn, int offset){writel(d, mmio_ptr + (0x1e00 + 0x20 * sens_chn + 0x1 * offset));} // CMDFRAMESEQ absolute frame address/command
void x393_cmdframeseq_rel (u32 d, int sens_chn, int offset){writel(d, mmio_ptr + (0x1e40 + 0x20 * sens_chn + 0x1 * offset));} // CMDFRAMESEQ relative frame address/command
// Command sequencer multiplexer, provides current frame number for each sensor channel and interrupt status/interrupt masks for them.
// Interrupts and interrupt masks are controlled through channel CMDFRAMESEQ module
void set_x393_cmdseqmux_status_ctrl (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x1c08);} // CMDSEQMUX status control mode (status provides current frame numbers)
x393_status_ctrl_t get_x393_cmdseqmux_status_ctrl (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x1c08); return d; }
x393_cmdseqmux_status_t x393_cmdseqmux_status (void) { x393_cmdseqmux_status_t d; d.d32 = readl(mmio_ptr + 0x20e0); return d; } // CMDSEQMUX status data (frame numbers and interrupts
// Event logger
// Event logger configuration/data is writtent to the module ising two 32-bit register locations : data and address.
// Address consists of 2 parts - 2-bit page (configuration, imu, gps, message) and a 5-bit sub-address autoincremented when writing data.
// Register pages:
// Register configuration addresses (with X393_LOGGER_PAGE_CONF):
void set_x393_logger_status_ctrl (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x1c88);} // Logger status configuration (to report sample number)
x393_status_ctrl_t get_x393_logger_status_ctrl (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x1c88); return d; }
void x393_logger_data (x393_logger_data_t d){writel(d.d32, mmio_ptr + 0x1c80);} // Logger register write data
void x393_logger_address (x393_logger_address_t d){writel(d.d32, mmio_ptr + 0x1c84);} // Logger register write page/address
x393_logger_status_t x393_logger_status (void) { x393_logger_status_t d; d.d32 = readl(mmio_ptr + 0x20e4); return d; } // Logger status data (sequence number)
// MULT SAXI DMA engine control. Of 4 channels only one (number 0) is currently used - for the event logger
void set_x393_mult_saxi_status_ctrl (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x1ce0);} // MULT_SAXI status control mode (status provides current DWORD pointer)
x393_status_ctrl_t get_x393_mult_saxi_status_ctrl (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x1ce0); return d; }
void x393_mult_saxi_buf_address (x393_mult_saxi_al_t d, int chn){writel(d.d32, mmio_ptr + (0x1cc0 + 0x8 * chn));} // MULT_SAXI buffer start address in DWORDS
void x393_mult_saxi_buf_len (x393_mult_saxi_al_t d, int chn){writel(d.d32, mmio_ptr + (0x1cc4 + 0x8 * chn));} // MULT_SAXI buffer length in DWORDS
x393_mult_saxi_al_t x393_mult_saxi_status (int chn) { x393_mult_saxi_al_t d; d.d32 = readl(mmio_ptr + (0x20d0 + 0x4 * chn)); return d; } // MULT_SAXI current DWORD pointer
// MULTI_CLK - global clock generation PLLs. Interface provided for debugging, no interaction is needed for normal operation
void set_x393_multiclk_status_ctrl (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x1ca4);} // MULTI_CLK status generation (do not use or do not set auto)
x393_status_ctrl_t get_x393_multiclk_status_ctrl (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x1ca4); return d; }
void set_x393_multiclk_ctrl (x393_multiclk_ctl_t d){writel(d.d32, mmio_ptr + 0x1ca0);} // MULTI_CLK reset and power down control
x393_multiclk_ctl_t get_x393_multiclk_ctrl (void) { x393_multiclk_ctl_t d; d.d32 = readl(mmio_ptr + 0x1ca0); return d; }
x393_multiclk_status_t x393_multiclk_status (void) { x393_multiclk_status_t d; d.d32 = readl(mmio_ptr + 0x20e8); return d; } // MULTI_CLK lock and toggle state
// Debug ring module
// Debug ring module (when enabled with DEBUG_RING in system_defines.vh) provides low-overhead read/write access to internal test points
// To write data you need to write 32-bit data with x393_debug_shift(u32) multiple times to fill the ring register (length depends on
// implementation), skip this step if only reading from the modules under test is required.
// Exchange data with x393_debug_load(), the data from the ring shift register.
// Write 0xffffffff (or other "magic" data) if the ring length is unknown - this DWORD will appear on the output after the useful data
// Read all data, waiting for status sequence number to be incremented,status mode should be set to auto (3) wor each DWORD certain
// number of times or until the "magic" DWORD appears, writing "magic" to shift out next 32 bits.
void set_x393_debug_status_ctrl (x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x1c48);} // Debug ring status generation - set to auto(3) if used
x393_status_ctrl_t get_x393_debug_status_ctrl (void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x1c48); return d; }
void x393_debug_load (void) {writel(0, mmio_ptr + 0x1c44);} // Debug ring copy shift register to/from tested modules
void x393_debug_shift (u32 d) {writel(d, mmio_ptr + 0x1c40);} // Debug ring shift ring by 32 bits
x393_debug_status_t x393_debug_status (void) { x393_debug_status_t d; d.d32 = readl(mmio_ptr + 0x23f0); return d; } // Debug read status (watch sequence number)
u32 x393_debug_read (void) { u32 d; d = readl(mmio_ptr + 0x23f4); return d; } // Debug read DWORD form ring register
// Write-only addresses to program memory channel 3 (test channel)
void x393_mcntrl_chn3_scanline_mode (x393_mcntrl_mode_scan_t d){writel(d.d32, mmio_ptr + 0x04c0);} // Set mode register (write last after other channel registers are set)
void set_x393_mcntrl_chn3_scanline_status_cntrl(x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x04c4);} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_chn3_scanline_status_cntrl(void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x04c4); return d; }
void x393_mcntrl_chn3_scanline_startaddr (x393_mcntrl_window_frame_sa_t d){writel(d.d32, mmio_ptr + 0x04c8);} // Set frame start address
void x393_mcntrl_chn3_scanline_frame_size(x393_mcntrl_window_frame_sa_inc_t d){writel(d.d32, mmio_ptr + 0x04cc);} // Set frame size (address increment)
void x393_mcntrl_chn3_scanline_frame_last(x393_mcntrl_window_last_frame_num_t d){writel(d.d32, mmio_ptr + 0x04d0);} // Set last frame number (number of frames in buffer minus 1)
void x393_mcntrl_chn3_scanline_frame_full_width(x393_mcntrl_window_full_width_t d){writel(d.d32, mmio_ptr + 0x04d4);} // Set frame full(padded) width
void x393_mcntrl_chn3_scanline_window_wh (x393_mcntrl_window_width_height_t d){writel(d.d32, mmio_ptr + 0x04d8);} // Set frame window size
void x393_mcntrl_chn3_scanline_window_x0y0(x393_mcntrl_window_left_top_t d){writel(d.d32, mmio_ptr + 0x04dc);} // Set frame position
void x393_mcntrl_chn3_scanline_startxy (x393_mcntrl_window_startx_starty_t d){writel(d.d32, mmio_ptr + 0x04e0);} // Set startXY register
// Write-only addresses to program memory channel 2 (test channel)
void x393_mcntrl_chn2_tiled_mode (x393_mcntrl_mode_scan_t d){writel(d.d32, mmio_ptr + 0x0500);} // Set mode register (write last after other channel registers are set)
void set_x393_mcntrl_chn2_tiled_status_cntrl(x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x0504);} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_chn2_tiled_status_cntrl(void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x0504); return d; }
void x393_mcntrl_chn2_tiled_startaddr (x393_mcntrl_window_frame_sa_t d){writel(d.d32, mmio_ptr + 0x0508);} // Set frame start address
void x393_mcntrl_chn2_tiled_frame_size (x393_mcntrl_window_frame_sa_inc_t d){writel(d.d32, mmio_ptr + 0x050c);} // Set frame size (address increment)
void x393_mcntrl_chn2_tiled_frame_last (x393_mcntrl_window_last_frame_num_t d){writel(d.d32, mmio_ptr + 0x0510);} // Set last frame number (number of frames in buffer minus 1)
void x393_mcntrl_chn2_tiled_frame_full_width(x393_mcntrl_window_full_width_t d){writel(d.d32, mmio_ptr + 0x0514);} // Set frame full(padded) width
void x393_mcntrl_chn2_tiled_window_wh (x393_mcntrl_window_width_height_t d){writel(d.d32, mmio_ptr + 0x0518);} // Set frame window size
void x393_mcntrl_chn2_tiled_window_x0y0 (x393_mcntrl_window_left_top_t d){writel(d.d32, mmio_ptr + 0x051c);} // Set frame position
void x393_mcntrl_chn2_tiled_startxy (x393_mcntrl_window_startx_starty_t d){writel(d.d32, mmio_ptr + 0x0520);} // Set startXY register
void x393_mcntrl_chn2_tiled_tile_whs (x393_mcntrl_window_tile_whs_t d){writel(d.d32, mmio_ptr + 0x0524);} // Set tile size/step (tiled mode only)
// Write-only addresses to program memory channel 4 (test channel)
void x393_mcntrl_chn4_tiled_mode (x393_mcntrl_mode_scan_t d){writel(d.d32, mmio_ptr + 0x0540);} // Set mode register (write last after other channel registers are set)
void set_x393_mcntrl_chn4_tiled_status_cntrl(x393_status_ctrl_t d){writel(d.d32, mmio_ptr + 0x0544);} // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_chn4_tiled_status_cntrl(void) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + 0x0544); return d; }
void x393_mcntrl_chn4_tiled_startaddr (x393_mcntrl_window_frame_sa_t d){writel(d.d32, mmio_ptr + 0x0548);} // Set frame start address
void x393_mcntrl_chn4_tiled_frame_size (x393_mcntrl_window_frame_sa_inc_t d){writel(d.d32, mmio_ptr + 0x054c);} // Set frame size (address increment)
void x393_mcntrl_chn4_tiled_frame_last (x393_mcntrl_window_last_frame_num_t d){writel(d.d32, mmio_ptr + 0x0550);} // Set last frame number (number of frames in buffer minus 1)
void x393_mcntrl_chn4_tiled_frame_full_width(x393_mcntrl_window_full_width_t d){writel(d.d32, mmio_ptr + 0x0554);} // Set frame full(padded) width
void x393_mcntrl_chn4_tiled_window_wh (x393_mcntrl_window_width_height_t d){writel(d.d32, mmio_ptr + 0x0558);} // Set frame window size
void x393_mcntrl_chn4_tiled_window_x0y0 (x393_mcntrl_window_left_top_t d){writel(d.d32, mmio_ptr + 0x055c);} // Set frame position
void x393_mcntrl_chn4_tiled_startxy (x393_mcntrl_window_startx_starty_t d){writel(d.d32, mmio_ptr + 0x0560);} // Set startXY register
void x393_mcntrl_chn4_tiled_tile_whs (x393_mcntrl_window_tile_whs_t d){writel(d.d32, mmio_ptr + 0x0564);} // Set tile size/step (tiled mode only)
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/x393.h 0000664 0000000 0000000 00000146707 12703306510 0025762 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* File: x393.h
* Date: 2016-04-06
* Author: auto-generated file, see x393_export_c.py
* Description: Constants definitions and functions declarations to access x393 hardware registers
*******************************************************************************/
#include "x393_types.h"
//#include "elphel/x393_defs.h // alternative variant"
// See elphel/x393_map.h for the ordered list of all I/O register addresses used
// init_mmio_ptr() should be called once before using any of the other declared functions
int init_mmio_ptr(void);
// R/W addresses to set up memory arbiter priorities. For sensors (chn = 8..11), for compressors - 12..15
void set_x393_mcntrl_arbiter_priority (x393_arbite_pri_t d, int chn); // Set memory arbiter priority (currently r/w, may become just wo)
x393_arbite_pri_t get_x393_mcntrl_arbiter_priority (int chn);
// Enable/disable memory channels (bits in a 16-bit word). For sensors (chn = 8..11), for compressors - 12..15
void set_x393_mcntrl_chn_en (x393_mcntr_chn_en_t d); // Enable/disable memory channels (currently r/w, may become just wo)
x393_mcntr_chn_en_t get_x393_mcntrl_chn_en (void);
void set_x393_mcntrl_dqs_dqm_patt (x393_mcntr_dqs_dqm_patt_t d); // Setup DQS and DQM patterns
x393_mcntr_dqs_dqm_patt_t get_x393_mcntrl_dqs_dqm_patt (void);
void set_x393_mcntrl_dq_dqs_tri (x393_mcntr_dqs_dqm_tri_t d); // Setup DQS and DQ on/off sequence
x393_mcntr_dqs_dqm_tri_t get_x393_mcntrl_dq_dqs_tri (void);
// Following enable/disable addresses can be written with any data, only addresses matter
void x393_mcntrl_dis (void); // Disable DDR3 memory controller
void x393_mcntrl_en (void); // Enable DDR3 memory controller
void x393_mcntrl_refresh_dis (void); // Disable DDR3 memory refresh
void x393_mcntrl_refresh_en (void); // Enable DDR3 memory refresh
void x393_mcntrl_sdrst_dis (void); // Disable DDR3 memory reset
void x393_mcntrl_sdrst_en (void); // Enable DDR3 memory reset
void x393_mcntrl_cke_dis (void); // Disable DDR3 memory CKE
void x393_mcntrl_cke_en (void); // Enable DDR3 memory CKE
void x393_mcntrl_cmda_dis (void); // Disable DDR3 memory command/address lines
void x393_mcntrl_cmda_en (void); // Enable DDR3 memory command/address lines
// Set DDR3 memory controller I/O delays and other timing parameters (should use individually calibrated values)
void set_x393_mcntrl_dq_odly0 (x393_dly_t d, int chn); // Lane0 DQ output delays
x393_dly_t get_x393_mcntrl_dq_odly0 (int chn);
void set_x393_mcntrl_dq_odly1 (x393_dly_t d, int chn); // Lane1 DQ output delays
x393_dly_t get_x393_mcntrl_dq_odly1 (int chn);
void set_x393_mcntrl_dq_idly0 (x393_dly_t d, int chn); // Lane0 DQ input delays
x393_dly_t get_x393_mcntrl_dq_idly0 (int chn);
void set_x393_mcntrl_dq_idly1 (x393_dly_t d, int chn); // Lane1 DQ input delays
x393_dly_t get_x393_mcntrl_dq_idly1 (int chn);
void set_x393_mcntrl_dqs_odly0 (x393_dly_t d); // Lane0 DQS output delay
x393_dly_t get_x393_mcntrl_dqs_odly0 (void);
void set_x393_mcntrl_dqs_odly1 (x393_dly_t d); // Lane1 DQS output delay
x393_dly_t get_x393_mcntrl_dqs_odly1 (void);
void set_x393_mcntrl_dqs_idly0 (x393_dly_t d); // Lane0 DQS input delay
x393_dly_t get_x393_mcntrl_dqs_idly0 (void);
void set_x393_mcntrl_dqs_idly1 (x393_dly_t d); // Lane1 DQS input delay
x393_dly_t get_x393_mcntrl_dqs_idly1 (void);
void set_x393_mcntrl_dm_odly0 (x393_dly_t d); // Lane0 DM output delay
x393_dly_t get_x393_mcntrl_dm_odly0 (void);
void set_x393_mcntrl_dm_odly1 (x393_dly_t d); // Lane1 DM output delay
x393_dly_t get_x393_mcntrl_dm_odly1 (void);
void set_x393_mcntrl_cmda_odly (x393_dly_t d, int chn); // Address, bank and commands delays
x393_dly_t get_x393_mcntrl_cmda_odly (int chn);
void set_x393_mcntrl_phase (x393_dly_t d); // Clock phase
x393_dly_t get_x393_mcntrl_phase (void);
void x393_mcntrl_dly_set (void); // Set all pre-programmed delays
void set_x393_mcntrl_wbuf_dly (x393_wbuf_dly_t d); // Set write buffer delay
x393_wbuf_dly_t get_x393_mcntrl_wbuf_dly (void);
// Write-only addresses to program memory channels for sensors (chn = 0..3), memory channels 8..11
void x393_sens_mcntrl_scanline_mode (x393_mcntrl_mode_scan_t d, int chn); // Set mode register (write last after other channel registers are set)
void set_x393_sens_mcntrl_scanline_status_cntrl(x393_status_ctrl_t d, int chn); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_sens_mcntrl_scanline_status_cntrl(int chn);
void x393_sens_mcntrl_scanline_startaddr (x393_mcntrl_window_frame_sa_t d, int chn); // Set frame start address
void x393_sens_mcntrl_scanline_frame_size(x393_mcntrl_window_frame_sa_inc_t d, int chn); // Set frame size (address increment)
void x393_sens_mcntrl_scanline_frame_last(x393_mcntrl_window_last_frame_num_t d, int chn); // Set last frame number (number of frames in buffer minus 1)
void x393_sens_mcntrl_scanline_frame_full_width(x393_mcntrl_window_full_width_t d, int chn); // Set frame full(padded) width
void x393_sens_mcntrl_scanline_window_wh (x393_mcntrl_window_width_height_t d, int chn); // Set frame window size
void x393_sens_mcntrl_scanline_window_x0y0(x393_mcntrl_window_left_top_t d, int chn); // Set frame position
void x393_sens_mcntrl_scanline_startxy (x393_mcntrl_window_startx_starty_t d, int chn); // Set startXY register
// Write-only addresses to program memory channels for compressors (chn = 0..3), memory channels 12..15
void x393_sens_mcntrl_tiled_mode (x393_mcntrl_mode_scan_t d, int chn); // Set mode register (write last after other channel registers are set)
void set_x393_sens_mcntrl_tiled_status_cntrl(x393_status_ctrl_t d, int chn); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_sens_mcntrl_tiled_status_cntrl(int chn);
void x393_sens_mcntrl_tiled_startaddr (x393_mcntrl_window_frame_sa_t d, int chn); // Set frame start address
void x393_sens_mcntrl_tiled_frame_size (x393_mcntrl_window_frame_sa_inc_t d, int chn); // Set frame size (address increment)
void x393_sens_mcntrl_tiled_frame_last (x393_mcntrl_window_last_frame_num_t d, int chn); // Set last frame number (number of frames in buffer minus 1)
void x393_sens_mcntrl_tiled_frame_full_width(x393_mcntrl_window_full_width_t d, int chn); // Set frame full(padded) width
void x393_sens_mcntrl_tiled_window_wh (x393_mcntrl_window_width_height_t d, int chn); // Set frame window size
void x393_sens_mcntrl_tiled_window_x0y0 (x393_mcntrl_window_left_top_t d, int chn); // Set frame position
void x393_sens_mcntrl_tiled_startxy (x393_mcntrl_window_startx_starty_t d, int chn); // Set startXY register
void x393_sens_mcntrl_tiled_tile_whs (x393_mcntrl_window_tile_whs_t d, int chn); // Set tile size/step (tiled mode only)
// Write-only addresses to program memory channel for membridge, memory channel 1
void x393_membridge_scanline_mode (x393_mcntrl_mode_scan_t d); // Set mode register (write last after other channel registers are set)
void set_x393_membridge_scanline_status_cntrl(x393_status_ctrl_t d); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_membridge_scanline_status_cntrl(void);
void x393_membridge_scanline_startaddr (x393_mcntrl_window_frame_sa_t d); // Set frame start address
void x393_membridge_scanline_frame_size (x393_mcntrl_window_frame_sa_inc_t d); // Set frame size (address increment)
void x393_membridge_scanline_frame_last (x393_mcntrl_window_last_frame_num_t d); // Set last frame number (number of frames in buffer minus 1)
void x393_membridge_scanline_frame_full_width(x393_mcntrl_window_full_width_t d); // Set frame full(padded) width
void x393_membridge_scanline_window_wh (x393_mcntrl_window_width_height_t d); // Set frame window size
void x393_membridge_scanline_window_x0y0 (x393_mcntrl_window_left_top_t d); // Set frame position
void x393_membridge_scanline_startxy (x393_mcntrl_window_startx_starty_t d); // Set startXY register
void x393_membridge_ctrl (x393_membridge_cmd_t d); // Issue membridge command
void set_x393_membridge_status_cntrl (x393_status_ctrl_t d); // Set membridge status control register
x393_status_ctrl_t get_x393_membridge_status_cntrl (void);
void x393_membridge_lo_addr64 (u29_t d); // start address of the system memory range in QWORDs (4 LSBs==0)
void x393_membridge_size64 (u29_t d); // size of the system memory range in QWORDs (4 LSBs==0), rolls over
void x393_membridge_start64 (u29_t d); // start of transfer offset to system memory range in QWORDs (4 LSBs==0)
void x393_membridge_len64 (u29_t d); // Full length of transfer in QWORDs
void x393_membridge_width64 (u29_t d); // Frame width in QWORDs (last xfer in each line may be partial)
void x393_membridge_mode (x393_membridge_mode_t d); // AXI cache mode
// Write-only addresses to PS PIO (Software generated DDR3 memory access sequences)
void x393_mcntrl_ps_en_rst (x393_ps_pio_en_rst_t d); // Set PS PIO enable and reset
void x393_mcntrl_ps_cmd (x393_ps_pio_cmd_t d); // Set PS PIO commands
void set_x393_mcntrl_ps_status_cntrl (x393_status_ctrl_t d); // Set PS PIO status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_ps_status_cntrl (void);
// Write-only addresses to to program status report mode for memory controller
void set_x393_mcontr_phy_status_cntrl (x393_status_ctrl_t d); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcontr_phy_status_cntrl (void);
void set_x393_mcontr_top_16bit_status_cntrl(x393_status_ctrl_t d); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcontr_top_16bit_status_cntrl(void);
// Write-only addresses to to program status report mode for test channels
void set_x393_mcntrl_test01_chn2_status_cntrl(x393_status_ctrl_t d); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_test01_chn2_status_cntrl(void);
void set_x393_mcntrl_test01_chn3_status_cntrl(x393_status_ctrl_t d); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_test01_chn3_status_cntrl(void);
void set_x393_mcntrl_test01_chn4_status_cntrl(x393_status_ctrl_t d); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_test01_chn4_status_cntrl(void);
// Write-only addresses for test channels commands
void x393_mcntrl_test01_chn2_mode (x393_test01_mode_t d); // Set command for test01 channel 2
void x393_mcntrl_test01_chn3_mode (x393_test01_mode_t d); // Set command for test01 channel 3
void x393_mcntrl_test01_chn4_mode (x393_test01_mode_t d); // Set command for test01 channel 4
// Read-only addresses for status information
x393_status_mcntrl_phy_t x393_mcontr_phy_status (void); // Status register for MCNTRL PHY
x393_status_mcntrl_top_t x393_mcontr_top_status (void); // Status register for MCNTRL requests
x393_status_mcntrl_ps_t x393_mcntrl_ps_status (void); // Status register for MCNTRL software R/W
x393_status_mcntrl_lintile_t x393_mcntrl_chn1_status (void); // Status register for MCNTRL CHN1 (membridge)
x393_status_mcntrl_lintile_t x393_mcntrl_chn3_status (void); // Status register for MCNTRL CHN3 (scanline)
x393_status_mcntrl_lintile_t x393_mcntrl_chn2_status (void); // Status register for MCNTRL CHN2 (tiled)
x393_status_mcntrl_lintile_t x393_mcntrl_chn4_status (void); // Status register for MCNTRL CHN4 (tiled)
x393_status_mcntrl_testchn_t x393_test01_chn2_status (void); // Status register for test channel 2
x393_status_mcntrl_testchn_t x393_test01_chn3_status (void); // Status register for test channel 3
x393_status_mcntrl_testchn_t x393_test01_chn4_status (void); // Status register for test channel 4
x393_status_membridge_t x393_membridge_status (void); // Status register for membridge
// Write-only control of the sensor channels
void x393_sens_mode (x393_sens_mode_t d, int sens_num); // Write sensor channel mode
void x393_sensi2c_ctrl (x393_i2c_ctltbl_t d, int sens_num); // Control sensor i2c, write i2c LUT
void set_x393_sensi2c_status_ctrl (x393_status_ctrl_t d, int sens_num); // Setup sensor i2c status report mode
x393_status_ctrl_t get_x393_sensi2c_status_ctrl (int sens_num);
void x393_sens_sync_mult (x393_sens_sync_mult_t d, int sens_num); // Configure frames combining
void x393_sens_sync_late (x393_sens_sync_late_t d, int sens_num); // Configure frame sync delay
void x393_sensio_ctrl (x393_sensio_ctl_t d, int sens_num); // Configure sensor I/O port
void set_x393_sensio_status_cntrl (x393_status_ctrl_t d, int sens_num); // Set status control for SENSIO module
x393_status_ctrl_t get_x393_sensio_status_cntrl (int sens_num);
void x393_sensio_jtag (x393_sensio_jtag_t d, int sens_num); // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS)
void set_x393_sensio_width (x393_sensio_width_t d, int sens_num); // Set sensor line in pixels (0 - use line sync from the sensor)
x393_sensio_width_t get_x393_sensio_width (int sens_num);
void set_x393_sensio_tim0 (x393_sensio_tim0_t d, int sens_num); // Sensor port i/o timing configuration, register 0
x393_sensio_tim0_t get_x393_sensio_tim0 (int sens_num);
void set_x393_sensio_tim1 (x393_sensio_tim1_t d, int sens_num); // Sensor port i/o timing configuration, register 1
x393_sensio_tim1_t get_x393_sensio_tim1 (int sens_num);
void set_x393_sensio_tim2 (x393_sensio_tim2_t d, int sens_num); // Sensor port i/o timing configuration, register 2
x393_sensio_tim2_t get_x393_sensio_tim2 (int sens_num);
void set_x393_sensio_tim3 (x393_sensio_tim3_t d, int sens_num); // Sensor port i/o timing configuration, register 3
x393_sensio_tim3_t get_x393_sensio_tim3 (int sens_num);
// I2C command sequencer, block of 16 DWORD slots for absolute frame numbers (modulo 16) and 15 slots for relative ones
// 0 - ASAP, 1 next frame, 14 -14-th next.
// Data written depends on context:
// 1 - I2C register write: index page (MSB), 3 payload bytes. Payload bytes are used according to table and sent
// after the slave address and optional high address byte. Other bytes are sent in descending order (LSB- last).
// If less than 4 bytes are programmed in the table the high bytes (starting with the one from the table) are
// skipped.
// If more than 4 bytes are programmed in the table for the page (high byte), one or two next 32-bit words
// bypass the index table and all 4 bytes are considered payload ones. If less than 4 extra bytes are to be
// sent for such extra word, only the lower bytes are sent.
//
// 2 - I2C register read: index page, slave address (8-bit, with lower bit 0) and one or 2 address bytes (as programmed
// in the table. Slave address is always in byte 2 (bits 23:16), byte1 (high register address) is skipped if
// read address in the table is programmed to be a single-byte one
void x393_sensi2c_abs (u32 d, int sens_num, int offset); // Write sensor i2c sequencer
void x393_sensi2c_rel (u32 d, int sens_num, int offset); // Write sensor i2c sequencer
// Lens vignetting correction (for each sub-frame separately)
void set_x393_lens_height0_m1 (x393_lens_height_m1_t d, int sens_num); // Subframe 0 height minus 1
x393_lens_height_m1_t get_x393_lens_height0_m1 (int sens_num);
void set_x393_lens_height1_m1 (x393_lens_height_m1_t d, int sens_num); // Subframe 1 height minus 1
x393_lens_height_m1_t get_x393_lens_height1_m1 (int sens_num);
void set_x393_lens_height2_m1 (x393_lens_height_m1_t d, int sens_num); // Subframe 2 height minus 1
x393_lens_height_m1_t get_x393_lens_height2_m1 (int sens_num);
void x393_lens_corr_cnh_addr_data (x393_lens_corr_t d, int sens_num); // Combined address/data to write lens vignetting correction coefficients
// Lens vignetting coefficient addresses - use with x393_lens_corr_wo_t (X393_LENS_CORR_CNH_ADDR_DATA)
#define X393_LENS_AX 0x00000000 // Address of correction parameter Ax
#define X393_LENS_AX_MASK 0x000000f8 // Correction parameter Ax mask
#define X393_LENS_AY 0x00000008 // Address of correction parameter Ay
#define X393_LENS_AY_MASK 0x000000f8 // Correction parameter Ay mask
#define X393_LENS_C 0x00000010 // Address of correction parameter C
#define X393_LENS_C_MASK 0x000000f8 // Correction parameter C mask
#define X393_LENS_BX 0x00000020 // Address of correction parameter Bx
#define X393_LENS_BX_MASK 0x000000e0 // Correction parameter Bx mask
#define X393_LENS_BY 0x00000040 // Address of correction parameter By
#define X393_LENS_BY_MASK 0x000000e0 // Correction parameter By mask
#define X393_LENS_SCALE0 0x00000060 // Address of correction parameter scale0
#define X393_LENS_SCALE1 0x00000062 // Address of correction parameter scale1
#define X393_LENS_SCALE2 0x00000064 // Address of correction parameter scale2
#define X393_LENS_SCALE3 0x00000066 // Address of correction parameter scale3
#define X393_LENS_SCALES_MASK 0x000000f8 // Common mask for scales
#define X393_LENS_FAT0_IN 0x00000068 // Address of input fat zero parameter (to subtract from input)
#define X393_LENS_FAT0_IN_MASK 0x000000ff // Mask for fat zero input parameter
#define X393_LENS_FAT0_OUT 0x00000069 // Address of output fat zero parameter (to add to output)
#define X393_LENS_FAT0_OUT_MASK 0x000000ff // Mask for fat zero output parameters
#define X393_LENS_POST_SCALE 0x0000006a // Address of post scale (shift output) parameter
#define X393_LENS_POST_SCALE_MASK 0x000000ff // Mask for post scale parameter
// Sensor gamma conversion control (See Python code for examples of the table data generation)
void set_x393_sens_gamma_ctrl (x393_gamma_ctl_t d, int sens_num); // Gamma module control
x393_gamma_ctl_t get_x393_sens_gamma_ctrl (int sens_num);
void x393_sens_gamma_tbl (x393_gamma_tbl_t d, int sens_num); // Write sensor gamma table address/data (with autoincrement)
void set_x393_sens_gamma_height01m1 (x393_gamma_height01m1_t d, int sens_num); // Gamma module subframes 0,1 heights minus 1
x393_gamma_height01m1_t get_x393_sens_gamma_height01m1 (int sens_num);
void set_x393_sens_gamma_height2m1 (x393_gamma_height2m1_t d, int sens_num); // Gamma module subframe 2 height minus 1
x393_gamma_height2m1_t get_x393_sens_gamma_height2m1 (int sens_num);
// Windows for histogram subchannels
void set_x393_histogram_lt0 (x393_hist_left_top_t d, int sens_num); // Specify histogram 0 left/top
x393_hist_left_top_t get_x393_histogram_lt0 (int sens_num);
void set_x393_histogram_wh0 (x393_hist_width_height_m1_t d, int sens_num); // Specify histogram 0 width/height
x393_hist_width_height_m1_t get_x393_histogram_wh0 (int sens_num);
void set_x393_histogram_lt1 (x393_hist_left_top_t d, int sens_num); // Specify histogram 1 left/top
x393_hist_left_top_t get_x393_histogram_lt1 (int sens_num);
void set_x393_histogram_wh1 (x393_hist_width_height_m1_t d, int sens_num); // Specify histogram 1 width/height
x393_hist_width_height_m1_t get_x393_histogram_wh1 (int sens_num);
void set_x393_histogram_lt2 (x393_hist_left_top_t d, int sens_num); // Specify histogram 2 left/top
x393_hist_left_top_t get_x393_histogram_lt2 (int sens_num);
void set_x393_histogram_wh2 (x393_hist_width_height_m1_t d, int sens_num); // Specify histogram 2 width/height
x393_hist_width_height_m1_t get_x393_histogram_wh2 (int sens_num);
void set_x393_histogram_lt3 (x393_hist_left_top_t d, int sens_num); // Specify histogram 3 left/top
x393_hist_left_top_t get_x393_histogram_lt3 (int sens_num);
void set_x393_histogram_wh3 (x393_hist_width_height_m1_t d, int sens_num); // Specify histogram 3 width/height
x393_hist_width_height_m1_t get_x393_histogram_wh3 (int sens_num);
// DMA control for the histograms. Subchannel here is 4*sensor_port+ histogram_subchannel
void set_x393_hist_saxi_mode (x393_hist_saxi_mode_t d); // Histogram DMA operation mode
x393_hist_saxi_mode_t get_x393_hist_saxi_mode (void);
void set_x393_hist_saxi_addr (x393_hist_saxi_addr_t d, int subchannel); // Histogram DMA addresses (in 4096 byte pages)
x393_hist_saxi_addr_t get_x393_hist_saxi_addr (int subchannel);
// Read-only addresses for sensors status information
x393_status_sens_i2c_t x393_sensi2c_status (int sens_num); // Status of the sensors i2c
x393_status_sens_io_t x393_sensio_status (int sens_num); // Status of the sensor ports I/O pins
// Compressor bitfields values
#define X393_CMPRS_CBIT_RUN_RST 0x00000000 // Reset compressor, stop immediately
#define X393_CMPRS_CBIT_RUN_DISABLE 0x00000001 // Disable compression of the new frames, finish any already started
#define X393_CMPRS_CBIT_RUN_STANDALONE 0x00000002 // Enable compressor, compress single frame from memory (async)
#define X393_CMPRS_CBIT_RUN_ENABLE 0x00000003 // Enable synchronous compression mode
#define X393_CMPRS_CBIT_CMODE_JPEG18 0x00000000 // Color 4:2:0 3x3 de-bayer core
#define X393_CMPRS_CBIT_CMODE_MONO6 0x00000001 // Mono 4:2:0 (6 blocks)
#define X393_CMPRS_CBIT_CMODE_JP46 0x00000002 // jp4, 6 blocks, original
#define X393_CMPRS_CBIT_CMODE_JP46DC 0x00000003 // jp4, 6 blocks, DC-improved
#define X393_CMPRS_CBIT_CMODE_JPEG20 0x00000004 // Color 4:2:0 with 5x5 de-bayer (not implemented)
#define X393_CMPRS_CBIT_CMODE_JP4 0x00000005 // jp4, 4 blocks
#define X393_CMPRS_CBIT_CMODE_JP4DC 0x00000006 // jp4, 4 blocks, DC-improved
#define X393_CMPRS_CBIT_CMODE_JP4DIFF 0x00000007 // jp4, 4 blocks, differential
#define X393_CMPRS_CBIT_CMODE_JP4DIFFHDR 0x00000008 // jp4, 4 blocks, differential, hdr
#define X393_CMPRS_CBIT_CMODE_JP4DIFFDIV2 0x00000009 // jp4, 4 blocks, differential, divide by 2
#define X393_CMPRS_CBIT_CMODE_JP4DIFFHDRDIV2 0x0000000a // jp4, 4 blocks, differential, hdr,divide by 2
#define X393_CMPRS_CBIT_CMODE_MONO1 0x0000000b // Mono JPEG (not yet implemented)
#define X393_CMPRS_CBIT_CMODE_MONO4 0x0000000e // Mono, 4 blocks (2x2 macroblocks)
#define X393_CMPRS_CBIT_CMODE_JPEG18 0x00000000 // Color 4:2:0
#define X393_CMPRS_CBIT_FRAMES_SINGLE 0x00000000 // Use single-frame buffer
#define X393_CMPRS_CBIT_FRAMES_MULTI 0x00000001 // Use multi-frame buffer
// Compressor control
void x393_cmprs_control_reg (x393_cmprs_mode_t d, int cmprs_chn); // Program compressor channel operation mode
void set_x393_cmprs_status (x393_status_ctrl_t d, int cmprs_chn); // Setup compressor status report mode
x393_status_ctrl_t get_x393_cmprs_status (int cmprs_chn);
void set_x393_cmprs_format (x393_cmprs_frame_format_t d, int cmprs_chn); // Compressor frame format
x393_cmprs_frame_format_t get_x393_cmprs_format (int cmprs_chn);
void set_x393_cmprs_color_saturation (x393_cmprs_colorsat_t d, int cmprs_chn); // Compressor color saturation
x393_cmprs_colorsat_t get_x393_cmprs_color_saturation (int cmprs_chn);
void set_x393_cmprs_coring_mode (x393_cmprs_coring_mode_t d, int cmprs_chn); // Select coring mode
x393_cmprs_coring_mode_t get_x393_cmprs_coring_mode (int cmprs_chn);
void x393_cmprs_interrupts (x393_cmprs_interrupts_t d, int cmprs_chn); // Compressor interrupts control (1 - clear, 2 - disable, 3 - enable)
// Compressor tables load control
// Several tables can be loaded to the compressor, there are 4 types of them:
// 0:quantization tables - 8 pairs can be loaded and switched at run time,
// 1:coring tables - 8 pairs can be loaded and switched at run time,
// 2:focusing tables - 15 tables can be loaded and switched at run time (16-th table address space
// is used to program other focusing mode parameters,
// 3:Huffman tables - 1 pair tables can be loaded
// Default tables are loaded with the bitstream file (100% quality for quantization table 0
// Loading a table requires to load address of the beginning of data, it includes table type and optional offset
// when multiple tables of the same type are used. Next the data should be written to the same register address,
// the table address is auto-incremented,
// Data for the tables 0..2 should be combined: two items into a single 32-bit DWORD (little endian), treating
// each item as a 16-bit word. The Huffman table is one item per DWORD. Address offset is calculated in DWORDs
// Compressor table types
#define X393_TABLE_QUANTIZATION_TYPE 0x00000000 // Quantization table type
#define X393_TABLE_CORING_TYPE 0x00000001 // Coring table type
#define X393_TABLE_FOCUS_TYPE 0x00000002 // Focus table type
#define X393_TABLE_HUFFMAN_TYPE 0x00000003 // Huffman table type
// Compressor tables control
void x393_cmprs_tables_data (u32 d, int cmprs_chn); // Compressor tables data
void x393_cmprs_tables_address (x393_cmprs_table_addr_t d, int cmprs_chn); // Compressor tables type/address
// Compressor channel status)
x393_cmprs_status_t x393_cmprs_status (int chn); // Status of the compressor channel (incl. interrupt
u32 x393_cmprs_hifreq (int chn); // Focus helper high-frequency amount
// Compressor DMA control:
// Camera can be configured to use either 2 AXI HP channels (with 2 compressors served by each one) or to use a single AXI HP channel
// serving all 4 compressor channels through its input ports. Below afi_port (0..3) references to one of the 4 ports of each. Control
// for two AXI HP channels is implemented as separate functions. Currently only the first channel is used
void x393_afimux0_en (x393_afimux_en_t d); // AFI MUX 0 global/port run/pause control
void set_x393_afimux0_rst (x393_afimux_rst_t d); // AFI MUX 0 per-port resets
x393_afimux_rst_t get_x393_afimux0_rst (void);
void x393_afimux0_report_mode (x393_afimux_report_t d); // AFI MUX 0 readout pointer report mode
void set_x393_afimux0_status_control (x393_status_ctrl_t d); // AFI MUX 0 status report mode
x393_status_ctrl_t get_x393_afimux0_status_control (void);
void set_x393_afimux0_sa (x393_afimux_sa_t d, int afi_port); // AFI MUX 0 DMA buffer start address in 32-byte blocks
x393_afimux_sa_t get_x393_afimux0_sa (int afi_port);
void set_x393_afimux0_len (x393_afimux_len_t d, int afi_port); // AFI MUX 0 DMA buffer length in 32-byte blocks
x393_afimux_len_t get_x393_afimux0_len (int afi_port);
// Same for the second AXI HP channel (not currently used)
void x393_afimux1_en (x393_afimux_en_t d); // AFI MUX 1 global/port run/pause control
void set_x393_afimux1_rst (x393_afimux_rst_t d); // AFI MUX 1 per-port resets
x393_afimux_rst_t get_x393_afimux1_rst (void);
void x393_afimux1_report_mode (x393_afimux_report_t d); // AFI MUX 1 readout pointer report mode
void set_x393_afimux1_status_control (x393_status_ctrl_t d); // AFI MUX 1 status report mode
x393_status_ctrl_t get_x393_afimux1_status_control (void);
void set_x393_afimux1_sa (x393_afimux_sa_t d, int afi_port); // AFI MUX 1 DMA buffer start address in 32-byte blocks
x393_afimux_sa_t get_x393_afimux1_sa (int afi_port);
void set_x393_afimux1_len (x393_afimux_len_t d, int afi_port); // AFI MUX 1 DMA buffer length in 32-byte blocks
x393_afimux_len_t get_x393_afimux1_len (int afi_port);
// Read-only sensors status information (pointer offset and last sequence number)
x393_afimux_status_t x393_afimux0_status (int afi_port); // Status of the AFI MUX 0 (including image pointer)
x393_afimux_status_t x393_afimux1_status (int afi_port); // Status of the AFI MUX 1 (including image pointer)
//
// GPIO contol. Each of the 10 pins can be controlled by the software - individually or simultaneously or from any of the 3 masters (other FPGA modules)
// Currently these modules are;
// A - camsync (intercamera synchronization), uses up to 4 pins
// B - reserved (not yet used) and
// C - logger (IMU, GPS, images), uses 6 pins, including separate i2c available on extension boards
// If several enabled ports try to contol the same bit, highest priority has port C, lowest - software controlled
void x393_gpio_set_pins (x393_gpio_set_pins_t d); // State of the GPIO pins and seq. number
void set_x393_gpio_status_control (x393_status_ctrl_t d); // GPIO status control mode
x393_status_ctrl_t get_x393_gpio_status_control (void);
// Read-only GPIO pins state
x393_gpio_status_t x393_gpio_status (void); // State of the GPIO pins and seq. number
// RTC control
void set_x393_rtc_usec (x393_rtc_usec_t d); // RTC microseconds
x393_rtc_usec_t get_x393_rtc_usec (void);
void set_x393_rtc_sec_set (x393_rtc_sec_t d); // RTC seconds and set clock
x393_rtc_sec_t get_x393_rtc_sec_set (void);
void set_x393_rtc_corr (x393_rtc_corr_t d); // RTC correction (+/- 1/256 full scale)
x393_rtc_corr_t get_x393_rtc_corr (void);
void set_x393_rtc_set_status (x393_status_ctrl_t d); // RTC status control mode, write makes a snapshot to be read out
x393_status_ctrl_t get_x393_rtc_set_status (void);
// Read-only RTC state
x393_rtc_status_t x393_rtc_status (void); // RTC status reg
x393_rtc_sec_t x393_rtc_status_sec (void); // RTC snapshot seconds
x393_rtc_usec_t x393_rtc_status_usec (void); // RTC snapshot microseconds
// CAMSYNC control
void x393_camsync_mode (x393_camsync_mode_t d); // CAMSYNC mode
void x393_camsync_trig_src (x393_camsync_io_t d); // CAMSYNC trigger source
void x393_camsync_trig_dst (x393_camsync_io_t d); // CAMSYNC trigger destination
// Trigger period has special value for small (<255) values written to this register
// d == 0 - disable (stop periodic mode)
// d == 1 - single trigger
// d == 2..255 - set output pulse / input-output serial bit duration (no start generated)
// d >= 256 - repetitive trigger
void set_x393_camsync_trig_period (u32 d); // CAMSYNC trigger period
u32 get_x393_camsync_trig_period (void);
void set_x393_camsync_trig_delay (u32 d, int sens_chn); // CAMSYNC trigger delay
u32 get_x393_camsync_trig_delay (int sens_chn);
// Command sequencer control
// Controller is programmed through 32 locations. Each registers but the control require two writes:
// First write - register address (AXI_WR_ADDR_BITS bits), second - register data (32 bits)
// Writing to the contol register (0x1f) resets the first/second counter so the next write will be "first"
// 0x0..0xf write directly to the frame number [3:0] modulo 16, except if you write to the frame
// "just missed" - in that case data will go to the current frame.
// 0x10 - write seq commands to be sent ASAP
// 0x11 - write seq commands to be sent after the next frame starts
//
// 0x1e - write seq commands to be sent after the next 14 frame start pulses
// 0x1f - control register:
// [14] - reset all FIFO (takes 32 clock pulses), also - stops seq until run command
// [13:12] - 3 - run seq, 2 - stop seq , 1,0 - no change to run state
// [1:0] - 0: NOP, 1: clear IRQ, 2 - Clear IE, 3: set IE
void x393_cmdframeseq_ctrl (x393_cmdframeseq_mode_t d, int sens_chn); // CMDFRAMESEQ control register
void x393_cmdframeseq_abs (u32 d, int sens_chn, int offset); // CMDFRAMESEQ absolute frame address/command
void x393_cmdframeseq_rel (u32 d, int sens_chn, int offset); // CMDFRAMESEQ relative frame address/command
// Command sequencer multiplexer, provides current frame number for each sensor channel and interrupt status/interrupt masks for them.
// Interrupts and interrupt masks are controlled through channel CMDFRAMESEQ module
void set_x393_cmdseqmux_status_ctrl (x393_status_ctrl_t d); // CMDSEQMUX status control mode (status provides current frame numbers)
x393_status_ctrl_t get_x393_cmdseqmux_status_ctrl (void);
x393_cmdseqmux_status_t x393_cmdseqmux_status (void); // CMDSEQMUX status data (frame numbers and interrupts
// Event logger
// Event logger configuration/data is writtent to the module ising two 32-bit register locations : data and address.
// Address consists of 2 parts - 2-bit page (configuration, imu, gps, message) and a 5-bit sub-address autoincremented when writing data.
// Register pages:
#define X393_LOGGER_PAGE_CONF 0x00000000 // Logger configuration page
#define X393_LOGGER_PAGE_IMU 0x00000003 // Logger IMU parameters page
#define X393_LOGGER_PAGE_GPS 0x00000001 // Logger GPS parameters page
#define X393_LOGGER_PAGE_MSG 0x00000002 // Logger MSG (odometer) parameters page
// Register configuration addresses (with X393_LOGGER_PAGE_CONF):
#define X393_LOGGER_PERIOD 0x00000000 // IMU period (in SPI clocks, high word 0xffff - use IMU ready)
#define X393_LOGGER_BIT_DURATION 0x00000001 // IMU SPI bit duration (in mclk == 50 ns periods?)
#define X393_LOGGER_BIT_HALF_PERIOD 0x00000002 // Logger rs232 half bit period (in mclk == 50 ns periods?)
#define X393_LOGGER_CONFIG 0x00000003 // Logger IMU parameters page
void set_x393_logger_status_ctrl (x393_status_ctrl_t d); // Logger status configuration (to report sample number)
x393_status_ctrl_t get_x393_logger_status_ctrl (void);
void x393_logger_data (x393_logger_data_t d); // Logger register write data
void x393_logger_address (x393_logger_address_t d); // Logger register write page/address
x393_logger_status_t x393_logger_status (void); // Logger status data (sequence number)
// MULT SAXI DMA engine control. Of 4 channels only one (number 0) is currently used - for the event logger
void set_x393_mult_saxi_status_ctrl (x393_status_ctrl_t d); // MULT_SAXI status control mode (status provides current DWORD pointer)
x393_status_ctrl_t get_x393_mult_saxi_status_ctrl (void);
void x393_mult_saxi_buf_address (x393_mult_saxi_al_t d, int chn); // MULT_SAXI buffer start address in DWORDS
void x393_mult_saxi_buf_len (x393_mult_saxi_al_t d, int chn); // MULT_SAXI buffer length in DWORDS
x393_mult_saxi_al_t x393_mult_saxi_status (int chn); // MULT_SAXI current DWORD pointer
// MULTI_CLK - global clock generation PLLs. Interface provided for debugging, no interaction is needed for normal operation
void set_x393_multiclk_status_ctrl (x393_status_ctrl_t d); // MULTI_CLK status generation (do not use or do not set auto)
x393_status_ctrl_t get_x393_multiclk_status_ctrl (void);
void set_x393_multiclk_ctrl (x393_multiclk_ctl_t d); // MULTI_CLK reset and power down control
x393_multiclk_ctl_t get_x393_multiclk_ctrl (void);
x393_multiclk_status_t x393_multiclk_status (void); // MULTI_CLK lock and toggle state
// Debug ring module
// Debug ring module (when enabled with DEBUG_RING in system_defines.vh) provides low-overhead read/write access to internal test points
// To write data you need to write 32-bit data with x393_debug_shift(u32) multiple times to fill the ring register (length depends on
// implementation), skip this step if only reading from the modules under test is required.
// Exchange data with x393_debug_load(), the data from the ring shift register.
// Write 0xffffffff (or other "magic" data) if the ring length is unknown - this DWORD will appear on the output after the useful data
// Read all data, waiting for status sequence number to be incremented,status mode should be set to auto (3) wor each DWORD certain
// number of times or until the "magic" DWORD appears, writing "magic" to shift out next 32 bits.
void set_x393_debug_status_ctrl (x393_status_ctrl_t d); // Debug ring status generation - set to auto(3) if used
x393_status_ctrl_t get_x393_debug_status_ctrl (void);
void x393_debug_load (void); // Debug ring copy shift register to/from tested modules
void x393_debug_shift (u32 d); // Debug ring shift ring by 32 bits
x393_debug_status_t x393_debug_status (void); // Debug read status (watch sequence number)
u32 x393_debug_read (void); // Debug read DWORD form ring register
// Write-only addresses to program memory channel 3 (test channel)
void x393_mcntrl_chn3_scanline_mode (x393_mcntrl_mode_scan_t d); // Set mode register (write last after other channel registers are set)
void set_x393_mcntrl_chn3_scanline_status_cntrl(x393_status_ctrl_t d); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_chn3_scanline_status_cntrl(void);
void x393_mcntrl_chn3_scanline_startaddr (x393_mcntrl_window_frame_sa_t d); // Set frame start address
void x393_mcntrl_chn3_scanline_frame_size(x393_mcntrl_window_frame_sa_inc_t d); // Set frame size (address increment)
void x393_mcntrl_chn3_scanline_frame_last(x393_mcntrl_window_last_frame_num_t d); // Set last frame number (number of frames in buffer minus 1)
void x393_mcntrl_chn3_scanline_frame_full_width(x393_mcntrl_window_full_width_t d); // Set frame full(padded) width
void x393_mcntrl_chn3_scanline_window_wh (x393_mcntrl_window_width_height_t d); // Set frame window size
void x393_mcntrl_chn3_scanline_window_x0y0(x393_mcntrl_window_left_top_t d); // Set frame position
void x393_mcntrl_chn3_scanline_startxy (x393_mcntrl_window_startx_starty_t d); // Set startXY register
// Write-only addresses to program memory channel 2 (test channel)
void x393_mcntrl_chn2_tiled_mode (x393_mcntrl_mode_scan_t d); // Set mode register (write last after other channel registers are set)
void set_x393_mcntrl_chn2_tiled_status_cntrl(x393_status_ctrl_t d); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_chn2_tiled_status_cntrl(void);
void x393_mcntrl_chn2_tiled_startaddr (x393_mcntrl_window_frame_sa_t d); // Set frame start address
void x393_mcntrl_chn2_tiled_frame_size (x393_mcntrl_window_frame_sa_inc_t d); // Set frame size (address increment)
void x393_mcntrl_chn2_tiled_frame_last (x393_mcntrl_window_last_frame_num_t d); // Set last frame number (number of frames in buffer minus 1)
void x393_mcntrl_chn2_tiled_frame_full_width(x393_mcntrl_window_full_width_t d); // Set frame full(padded) width
void x393_mcntrl_chn2_tiled_window_wh (x393_mcntrl_window_width_height_t d); // Set frame window size
void x393_mcntrl_chn2_tiled_window_x0y0 (x393_mcntrl_window_left_top_t d); // Set frame position
void x393_mcntrl_chn2_tiled_startxy (x393_mcntrl_window_startx_starty_t d); // Set startXY register
void x393_mcntrl_chn2_tiled_tile_whs (x393_mcntrl_window_tile_whs_t d); // Set tile size/step (tiled mode only)
// Write-only addresses to program memory channel 4 (test channel)
void x393_mcntrl_chn4_tiled_mode (x393_mcntrl_mode_scan_t d); // Set mode register (write last after other channel registers are set)
void set_x393_mcntrl_chn4_tiled_status_cntrl(x393_status_ctrl_t d); // Set status control register (status update mode)
x393_status_ctrl_t get_x393_mcntrl_chn4_tiled_status_cntrl(void);
void x393_mcntrl_chn4_tiled_startaddr (x393_mcntrl_window_frame_sa_t d); // Set frame start address
void x393_mcntrl_chn4_tiled_frame_size (x393_mcntrl_window_frame_sa_inc_t d); // Set frame size (address increment)
void x393_mcntrl_chn4_tiled_frame_last (x393_mcntrl_window_last_frame_num_t d); // Set last frame number (number of frames in buffer minus 1)
void x393_mcntrl_chn4_tiled_frame_full_width(x393_mcntrl_window_full_width_t d); // Set frame full(padded) width
void x393_mcntrl_chn4_tiled_window_wh (x393_mcntrl_window_width_height_t d); // Set frame window size
void x393_mcntrl_chn4_tiled_window_x0y0 (x393_mcntrl_window_left_top_t d); // Set frame position
void x393_mcntrl_chn4_tiled_startxy (x393_mcntrl_window_startx_starty_t d); // Set startXY register
void x393_mcntrl_chn4_tiled_tile_whs (x393_mcntrl_window_tile_whs_t d); // Set tile size/step (tiled mode only)
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/x393_defs.h 0000664 0000000 0000000 00000134544 12703306510 0026757 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* File: x393_defs.h
* Date: 2016-04-06
* Author: auto-generated file, see x393_export_c.py
* Description: Constants and hardware addresses definitions to access x393 hardware registers
*******************************************************************************/
// R/W addresses to set up memory arbiter priorities. For sensors (chn = 8..11), for compressors - 12..15
#define X393_MCNTRL_ARBITER_PRIORITY(chn) (0x40000180 + 0x4 * (chn)) // Set memory arbiter priority (currently r/w, may become just wo), chn = 0..15, data type: x393_arbite_pri_t (rw)
// Enable/disable memory channels (bits in a 16-bit word). For sensors (chn = 8..11), for compressors - 12..15
#define X393_MCNTRL_CHN_EN 0x400001c0 // Enable/disable memory channels (currently r/w, may become just wo), data type: x393_mcntr_chn_en_t (rw)
#define X393_MCNTRL_DQS_DQM_PATT 0x40000140 // Setup DQS and DQM patterns, data type: x393_mcntr_dqs_dqm_patt_t (rw)
#define X393_MCNTRL_DQ_DQS_TRI 0x40000144 // Setup DQS and DQ on/off sequence, data type: x393_mcntr_dqs_dqm_tri_t (rw)
// Following enable/disable addresses can be written with any data, only addresses matter
#define X393_MCNTRL_DIS 0x400000c0 // Disable DDR3 memory controller
#define X393_MCNTRL_EN 0x400000c4 // Enable DDR3 memory controller
#define X393_MCNTRL_REFRESH_DIS 0x400000c8 // Disable DDR3 memory refresh
#define X393_MCNTRL_REFRESH_EN 0x400000cc // Enable DDR3 memory refresh
#define X393_MCNTRL_SDRST_DIS 0x40000098 // Disable DDR3 memory reset
#define X393_MCNTRL_SDRST_EN 0x4000009c // Enable DDR3 memory reset
#define X393_MCNTRL_CKE_DIS 0x400000a0 // Disable DDR3 memory CKE
#define X393_MCNTRL_CKE_EN 0x400000a4 // Enable DDR3 memory CKE
#define X393_MCNTRL_CMDA_DIS 0x40000090 // Disable DDR3 memory command/address lines
#define X393_MCNTRL_CMDA_EN 0x40000094 // Enable DDR3 memory command/address lines
// Set DDR3 memory controller I/O delays and other timing parameters (should use individually calibrated values)
#define X393_MCNTRL_DQ_ODLY0(chn) (0x40000200 + 0x4 * (chn)) // Lane0 DQ output delays , chn = 0..7, data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY1(chn) (0x40000280 + 0x4 * (chn)) // Lane1 DQ output delays , chn = 0..7, data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY0(chn) (0x40000240 + 0x4 * (chn)) // Lane0 DQ input delays , chn = 0..7, data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY1(chn) (0x400002c0 + 0x4 * (chn)) // Lane1 DQ input delays , chn = 0..7, data type: x393_dly_t (rw)
#define X393_MCNTRL_DQS_ODLY0 0x40000220 // Lane0 DQS output delay , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQS_ODLY1 0x400002a0 // Lane1 DQS output delay , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQS_IDLY0 0x40000260 // Lane0 DQS input delay , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQS_IDLY1 0x400002e0 // Lane1 DQS input delay , data type: x393_dly_t (rw)
#define X393_MCNTRL_DM_ODLY0 0x40000224 // Lane0 DM output delay , data type: x393_dly_t (rw)
#define X393_MCNTRL_DM_ODLY1 0x400002a4 // Lane1 DM output delay , data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY(chn) (0x40000300 + 0x4 * (chn)) // Address, bank and commands delays, chn = 0..31, data type: x393_dly_t (rw)
#define X393_MCNTRL_PHASE 0x40000380 // Clock phase, data type: x393_dly_t (rw)
#define X393_MCNTRL_DLY_SET 0x40000080 // Set all pre-programmed delays
#define X393_MCNTRL_WBUF_DLY 0x40000148 // Set write buffer delay, data type: x393_wbuf_dly_t (rw)
// Write-only addresses to program memory channels for sensors (chn = 0..3), memory channels 8..11
#define X393_SENS_MCNTRL_SCANLINE_MODE(chn) (0x40001a00 + 0x40 * (chn)) // Set mode register (write last after other channel registers are set), chn = 0..3, data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STATUS_CNTRL(chn) (0x40001a04 + 0x40 * (chn)) // Set status control register (status update mode), chn = 0..3, data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_SCANLINE_STARTADDR(chn) (0x40001a08 + 0x40 * (chn)) // Set frame start address, chn = 0..3, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_SIZE(chn) (0x40001a0c + 0x40 * (chn)) // Set frame size (address increment), chn = 0..3, data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_LAST(chn) (0x40001a10 + 0x40 * (chn)) // Set last frame number (number of frames in buffer minus 1), chn = 0..3, data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_FULL_WIDTH(chn) (0x40001a14 + 0x40 * (chn)) // Set frame full(padded) width, chn = 0..3, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_WH(chn) (0x40001a18 + 0x40 * (chn)) // Set frame window size, chn = 0..3, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_X0Y0(chn) (0x40001a1c + 0x40 * (chn)) // Set frame position, chn = 0..3, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STARTXY(chn) (0x40001a20 + 0x40 * (chn)) // Set startXY register, chn = 0..3, data type: x393_mcntrl_window_startx_starty_t (wo)
// Write-only addresses to program memory channels for compressors (chn = 0..3), memory channels 12..15
#define X393_SENS_MCNTRL_TILED_MODE(chn) (0x40001b00 + 0x40 * (chn)) // Set mode register (write last after other channel registers are set), chn = 0..3, data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_TILED_STATUS_CNTRL(chn) (0x40001b04 + 0x40 * (chn)) // Set status control register (status update mode), chn = 0..3, data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_TILED_STARTADDR(chn) (0x40001b08 + 0x40 * (chn)) // Set frame start address, chn = 0..3, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_SIZE(chn) (0x40001b0c + 0x40 * (chn)) // Set frame size (address increment), chn = 0..3, data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_LAST(chn) (0x40001b10 + 0x40 * (chn)) // Set last frame number (number of frames in buffer minus 1), chn = 0..3, data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_FULL_WIDTH(chn) (0x40001b14 + 0x40 * (chn)) // Set frame full(padded) width, chn = 0..3, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_WH(chn) (0x40001b18 + 0x40 * (chn)) // Set frame window size, chn = 0..3, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_X0Y0(chn) (0x40001b1c + 0x40 * (chn)) // Set frame position, chn = 0..3, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_TILED_STARTXY(chn) (0x40001b20 + 0x40 * (chn)) // Set startXY register, chn = 0..3, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_SENS_MCNTRL_TILED_TILE_WHS(chn) (0x40001b24 + 0x40 * (chn)) // Set tile size/step (tiled mode only), chn = 0..3, data type: x393_mcntrl_window_tile_whs_t (wo)
// Write-only addresses to program memory channel for membridge, memory channel 1
#define X393_MEMBRIDGE_SCANLINE_MODE 0x40000480 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_MEMBRIDGE_SCANLINE_STATUS_CNTRL 0x40000484 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MEMBRIDGE_SCANLINE_STARTADDR 0x40000488 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_MEMBRIDGE_SCANLINE_FRAME_SIZE 0x4000048c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_MEMBRIDGE_SCANLINE_FRAME_LAST 0x40000490 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_MEMBRIDGE_SCANLINE_FRAME_FULL_WIDTH 0x40000494 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_MEMBRIDGE_SCANLINE_WINDOW_WH 0x40000498 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_MEMBRIDGE_SCANLINE_WINDOW_X0Y0 0x4000049c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_MEMBRIDGE_SCANLINE_STARTXY 0x400004a0 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_MEMBRIDGE_CTRL 0x40000800 // Issue membridge command, data type: x393_membridge_cmd_t (wo)
#define X393_MEMBRIDGE_STATUS_CNTRL 0x40000804 // Set membridge status control register, data type: x393_status_ctrl_t (rw)
#define X393_MEMBRIDGE_LO_ADDR64 0x40000808 // start address of the system memory range in QWORDs (4 LSBs==0), data type: u29_t (wo)
#define X393_MEMBRIDGE_SIZE64 0x4000080c // size of the system memory range in QWORDs (4 LSBs==0), rolls over, data type: u29_t (wo)
#define X393_MEMBRIDGE_START64 0x40000810 // start of transfer offset to system memory range in QWORDs (4 LSBs==0), data type: u29_t (wo)
#define X393_MEMBRIDGE_LEN64 0x40000814 // Full length of transfer in QWORDs, data type: u29_t (wo)
#define X393_MEMBRIDGE_WIDTH64 0x40000818 // Frame width in QWORDs (last xfer in each line may be partial), data type: u29_t (wo)
#define X393_MEMBRIDGE_MODE 0x4000081c // AXI cache mode, data type: x393_membridge_mode_t (wo)
// Write-only addresses to PS PIO (Software generated DDR3 memory access sequences)
#define X393_MCNTRL_PS_EN_RST 0x40000400 // Set PS PIO enable and reset, data type: x393_ps_pio_en_rst_t (wo)
#define X393_MCNTRL_PS_CMD 0x40000404 // Set PS PIO commands, data type: x393_ps_pio_cmd_t (wo)
#define X393_MCNTRL_PS_STATUS_CNTRL 0x40000408 // Set PS PIO status control register (status update mode), data type: x393_status_ctrl_t (rw)
// Write-only addresses to to program status report mode for memory controller
#define X393_MCONTR_PHY_STATUS_CNTRL 0x40000150 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCONTR_TOP_16BIT_STATUS_CNTRL 0x4000014c // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
// Write-only addresses to to program status report mode for test channels
#define X393_MCNTRL_TEST01_CHN2_STATUS_CNTRL 0x400003d4 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_TEST01_CHN3_STATUS_CNTRL 0x400003dc // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_TEST01_CHN4_STATUS_CNTRL 0x400003e4 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
// Write-only addresses for test channels commands
#define X393_MCNTRL_TEST01_CHN2_MODE 0x400003d0 // Set command for test01 channel 2, data type: x393_test01_mode_t (wo)
#define X393_MCNTRL_TEST01_CHN3_MODE 0x400003d8 // Set command for test01 channel 3, data type: x393_test01_mode_t (wo)
#define X393_MCNTRL_TEST01_CHN4_MODE 0x400003e0 // Set command for test01 channel 4, data type: x393_test01_mode_t (wo)
// Read-only addresses for status information
#define X393_MCONTR_PHY_STATUS 0x40002000 // Status register for MCNTRL PHY, data type: x393_status_mcntrl_phy_t (ro)
#define X393_MCONTR_TOP_STATUS 0x40002004 // Status register for MCNTRL requests, data type: x393_status_mcntrl_top_t (ro)
#define X393_MCNTRL_PS_STATUS 0x40002008 // Status register for MCNTRL software R/W, data type: x393_status_mcntrl_ps_t (ro)
#define X393_MCNTRL_CHN1_STATUS 0x40002010 // Status register for MCNTRL CHN1 (membridge), data type: x393_status_mcntrl_lintile_t (ro)
#define X393_MCNTRL_CHN3_STATUS 0x40002018 // Status register for MCNTRL CHN3 (scanline), data type: x393_status_mcntrl_lintile_t (ro)
#define X393_MCNTRL_CHN2_STATUS 0x40002014 // Status register for MCNTRL CHN2 (tiled), data type: x393_status_mcntrl_lintile_t (ro)
#define X393_MCNTRL_CHN4_STATUS 0x4000201c // Status register for MCNTRL CHN4 (tiled), data type: x393_status_mcntrl_lintile_t (ro)
#define X393_TEST01_CHN2_STATUS 0x400020f4 // Status register for test channel 2, data type: x393_status_mcntrl_testchn_t (ro)
#define X393_TEST01_CHN3_STATUS 0x400020f8 // Status register for test channel 3, data type: x393_status_mcntrl_testchn_t (ro)
#define X393_TEST01_CHN4_STATUS 0x400020fc // Status register for test channel 4, data type: x393_status_mcntrl_testchn_t (ro)
#define X393_MEMBRIDGE_STATUS 0x400020ec // Status register for membridge, data type: x393_status_membridge_t (ro)
// Write-only control of the sensor channels
#define X393_SENS_MODE(sens_num) (0x40001000 + 0x100 * (sens_num)) // Write sensor channel mode, sens_num = 0..3, data type: x393_sens_mode_t (wo)
#define X393_SENSI2C_CTRL(sens_num) (0x40001008 + 0x100 * (sens_num)) // Control sensor i2c, write i2c LUT, sens_num = 0..3, data type: x393_i2c_ctltbl_t (wo)
#define X393_SENSI2C_STATUS_CTRL(sens_num) (0x4000100c + 0x100 * (sens_num)) // Setup sensor i2c status report mode, sens_num = 0..3, data type: x393_status_ctrl_t (rw)
#define X393_SENS_SYNC_MULT(sens_num) (0x40001018 + 0x100 * (sens_num)) // Configure frames combining, sens_num = 0..3, data type: x393_sens_sync_mult_t (wo)
#define X393_SENS_SYNC_LATE(sens_num) (0x4000101c + 0x100 * (sens_num)) // Configure frame sync delay, sens_num = 0..3, data type: x393_sens_sync_late_t (wo)
#define X393_SENSIO_CTRL(sens_num) (0x40001020 + 0x100 * (sens_num)) // Configure sensor I/O port, sens_num = 0..3, data type: x393_sensio_ctl_t (wo)
#define X393_SENSIO_STATUS_CNTRL(sens_num) (0x40001024 + 0x100 * (sens_num)) // Set status control for SENSIO module, sens_num = 0..3, data type: x393_status_ctrl_t (rw)
#define X393_SENSIO_JTAG(sens_num) (0x40001028 + 0x100 * (sens_num)) // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), sens_num = 0..3, data type: x393_sensio_jtag_t (wo)
#define X393_SENSIO_WIDTH(sens_num) (0x4000102c + 0x100 * (sens_num)) // Set sensor line in pixels (0 - use line sync from the sensor), sens_num = 0..3, data type: x393_sensio_width_t (rw)
#define X393_SENSIO_TIM0(sens_num) (0x40001030 + 0x100 * (sens_num)) // Sensor port i/o timing configuration, register 0, sens_num = 0..3, data type: x393_sensio_tim0_t (rw)
#define X393_SENSIO_TIM1(sens_num) (0x40001034 + 0x100 * (sens_num)) // Sensor port i/o timing configuration, register 1, sens_num = 0..3, data type: x393_sensio_tim1_t (rw)
#define X393_SENSIO_TIM2(sens_num) (0x40001038 + 0x100 * (sens_num)) // Sensor port i/o timing configuration, register 2, sens_num = 0..3, data type: x393_sensio_tim2_t (rw)
#define X393_SENSIO_TIM3(sens_num) (0x4000103c + 0x100 * (sens_num)) // Sensor port i/o timing configuration, register 3, sens_num = 0..3, data type: x393_sensio_tim3_t (rw)
// I2C command sequencer, block of 16 DWORD slots for absolute frame numbers (modulo 16) and 15 slots for relative ones
// 0 - ASAP, 1 next frame, 14 -14-th next.
// Data written depends on context:
// 1 - I2C register write: index page (MSB), 3 payload bytes. Payload bytes are used according to table and sent
// after the slave address and optional high address byte. Other bytes are sent in descending order (LSB- last).
// If less than 4 bytes are programmed in the table the high bytes (starting with the one from the table) are
// skipped.
// If more than 4 bytes are programmed in the table for the page (high byte), one or two next 32-bit words
// bypass the index table and all 4 bytes are considered payload ones. If less than 4 extra bytes are to be
// sent for such extra word, only the lower bytes are sent.
//
// 2 - I2C register read: index page, slave address (8-bit, with lower bit 0) and one or 2 address bytes (as programmed
// in the table. Slave address is always in byte 2 (bits 23:16), byte1 (high register address) is skipped if
// read address in the table is programmed to be a single-byte one
#define X393_SENSI2C_ABS(sens_num,offset) (0x40001040)+ 0x40 * (sens_num)+ 0x1 * (offset)) // Write sensor i2c sequencer, sens_num = 0..3, offset = 0..15, data type: u32 (wo)
#define X393_SENSI2C_REL(sens_num,offset) (0x40001080)+ 0x40 * (sens_num)+ 0x1 * (offset)) // Write sensor i2c sequencer, sens_num = 0..3, offset = 0..15, data type: u32 (wo)
// Lens vignetting correction (for each sub-frame separately)
#define X393_LENS_HEIGHT0_M1(sens_num) (0x400010f0 + 0x100 * (sens_num)) // Subframe 0 height minus 1, sens_num = 0..3, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT1_M1(sens_num) (0x400010f4 + 0x100 * (sens_num)) // Subframe 1 height minus 1, sens_num = 0..3, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT2_M1(sens_num) (0x400010f8 + 0x100 * (sens_num)) // Subframe 2 height minus 1, sens_num = 0..3, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_CORR_CNH_ADDR_DATA(sens_num) (0x400010fc + 0x100 * (sens_num)) // Combined address/data to write lens vignetting correction coefficients, sens_num = 0..3, data type: x393_lens_corr_t (wo)
// Lens vignetting coefficient addresses - use with x393_lens_corr_wo_t (X393_LENS_CORR_CNH_ADDR_DATA)
#define X393_LENS_AX 0x00000000 // Address of correction parameter Ax
#define X393_LENS_AX_MASK 0x000000f8 // Correction parameter Ax mask
#define X393_LENS_AY 0x00000008 // Address of correction parameter Ay
#define X393_LENS_AY_MASK 0x000000f8 // Correction parameter Ay mask
#define X393_LENS_C 0x00000010 // Address of correction parameter C
#define X393_LENS_C_MASK 0x000000f8 // Correction parameter C mask
#define X393_LENS_BX 0x00000020 // Address of correction parameter Bx
#define X393_LENS_BX_MASK 0x000000e0 // Correction parameter Bx mask
#define X393_LENS_BY 0x00000040 // Address of correction parameter By
#define X393_LENS_BY_MASK 0x000000e0 // Correction parameter By mask
#define X393_LENS_SCALE0 0x00000060 // Address of correction parameter scale0
#define X393_LENS_SCALE1 0x00000062 // Address of correction parameter scale1
#define X393_LENS_SCALE2 0x00000064 // Address of correction parameter scale2
#define X393_LENS_SCALE3 0x00000066 // Address of correction parameter scale3
#define X393_LENS_SCALES_MASK 0x000000f8 // Common mask for scales
#define X393_LENS_FAT0_IN 0x00000068 // Address of input fat zero parameter (to subtract from input)
#define X393_LENS_FAT0_IN_MASK 0x000000ff // Mask for fat zero input parameter
#define X393_LENS_FAT0_OUT 0x00000069 // Address of output fat zero parameter (to add to output)
#define X393_LENS_FAT0_OUT_MASK 0x000000ff // Mask for fat zero output parameters
#define X393_LENS_POST_SCALE 0x0000006a // Address of post scale (shift output) parameter
#define X393_LENS_POST_SCALE_MASK 0x000000ff // Mask for post scale parameter
// Sensor gamma conversion control (See Python code for examples of the table data generation)
#define X393_SENS_GAMMA_CTRL(sens_num) (0x400010e0 + 0x100 * (sens_num)) // Gamma module control, sens_num = 0..3, data type: x393_gamma_ctl_t (rw)
#define X393_SENS_GAMMA_TBL(sens_num) (0x400010e4 + 0x100 * (sens_num)) // Write sensor gamma table address/data (with autoincrement), sens_num = 0..3, data type: x393_gamma_tbl_t (wo)
#define X393_SENS_GAMMA_HEIGHT01M1(sens_num) (0x400010e8 + 0x100 * (sens_num)) // Gamma module subframes 0,1 heights minus 1, sens_num = 0..3, data type: x393_gamma_height01m1_t (rw)
#define X393_SENS_GAMMA_HEIGHT2M1(sens_num) (0x400010ec + 0x100 * (sens_num)) // Gamma module subframe 2 height minus 1, sens_num = 0..3, data type: x393_gamma_height2m1_t (rw)
// Windows for histogram subchannels
#define X393_HISTOGRAM_LT0(sens_num) (0x400010c0 + 0x100 * (sens_num)) // Specify histogram 0 left/top, sens_num = 0..3, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH0(sens_num) (0x400010c4 + 0x100 * (sens_num)) // Specify histogram 0 width/height, sens_num = 0..3, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT1(sens_num) (0x400010c8 + 0x100 * (sens_num)) // Specify histogram 1 left/top, sens_num = 0..3, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH1(sens_num) (0x400010cc + 0x100 * (sens_num)) // Specify histogram 1 width/height, sens_num = 0..3, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT2(sens_num) (0x400010d0 + 0x100 * (sens_num)) // Specify histogram 2 left/top, sens_num = 0..3, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH2(sens_num) (0x400010d4 + 0x100 * (sens_num)) // Specify histogram 2 width/height, sens_num = 0..3, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT3(sens_num) (0x400010d8 + 0x100 * (sens_num)) // Specify histogram 3 left/top, sens_num = 0..3, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH3(sens_num) (0x400010dc + 0x100 * (sens_num)) // Specify histogram 3 width/height, sens_num = 0..3, data type: x393_hist_width_height_m1_t (rw)
// DMA control for the histograms. Subchannel here is 4*sensor_port+ histogram_subchannel
#define X393_HIST_SAXI_MODE 0x40001440 // Histogram DMA operation mode, data type: x393_hist_saxi_mode_t (rw)
#define X393_HIST_SAXI_ADDR(subchannel) (0x40001400 + 0x4 * (subchannel)) // Histogram DMA addresses (in 4096 byte pages), subchannel = 0..15, data type: x393_hist_saxi_addr_t (rw)
// Read-only addresses for sensors status information
#define X393_SENSI2C_STATUS(sens_num) (0x40002080 + 0x8 * (sens_num)) // Status of the sensors i2c, sens_num = 0..3, data type: x393_status_sens_i2c_t (ro)
#define X393_SENSIO_STATUS(sens_num) (0x40002084 + 0x8 * (sens_num)) // Status of the sensor ports I/O pins, sens_num = 0..3, data type: x393_status_sens_io_t (ro)
// Compressor bitfields values
#define X393_CMPRS_CBIT_RUN_RST 0x00000000 // Reset compressor, stop immediately
#define X393_CMPRS_CBIT_RUN_DISABLE 0x00000001 // Disable compression of the new frames, finish any already started
#define X393_CMPRS_CBIT_RUN_STANDALONE 0x00000002 // Enable compressor, compress single frame from memory (async)
#define X393_CMPRS_CBIT_RUN_ENABLE 0x00000003 // Enable synchronous compression mode
#define X393_CMPRS_CBIT_CMODE_JPEG18 0x00000000 // Color 4:2:0 3x3 de-bayer core
#define X393_CMPRS_CBIT_CMODE_MONO6 0x00000001 // Mono 4:2:0 (6 blocks)
#define X393_CMPRS_CBIT_CMODE_JP46 0x00000002 // jp4, 6 blocks, original
#define X393_CMPRS_CBIT_CMODE_JP46DC 0x00000003 // jp4, 6 blocks, DC-improved
#define X393_CMPRS_CBIT_CMODE_JPEG20 0x00000004 // Color 4:2:0 with 5x5 de-bayer (not implemented)
#define X393_CMPRS_CBIT_CMODE_JP4 0x00000005 // jp4, 4 blocks
#define X393_CMPRS_CBIT_CMODE_JP4DC 0x00000006 // jp4, 4 blocks, DC-improved
#define X393_CMPRS_CBIT_CMODE_JP4DIFF 0x00000007 // jp4, 4 blocks, differential
#define X393_CMPRS_CBIT_CMODE_JP4DIFFHDR 0x00000008 // jp4, 4 blocks, differential, hdr
#define X393_CMPRS_CBIT_CMODE_JP4DIFFDIV2 0x00000009 // jp4, 4 blocks, differential, divide by 2
#define X393_CMPRS_CBIT_CMODE_JP4DIFFHDRDIV2 0x0000000a // jp4, 4 blocks, differential, hdr,divide by 2
#define X393_CMPRS_CBIT_CMODE_MONO1 0x0000000b // Mono JPEG (not yet implemented)
#define X393_CMPRS_CBIT_CMODE_MONO4 0x0000000e // Mono, 4 blocks (2x2 macroblocks)
#define X393_CMPRS_CBIT_CMODE_JPEG18 0x00000000 // Color 4:2:0
#define X393_CMPRS_CBIT_FRAMES_SINGLE 0x00000000 // Use single-frame buffer
#define X393_CMPRS_CBIT_FRAMES_MULTI 0x00000001 // Use multi-frame buffer
// Compressor control
#define X393_CMPRS_CONTROL_REG(cmprs_chn) (0x40001800 + 0x40 * (cmprs_chn)) // Program compressor channel operation mode, cmprs_chn = 0..3, data type: x393_cmprs_mode_t (wo)
#define X393_CMPRS_STATUS(cmprs_chn) (0x40001804 + 0x40 * (cmprs_chn)) // Setup compressor status report mode, cmprs_chn = 0..3, data type: x393_status_ctrl_t (rw)
#define X393_CMPRS_FORMAT(cmprs_chn) (0x40001808 + 0x40 * (cmprs_chn)) // Compressor frame format, cmprs_chn = 0..3, data type: x393_cmprs_frame_format_t (rw)
#define X393_CMPRS_COLOR_SATURATION(cmprs_chn) (0x4000180c + 0x40 * (cmprs_chn)) // Compressor color saturation, cmprs_chn = 0..3, data type: x393_cmprs_colorsat_t (rw)
#define X393_CMPRS_CORING_MODE(cmprs_chn) (0x40001810 + 0x40 * (cmprs_chn)) // Select coring mode, cmprs_chn = 0..3, data type: x393_cmprs_coring_mode_t (rw)
#define X393_CMPRS_INTERRUPTS(cmprs_chn) (0x40001814 + 0x40 * (cmprs_chn)) // Compressor interrupts control (1 - clear, 2 - disable, 3 - enable), cmprs_chn = 0..3, data type: x393_cmprs_interrupts_t (wo)
// Compressor tables load control
// Several tables can be loaded to the compressor, there are 4 types of them:
// 0:quantization tables - 8 pairs can be loaded and switched at run time,
// 1:coring tables - 8 pairs can be loaded and switched at run time,
// 2:focusing tables - 15 tables can be loaded and switched at run time (16-th table address space
// is used to program other focusing mode parameters,
// 3:Huffman tables - 1 pair tables can be loaded
// Default tables are loaded with the bitstream file (100% quality for quantization table 0
// Loading a table requires to load address of the beginning of data, it includes table type and optional offset
// when multiple tables of the same type are used. Next the data should be written to the same register address,
// the table address is auto-incremented,
// Data for the tables 0..2 should be combined: two items into a single 32-bit DWORD (little endian), treating
// each item as a 16-bit word. The Huffman table is one item per DWORD. Address offset is calculated in DWORDs
// Compressor table types
#define X393_TABLE_QUANTIZATION_TYPE 0x00000000 // Quantization table type
#define X393_TABLE_CORING_TYPE 0x00000001 // Coring table type
#define X393_TABLE_FOCUS_TYPE 0x00000002 // Focus table type
#define X393_TABLE_HUFFMAN_TYPE 0x00000003 // Huffman table type
// Compressor tables control
#define X393_CMPRS_TABLES_DATA(cmprs_chn) (0x40001818 + 0x40 * (cmprs_chn)) // Compressor tables data, cmprs_chn = 0..3, data type: u32 (wo)
#define X393_CMPRS_TABLES_ADDRESS(cmprs_chn) (0x4000181c + 0x40 * (cmprs_chn)) // Compressor tables type/address, cmprs_chn = 0..3, data type: x393_cmprs_table_addr_t (wo)
// Compressor channel status)
#define X393_CMPRS_STATUS(chn) (0x40002040 + 0x4 * (chn)) // Status of the compressor channel (incl. interrupt, chn = 0..3, data type: x393_cmprs_status_t (ro)
#define X393_CMPRS_HIFREQ(chn) (0x40002050 + 0x4 * (chn)) // Focus helper high-frequency amount, chn = 0..3, data type: u32 (ro)
// Compressor DMA control:
// Camera can be configured to use either 2 AXI HP channels (with 2 compressors served by each one) or to use a single AXI HP channel
// serving all 4 compressor channels through its input ports. Below afi_port (0..3) references to one of the 4 ports of each. Control
// for two AXI HP channels is implemented as separate functions. Currently only the first channel is used
#define X393_AFIMUX0_EN 0x40001900 // AFI MUX 0 global/port run/pause control, data type: x393_afimux_en_t (wo)
#define X393_AFIMUX0_RST 0x40001904 // AFI MUX 0 per-port resets, data type: x393_afimux_rst_t (rw)
#define X393_AFIMUX0_REPORT_MODE 0x40001908 // AFI MUX 0 readout pointer report mode, data type: x393_afimux_report_t (wo)
#define X393_AFIMUX0_STATUS_CONTROL 0x40001910 // AFI MUX 0 status report mode, data type: x393_status_ctrl_t (rw)
#define X393_AFIMUX0_SA(afi_port) (0x40001920 + 0x4 * (afi_port)) // AFI MUX 0 DMA buffer start address in 32-byte blocks, afi_port = 0..3, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX0_LEN(afi_port) (0x40001930 + 0x4 * (afi_port)) // AFI MUX 0 DMA buffer length in 32-byte blocks, afi_port = 0..3, data type: x393_afimux_len_t (rw)
// Same for the second AXI HP channel (not currently used)
#define X393_AFIMUX1_EN 0x40001940 // AFI MUX 1 global/port run/pause control, data type: x393_afimux_en_t (wo)
#define X393_AFIMUX1_RST 0x40001944 // AFI MUX 1 per-port resets, data type: x393_afimux_rst_t (rw)
#define X393_AFIMUX1_REPORT_MODE 0x40001948 // AFI MUX 1 readout pointer report mode, data type: x393_afimux_report_t (wo)
#define X393_AFIMUX1_STATUS_CONTROL 0x40001950 // AFI MUX 1 status report mode, data type: x393_status_ctrl_t (rw)
#define X393_AFIMUX1_SA(afi_port) (0x40001960 + 0x4 * (afi_port)) // AFI MUX 1 DMA buffer start address in 32-byte blocks, afi_port = 0..3, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX1_LEN(afi_port) (0x40001970 + 0x4 * (afi_port)) // AFI MUX 1 DMA buffer length in 32-byte blocks, afi_port = 0..3, data type: x393_afimux_len_t (rw)
// Read-only sensors status information (pointer offset and last sequence number)
#define X393_AFIMUX0_STATUS(afi_port) (0x40002060 + 0x4 * (afi_port)) // Status of the AFI MUX 0 (including image pointer), afi_port = 0..3, data type: x393_afimux_status_t (ro)
#define X393_AFIMUX1_STATUS(afi_port) (0x40002070 + 0x4 * (afi_port)) // Status of the AFI MUX 1 (including image pointer), afi_port = 0..3, data type: x393_afimux_status_t (ro)
//
// GPIO contol. Each of the 10 pins can be controlled by the software - individually or simultaneously or from any of the 3 masters (other FPGA modules)
// Currently these modules are;
// A - camsync (intercamera synchronization), uses up to 4 pins
// B - reserved (not yet used) and
// C - logger (IMU, GPS, images), uses 6 pins, including separate i2c available on extension boards
// If several enabled ports try to contol the same bit, highest priority has port C, lowest - software controlled
#define X393_GPIO_SET_PINS 0x40001c00 // State of the GPIO pins and seq. number, data type: x393_gpio_set_pins_t (wo)
#define X393_GPIO_STATUS_CONTROL 0x40001c04 // GPIO status control mode, data type: x393_status_ctrl_t (rw)
// Read-only GPIO pins state
#define X393_GPIO_STATUS 0x400020c0 // State of the GPIO pins and seq. number, data type: x393_gpio_status_t (ro)
// RTC control
#define X393_RTC_USEC 0x40001c10 // RTC microseconds, data type: x393_rtc_usec_t (rw)
#define X393_RTC_SEC_SET 0x40001c14 // RTC seconds and set clock, data type: x393_rtc_sec_t (rw)
#define X393_RTC_CORR 0x40001c18 // RTC correction (+/- 1/256 full scale), data type: x393_rtc_corr_t (rw)
#define X393_RTC_SET_STATUS 0x40001c1c // RTC status control mode, write makes a snapshot to be read out, data type: x393_status_ctrl_t (rw)
// Read-only RTC state
#define X393_RTC_STATUS 0x400020c4 // RTC status reg, data type: x393_rtc_status_t (ro)
#define X393_RTC_STATUS_SEC 0x400020c8 // RTC snapshot seconds, data type: x393_rtc_sec_t (ro)
#define X393_RTC_STATUS_USEC 0x400020cc // RTC snapshot microseconds, data type: x393_rtc_usec_t (ro)
// CAMSYNC control
#define X393_CAMSYNC_MODE 0x40001c20 // CAMSYNC mode, data type: x393_camsync_mode_t (wo)
#define X393_CAMSYNC_TRIG_SRC 0x40001c24 // CAMSYNC trigger source, data type: x393_camsync_io_t (wo)
#define X393_CAMSYNC_TRIG_DST 0x40001c28 // CAMSYNC trigger destination, data type: x393_camsync_io_t (wo)
// Trigger period has special value for small (<255) values written to this register
// d == 0 - disable (stop periodic mode)
// d == 1 - single trigger
// d == 2..255 - set output pulse / input-output serial bit duration (no start generated)
// d >= 256 - repetitive trigger
#define X393_CAMSYNC_TRIG_PERIOD 0x40001c2c // CAMSYNC trigger period, data type: u32 (rw)
#define X393_CAMSYNC_TRIG_DELAY(sens_chn) (0x40001c30 + 0x4 * (sens_chn)) // CAMSYNC trigger delay, sens_chn = 0..3, data type: u32 (rw)
// Command sequencer control
// Controller is programmed through 32 locations. Each registers but the control require two writes:
// First write - register address (AXI_WR_ADDR_BITS bits), second - register data (32 bits)
// Writing to the contol register (0x1f) resets the first/second counter so the next write will be "first"
// 0x0..0xf write directly to the frame number [3:0] modulo 16, except if you write to the frame
// "just missed" - in that case data will go to the current frame.
// 0x10 - write seq commands to be sent ASAP
// 0x11 - write seq commands to be sent after the next frame starts
//
// 0x1e - write seq commands to be sent after the next 14 frame start pulses
// 0x1f - control register:
// [14] - reset all FIFO (takes 32 clock pulses), also - stops seq until run command
// [13:12] - 3 - run seq, 2 - stop seq , 1,0 - no change to run state
// [1:0] - 0: NOP, 1: clear IRQ, 2 - Clear IE, 3: set IE
#define X393_CMDFRAMESEQ_CTRL(sens_chn) (0x40001e7c + 0x80 * (sens_chn)) // CMDFRAMESEQ control register, sens_chn = 0..3, data type: x393_cmdframeseq_mode_t (wo)
#define X393_CMDFRAMESEQ_ABS(sens_chn,offset) (0x40001e00)+ 0x20 * (sens_chn)+ 0x1 * (offset)) // CMDFRAMESEQ absolute frame address/command, sens_chn = 0..3, offset = 0..15, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL(sens_chn,offset) (0x40001e40)+ 0x20 * (sens_chn)+ 0x1 * (offset)) // CMDFRAMESEQ relative frame address/command, sens_chn = 0..3, offset = 0..14, data type: u32 (wo)
// Command sequencer multiplexer, provides current frame number for each sensor channel and interrupt status/interrupt masks for them.
// Interrupts and interrupt masks are controlled through channel CMDFRAMESEQ module
#define X393_CMDSEQMUX_STATUS_CTRL 0x40001c08 // CMDSEQMUX status control mode (status provides current frame numbers), data type: x393_status_ctrl_t (rw)
#define X393_CMDSEQMUX_STATUS 0x400020e0 // CMDSEQMUX status data (frame numbers and interrupts, data type: x393_cmdseqmux_status_t (ro)
// Event logger
// Event logger configuration/data is writtent to the module ising two 32-bit register locations : data and address.
// Address consists of 2 parts - 2-bit page (configuration, imu, gps, message) and a 5-bit sub-address autoincremented when writing data.
// Register pages:
#define X393_LOGGER_PAGE_CONF 0x00000000 // Logger configuration page
#define X393_LOGGER_PAGE_IMU 0x00000003 // Logger IMU parameters page
#define X393_LOGGER_PAGE_GPS 0x00000001 // Logger GPS parameters page
#define X393_LOGGER_PAGE_MSG 0x00000002 // Logger MSG (odometer) parameters page
// Register configuration addresses (with X393_LOGGER_PAGE_CONF):
#define X393_LOGGER_PERIOD 0x00000000 // IMU period (in SPI clocks, high word 0xffff - use IMU ready)
#define X393_LOGGER_BIT_DURATION 0x00000001 // IMU SPI bit duration (in mclk == 50 ns periods?)
#define X393_LOGGER_BIT_HALF_PERIOD 0x00000002 // Logger rs232 half bit period (in mclk == 50 ns periods?)
#define X393_LOGGER_CONFIG 0x00000003 // Logger IMU parameters page
#define X393_LOGGER_STATUS_CTRL 0x40001c88 // Logger status configuration (to report sample number), data type: x393_status_ctrl_t (rw)
#define X393_LOGGER_DATA 0x40001c80 // Logger register write data, data type: x393_logger_data_t (wo)
#define X393_LOGGER_ADDRESS 0x40001c84 // Logger register write page/address, data type: x393_logger_address_t (wo)
#define X393_LOGGER_STATUS 0x400020e4 // Logger status data (sequence number), data type: x393_logger_status_t (ro)
// MULT SAXI DMA engine control. Of 4 channels only one (number 0) is currently used - for the event logger
#define X393_MULT_SAXI_STATUS_CTRL 0x40001ce0 // MULT_SAXI status control mode (status provides current DWORD pointer), data type: x393_status_ctrl_t (rw)
#define X393_MULT_SAXI_BUF_ADDRESS(chn) (0x40001cc0 + 0x8 * (chn)) // MULT_SAXI buffer start address in DWORDS, chn = 0..3, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_BUF_LEN(chn) (0x40001cc4 + 0x8 * (chn)) // MULT_SAXI buffer length in DWORDS, chn = 0..3, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_STATUS(chn) (0x400020d0 + 0x4 * (chn)) // MULT_SAXI current DWORD pointer, chn = 0..3, data type: x393_mult_saxi_al_t (ro)
// MULTI_CLK - global clock generation PLLs. Interface provided for debugging, no interaction is needed for normal operation
#define X393_MULTICLK_STATUS_CTRL 0x40001ca4 // MULTI_CLK status generation (do not use or do not set auto), data type: x393_status_ctrl_t (rw)
#define X393_MULTICLK_CTRL 0x40001ca0 // MULTI_CLK reset and power down control, data type: x393_multiclk_ctl_t (rw)
#define X393_MULTICLK_STATUS 0x400020e8 // MULTI_CLK lock and toggle state, data type: x393_multiclk_status_t (ro)
// Debug ring module
// Debug ring module (when enabled with DEBUG_RING in system_defines.vh) provides low-overhead read/write access to internal test points
// To write data you need to write 32-bit data with x393_debug_shift(u32) multiple times to fill the ring register (length depends on
// implementation), skip this step if only reading from the modules under test is required.
// Exchange data with x393_debug_load(), the data from the ring shift register.
// Write 0xffffffff (or other "magic" data) if the ring length is unknown - this DWORD will appear on the output after the useful data
// Read all data, waiting for status sequence number to be incremented,status mode should be set to auto (3) wor each DWORD certain
// number of times or until the "magic" DWORD appears, writing "magic" to shift out next 32 bits.
#define X393_DEBUG_STATUS_CTRL 0x40001c48 // Debug ring status generation - set to auto(3) if used, data type: x393_status_ctrl_t (rw)
#define X393_DEBUG_LOAD 0x40001c44 // Debug ring copy shift register to/from tested modules
#define X393_DEBUG_SHIFT 0x40001c40 // Debug ring shift ring by 32 bits, data type: u32 (wo)
#define X393_DEBUG_STATUS 0x400023f0 // Debug read status (watch sequence number), data type: x393_debug_status_t (ro)
#define X393_DEBUG_READ 0x400023f4 // Debug read DWORD form ring register, data type: u32 (ro)
// Write-only addresses to program memory channel 3 (test channel)
#define X393_MCNTRL_CHN3_SCANLINE_MODE 0x400004c0 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_STATUS_CNTRL 0x400004c4 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_CHN3_SCANLINE_STARTADDR 0x400004c8 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_FRAME_SIZE 0x400004cc // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_FRAME_LAST 0x400004d0 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_FRAME_FULL_WIDTH 0x400004d4 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_WINDOW_WH 0x400004d8 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_WINDOW_X0Y0 0x400004dc // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_STARTXY 0x400004e0 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
// Write-only addresses to program memory channel 2 (test channel)
#define X393_MCNTRL_CHN2_TILED_MODE 0x40000500 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_MCNTRL_CHN2_TILED_STATUS_CNTRL 0x40000504 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_CHN2_TILED_STARTADDR 0x40000508 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_MCNTRL_CHN2_TILED_FRAME_SIZE 0x4000050c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_MCNTRL_CHN2_TILED_FRAME_LAST 0x40000510 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_MCNTRL_CHN2_TILED_FRAME_FULL_WIDTH 0x40000514 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_MCNTRL_CHN2_TILED_WINDOW_WH 0x40000518 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_MCNTRL_CHN2_TILED_WINDOW_X0Y0 0x4000051c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_MCNTRL_CHN2_TILED_STARTXY 0x40000520 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_MCNTRL_CHN2_TILED_TILE_WHS 0x40000524 // Set tile size/step (tiled mode only), data type: x393_mcntrl_window_tile_whs_t (wo)
// Write-only addresses to program memory channel 4 (test channel)
#define X393_MCNTRL_CHN4_TILED_MODE 0x40000540 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_MCNTRL_CHN4_TILED_STATUS_CNTRL 0x40000544 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_CHN4_TILED_STARTADDR 0x40000548 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_MCNTRL_CHN4_TILED_FRAME_SIZE 0x4000054c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_MCNTRL_CHN4_TILED_FRAME_LAST 0x40000550 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_MCNTRL_CHN4_TILED_FRAME_FULL_WIDTH 0x40000554 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_MCNTRL_CHN4_TILED_WINDOW_WH 0x40000558 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_MCNTRL_CHN4_TILED_WINDOW_X0Y0 0x4000055c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_MCNTRL_CHN4_TILED_STARTXY 0x40000560 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_MCNTRL_CHN4_TILED_TILE_WHS 0x40000564 // Set tile size/step (tiled mode only), data type: x393_mcntrl_window_tile_whs_t (wo)
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/x393_map.h 0000664 0000000 0000000 00000321465 12703306510 0026613 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* File: x393_map.h
* Date: 2016-04-06
* Author: auto-generated file, see x393_export_c.py
* Description: Sorted hardware addresses map
*******************************************************************************/
#define X393_MCNTRL_DLY_SET 0x40000080 // Set all pre-programmed delays
// RESERVED: 0x3 DWORDs
#define X393_MCNTRL_CMDA_DIS 0x40000090 // Disable DDR3 memory command/address lines
#define X393_MCNTRL_CMDA_EN 0x40000094 // Enable DDR3 memory command/address lines
#define X393_MCNTRL_SDRST_DIS 0x40000098 // Disable DDR3 memory reset
#define X393_MCNTRL_SDRST_EN 0x4000009c // Enable DDR3 memory reset
#define X393_MCNTRL_CKE_DIS 0x400000a0 // Disable DDR3 memory CKE
#define X393_MCNTRL_CKE_EN 0x400000a4 // Enable DDR3 memory CKE
// RESERVED: 0x6 DWORDs
#define X393_MCNTRL_DIS 0x400000c0 // Disable DDR3 memory controller
#define X393_MCNTRL_EN 0x400000c4 // Enable DDR3 memory controller
#define X393_MCNTRL_REFRESH_DIS 0x400000c8 // Disable DDR3 memory refresh
#define X393_MCNTRL_REFRESH_EN 0x400000cc // Enable DDR3 memory refresh
// RESERVED: 0x1c DWORDs
#define X393_MCNTRL_DQS_DQM_PATT 0x40000140 // Setup DQS and DQM patterns, data type: x393_mcntr_dqs_dqm_patt_t (rw)
#define X393_MCNTRL_DQ_DQS_TRI 0x40000144 // Setup DQS and DQ on/off sequence, data type: x393_mcntr_dqs_dqm_tri_t (rw)
#define X393_MCNTRL_WBUF_DLY 0x40000148 // Set write buffer delay, data type: x393_wbuf_dly_t (rw)
#define X393_MCONTR_TOP_16BIT_STATUS_CNTRL 0x4000014c // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCONTR_PHY_STATUS_CNTRL 0x40000150 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
// RESERVED: 0xb DWORDs
#define X393_MCNTRL_ARBITER_PRIORITY__0 0x40000180 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__1 0x40000184 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__2 0x40000188 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__3 0x4000018c // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__4 0x40000190 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__5 0x40000194 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__6 0x40000198 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__7 0x4000019c // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__8 0x400001a0 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__9 0x400001a4 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__10 0x400001a8 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__11 0x400001ac // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__12 0x400001b0 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__13 0x400001b4 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__14 0x400001b8 // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_ARBITER_PRIORITY__15 0x400001bc // Set memory arbiter priority (currently r/w, may become just wo), data type: x393_arbite_pri_t (rw)
#define X393_MCNTRL_CHN_EN 0x400001c0 // Enable/disable memory channels (currently r/w, may become just wo), data type: x393_mcntr_chn_en_t (rw)
// RESERVED: 0xf DWORDs
#define X393_MCNTRL_DQ_ODLY0__0 0x40000200 // Lane0 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY0__1 0x40000204 // Lane0 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY0__2 0x40000208 // Lane0 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY0__3 0x4000020c // Lane0 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY0__4 0x40000210 // Lane0 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY0__5 0x40000214 // Lane0 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY0__6 0x40000218 // Lane0 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY0__7 0x4000021c // Lane0 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQS_ODLY0 0x40000220 // Lane0 DQS output delay , data type: x393_dly_t (rw)
#define X393_MCNTRL_DM_ODLY0 0x40000224 // Lane0 DM output delay , data type: x393_dly_t (rw)
// RESERVED: 0x6 DWORDs
#define X393_MCNTRL_DQ_IDLY0__0 0x40000240 // Lane0 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY0__1 0x40000244 // Lane0 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY0__2 0x40000248 // Lane0 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY0__3 0x4000024c // Lane0 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY0__4 0x40000250 // Lane0 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY0__5 0x40000254 // Lane0 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY0__6 0x40000258 // Lane0 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY0__7 0x4000025c // Lane0 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQS_IDLY0 0x40000260 // Lane0 DQS input delay , data type: x393_dly_t (rw)
// RESERVED: 0x7 DWORDs
#define X393_MCNTRL_DQ_ODLY1__0 0x40000280 // Lane1 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY1__1 0x40000284 // Lane1 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY1__2 0x40000288 // Lane1 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY1__3 0x4000028c // Lane1 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY1__4 0x40000290 // Lane1 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY1__5 0x40000294 // Lane1 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY1__6 0x40000298 // Lane1 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_ODLY1__7 0x4000029c // Lane1 DQ output delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQS_ODLY1 0x400002a0 // Lane1 DQS output delay , data type: x393_dly_t (rw)
#define X393_MCNTRL_DM_ODLY1 0x400002a4 // Lane1 DM output delay , data type: x393_dly_t (rw)
// RESERVED: 0x6 DWORDs
#define X393_MCNTRL_DQ_IDLY1__0 0x400002c0 // Lane1 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY1__1 0x400002c4 // Lane1 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY1__2 0x400002c8 // Lane1 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY1__3 0x400002cc // Lane1 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY1__4 0x400002d0 // Lane1 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY1__5 0x400002d4 // Lane1 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY1__6 0x400002d8 // Lane1 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQ_IDLY1__7 0x400002dc // Lane1 DQ input delays , data type: x393_dly_t (rw)
#define X393_MCNTRL_DQS_IDLY1 0x400002e0 // Lane1 DQS input delay , data type: x393_dly_t (rw)
// RESERVED: 0x7 DWORDs
#define X393_MCNTRL_CMDA_ODLY__0 0x40000300 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__1 0x40000304 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__2 0x40000308 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__3 0x4000030c // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__4 0x40000310 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__5 0x40000314 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__6 0x40000318 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__7 0x4000031c // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__8 0x40000320 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__9 0x40000324 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__10 0x40000328 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__11 0x4000032c // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__12 0x40000330 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__13 0x40000334 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__14 0x40000338 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__15 0x4000033c // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__16 0x40000340 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__17 0x40000344 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__18 0x40000348 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__19 0x4000034c // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__20 0x40000350 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__21 0x40000354 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__22 0x40000358 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__23 0x4000035c // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__24 0x40000360 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__25 0x40000364 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__26 0x40000368 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__27 0x4000036c // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__28 0x40000370 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__29 0x40000374 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__30 0x40000378 // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_CMDA_ODLY__31 0x4000037c // Address, bank and commands delays, data type: x393_dly_t (rw)
#define X393_MCNTRL_PHASE 0x40000380 // Clock phase, data type: x393_dly_t (rw)
// RESERVED: 0x13 DWORDs
#define X393_MCNTRL_TEST01_CHN2_MODE 0x400003d0 // Set command for test01 channel 2, data type: x393_test01_mode_t (wo)
#define X393_MCNTRL_TEST01_CHN2_STATUS_CNTRL 0x400003d4 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_TEST01_CHN3_MODE 0x400003d8 // Set command for test01 channel 3, data type: x393_test01_mode_t (wo)
#define X393_MCNTRL_TEST01_CHN3_STATUS_CNTRL 0x400003dc // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_TEST01_CHN4_MODE 0x400003e0 // Set command for test01 channel 4, data type: x393_test01_mode_t (wo)
#define X393_MCNTRL_TEST01_CHN4_STATUS_CNTRL 0x400003e4 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
// RESERVED: 0x6 DWORDs
#define X393_MCNTRL_PS_EN_RST 0x40000400 // Set PS PIO enable and reset, data type: x393_ps_pio_en_rst_t (wo)
#define X393_MCNTRL_PS_CMD 0x40000404 // Set PS PIO commands, data type: x393_ps_pio_cmd_t (wo)
#define X393_MCNTRL_PS_STATUS_CNTRL 0x40000408 // Set PS PIO status control register (status update mode), data type: x393_status_ctrl_t (rw)
// RESERVED: 0x1d DWORDs
#define X393_MEMBRIDGE_SCANLINE_MODE 0x40000480 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_MEMBRIDGE_SCANLINE_STATUS_CNTRL 0x40000484 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MEMBRIDGE_SCANLINE_STARTADDR 0x40000488 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_MEMBRIDGE_SCANLINE_FRAME_SIZE 0x4000048c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_MEMBRIDGE_SCANLINE_FRAME_LAST 0x40000490 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_MEMBRIDGE_SCANLINE_FRAME_FULL_WIDTH 0x40000494 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_MEMBRIDGE_SCANLINE_WINDOW_WH 0x40000498 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_MEMBRIDGE_SCANLINE_WINDOW_X0Y0 0x4000049c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_MEMBRIDGE_SCANLINE_STARTXY 0x400004a0 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
// RESERVED: 0x7 DWORDs
#define X393_MCNTRL_CHN3_SCANLINE_MODE 0x400004c0 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_STATUS_CNTRL 0x400004c4 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_CHN3_SCANLINE_STARTADDR 0x400004c8 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_FRAME_SIZE 0x400004cc // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_FRAME_LAST 0x400004d0 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_FRAME_FULL_WIDTH 0x400004d4 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_WINDOW_WH 0x400004d8 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_WINDOW_X0Y0 0x400004dc // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_MCNTRL_CHN3_SCANLINE_STARTXY 0x400004e0 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
// RESERVED: 0x7 DWORDs
#define X393_MCNTRL_CHN2_TILED_MODE 0x40000500 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_MCNTRL_CHN2_TILED_STATUS_CNTRL 0x40000504 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_CHN2_TILED_STARTADDR 0x40000508 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_MCNTRL_CHN2_TILED_FRAME_SIZE 0x4000050c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_MCNTRL_CHN2_TILED_FRAME_LAST 0x40000510 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_MCNTRL_CHN2_TILED_FRAME_FULL_WIDTH 0x40000514 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_MCNTRL_CHN2_TILED_WINDOW_WH 0x40000518 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_MCNTRL_CHN2_TILED_WINDOW_X0Y0 0x4000051c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_MCNTRL_CHN2_TILED_STARTXY 0x40000520 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_MCNTRL_CHN2_TILED_TILE_WHS 0x40000524 // Set tile size/step (tiled mode only), data type: x393_mcntrl_window_tile_whs_t (wo)
// RESERVED: 0x6 DWORDs
#define X393_MCNTRL_CHN4_TILED_MODE 0x40000540 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_MCNTRL_CHN4_TILED_STATUS_CNTRL 0x40000544 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_MCNTRL_CHN4_TILED_STARTADDR 0x40000548 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_MCNTRL_CHN4_TILED_FRAME_SIZE 0x4000054c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_MCNTRL_CHN4_TILED_FRAME_LAST 0x40000550 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_MCNTRL_CHN4_TILED_FRAME_FULL_WIDTH 0x40000554 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_MCNTRL_CHN4_TILED_WINDOW_WH 0x40000558 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_MCNTRL_CHN4_TILED_WINDOW_X0Y0 0x4000055c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_MCNTRL_CHN4_TILED_STARTXY 0x40000560 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_MCNTRL_CHN4_TILED_TILE_WHS 0x40000564 // Set tile size/step (tiled mode only), data type: x393_mcntrl_window_tile_whs_t (wo)
// RESERVED: 0xa6 DWORDs
#define X393_MEMBRIDGE_CTRL 0x40000800 // Issue membridge command, data type: x393_membridge_cmd_t (wo)
#define X393_MEMBRIDGE_STATUS_CNTRL 0x40000804 // Set membridge status control register, data type: x393_status_ctrl_t (rw)
#define X393_MEMBRIDGE_LO_ADDR64 0x40000808 // start address of the system memory range in QWORDs (4 LSBs==0), data type: u29_t (wo)
#define X393_MEMBRIDGE_SIZE64 0x4000080c // size of the system memory range in QWORDs (4 LSBs==0), rolls over, data type: u29_t (wo)
#define X393_MEMBRIDGE_START64 0x40000810 // start of transfer offset to system memory range in QWORDs (4 LSBs==0), data type: u29_t (wo)
#define X393_MEMBRIDGE_LEN64 0x40000814 // Full length of transfer in QWORDs, data type: u29_t (wo)
#define X393_MEMBRIDGE_WIDTH64 0x40000818 // Frame width in QWORDs (last xfer in each line may be partial), data type: u29_t (wo)
#define X393_MEMBRIDGE_MODE 0x4000081c // AXI cache mode, data type: x393_membridge_mode_t (wo)
// RESERVED: 0x1f8 DWORDs
#define X393_SENS_MODE__0 0x40001000 // Write sensor channel mode, data type: x393_sens_mode_t (wo)
// RESERVED: 0x1 DWORD
#define X393_SENSI2C_CTRL__0 0x40001008 // Control sensor i2c, write i2c LUT, data type: x393_i2c_ctltbl_t (wo)
#define X393_SENSI2C_STATUS_CTRL__0 0x4000100c // Setup sensor i2c status report mode, data type: x393_status_ctrl_t (rw)
// RESERVED: 0x2 DWORDs
#define X393_SENS_SYNC_MULT__0 0x40001018 // Configure frames combining, data type: x393_sens_sync_mult_t (wo)
#define X393_SENS_SYNC_LATE__0 0x4000101c // Configure frame sync delay, data type: x393_sens_sync_late_t (wo)
#define X393_SENSIO_CTRL__0 0x40001020 // Configure sensor I/O port, data type: x393_sensio_ctl_t (wo)
#define X393_SENSIO_STATUS_CNTRL__0 0x40001024 // Set status control for SENSIO module, data type: x393_status_ctrl_t (rw)
#define X393_SENSIO_JTAG__0 0x40001028 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jtag_t (wo)
#define X393_SENSIO_WIDTH__0 0x4000102c // Set sensor line in pixels (0 - use line sync from the sensor), data type: x393_sensio_width_t (rw)
#define X393_SENSIO_TIM0__0 0x40001030 // Sensor port i/o timing configuration, register 0, data type: x393_sensio_tim0_t (rw)
#define X393_SENSIO_TIM1__0 0x40001034 // Sensor port i/o timing configuration, register 1, data type: x393_sensio_tim1_t (rw)
#define X393_SENSIO_TIM2__0 0x40001038 // Sensor port i/o timing configuration, register 2, data type: x393_sensio_tim2_t (rw)
#define X393_SENSIO_TIM3__0 0x4000103c // Sensor port i/o timing configuration, register 3, data type: x393_sensio_tim3_t (rw)
#define X393_SENSI2C_ABS__0__0 0x40001040 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__1 0x40001044 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__2 0x40001048 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__3 0x4000104c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__4 0x40001050 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__5 0x40001054 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__6 0x40001058 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__7 0x4000105c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__8 0x40001060 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__9 0x40001064 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__10 0x40001068 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__11 0x4000106c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__12 0x40001070 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__13 0x40001074 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__14 0x40001078 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__0__15 0x4000107c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__0 0x40001080 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__1 0x40001084 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__2 0x40001088 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__3 0x4000108c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__4 0x40001090 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__5 0x40001094 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__6 0x40001098 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__7 0x4000109c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__8 0x400010a0 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__9 0x400010a4 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__10 0x400010a8 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__11 0x400010ac // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__12 0x400010b0 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__13 0x400010b4 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__14 0x400010b8 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__0__15 0x400010bc // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_HISTOGRAM_LT0__0 0x400010c0 // Specify histogram 0 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH0__0 0x400010c4 // Specify histogram 0 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT1__0 0x400010c8 // Specify histogram 1 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH1__0 0x400010cc // Specify histogram 1 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT2__0 0x400010d0 // Specify histogram 2 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH2__0 0x400010d4 // Specify histogram 2 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT3__0 0x400010d8 // Specify histogram 3 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH3__0 0x400010dc // Specify histogram 3 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_SENS_GAMMA_CTRL__0 0x400010e0 // Gamma module control, data type: x393_gamma_ctl_t (rw)
#define X393_SENS_GAMMA_TBL__0 0x400010e4 // Write sensor gamma table address/data (with autoincrement), data type: x393_gamma_tbl_t (wo)
#define X393_SENS_GAMMA_HEIGHT01M1__0 0x400010e8 // Gamma module subframes 0,1 heights minus 1, data type: x393_gamma_height01m1_t (rw)
#define X393_SENS_GAMMA_HEIGHT2M1__0 0x400010ec // Gamma module subframe 2 height minus 1, data type: x393_gamma_height2m1_t (rw)
#define X393_LENS_HEIGHT0_M1__0 0x400010f0 // Subframe 0 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT1_M1__0 0x400010f4 // Subframe 1 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT2_M1__0 0x400010f8 // Subframe 2 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_CORR_CNH_ADDR_DATA__0 0x400010fc // Combined address/data to write lens vignetting correction coefficients, data type: x393_lens_corr_t (wo)
#define X393_SENS_MODE__1 0x40001100 // Write sensor channel mode, data type: x393_sens_mode_t (wo)
// RESERVED: 0x1 DWORD
#define X393_SENSI2C_CTRL__1 0x40001108 // Control sensor i2c, write i2c LUT, data type: x393_i2c_ctltbl_t (wo)
#define X393_SENSI2C_STATUS_CTRL__1 0x4000110c // Setup sensor i2c status report mode, data type: x393_status_ctrl_t (rw)
// RESERVED: 0x2 DWORDs
#define X393_SENS_SYNC_MULT__1 0x40001118 // Configure frames combining, data type: x393_sens_sync_mult_t (wo)
#define X393_SENS_SYNC_LATE__1 0x4000111c // Configure frame sync delay, data type: x393_sens_sync_late_t (wo)
#define X393_SENSIO_CTRL__1 0x40001120 // Configure sensor I/O port, data type: x393_sensio_ctl_t (wo)
#define X393_SENSIO_STATUS_CNTRL__1 0x40001124 // Set status control for SENSIO module, data type: x393_status_ctrl_t (rw)
#define X393_SENSIO_JTAG__1 0x40001128 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jtag_t (wo)
#define X393_SENSIO_WIDTH__1 0x4000112c // Set sensor line in pixels (0 - use line sync from the sensor), data type: x393_sensio_width_t (rw)
#define X393_SENSIO_TIM0__1 0x40001130 // Sensor port i/o timing configuration, register 0, data type: x393_sensio_tim0_t (rw)
#define X393_SENSIO_TIM1__1 0x40001134 // Sensor port i/o timing configuration, register 1, data type: x393_sensio_tim1_t (rw)
#define X393_SENSIO_TIM2__1 0x40001138 // Sensor port i/o timing configuration, register 2, data type: x393_sensio_tim2_t (rw)
#define X393_SENSIO_TIM3__1 0x4000113c // Sensor port i/o timing configuration, register 3, data type: x393_sensio_tim3_t (rw)
#define X393_SENSI2C_ABS__1__0 0x40001140 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__1 0x40001144 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__2 0x40001148 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__3 0x4000114c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__4 0x40001150 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__5 0x40001154 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__6 0x40001158 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__7 0x4000115c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__8 0x40001160 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__9 0x40001164 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__10 0x40001168 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__11 0x4000116c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__12 0x40001170 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__13 0x40001174 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__14 0x40001178 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__1__15 0x4000117c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__0 0x40001180 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__1 0x40001184 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__2 0x40001188 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__3 0x4000118c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__4 0x40001190 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__5 0x40001194 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__6 0x40001198 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__7 0x4000119c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__8 0x400011a0 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__9 0x400011a4 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__10 0x400011a8 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__11 0x400011ac // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__12 0x400011b0 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__13 0x400011b4 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__14 0x400011b8 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__1__15 0x400011bc // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_HISTOGRAM_LT0__1 0x400011c0 // Specify histogram 0 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH0__1 0x400011c4 // Specify histogram 0 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT1__1 0x400011c8 // Specify histogram 1 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH1__1 0x400011cc // Specify histogram 1 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT2__1 0x400011d0 // Specify histogram 2 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH2__1 0x400011d4 // Specify histogram 2 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT3__1 0x400011d8 // Specify histogram 3 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH3__1 0x400011dc // Specify histogram 3 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_SENS_GAMMA_CTRL__1 0x400011e0 // Gamma module control, data type: x393_gamma_ctl_t (rw)
#define X393_SENS_GAMMA_TBL__1 0x400011e4 // Write sensor gamma table address/data (with autoincrement), data type: x393_gamma_tbl_t (wo)
#define X393_SENS_GAMMA_HEIGHT01M1__1 0x400011e8 // Gamma module subframes 0,1 heights minus 1, data type: x393_gamma_height01m1_t (rw)
#define X393_SENS_GAMMA_HEIGHT2M1__1 0x400011ec // Gamma module subframe 2 height minus 1, data type: x393_gamma_height2m1_t (rw)
#define X393_LENS_HEIGHT0_M1__1 0x400011f0 // Subframe 0 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT1_M1__1 0x400011f4 // Subframe 1 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT2_M1__1 0x400011f8 // Subframe 2 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_CORR_CNH_ADDR_DATA__1 0x400011fc // Combined address/data to write lens vignetting correction coefficients, data type: x393_lens_corr_t (wo)
#define X393_SENS_MODE__2 0x40001200 // Write sensor channel mode, data type: x393_sens_mode_t (wo)
// RESERVED: 0x1 DWORD
#define X393_SENSI2C_CTRL__2 0x40001208 // Control sensor i2c, write i2c LUT, data type: x393_i2c_ctltbl_t (wo)
#define X393_SENSI2C_STATUS_CTRL__2 0x4000120c // Setup sensor i2c status report mode, data type: x393_status_ctrl_t (rw)
// RESERVED: 0x2 DWORDs
#define X393_SENS_SYNC_MULT__2 0x40001218 // Configure frames combining, data type: x393_sens_sync_mult_t (wo)
#define X393_SENS_SYNC_LATE__2 0x4000121c // Configure frame sync delay, data type: x393_sens_sync_late_t (wo)
#define X393_SENSIO_CTRL__2 0x40001220 // Configure sensor I/O port, data type: x393_sensio_ctl_t (wo)
#define X393_SENSIO_STATUS_CNTRL__2 0x40001224 // Set status control for SENSIO module, data type: x393_status_ctrl_t (rw)
#define X393_SENSIO_JTAG__2 0x40001228 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jtag_t (wo)
#define X393_SENSIO_WIDTH__2 0x4000122c // Set sensor line in pixels (0 - use line sync from the sensor), data type: x393_sensio_width_t (rw)
#define X393_SENSIO_TIM0__2 0x40001230 // Sensor port i/o timing configuration, register 0, data type: x393_sensio_tim0_t (rw)
#define X393_SENSIO_TIM1__2 0x40001234 // Sensor port i/o timing configuration, register 1, data type: x393_sensio_tim1_t (rw)
#define X393_SENSIO_TIM2__2 0x40001238 // Sensor port i/o timing configuration, register 2, data type: x393_sensio_tim2_t (rw)
#define X393_SENSIO_TIM3__2 0x4000123c // Sensor port i/o timing configuration, register 3, data type: x393_sensio_tim3_t (rw)
#define X393_SENSI2C_ABS__2__0 0x40001240 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__1 0x40001244 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__2 0x40001248 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__3 0x4000124c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__4 0x40001250 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__5 0x40001254 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__6 0x40001258 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__7 0x4000125c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__8 0x40001260 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__9 0x40001264 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__10 0x40001268 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__11 0x4000126c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__12 0x40001270 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__13 0x40001274 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__14 0x40001278 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__2__15 0x4000127c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__0 0x40001280 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__1 0x40001284 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__2 0x40001288 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__3 0x4000128c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__4 0x40001290 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__5 0x40001294 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__6 0x40001298 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__7 0x4000129c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__8 0x400012a0 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__9 0x400012a4 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__10 0x400012a8 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__11 0x400012ac // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__12 0x400012b0 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__13 0x400012b4 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__14 0x400012b8 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__2__15 0x400012bc // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_HISTOGRAM_LT0__2 0x400012c0 // Specify histogram 0 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH0__2 0x400012c4 // Specify histogram 0 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT1__2 0x400012c8 // Specify histogram 1 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH1__2 0x400012cc // Specify histogram 1 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT2__2 0x400012d0 // Specify histogram 2 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH2__2 0x400012d4 // Specify histogram 2 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT3__2 0x400012d8 // Specify histogram 3 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH3__2 0x400012dc // Specify histogram 3 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_SENS_GAMMA_CTRL__2 0x400012e0 // Gamma module control, data type: x393_gamma_ctl_t (rw)
#define X393_SENS_GAMMA_TBL__2 0x400012e4 // Write sensor gamma table address/data (with autoincrement), data type: x393_gamma_tbl_t (wo)
#define X393_SENS_GAMMA_HEIGHT01M1__2 0x400012e8 // Gamma module subframes 0,1 heights minus 1, data type: x393_gamma_height01m1_t (rw)
#define X393_SENS_GAMMA_HEIGHT2M1__2 0x400012ec // Gamma module subframe 2 height minus 1, data type: x393_gamma_height2m1_t (rw)
#define X393_LENS_HEIGHT0_M1__2 0x400012f0 // Subframe 0 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT1_M1__2 0x400012f4 // Subframe 1 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT2_M1__2 0x400012f8 // Subframe 2 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_CORR_CNH_ADDR_DATA__2 0x400012fc // Combined address/data to write lens vignetting correction coefficients, data type: x393_lens_corr_t (wo)
#define X393_SENS_MODE__3 0x40001300 // Write sensor channel mode, data type: x393_sens_mode_t (wo)
// RESERVED: 0x1 DWORD
#define X393_SENSI2C_CTRL__3 0x40001308 // Control sensor i2c, write i2c LUT, data type: x393_i2c_ctltbl_t (wo)
#define X393_SENSI2C_STATUS_CTRL__3 0x4000130c // Setup sensor i2c status report mode, data type: x393_status_ctrl_t (rw)
// RESERVED: 0x2 DWORDs
#define X393_SENS_SYNC_MULT__3 0x40001318 // Configure frames combining, data type: x393_sens_sync_mult_t (wo)
#define X393_SENS_SYNC_LATE__3 0x4000131c // Configure frame sync delay, data type: x393_sens_sync_late_t (wo)
#define X393_SENSIO_CTRL__3 0x40001320 // Configure sensor I/O port, data type: x393_sensio_ctl_t (wo)
#define X393_SENSIO_STATUS_CNTRL__3 0x40001324 // Set status control for SENSIO module, data type: x393_status_ctrl_t (rw)
#define X393_SENSIO_JTAG__3 0x40001328 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jtag_t (wo)
#define X393_SENSIO_WIDTH__3 0x4000132c // Set sensor line in pixels (0 - use line sync from the sensor), data type: x393_sensio_width_t (rw)
#define X393_SENSIO_TIM0__3 0x40001330 // Sensor port i/o timing configuration, register 0, data type: x393_sensio_tim0_t (rw)
#define X393_SENSIO_TIM1__3 0x40001334 // Sensor port i/o timing configuration, register 1, data type: x393_sensio_tim1_t (rw)
#define X393_SENSIO_TIM2__3 0x40001338 // Sensor port i/o timing configuration, register 2, data type: x393_sensio_tim2_t (rw)
#define X393_SENSIO_TIM3__3 0x4000133c // Sensor port i/o timing configuration, register 3, data type: x393_sensio_tim3_t (rw)
#define X393_SENSI2C_ABS__3__0 0x40001340 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__1 0x40001344 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__2 0x40001348 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__3 0x4000134c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__4 0x40001350 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__5 0x40001354 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__6 0x40001358 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__7 0x4000135c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__8 0x40001360 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__9 0x40001364 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__10 0x40001368 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__11 0x4000136c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__12 0x40001370 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__13 0x40001374 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__14 0x40001378 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_ABS__3__15 0x4000137c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__0 0x40001380 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__1 0x40001384 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__2 0x40001388 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__3 0x4000138c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__4 0x40001390 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__5 0x40001394 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__6 0x40001398 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__7 0x4000139c // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__8 0x400013a0 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__9 0x400013a4 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__10 0x400013a8 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__11 0x400013ac // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__12 0x400013b0 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__13 0x400013b4 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__14 0x400013b8 // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_SENSI2C_REL__3__15 0x400013bc // Write sensor i2c sequencer, data type: u32 (wo)
#define X393_HISTOGRAM_LT0__3 0x400013c0 // Specify histogram 0 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH0__3 0x400013c4 // Specify histogram 0 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT1__3 0x400013c8 // Specify histogram 1 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH1__3 0x400013cc // Specify histogram 1 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT2__3 0x400013d0 // Specify histogram 2 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH2__3 0x400013d4 // Specify histogram 2 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_HISTOGRAM_LT3__3 0x400013d8 // Specify histogram 3 left/top, data type: x393_hist_left_top_t (rw)
#define X393_HISTOGRAM_WH3__3 0x400013dc // Specify histogram 3 width/height, data type: x393_hist_width_height_m1_t (rw)
#define X393_SENS_GAMMA_CTRL__3 0x400013e0 // Gamma module control, data type: x393_gamma_ctl_t (rw)
#define X393_SENS_GAMMA_TBL__3 0x400013e4 // Write sensor gamma table address/data (with autoincrement), data type: x393_gamma_tbl_t (wo)
#define X393_SENS_GAMMA_HEIGHT01M1__3 0x400013e8 // Gamma module subframes 0,1 heights minus 1, data type: x393_gamma_height01m1_t (rw)
#define X393_SENS_GAMMA_HEIGHT2M1__3 0x400013ec // Gamma module subframe 2 height minus 1, data type: x393_gamma_height2m1_t (rw)
#define X393_LENS_HEIGHT0_M1__3 0x400013f0 // Subframe 0 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT1_M1__3 0x400013f4 // Subframe 1 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_HEIGHT2_M1__3 0x400013f8 // Subframe 2 height minus 1, data type: x393_lens_height_m1_t (rw)
#define X393_LENS_CORR_CNH_ADDR_DATA__3 0x400013fc // Combined address/data to write lens vignetting correction coefficients, data type: x393_lens_corr_t (wo)
#define X393_HIST_SAXI_ADDR__0 0x40001400 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__1 0x40001404 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__2 0x40001408 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__3 0x4000140c // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__4 0x40001410 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__5 0x40001414 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__6 0x40001418 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__7 0x4000141c // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__8 0x40001420 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__9 0x40001424 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__10 0x40001428 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__11 0x4000142c // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__12 0x40001430 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__13 0x40001434 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__14 0x40001438 // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_ADDR__15 0x4000143c // Histogram DMA addresses (in 4096 byte pages), data type: x393_hist_saxi_addr_t (rw)
#define X393_HIST_SAXI_MODE 0x40001440 // Histogram DMA operation mode, data type: x393_hist_saxi_mode_t (rw)
// RESERVED: 0xef DWORDs
#define X393_CMPRS_CONTROL_REG__0 0x40001800 // Program compressor channel operation mode, data type: x393_cmprs_mode_t (wo)
#define X393_CMPRS_STATUS__0 0x40001804 // Setup compressor status report mode, data type: x393_status_ctrl_t (rw)
#define X393_CMPRS_FORMAT__0 0x40001808 // Compressor frame format, data type: x393_cmprs_frame_format_t (rw)
#define X393_CMPRS_COLOR_SATURATION__0 0x4000180c // Compressor color saturation, data type: x393_cmprs_colorsat_t (rw)
#define X393_CMPRS_CORING_MODE__0 0x40001810 // Select coring mode, data type: x393_cmprs_coring_mode_t (rw)
#define X393_CMPRS_INTERRUPTS__0 0x40001814 // Compressor interrupts control (1 - clear, 2 - disable, 3 - enable), data type: x393_cmprs_interrupts_t (wo)
#define X393_CMPRS_TABLES_DATA__0 0x40001818 // Compressor tables data, data type: u32 (wo)
#define X393_CMPRS_TABLES_ADDRESS__0 0x4000181c // Compressor tables type/address, data type: x393_cmprs_table_addr_t (wo)
// RESERVED: 0x8 DWORDs
#define X393_CMPRS_CONTROL_REG__1 0x40001840 // Program compressor channel operation mode, data type: x393_cmprs_mode_t (wo)
#define X393_CMPRS_STATUS__1 0x40001844 // Setup compressor status report mode, data type: x393_status_ctrl_t (rw)
#define X393_CMPRS_FORMAT__1 0x40001848 // Compressor frame format, data type: x393_cmprs_frame_format_t (rw)
#define X393_CMPRS_COLOR_SATURATION__1 0x4000184c // Compressor color saturation, data type: x393_cmprs_colorsat_t (rw)
#define X393_CMPRS_CORING_MODE__1 0x40001850 // Select coring mode, data type: x393_cmprs_coring_mode_t (rw)
#define X393_CMPRS_INTERRUPTS__1 0x40001854 // Compressor interrupts control (1 - clear, 2 - disable, 3 - enable), data type: x393_cmprs_interrupts_t (wo)
#define X393_CMPRS_TABLES_DATA__1 0x40001858 // Compressor tables data, data type: u32 (wo)
#define X393_CMPRS_TABLES_ADDRESS__1 0x4000185c // Compressor tables type/address, data type: x393_cmprs_table_addr_t (wo)
// RESERVED: 0x8 DWORDs
#define X393_CMPRS_CONTROL_REG__2 0x40001880 // Program compressor channel operation mode, data type: x393_cmprs_mode_t (wo)
#define X393_CMPRS_STATUS__2 0x40001884 // Setup compressor status report mode, data type: x393_status_ctrl_t (rw)
#define X393_CMPRS_FORMAT__2 0x40001888 // Compressor frame format, data type: x393_cmprs_frame_format_t (rw)
#define X393_CMPRS_COLOR_SATURATION__2 0x4000188c // Compressor color saturation, data type: x393_cmprs_colorsat_t (rw)
#define X393_CMPRS_CORING_MODE__2 0x40001890 // Select coring mode, data type: x393_cmprs_coring_mode_t (rw)
#define X393_CMPRS_INTERRUPTS__2 0x40001894 // Compressor interrupts control (1 - clear, 2 - disable, 3 - enable), data type: x393_cmprs_interrupts_t (wo)
#define X393_CMPRS_TABLES_DATA__2 0x40001898 // Compressor tables data, data type: u32 (wo)
#define X393_CMPRS_TABLES_ADDRESS__2 0x4000189c // Compressor tables type/address, data type: x393_cmprs_table_addr_t (wo)
// RESERVED: 0x8 DWORDs
#define X393_CMPRS_CONTROL_REG__3 0x400018c0 // Program compressor channel operation mode, data type: x393_cmprs_mode_t (wo)
#define X393_CMPRS_STATUS__3 0x400018c4 // Setup compressor status report mode, data type: x393_status_ctrl_t (rw)
#define X393_CMPRS_FORMAT__3 0x400018c8 // Compressor frame format, data type: x393_cmprs_frame_format_t (rw)
#define X393_CMPRS_COLOR_SATURATION__3 0x400018cc // Compressor color saturation, data type: x393_cmprs_colorsat_t (rw)
#define X393_CMPRS_CORING_MODE__3 0x400018d0 // Select coring mode, data type: x393_cmprs_coring_mode_t (rw)
#define X393_CMPRS_INTERRUPTS__3 0x400018d4 // Compressor interrupts control (1 - clear, 2 - disable, 3 - enable), data type: x393_cmprs_interrupts_t (wo)
#define X393_CMPRS_TABLES_DATA__3 0x400018d8 // Compressor tables data, data type: u32 (wo)
#define X393_CMPRS_TABLES_ADDRESS__3 0x400018dc // Compressor tables type/address, data type: x393_cmprs_table_addr_t (wo)
// RESERVED: 0x8 DWORDs
#define X393_AFIMUX0_EN 0x40001900 // AFI MUX 0 global/port run/pause control, data type: x393_afimux_en_t (wo)
#define X393_AFIMUX0_RST 0x40001904 // AFI MUX 0 per-port resets, data type: x393_afimux_rst_t (rw)
#define X393_AFIMUX0_REPORT_MODE 0x40001908 // AFI MUX 0 readout pointer report mode, data type: x393_afimux_report_t (wo)
// RESERVED: 0x1 DWORD
#define X393_AFIMUX0_STATUS_CONTROL 0x40001910 // AFI MUX 0 status report mode, data type: x393_status_ctrl_t (rw)
// RESERVED: 0x3 DWORDs
#define X393_AFIMUX0_SA__0 0x40001920 // AFI MUX 0 DMA buffer start address in 32-byte blocks, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX0_SA__1 0x40001924 // AFI MUX 0 DMA buffer start address in 32-byte blocks, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX0_SA__2 0x40001928 // AFI MUX 0 DMA buffer start address in 32-byte blocks, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX0_SA__3 0x4000192c // AFI MUX 0 DMA buffer start address in 32-byte blocks, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX0_LEN__0 0x40001930 // AFI MUX 0 DMA buffer length in 32-byte blocks, data type: x393_afimux_len_t (rw)
#define X393_AFIMUX0_LEN__1 0x40001934 // AFI MUX 0 DMA buffer length in 32-byte blocks, data type: x393_afimux_len_t (rw)
#define X393_AFIMUX0_LEN__2 0x40001938 // AFI MUX 0 DMA buffer length in 32-byte blocks, data type: x393_afimux_len_t (rw)
#define X393_AFIMUX0_LEN__3 0x4000193c // AFI MUX 0 DMA buffer length in 32-byte blocks, data type: x393_afimux_len_t (rw)
#define X393_AFIMUX1_EN 0x40001940 // AFI MUX 1 global/port run/pause control, data type: x393_afimux_en_t (wo)
#define X393_AFIMUX1_RST 0x40001944 // AFI MUX 1 per-port resets, data type: x393_afimux_rst_t (rw)
#define X393_AFIMUX1_REPORT_MODE 0x40001948 // AFI MUX 1 readout pointer report mode, data type: x393_afimux_report_t (wo)
// RESERVED: 0x1 DWORD
#define X393_AFIMUX1_STATUS_CONTROL 0x40001950 // AFI MUX 1 status report mode, data type: x393_status_ctrl_t (rw)
// RESERVED: 0x3 DWORDs
#define X393_AFIMUX1_SA__0 0x40001960 // AFI MUX 1 DMA buffer start address in 32-byte blocks, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX1_SA__1 0x40001964 // AFI MUX 1 DMA buffer start address in 32-byte blocks, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX1_SA__2 0x40001968 // AFI MUX 1 DMA buffer start address in 32-byte blocks, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX1_SA__3 0x4000196c // AFI MUX 1 DMA buffer start address in 32-byte blocks, data type: x393_afimux_sa_t (rw)
#define X393_AFIMUX1_LEN__0 0x40001970 // AFI MUX 1 DMA buffer length in 32-byte blocks, data type: x393_afimux_len_t (rw)
#define X393_AFIMUX1_LEN__1 0x40001974 // AFI MUX 1 DMA buffer length in 32-byte blocks, data type: x393_afimux_len_t (rw)
#define X393_AFIMUX1_LEN__2 0x40001978 // AFI MUX 1 DMA buffer length in 32-byte blocks, data type: x393_afimux_len_t (rw)
#define X393_AFIMUX1_LEN__3 0x4000197c // AFI MUX 1 DMA buffer length in 32-byte blocks, data type: x393_afimux_len_t (rw)
// RESERVED: 0x20 DWORDs
#define X393_SENS_MCNTRL_SCANLINE_MODE__0 0x40001a00 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STATUS_CNTRL__0 0x40001a04 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_SCANLINE_STARTADDR__0 0x40001a08 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_SIZE__0 0x40001a0c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_LAST__0 0x40001a10 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_FULL_WIDTH__0 0x40001a14 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_WH__0 0x40001a18 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_X0Y0__0 0x40001a1c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STARTXY__0 0x40001a20 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
// RESERVED: 0x7 DWORDs
#define X393_SENS_MCNTRL_SCANLINE_MODE__1 0x40001a40 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STATUS_CNTRL__1 0x40001a44 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_SCANLINE_STARTADDR__1 0x40001a48 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_SIZE__1 0x40001a4c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_LAST__1 0x40001a50 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_FULL_WIDTH__1 0x40001a54 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_WH__1 0x40001a58 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_X0Y0__1 0x40001a5c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STARTXY__1 0x40001a60 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
// RESERVED: 0x7 DWORDs
#define X393_SENS_MCNTRL_SCANLINE_MODE__2 0x40001a80 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STATUS_CNTRL__2 0x40001a84 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_SCANLINE_STARTADDR__2 0x40001a88 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_SIZE__2 0x40001a8c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_LAST__2 0x40001a90 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_FULL_WIDTH__2 0x40001a94 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_WH__2 0x40001a98 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_X0Y0__2 0x40001a9c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STARTXY__2 0x40001aa0 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
// RESERVED: 0x7 DWORDs
#define X393_SENS_MCNTRL_SCANLINE_MODE__3 0x40001ac0 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STATUS_CNTRL__3 0x40001ac4 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_SCANLINE_STARTADDR__3 0x40001ac8 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_SIZE__3 0x40001acc // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_LAST__3 0x40001ad0 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_FRAME_FULL_WIDTH__3 0x40001ad4 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_WH__3 0x40001ad8 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_WINDOW_X0Y0__3 0x40001adc // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_SCANLINE_STARTXY__3 0x40001ae0 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
// RESERVED: 0x7 DWORDs
#define X393_SENS_MCNTRL_TILED_MODE__0 0x40001b00 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_TILED_STATUS_CNTRL__0 0x40001b04 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_TILED_STARTADDR__0 0x40001b08 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_SIZE__0 0x40001b0c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_LAST__0 0x40001b10 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_FULL_WIDTH__0 0x40001b14 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_WH__0 0x40001b18 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_X0Y0__0 0x40001b1c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_TILED_STARTXY__0 0x40001b20 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_SENS_MCNTRL_TILED_TILE_WHS__0 0x40001b24 // Set tile size/step (tiled mode only), data type: x393_mcntrl_window_tile_whs_t (wo)
// RESERVED: 0x6 DWORDs
#define X393_SENS_MCNTRL_TILED_MODE__1 0x40001b40 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_TILED_STATUS_CNTRL__1 0x40001b44 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_TILED_STARTADDR__1 0x40001b48 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_SIZE__1 0x40001b4c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_LAST__1 0x40001b50 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_FULL_WIDTH__1 0x40001b54 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_WH__1 0x40001b58 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_X0Y0__1 0x40001b5c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_TILED_STARTXY__1 0x40001b60 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_SENS_MCNTRL_TILED_TILE_WHS__1 0x40001b64 // Set tile size/step (tiled mode only), data type: x393_mcntrl_window_tile_whs_t (wo)
// RESERVED: 0x6 DWORDs
#define X393_SENS_MCNTRL_TILED_MODE__2 0x40001b80 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_TILED_STATUS_CNTRL__2 0x40001b84 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_TILED_STARTADDR__2 0x40001b88 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_SIZE__2 0x40001b8c // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_LAST__2 0x40001b90 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_FULL_WIDTH__2 0x40001b94 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_WH__2 0x40001b98 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_X0Y0__2 0x40001b9c // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_TILED_STARTXY__2 0x40001ba0 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_SENS_MCNTRL_TILED_TILE_WHS__2 0x40001ba4 // Set tile size/step (tiled mode only), data type: x393_mcntrl_window_tile_whs_t (wo)
// RESERVED: 0x6 DWORDs
#define X393_SENS_MCNTRL_TILED_MODE__3 0x40001bc0 // Set mode register (write last after other channel registers are set), data type: x393_mcntrl_mode_scan_t (wo)
#define X393_SENS_MCNTRL_TILED_STATUS_CNTRL__3 0x40001bc4 // Set status control register (status update mode), data type: x393_status_ctrl_t (rw)
#define X393_SENS_MCNTRL_TILED_STARTADDR__3 0x40001bc8 // Set frame start address, data type: x393_mcntrl_window_frame_sa_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_SIZE__3 0x40001bcc // Set frame size (address increment), data type: x393_mcntrl_window_frame_sa_inc_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_LAST__3 0x40001bd0 // Set last frame number (number of frames in buffer minus 1), data type: x393_mcntrl_window_last_frame_num_t (wo)
#define X393_SENS_MCNTRL_TILED_FRAME_FULL_WIDTH__3 0x40001bd4 // Set frame full(padded) width, data type: x393_mcntrl_window_full_width_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_WH__3 0x40001bd8 // Set frame window size, data type: x393_mcntrl_window_width_height_t (wo)
#define X393_SENS_MCNTRL_TILED_WINDOW_X0Y0__3 0x40001bdc // Set frame position, data type: x393_mcntrl_window_left_top_t (wo)
#define X393_SENS_MCNTRL_TILED_STARTXY__3 0x40001be0 // Set startXY register, data type: x393_mcntrl_window_startx_starty_t (wo)
#define X393_SENS_MCNTRL_TILED_TILE_WHS__3 0x40001be4 // Set tile size/step (tiled mode only), data type: x393_mcntrl_window_tile_whs_t (wo)
// RESERVED: 0x6 DWORDs
#define X393_GPIO_SET_PINS 0x40001c00 // State of the GPIO pins and seq. number, data type: x393_gpio_set_pins_t (wo)
#define X393_GPIO_STATUS_CONTROL 0x40001c04 // GPIO status control mode, data type: x393_status_ctrl_t (rw)
#define X393_CMDSEQMUX_STATUS_CTRL 0x40001c08 // CMDSEQMUX status control mode (status provides current frame numbers), data type: x393_status_ctrl_t (rw)
// RESERVED: 0x1 DWORD
#define X393_RTC_USEC 0x40001c10 // RTC microseconds, data type: x393_rtc_usec_t (rw)
#define X393_RTC_SEC_SET 0x40001c14 // RTC seconds and set clock, data type: x393_rtc_sec_t (rw)
#define X393_RTC_CORR 0x40001c18 // RTC correction (+/- 1/256 full scale), data type: x393_rtc_corr_t (rw)
#define X393_RTC_SET_STATUS 0x40001c1c // RTC status control mode, write makes a snapshot to be read out, data type: x393_status_ctrl_t (rw)
#define X393_CAMSYNC_MODE 0x40001c20 // CAMSYNC mode, data type: x393_camsync_mode_t (wo)
#define X393_CAMSYNC_TRIG_SRC 0x40001c24 // CAMSYNC trigger source, data type: x393_camsync_io_t (wo)
#define X393_CAMSYNC_TRIG_DST 0x40001c28 // CAMSYNC trigger destination, data type: x393_camsync_io_t (wo)
#define X393_CAMSYNC_TRIG_PERIOD 0x40001c2c // CAMSYNC trigger period, data type: u32 (rw)
#define X393_CAMSYNC_TRIG_DELAY__0 0x40001c30 // CAMSYNC trigger delay, data type: u32 (rw)
#define X393_CAMSYNC_TRIG_DELAY__1 0x40001c34 // CAMSYNC trigger delay, data type: u32 (rw)
#define X393_CAMSYNC_TRIG_DELAY__2 0x40001c38 // CAMSYNC trigger delay, data type: u32 (rw)
#define X393_CAMSYNC_TRIG_DELAY__3 0x40001c3c // CAMSYNC trigger delay, data type: u32 (rw)
#define X393_DEBUG_SHIFT 0x40001c40 // Debug ring shift ring by 32 bits, data type: u32 (wo)
#define X393_DEBUG_LOAD 0x40001c44 // Debug ring copy shift register to/from tested modules
#define X393_DEBUG_STATUS_CTRL 0x40001c48 // Debug ring status generation - set to auto(3) if used, data type: x393_status_ctrl_t (rw)
// RESERVED: 0xd DWORDs
#define X393_LOGGER_DATA 0x40001c80 // Logger register write data, data type: x393_logger_data_t (wo)
#define X393_LOGGER_ADDRESS 0x40001c84 // Logger register write page/address, data type: x393_logger_address_t (wo)
#define X393_LOGGER_STATUS_CTRL 0x40001c88 // Logger status configuration (to report sample number), data type: x393_status_ctrl_t (rw)
// RESERVED: 0x5 DWORDs
#define X393_MULTICLK_CTRL 0x40001ca0 // MULTI_CLK reset and power down control, data type: x393_multiclk_ctl_t (rw)
#define X393_MULTICLK_STATUS_CTRL 0x40001ca4 // MULTI_CLK status generation (do not use or do not set auto), data type: x393_status_ctrl_t (rw)
// RESERVED: 0x6 DWORDs
#define X393_MULT_SAXI_BUF_ADDRESS__0 0x40001cc0 // MULT_SAXI buffer start address in DWORDS, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_BUF_LEN__0 0x40001cc4 // MULT_SAXI buffer length in DWORDS, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_BUF_ADDRESS__1 0x40001cc8 // MULT_SAXI buffer start address in DWORDS, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_BUF_LEN__1 0x40001ccc // MULT_SAXI buffer length in DWORDS, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_BUF_ADDRESS__2 0x40001cd0 // MULT_SAXI buffer start address in DWORDS, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_BUF_LEN__2 0x40001cd4 // MULT_SAXI buffer length in DWORDS, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_BUF_ADDRESS__3 0x40001cd8 // MULT_SAXI buffer start address in DWORDS, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_BUF_LEN__3 0x40001cdc // MULT_SAXI buffer length in DWORDS, data type: x393_mult_saxi_al_t (wo)
#define X393_MULT_SAXI_STATUS_CTRL 0x40001ce0 // MULT_SAXI status control mode (status provides current DWORD pointer), data type: x393_status_ctrl_t (rw)
// RESERVED: 0x47 DWORDs
#define X393_CMDFRAMESEQ_ABS__0__0 0x40001e00 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__1 0x40001e04 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__2 0x40001e08 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__3 0x40001e0c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__4 0x40001e10 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__5 0x40001e14 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__6 0x40001e18 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__7 0x40001e1c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__8 0x40001e20 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__9 0x40001e24 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__10 0x40001e28 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__11 0x40001e2c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__12 0x40001e30 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__13 0x40001e34 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__14 0x40001e38 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__0__15 0x40001e3c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__0 0x40001e40 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__1 0x40001e44 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__2 0x40001e48 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__3 0x40001e4c // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__4 0x40001e50 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__5 0x40001e54 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__6 0x40001e58 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__7 0x40001e5c // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__8 0x40001e60 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__9 0x40001e64 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__10 0x40001e68 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__11 0x40001e6c // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__12 0x40001e70 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__13 0x40001e74 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__0__14 0x40001e78 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_CTRL__0 0x40001e7c // CMDFRAMESEQ control register, data type: x393_cmdframeseq_mode_t (wo)
#define X393_CMDFRAMESEQ_ABS__1__0 0x40001e80 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__1 0x40001e84 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__2 0x40001e88 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__3 0x40001e8c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__4 0x40001e90 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__5 0x40001e94 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__6 0x40001e98 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__7 0x40001e9c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__8 0x40001ea0 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__9 0x40001ea4 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__10 0x40001ea8 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__11 0x40001eac // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__12 0x40001eb0 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__13 0x40001eb4 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__14 0x40001eb8 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__1__15 0x40001ebc // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__0 0x40001ec0 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__1 0x40001ec4 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__2 0x40001ec8 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__3 0x40001ecc // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__4 0x40001ed0 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__5 0x40001ed4 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__6 0x40001ed8 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__7 0x40001edc // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__8 0x40001ee0 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__9 0x40001ee4 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__10 0x40001ee8 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__11 0x40001eec // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__12 0x40001ef0 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__13 0x40001ef4 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__1__14 0x40001ef8 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_CTRL__1 0x40001efc // CMDFRAMESEQ control register, data type: x393_cmdframeseq_mode_t (wo)
#define X393_CMDFRAMESEQ_ABS__2__0 0x40001f00 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__1 0x40001f04 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__2 0x40001f08 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__3 0x40001f0c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__4 0x40001f10 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__5 0x40001f14 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__6 0x40001f18 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__7 0x40001f1c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__8 0x40001f20 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__9 0x40001f24 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__10 0x40001f28 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__11 0x40001f2c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__12 0x40001f30 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__13 0x40001f34 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__14 0x40001f38 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__2__15 0x40001f3c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__0 0x40001f40 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__1 0x40001f44 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__2 0x40001f48 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__3 0x40001f4c // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__4 0x40001f50 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__5 0x40001f54 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__6 0x40001f58 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__7 0x40001f5c // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__8 0x40001f60 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__9 0x40001f64 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__10 0x40001f68 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__11 0x40001f6c // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__12 0x40001f70 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__13 0x40001f74 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__2__14 0x40001f78 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_CTRL__2 0x40001f7c // CMDFRAMESEQ control register, data type: x393_cmdframeseq_mode_t (wo)
#define X393_CMDFRAMESEQ_ABS__3__0 0x40001f80 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__1 0x40001f84 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__2 0x40001f88 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__3 0x40001f8c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__4 0x40001f90 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__5 0x40001f94 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__6 0x40001f98 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__7 0x40001f9c // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__8 0x40001fa0 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__9 0x40001fa4 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__10 0x40001fa8 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__11 0x40001fac // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__12 0x40001fb0 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__13 0x40001fb4 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__14 0x40001fb8 // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_ABS__3__15 0x40001fbc // CMDFRAMESEQ absolute frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__0 0x40001fc0 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__1 0x40001fc4 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__2 0x40001fc8 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__3 0x40001fcc // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__4 0x40001fd0 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__5 0x40001fd4 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__6 0x40001fd8 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__7 0x40001fdc // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__8 0x40001fe0 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__9 0x40001fe4 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__10 0x40001fe8 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__11 0x40001fec // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__12 0x40001ff0 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__13 0x40001ff4 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_REL__3__14 0x40001ff8 // CMDFRAMESEQ relative frame address/command, data type: u32 (wo)
#define X393_CMDFRAMESEQ_CTRL__3 0x40001ffc // CMDFRAMESEQ control register, data type: x393_cmdframeseq_mode_t (wo)
#define X393_MCONTR_PHY_STATUS 0x40002000 // Status register for MCNTRL PHY, data type: x393_status_mcntrl_phy_t (ro)
#define X393_MCONTR_TOP_STATUS 0x40002004 // Status register for MCNTRL requests, data type: x393_status_mcntrl_top_t (ro)
#define X393_MCNTRL_PS_STATUS 0x40002008 // Status register for MCNTRL software R/W, data type: x393_status_mcntrl_ps_t (ro)
// RESERVED: 0x1 DWORD
#define X393_MCNTRL_CHN1_STATUS 0x40002010 // Status register for MCNTRL CHN1 (membridge), data type: x393_status_mcntrl_lintile_t (ro)
#define X393_MCNTRL_CHN2_STATUS 0x40002014 // Status register for MCNTRL CHN2 (tiled), data type: x393_status_mcntrl_lintile_t (ro)
#define X393_MCNTRL_CHN3_STATUS 0x40002018 // Status register for MCNTRL CHN3 (scanline), data type: x393_status_mcntrl_lintile_t (ro)
#define X393_MCNTRL_CHN4_STATUS 0x4000201c // Status register for MCNTRL CHN4 (tiled), data type: x393_status_mcntrl_lintile_t (ro)
// RESERVED: 0x8 DWORDs
#define X393_CMPRS_STATUS__0 0x40002040 // Status of the compressor channel (incl. interrupt, data type: x393_cmprs_status_t (ro)
#define X393_CMPRS_STATUS__1 0x40002044 // Status of the compressor channel (incl. interrupt, data type: x393_cmprs_status_t (ro)
#define X393_CMPRS_STATUS__2 0x40002048 // Status of the compressor channel (incl. interrupt, data type: x393_cmprs_status_t (ro)
#define X393_CMPRS_STATUS__3 0x4000204c // Status of the compressor channel (incl. interrupt, data type: x393_cmprs_status_t (ro)
#define X393_CMPRS_HIFREQ__0 0x40002050 // Focus helper high-frequency amount, data type: u32 (ro)
#define X393_CMPRS_HIFREQ__1 0x40002054 // Focus helper high-frequency amount, data type: u32 (ro)
#define X393_CMPRS_HIFREQ__2 0x40002058 // Focus helper high-frequency amount, data type: u32 (ro)
#define X393_CMPRS_HIFREQ__3 0x4000205c // Focus helper high-frequency amount, data type: u32 (ro)
#define X393_AFIMUX0_STATUS__0 0x40002060 // Status of the AFI MUX 0 (including image pointer), data type: x393_afimux_status_t (ro)
#define X393_AFIMUX0_STATUS__1 0x40002064 // Status of the AFI MUX 0 (including image pointer), data type: x393_afimux_status_t (ro)
#define X393_AFIMUX0_STATUS__2 0x40002068 // Status of the AFI MUX 0 (including image pointer), data type: x393_afimux_status_t (ro)
#define X393_AFIMUX0_STATUS__3 0x4000206c // Status of the AFI MUX 0 (including image pointer), data type: x393_afimux_status_t (ro)
#define X393_AFIMUX1_STATUS__0 0x40002070 // Status of the AFI MUX 1 (including image pointer), data type: x393_afimux_status_t (ro)
#define X393_AFIMUX1_STATUS__1 0x40002074 // Status of the AFI MUX 1 (including image pointer), data type: x393_afimux_status_t (ro)
#define X393_AFIMUX1_STATUS__2 0x40002078 // Status of the AFI MUX 1 (including image pointer), data type: x393_afimux_status_t (ro)
#define X393_AFIMUX1_STATUS__3 0x4000207c // Status of the AFI MUX 1 (including image pointer), data type: x393_afimux_status_t (ro)
#define X393_SENSI2C_STATUS__0 0x40002080 // Status of the sensors i2c, data type: x393_status_sens_i2c_t (ro)
#define X393_SENSIO_STATUS__0 0x40002084 // Status of the sensor ports I/O pins, data type: x393_status_sens_io_t (ro)
#define X393_SENSI2C_STATUS__1 0x40002088 // Status of the sensors i2c, data type: x393_status_sens_i2c_t (ro)
#define X393_SENSIO_STATUS__1 0x4000208c // Status of the sensor ports I/O pins, data type: x393_status_sens_io_t (ro)
#define X393_SENSI2C_STATUS__2 0x40002090 // Status of the sensors i2c, data type: x393_status_sens_i2c_t (ro)
#define X393_SENSIO_STATUS__2 0x40002094 // Status of the sensor ports I/O pins, data type: x393_status_sens_io_t (ro)
#define X393_SENSI2C_STATUS__3 0x40002098 // Status of the sensors i2c, data type: x393_status_sens_i2c_t (ro)
#define X393_SENSIO_STATUS__3 0x4000209c // Status of the sensor ports I/O pins, data type: x393_status_sens_io_t (ro)
// RESERVED: 0x8 DWORDs
#define X393_GPIO_STATUS 0x400020c0 // State of the GPIO pins and seq. number, data type: x393_gpio_status_t (ro)
#define X393_RTC_STATUS 0x400020c4 // RTC status reg, data type: x393_rtc_status_t (ro)
#define X393_RTC_STATUS_SEC 0x400020c8 // RTC snapshot seconds, data type: x393_rtc_sec_t (ro)
#define X393_RTC_STATUS_USEC 0x400020cc // RTC snapshot microseconds, data type: x393_rtc_usec_t (ro)
#define X393_MULT_SAXI_STATUS__0 0x400020d0 // MULT_SAXI current DWORD pointer, data type: x393_mult_saxi_al_t (ro)
#define X393_MULT_SAXI_STATUS__1 0x400020d4 // MULT_SAXI current DWORD pointer, data type: x393_mult_saxi_al_t (ro)
#define X393_MULT_SAXI_STATUS__2 0x400020d8 // MULT_SAXI current DWORD pointer, data type: x393_mult_saxi_al_t (ro)
#define X393_MULT_SAXI_STATUS__3 0x400020dc // MULT_SAXI current DWORD pointer, data type: x393_mult_saxi_al_t (ro)
#define X393_CMDSEQMUX_STATUS 0x400020e0 // CMDSEQMUX status data (frame numbers and interrupts, data type: x393_cmdseqmux_status_t (ro)
#define X393_LOGGER_STATUS 0x400020e4 // Logger status data (sequence number), data type: x393_logger_status_t (ro)
#define X393_MULTICLK_STATUS 0x400020e8 // MULTI_CLK lock and toggle state, data type: x393_multiclk_status_t (ro)
#define X393_MEMBRIDGE_STATUS 0x400020ec // Status register for membridge, data type: x393_status_membridge_t (ro)
// RESERVED: 0x1 DWORD
#define X393_TEST01_CHN2_STATUS 0x400020f4 // Status register for test channel 2, data type: x393_status_mcntrl_testchn_t (ro)
#define X393_TEST01_CHN3_STATUS 0x400020f8 // Status register for test channel 3, data type: x393_status_mcntrl_testchn_t (ro)
#define X393_TEST01_CHN4_STATUS 0x400020fc // Status register for test channel 4, data type: x393_status_mcntrl_testchn_t (ro)
// RESERVED: 0xbc DWORDs
#define X393_DEBUG_STATUS 0x400023f0 // Debug read status (watch sequence number), data type: x393_debug_status_t (ro)
#define X393_DEBUG_READ 0x400023f4 // Debug read DWORD form ring register, data type: u32 (ro)
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/elphel/x393_types.h 0000664 0000000 0000000 00000154204 12703306510 0027175 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* File: x393_types.h
* Date: 2016-04-06
* Author: auto-generated file, see x393_export_c.py
* Description: typedef definitions for the x393 hardware registers
*******************************************************************************/
// Status generation control
typedef union {
struct {
u32 seq_num: 6; // [ 5: 0] (0) 6-bit sequence number to be used with the next status response
u32 mode: 2; // [ 7: 6] (3) Status report mode: 0 - disable, 1 - single, 2 - auto, keep sequence number, 3 - auto, inc. seq. number
u32 :24;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_ctrl_t;
// Memory channel operation mode
typedef union {
struct {
u32 enable: 1; // [ 0] (1) enable requests from this channel ( 0 will let current to finish, but not raise want/need)
u32 chn_nreset: 1; // [ 1] (1) 0: immediately reset all the internal circuitry
u32 write_mem: 1; // [ 2] (0) 0 - read from memory, 1 - write to memory
u32 extra_pages: 2; // [ 4: 3] (0) 2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
u32 keep_open: 1; // [ 5] (0) for 8 or less rows - do not close page between accesses (not used in scanline mode)
u32 byte32: 1; // [ 6] (1) 32-byte columns (0 - 16-byte), not used in scanline mode
u32 : 1;
u32 reset_frame: 1; // [ 8] (0) reset frame number
u32 single: 1; // [ 9] (0) run single frame
u32 repetitive: 1; // [ 10] (1) run repetitive frames
u32 disable_need: 1; // [ 11] (0) disable 'need' generation, only 'want' (compressor channels)
u32 skip_too_late: 1; // [ 12] (0) Skip over missed blocks to preserve frame structure (increment pointers)
u32 :19;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntrl_mode_scan_t;
// Memory channel window tile size/step (tiled only)
typedef union {
struct {
u32 tile_width: 6; // [ 5: 0] (2) tile width in 8-bursts (16 bytes)
u32 : 2;
u32 tile_height: 6; // [13: 8] (0x12) tile height in lines (0 means 64 lines)
u32 : 2;
u32 vert_step: 8; // [23:16] (0x10) Tile vertical step to control tile overlap
u32 : 8;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntrl_window_tile_whs_t;
// Memory channel window size
typedef union {
struct {
u32 width:13; // [12: 0] (0) 13-bit window width - in 8*16=128 bit bursts
u32 : 3;
u32 height:16; // [31:16] (0) 16-bit window height in scan lines
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntrl_window_width_height_t;
// Memory channel window position
typedef union {
struct {
u32 left:13; // [12: 0] (0) 13-bit window left margin in 8-bursts (16 bytes)
u32 : 3;
u32 top:16; // [31:16] (0) 16-bit window top margin in scan lines
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntrl_window_left_top_t;
// Memory channel scan start (debug feature)
typedef union {
struct {
u32 start_x:13; // [12: 0] (0) 13-bit window start X relative to window left margin (debug feature, set = 0)
u32 : 3;
u32 start_y:16; // [31:16] (0) 16-bit window start Y relative to window top margin (debug feature, set = 0)
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntrl_window_startx_starty_t;
// Memory channel window full (padded) width
typedef union {
struct {
u32 full_width:13; // [12: 0] (0) 13-bit Padded line length (8-row increment), in 8-bursts (16 bytes)
u32 :19;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntrl_window_full_width_t;
// Memory channel last frame number in a buffer (number of frames minus 1)
typedef union {
struct {
u32 last_frame_num:16; // [15: 0] (0) 16-bit number of the last frame in a buffer (1 for a 2-frame ping-pong one)
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntrl_window_last_frame_num_t;
// Memory channel frame start address increment (for next frame in a buffer)
typedef union {
struct {
u32 frame_sa_inc:22; // [21: 0] (0) 22-bit frame start address increment (3 CA LSBs==0. BA==0)
u32 :10;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntrl_window_frame_sa_inc_t;
// Memory channel frame start address for the first frame in a buffer
typedef union {
struct {
u32 frame_sa:22; // [21: 0] (0) 22-bit frame start address (3 CA LSBs==0. BA==0)
u32 :10;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntrl_window_frame_sa_t;
// PS PIO (software-programmed DDR3) access sequences enable and reset
typedef union {
struct {
u32 nrst: 1; // [ 0] (1) Active-low reset for programmed DDR3 memory sequences
u32 en: 1; // [ 1] (1) Enable PS_PIO channel. Only influences request for arbitration, started transactions will finish if disabled
u32 :30;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_ps_pio_en_rst_t;
// PS PIO (software-programmed DDR3) access sequences control
typedef union {
struct {
u32 seq_addr:10; // [ 9: 0] (0) Sequence start address
u32 page: 2; // [11:10] (0) Buffer page number
u32 urgent: 1; // [ 12] (0) high priority request (only for competition with other channels, will not pass in this FIFO)
u32 chn: 1; // [ 13] (0) channel buffer to use: 0 - memory read, 1 - memory write
u32 wait_complete: 1; // [ 14] (0) Do not request a new transaction from the scheduler until previous memory transaction is finished
u32 :17;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_ps_pio_cmd_t;
// x393 generic status register
typedef union {
struct {
u32 status24:24; // [23: 0] (0) 24-bit status payload ([25:2] in Verilog
u32 status2: 2; // [25:24] (0) 2-bit status payload (2 LSB in Verilog)
u32 seq_num: 6; // [31:26] (0) Sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_t;
// Memory PHY status
typedef union {
struct {
u32 ps_out: 8; // [ 7: 0] (0) Current MMCM phase shift
u32 run_busy: 1; // [ 8] (0) Controller sequence in progress
u32 locked_pll: 1; // [ 9] (0) PLL is locked
u32 locked_mmcm: 1; // [ 10] (0) MMCM is locked
u32 dci_ready: 1; // [ 11] (0) DCI calibration is ready
u32 dly_ready: 1; // [ 12] (0) I/O delays calibration is ready
u32 :11;
u32 ps_rdy: 1; // [ 24] (0) Phase change is done
u32 locked: 1; // [ 25] (0) Both PLL and MMCM are locked
u32 seq_num: 6; // [31:26] (0) Sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_mcntrl_phy_t;
// Memory controller requests status
typedef union {
struct {
u32 chn_want:16; // [15: 0] (0) Bit mask of the channels that request memory access
u32 : 8;
u32 want_some: 1; // [ 24] (0) At least one channel requests memory access (normal priority)
u32 need_some: 1; // [ 25] (0) At least one channel requests urgent memory access (high priority)
u32 seq_num: 6; // [31:26] (0) Sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_mcntrl_top_t;
// Memory software access status
typedef union {
struct {
u32 :24;
u32 cmd_half_full: 1; // [ 24] (0) MCNTRL software access pending commands FIFO is half full
u32 cmd_nempty_busy: 1; // [ 25] (0) MCNTRL software access pending commands FIFO is not empty or command is running
u32 seq_num: 6; // [31:26] (0) Sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_mcntrl_ps_t;
// Memory test channels access status
typedef union {
struct {
u32 :24;
u32 busy: 1; // [ 24] (0) Channel is busy (started and some memory accesses are pending)
u32 frame_finished: 1; // [ 25] (0) Channel completed all memory accesses
u32 seq_num: 6; // [31:26] (0) Sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_mcntrl_lintile_t;
// Memory test channels status
typedef union {
struct {
u32 line_unfinished:16; // [15: 0] (0) Current unfinished frame line
u32 page: 4; // [19:16] (0) Current page number read/written through a channel (low bits)
u32 : 4;
u32 frame_busy: 1; // [ 24] (0) Channel is busy (started and some memory accesses are pending)
u32 frame_finished: 1; // [ 25] (0) Channel completed all memory accesses
u32 seq_num: 6; // [31:26] (0) Sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_mcntrl_testchn_t;
// Membridge channel status
typedef union {
struct {
u32 wresp_conf: 8; // [ 7: 0] (0) Number of 64-bit words confirmed through axi b channel (low bits)
u32 axi_arw_requested: 8; // [15: 8] (0) Number of 64-bit words to be read/written over axi queued to AR/AW channels (low bits)
u32 : 8;
u32 busy: 1; // [ 24] (0) Membridge operation in progress
u32 done: 1; // [ 25] (0) Membridge operation finished
u32 seq_num: 6; // [31:26] (0) Sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_membridge_t;
// Sensor/multiplexer I/O pins status
typedef union {
struct {
u32 ps_out: 8; // [ 7: 0] (0) Sensor MMCM current phase
u32 ps_rdy: 1; // [ 8] (0) Sensor MMCM phase ready
u32 xfpgadone: 1; // [ 9] (0) Multiplexer FPGA DONE output
u32 clkfb_pxd_stopped_mmcm: 1; // [ 10] (0) Sensor MMCM feedback clock stopped
u32 clkin_pxd_stopped_mmcm: 1; // [ 11] (0) Sensor MMCM input clock stopped
u32 locked_pxd_mmcm: 1; // [ 12] (0) Sensor MMCM locked
u32 hact_alive: 1; // [ 13] (0) HACT signal from the sensor (or internal) is toggling (N/A for HiSPI
u32 hact_ext_alive: 1; // [ 14] (0) HACT signal from the sensor is toggling (N/A for HiSPI)
u32 vact_alive: 1; // [ 15] (0) VACT signal from the sensor is toggling (N/A for HiSPI)
u32 : 8;
u32 senspgmin: 1; // [ 24] (0) senspgm pin state
u32 xfpgatdo: 1; // [ 25] (0) Multiplexer FPGA TDO output
u32 seq_num: 6; // [31:26] (0) Sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_sens_io_t;
// Sensor/multiplexer i2c status
typedef union {
struct {
u32 i2c_fifo_dout: 8; // [ 7: 0] (0) I2c byte read from the device through FIFO
u32 i2c_fifo_nempty: 1; // [ 8] (0) I2C read FIFO has data
u32 i2c_fifo_lsb: 1; // [ 9] (0) I2C FIFO byte counter (odd/even bytes)
u32 busy: 1; // [ 10] (0) I2C sequencer busy
u32 alive_fs: 1; // [ 11] (0) Sensor generated frame sync since last status update
u32 frame_num: 4; // [15:12] (0) I2C sequencer frame number
u32 req_clr: 1; // [ 16] (0) Request for clearing fifo_wp (delay frame sync if previous is not yet sent out)
u32 reset_on: 1; // [ 17] (0) Reset in progress
u32 : 6;
u32 scl_in: 1; // [ 24] (0) SCL pin state
u32 sda_in: 1; // [ 25] (0) SDA pin state
u32 seq_num: 6; // [31:26] (0) Sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_status_sens_i2c_t;
// Command bits for test01 module (test frame memory accesses)
typedef union {
struct {
u32 frame_start: 1; // [ 0] (0) start frame command
u32 next_page: 1; // [ 1] (0) Next page command
u32 suspend: 1; // [ 2] (0) Suspend command
u32 :29;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_test01_mode_t;
// Command for membridge
typedef union {
struct {
u32 enable: 1; // [ 0] (0) enable membridge
u32 start_reset: 2; // [ 2: 1] (0) 1 - start (from current address), 3 - start from reset address
u32 :29;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_membridge_cmd_t;
// Cache mode for membridge
typedef union {
struct {
u32 axi_cache: 4; // [ 3: 0] (3) AXI CACHE value (ignored by Zynq)
u32 debug_cache: 1; // [ 4] (0) 0 - normal operation, 1 debug (replace data)
u32 :27;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_membridge_mode_t;
// Address in 64-bit words
typedef union {
struct {
u32 addr64:29; // [28: 0] (0) Address/length in 64-bit words (<<3 to get byte address
u32 : 3;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} u29_t;
// I2C contol/table data
typedef union {
struct {
u32 tbl_addr: 8; // [ 7: 0] (0) Address/length in 64-bit words (<<3 to get byte address)
u32 :20;
u32 tbl_mode: 2; // [29:28] (3) Should be 3 to select table address write mode
u32 : 2;
};
struct {
u32 rah: 8; // [ 7: 0] (0) High byte of the i2c register address
u32 rnw: 1; // [ 8] (0) Read/not write i2c register, should be 0 here
u32 sa: 7; // [15: 9] (0) Slave address in write mode
u32 nbwr: 4; // [19:16] (0) Number of bytes to write (1..10)
u32 dly: 8; // [27:20] (0) Bit delay - number of mclk periods in 1/4 of the SCL period
u32 /*tbl_mode*/: 2; // [29:28] (2) Should be 2 to select table data write mode
u32 : 2;
};
struct {
u32 /*rah*/: 8; // [ 7: 0] (0) High byte of the i2c register address
u32 /*rnw*/: 1; // [ 8] (0) Read/not write i2c register, should be 1 here
u32 : 7;
u32 nbrd: 3; // [18:16] (0) Number of bytes to read (1..18, 0 means '8')
u32 nabrd: 1; // [ 19] (0) Number of address bytes for read (0 - one byte, 1 - two bytes)
u32 /*dly*/: 8; // [27:20] (0) Bit delay - number of mclk periods in 1/4 of the SCL period
u32 /*tbl_mode*/: 2; // [29:28] (2) Should be 2 to select table data write mode
u32 : 2;
};
struct {
u32 sda_drive_high: 1; // [ 0] (0) Actively drive SDA high during second half of SCL==1 (valid with drive_ctl)
u32 sda_release: 1; // [ 1] (0) Release SDA early if next bit ==1 (valid with drive_ctl)
u32 drive_ctl: 1; // [ 2] (0) 0 - nop, 1 - set sda_release and sda_drive_high
u32 next_fifo_rd: 1; // [ 3] (0) Advance I2C read FIFO pointer
u32 soft_scl: 2; // [ 5: 4] (0) Control SCL pin (when stopped): 0 - nop, 1 - low, 2 - high (driven), 3 - float
u32 soft_sda: 2; // [ 7: 6] (0) Control SDA pin (when stopped): 0 - nop, 1 - low, 2 - high (driven), 3 - float
u32 : 4;
u32 cmd_run: 2; // [13:12] (0) Sequencer run/stop control: 0,1 - nop, 2 - stop, 3 - run
u32 reset: 1; // [ 14] (0) Sequencer reset all FIFO (takes 16 clock pulses), also - stops i2c until run command
u32 :13;
u32 /*tbl_mode*/: 2; // [29:28] (0) Should be 0 to select controls
u32 : 2;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_i2c_ctltbl_t;
// Write sensor channel mode register
typedef union {
struct {
u32 hist_en: 4; // [ 3: 0] (0xf) Enable subchannel histogram modules (may be less than 4)
u32 hist_nrst: 4; // [ 7: 4] (0xf) Reset off for histograms subchannels (may be less than 4)
u32 chn_en: 1; // [ 8] (1) Enable this sensor channel
u32 bit16: 1; // [ 9] (0) 0 - 8 bpp mode, 1 - 16 bpp (bypass gamma). Gamma-processed data is still used for histograms
u32 :22;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sens_mode_t;
// Write number of sensor frames to combine into one virtual (linescan mode)
typedef union {
struct {
u32 mult_frames:16; // [15: 0] (0) Number of frames to combine into one minus 1 (0 - single,1 - two frames...)
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sens_sync_mult_t;
// Write sensor number of lines to delay frame sync
typedef union {
struct {
u32 mult_frames:16; // [15: 0] (0) Number of lines to delay late frame sync
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sens_sync_late_t;
// Configure memory controller priorities
typedef union {
struct {
u32 priority:16; // [15: 0] (0) Channel priority (the larger the higher)
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_arbite_pri_t;
// Enable/disable memory controller channels
typedef union {
struct {
u32 chn_en:16; // [15: 0] (0) Enabled memory channels
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntr_chn_en_t;
// DQS and DQM patterns (DQM - 0, DQS 0xaa or 0x55)
typedef union {
struct {
u32 dqs_patt: 8; // [ 7: 0] (0xaa) DQS pattern: 0xaa/0x55
u32 dqm_patt: 8; // [15: 8] (0) DQM pattern: 0x0
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntr_dqs_dqm_patt_t;
// DQ and DQS tristate control when turning on and off
typedef union {
struct {
u32 dq_tri_first: 4; // [ 3: 0] (3) DQ tristate start (0x3,0x7,0xf); early, nominal, late
u32 dq_tri_last: 4; // [ 7: 4] (0xe) DQ tristate end (0xf,0xe,0xc); early, nominal, late
u32 dqs_tri_first: 4; // [11: 8] (1) DQS tristate start (0x1,0x3,0x7); early, nominal, late
u32 dqs_tri_last: 4; // [15:12] (0xc) DQS tristate end (0xe,0xc,0x8); early, nominal, late
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mcntr_dqs_dqm_tri_t;
// DDR3 memory controller I/O delay
typedef union {
struct {
u32 dly: 8; // [ 7: 0] (0) 8-bit delay value: 5MSBs(0..31) and 3LSBs(0..4)
u32 :24;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_dly_t;
// Extra delay in mclk (fDDR/2) cycles) to data write buffer
typedef union {
struct {
u32 wbuf_dly: 4; // [ 3: 0] (9) Extra delay in mclk (fDDR/2) cycles) to data write buffer
u32 :28;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_wbuf_dly_t;
// Control for the gamma-conversion module
typedef union {
struct {
u32 bayer: 2; // [ 1: 0] (0) Bayer color shift (pixel to gamma table)
u32 page: 1; // [ 2] (0) Table page (only available if SENS_GAMMA_BUFFER in Verilog)
u32 en: 1; // [ 3] (1) Enable module
u32 repet: 1; // [ 4] (1) Repetitive (normal) mode. Set 0 for testing of the single-frame mode
u32 trig: 1; // [ 5] (0) Single trigger used when repetitive mode is off (self clearing bit)
u32 :26;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_gamma_ctl_t;
// Write gamma table address/data
typedef union {
struct {
u32 addr: 8; // [ 7: 0] (0) Start address in a gamma page (normally 0)
u32 color: 2; // [ 9: 8] (0) Color channel
u32 sub_chn: 2; // [11:10] (0) Sensor sub-channel (multiplexed to the same port)
u32 : 8;
u32 a_n_d: 1; // [ 20] (1) Address/not data, should be set to 1 here
u32 :11;
};
struct {
u32 base:10; // [ 9: 0] (0) Knee point value (to be interpolated between)
char diff: 7; // [16:10] (0) Difference to next (signed, -64..+63)
u32 diff_scale: 1; // [ 17] (0) Difference scale: 0 - keep diff, 1- multiply diff by 16
u32 :14;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_gamma_tbl_t;
// Heights of the first two subchannels frames
typedef union {
struct {
u32 height0m1:16; // [15: 0] (0) Height of subchannel 0 frame minus 1
u32 height1m1:16; // [31:16] (0) Height of subchannel 1 frame minus 1
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_gamma_height01m1_t;
// Height of the third subchannel frame
typedef union {
struct {
u32 height2m1:16; // [15: 0] (0) Height of subchannel 2 frame minus 1
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_gamma_height2m1_t;
// Sensor port I/O control
typedef union {
struct {
u32 mrst: 1; // [ 0] (0) MRST signal level to the sensor (0 - low(active), 1 - high (inactive)
u32 mrst_set: 1; // [ 1] (0) when set to 1, MRST is set to the 'mrst' field value
u32 arst: 1; // [ 2] (0) ARST signal to the sensor
u32 arst_set: 1; // [ 3] (0) ARST set to the 'arst' field
u32 aro: 1; // [ 4] (0) ARO signal to the sensor
u32 aro_set: 1; // [ 5] (0) ARO set to the 'aro' field
u32 mmcm_rst: 1; // [ 6] (0) MMCM (for sensor clock) reset signal
u32 mmcm_rst_set: 1; // [ 7] (0) MMCM reset set to 'mmcm_rst' field
u32 ext_clk: 1; // [ 8] (0) MMCM clock input: 0: clock to the sensor, 1 - clock from the sensor
u32 ext_clk_set: 1; // [ 9] (0) Set MMCM clock input to 'ext_clk' field
u32 set_dly: 1; // [ 10] (0) Set all pre-programmed delays to the sensor port input delays
u32 : 1;
u32 quadrants: 6; // [17:12] (1) 90-degree shifts for data [1:0], hact [3:2] and vact [5:4]
u32 : 2;
u32 quadrants_set: 1; // [ 20] (0) Set 'quadrants' values
u32 :11;
};
struct {
u32 /*mrst*/: 1; // [ 0] (0) MRST signal level to the sensor (0 - low(active), 1 - high (inactive)
u32 /*mrst_set*/: 1; // [ 1] (0) when set to 1, MRST is set to the 'mrst' field value
u32 /*arst*/: 1; // [ 2] (0) ARST signal to the sensor
u32 /*arst_set*/: 1; // [ 3] (0) ARST set to the 'arst' field
u32 /*aro*/: 1; // [ 4] (0) ARO signal to the sensor
u32 /*aro_set*/: 1; // [ 5] (0) ARO set to the 'aro' field
u32 /*mmcm_rst*/: 1; // [ 6] (0) MMCM (for sensor clock) reset signal
u32 /*mmcm_rst_set*/: 1; // [ 7] (0) MMCM reset set to 'mmcm_rst' field
u32 ign_embed: 1; // [ 8] (0) Ignore embedded data (non-image pixel lines
u32 ign_embed_set: 1; // [ 9] (0) Set mode to 'ign_embed' field
u32 /*set_dly*/: 1; // [ 10] (0) Set all pre-programmed delays to the sensor port input delays
u32 : 1;
u32 gp0: 1; // [ 12] (0) GP0 multipurpose signal to the sensor
u32 gp0_set: 1; // [ 13] (0) Set GP0 to 'gp0' value
u32 gp1: 1; // [ 14] (0) GP1 multipurpose signal to the sensor
u32 gp1_set: 1; // [ 15] (0) Set GP1 to 'gp1' value
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sensio_ctl_t;
// Programming interface for multiplexer FPGA
typedef union {
struct {
u32 tdi: 1; // [ 0] (0) JTAG TDI level
u32 tdi_set: 1; // [ 1] (0) JTAG TDI set to 'tdi' field
u32 tms: 1; // [ 2] (0) JTAG TMS level
u32 tms_set: 1; // [ 3] (0) JTAG TMS set to 'tms' field
u32 tck: 1; // [ 4] (0) JTAG TCK level
u32 tck_set: 1; // [ 5] (0) JTAG TCK set to 'tck' field
u32 prog: 1; // [ 6] (0) Sensor port PROG level
u32 prog_set: 1; // [ 7] (0) Sensor port PROG set to 'prog' field
u32 pgmen: 1; // [ 8] (0) Sensor port PGMEN level
u32 pgmen_set: 1; // [ 9] (0) Sensor port PGMEN set to 'pgmen' field
u32 :22;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sensio_jtag_t;
// Sensor i/o timing register 0 (different meanings for different sensor types)
typedef union {
struct {
u32 pxd0: 8; // [ 7: 0] (0) PXD0 input delay (3 LSB not used)
u32 pxd1: 8; // [15: 8] (0) PXD1 input delay (3 LSB not used)
u32 pxd2: 8; // [23:16] (0) PXD2 input delay (3 LSB not used)
u32 pxd3: 8; // [31:24] (0) PXD3 input delay (3 LSB not used)
};
struct {
u32 fifo_lag: 4; // [ 3: 0] (7) FIFO delay to start output
u32 :28;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sensio_tim0_t;
// Sensor i/o timing register 1 (different meanings for different sensor types)
typedef union {
struct {
u32 pxd4: 8; // [ 7: 0] (0) PXD4 input delay (3 LSB not used)
u32 pxd5: 8; // [15: 8] (0) PXD5 input delay (3 LSB not used)
u32 pxd6: 8; // [23:16] (0) PXD6 input delay (3 LSB not used)
u32 pxd7: 8; // [31:24] (0) PXD7 input delay (3 LSB not used)
};
struct {
u32 phys_lane0: 2; // [ 1: 0] (1) Physical lane for logical lane 0
u32 phys_lane1: 2; // [ 3: 2] (2) Physical lane for logical lane 1
u32 phys_lane2: 2; // [ 5: 4] (3) Physical lane for logical lane 2
u32 phys_lane3: 2; // [ 7: 6] (0) Physical lane for logical lane 3
u32 :24;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sensio_tim1_t;
// Sensor i/o timing register 2 (different meanings for different sensor types)
typedef union {
struct {
u32 pxd8: 8; // [ 7: 0] (0) PXD8 input delay (3 LSB not used)
u32 pxd9: 8; // [15: 8] (0) PXD9 input delay (3 LSB not used)
u32 pxd10: 8; // [23:16] (0) PXD10 input delay (3 LSB not used)
u32 pxd11: 8; // [31:24] (0) PXD11 input delay (3 LSB not used)
};
struct {
u32 dly_lane0: 8; // [ 7: 0] (0) lane 0 (phys) input delay (3 LSB not used)
u32 dly_lane1: 8; // [15: 8] (0) lane 1 (phys) input delay (3 LSB not used)
u32 dly_lane2: 8; // [23:16] (0) lane 2 (phys) input delay (3 LSB not used)
u32 dly_lane3: 8; // [31:24] (0) lane 3 (phys) input delay (3 LSB not used)
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sensio_tim2_t;
// Sensor i/o timing register 3 (different meanings for different sensor types)
typedef union {
struct {
u32 hact: 8; // [ 7: 0] (0) HACT input delay (3 LSB not used)
u32 vact: 8; // [15: 8] (0) VACT input delay (3 LSB not used)
u32 bpf: 8; // [23:16] (0) BPF (clock from sensor) input delay (3 LSB not used)
u32 phase_p: 8; // [31:24] (0) MMCM phase
};
struct {
u32 phase_h: 8; // [ 7: 0] (0) MMCM phase
u32 :24;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sensio_tim3_t;
// Set sensor frame width (0 - use received)
typedef union {
struct {
u32 sensor_width:16; // [15: 0] (0) Sensor frame width (0 - use line sync signals from the sensor)
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_sensio_width_t;
// Lens vignetting parameter (write address first, then data that may overlap som address bits)
typedef union {
struct {
u32 :16;
u32 addr: 8; // [23:16] (0) Lens correction address, should be written first (overlaps with data)
u32 sub_chn: 2; // [25:24] (0) Sensor subchannel
u32 : 6;
};
struct {
u32 ax:19; // [18: 0] (0x20000) Coefficient Ax
u32 :13;
};
struct {
u32 ay:19; // [18: 0] (0x20000) Coefficient Ay
u32 :13;
};
struct {
u32 bx:21; // [20: 0] (0x180000) Coefficient Bx
u32 :11;
};
struct {
u32 by:21; // [20: 0] (0x180000) Coefficient By
u32 :11;
};
struct {
u32 c:19; // [18: 0] (0x8000) Coefficient C
u32 :13;
};
struct {
u32 scale:17; // [16: 0] (0x8000) Scale (4 per-color values)
u32 :15;
};
struct {
u32 fatzero_in:16; // [15: 0] (0) 'Fat zero' on the input (subtract from the input)
u32 :16;
};
struct {
u32 fatzero_out:16; // [15: 0] (0) 'Fat zero' on the output (add to the result)
u32 :16;
};
struct {
u32 post_scale: 4; // [ 3: 0] (1) Shift result (bits)
u32 :28;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_lens_corr_t;
// Height of the subchannel frame for vignetting correction
typedef union {
struct {
u32 height_m1:16; // [15: 0] (0) Height of subframe minus 1
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_lens_height_m1_t;
// Histogram window left/top margins
typedef union {
struct {
u32 left:16; // [15: 0] (0) Histogram window left margin
u32 top:16; // [31:16] (0) Histogram window top margin
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_hist_left_top_t;
// Histogram window width and height minus 1 (0 use full)
typedef union {
struct {
u32 width_m1:16; // [15: 0] (0) Width of the histogram window minus 1. If 0 - use frame right margin (end of HACT)
u32 height_m1:16; // [31:16] (0) Height of he histogram window minus 1. If 0 - use frame bottom margin (end of VACT)
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_hist_width_height_m1_t;
// Histograms DMA mode
typedef union {
struct {
u32 en: 1; // [ 0] (1) Enable histograms DMA
u32 nrst: 1; // [ 1] (1) 0 - reset histograms DMA
u32 confirm: 1; // [ 2] (1) 1 - wait for confirmation that histogram was written to the system memory
u32 : 1;
u32 cache: 4; // [ 7: 4] (3) AXI cache mode (normal - 3), ignored by Zynq?
u32 :24;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_hist_saxi_mode_t;
// Histograms DMA addresses
typedef union {
struct {
u32 page:20; // [19: 0] (0) Start address of the subchannel histogram (in pages = 4096 bytes
u32 :12;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_hist_saxi_addr_t;
// Compressor mode control
typedef union {
struct {
u32 run: 2; // [ 1: 0] (0) Run mode
u32 run_set: 1; // [ 2] (0) Set 'run'
u32 qbank: 3; // [ 5: 3] (0) Quantization table bank
u32 qbank_set: 1; // [ 6] (0) Set 'qbank'
u32 dcsub: 1; // [ 7] (0) Subtract DC enable
u32 dcsub_set: 1; // [ 8] (0) Set 'qbank'
u32 cmode: 4; // [12: 9] (0) Color format
u32 cmode_set: 1; // [ 13] (0) Set 'cmode'
u32 multiframe: 1; // [ 14] (0) Multi/single frame mode
u32 multiframe_set: 1; // [ 15] (0) Set 'multiframe'
u32 : 2;
u32 bayer: 2; // [19:18] (0) Bayer shift
u32 bayer_set: 1; // [ 20] (0) Set 'bayer'
u32 focus: 2; // [22:21] (0) Focus mode
u32 focus_set: 1; // [ 23] (0) Set 'focus'
u32 : 8;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_cmprs_mode_t;
// Compressor coring mode (table number)
typedef union {
struct {
u32 coring_table: 3; // [ 2: 0] (0) Select coring table pair number
u32 :29;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_cmprs_coring_mode_t;
// Compressor color saturation
typedef union {
struct {
u32 colorsat_blue:10; // [ 9: 0] (0x120) Color saturation for blue (0x90 - 100%)
u32 : 2;
u32 colorsat_red:10; // [21:12] (0x16c) Color saturation for red (0xb6 - 100%)
u32 :10;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_cmprs_colorsat_t;
// Compressor frame format
typedef union {
struct {
u32 num_macro_cols_m1:13; // [12: 0] (0) Number of macroblock colums minus 1
u32 num_macro_rows_m1:13; // [25:13] (0) Number of macroblock rows minus 1
u32 left_margin: 5; // [30:26] (0) Left margin of the first pixel (0..31) for 32-pixel wide colums in memory access
u32 : 1;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_cmprs_frame_format_t;
// Compressor interrupts control
typedef union {
struct {
u32 interrupt_cmd: 2; // [ 1: 0] (0) 0: nop, 1: clear interrupt status, 2: disable interrupt, 3: enable interrupt
u32 :30;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_cmprs_interrupts_t;
// Compressor tables load control
typedef union {
struct {
u32 addr32:24; // [23: 0] (0) Table address to start writing to (autoincremented) for DWORDs
u32 type: 2; // [25:24] (0) 0: quantization, 1: coring, 2: focus, 3: huffman
u32 : 6;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_cmprs_table_addr_t;
// Compressor channel status
typedef union {
struct {
u32 is: 1; // [ 0] (0) Compressor channel interrupt status
u32 im: 1; // [ 1] (0) Compressor channel interrupt mask
u32 reading_frame: 1; // [ 2] (0) Compressor channel is reading frame from memory (debug feature)
u32 stuffer_running: 1; // [ 3] (0) Compressor channel bit stuffer is running (debug feature)
u32 flushing_fifo: 1; // [ 4] (0) Compressor channel is flushing FIFO (debug feature)
u32 :21;
u32 seq_num: 6; // [31:26] (0) Status sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_cmprs_status_t;
// Compressor DMA buffer address (in 32-byte blocks)
typedef union {
struct {
u32 sa256:27; // [26: 0] (0) System memory buffer start in multiples of 32 bytes (256 bits)
u32 : 5;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_afimux_sa_t;
// Compressor DMA buffer length (in 32-byte blocks)
typedef union {
struct {
u32 len256:27; // [26: 0] (0) System memory buffer length in multiples of 32 bytes (256 bits)
u32 : 5;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_afimux_len_t;
// Compressor DMA channels reset
typedef union {
struct {
u32 rst0: 1; // [ 0] (0) AXI HPx sub-channel0 reset (0 - normal operation, 1 - reset)
u32 rst1: 1; // [ 1] (0) AXI HPx sub-channel0 reset (0 - normal operation, 1 - reset)
u32 rst2: 1; // [ 2] (0) AXI HPx sub-channel0 reset (0 - normal operation, 1 - reset)
u32 rst3: 1; // [ 3] (0) AXI HPx sub-channel0 reset (0 - normal operation, 1 - reset)
u32 :28;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_afimux_rst_t;
// Compressor DMA enable (global and channels)
typedef union {
struct {
u32 en0: 1; // [ 0] (0) AXI HPx sub-channel0 enable value to set (0 - pause, 1 - run)
u32 en0_set: 1; // [ 1] (0) 0 - nop, 1 - set en0
u32 en1: 1; // [ 2] (0) AXI HPx sub-channel1 enable value to set (0 - pause, 1 - run)
u32 en1_set: 1; // [ 3] (0) 0 - nop, 1 - set en1
u32 en2: 1; // [ 4] (0) AXI HPx sub-channel2 enable value to set (0 - pause, 1 - run)
u32 en2_set: 1; // [ 5] (0) 0 - nop, 1 - set en2
u32 en3: 1; // [ 6] (0) AXI HPx sub-channel3 enable value to set (0 - pause, 1 - run)
u32 en3_set: 1; // [ 7] (0) 0 - nop, 1 - set en3
u32 en: 1; // [ 8] (0) AXI HPx global enable value to set (0 - pause, 1 - run)
u32 en_set: 1; // [ 9] (0) 0 - nop, 1 - set en
u32 :22;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_afimux_en_t;
// Compressor DMA report mode
typedef union {
struct {
u32 mode0: 2; // [ 1: 0] (0) channel0 report mode: 0 - EOF int, 1 - EOF confirmed, 2 - CP (current), 3 - CP confirmed
u32 mode0_set: 1; // [ 2] (0) 0 - nop, 1 - set mode0
u32 : 1;
u32 mode1: 2; // [ 5: 4] (0) channel0 report mode: 0 - EOF int, 1 - EOF confirmed, 2 - CP (current), 3 - CP confirmed
u32 mode1_set: 1; // [ 6] (0) 0 - nop, 1 - set mode0
u32 : 1;
u32 mode2: 2; // [ 9: 8] (0) channel0 report mode: 0 - EOF int, 1 - EOF confirmed, 2 - CP (current), 3 - CP confirmed
u32 mode2_set: 1; // [ 10] (0) 0 - nop, 1 - set mode0
u32 : 1;
u32 mode3: 2; // [13:12] (0) channel0 report mode: 0 - EOF int, 1 - EOF confirmed, 2 - CP (current), 3 - CP confirmed
u32 mode3_set: 1; // [ 14] (0) 0 - nop, 1 - set mode0
u32 :17;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_afimux_report_t;
// Compressor DMA status
typedef union {
struct {
u32 offset256:26; // [25: 0] (0) AFI MUX current/EOF pointer offset in 32-byte blocks
u32 seq_num: 6; // [31:26] (0) Status sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_afimux_status_t;
// GPIO output control
typedef union {
struct {
u32 pin0: 2; // [ 1: 0] (0) Output control for pin 0: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 pin1: 2; // [ 3: 2] (0) Output control for pin 1: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 pin2: 2; // [ 5: 4] (0) Output control for pin 2: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 pin3: 2; // [ 7: 6] (0) Output control for pin 3: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 pin4: 2; // [ 9: 8] (0) Output control for pin 4: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 pin5: 2; // [11:10] (0) Output control for pin 5: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 pin6: 2; // [13:12] (0) Output control for pin 6: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 pin7: 2; // [15:14] (0) Output control for pin 7: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 pin8: 2; // [17:16] (0) Output control for pin 8: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 pin9: 2; // [19:18] (0) Output control for pin 0: 0 - nop, 1 - set low, 2 - set high, 3 - tristate
u32 : 4;
u32 soft: 2; // [25:24] (0) Enable pin software control: 0,1 - nop, 2 - disab;e, 3 - enable
u32 chn_a: 2; // [27:26] (0) Enable A channel (camsync): 0,1 - nop, 2 - disab;e, 3 - enable
u32 chn_b: 2; // [29:28] (0) Enable B channel (reserved): 0,1 - nop, 2 - disab;e, 3 - enable
u32 chn_c: 2; // [31:30] (0) Enable C channel (logger): 0,1 - nop, 2 - disab;e, 3 - enable
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_gpio_set_pins_t;
// GPIO pins status
typedef union {
struct {
u32 pin0: 1; // [ 0] (0) GPIO pin 0 state
u32 pin1: 1; // [ 1] (0) GPIO pin 0 state
u32 pin2: 1; // [ 2] (0) GPIO pin 0 state
u32 pin3: 1; // [ 3] (0) GPIO pin 0 state
u32 pin4: 1; // [ 4] (0) GPIO pin 0 state
u32 pin5: 1; // [ 5] (0) GPIO pin 0 state
u32 pin6: 1; // [ 6] (0) GPIO pin 0 state
u32 pin7: 1; // [ 7] (0) GPIO pin 0 state
u32 pin8: 1; // [ 8] (0) GPIO pin 0 state
u32 pin9: 1; // [ 9] (0) GPIO pin 0 state
u32 :16;
u32 seq_num: 6; // [31:26] (0) Status sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_gpio_status_t;
// RTC seconds
typedef union {
struct {
u32 sec:32; // [31: 0] (0) RTC seconds
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_rtc_sec_t;
// RTC microseconds
typedef union {
struct {
u32 usec:20; // [19: 0] (0) RTC microseconds
u32 :12;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_rtc_usec_t;
// RTC correction
typedef union {
struct {
short corr:16; // [15: 0] (0) RTC correction, +/1 1/256 full scale
u32 :16;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_rtc_corr_t;
// RTC status
typedef union {
struct {
u32 :24;
u32 alt_snap: 1; // [ 24] (0) alternates 0/1 each time RTC timer makes a snapshot
u32 : 1;
u32 seq_num: 6; // [31:26] (0) Status sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_rtc_status_t;
// CAMSYNC I/O configuration
typedef union {
struct {
u32 line0: 2; // [ 1: 0] (1) line 0 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 line1: 2; // [ 3: 2] (1) line 1 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 line2: 2; // [ 5: 4] (1) line 2 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 line3: 2; // [ 7: 6] (1) line 3 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 line4: 2; // [ 9: 8] (1) line 4 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 line5: 2; // [11:10] (1) line 5 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 line6: 2; // [13:12] (1) line 6 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 line7: 2; // [15:14] (1) line 7 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 line8: 2; // [17:16] (1) line 8 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 line9: 2; // [19:18] (1) line 9 mode: 0 - inactive, 1 - keep (nop), 2 - active low, 3 - active high
u32 :12;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_camsync_io_t;
// CAMSYNC mode
typedef union {
struct {
u32 en: 1; // [ 0] (1) Enable CAMSYNC module
u32 en_snd: 1; // [ 1] (1) Enable sending timestamps (valid with 'en_snd_set')
u32 en_snd_set: 1; // [ 2] (0) Set 'en_snd'
u32 ext: 1; // [ 3] (1) Use external (received) timestamps, if available. O - use local timestamps
u32 ext_set: 1; // [ 4] (0) Set 'ext'
u32 trig: 1; // [ 5] (1) Sensor triggered mode (0 - free running sensor)
u32 trig_set: 1; // [ 6] (0) Set 'trig'
u32 master_chn: 2; // [ 8: 7] (0) master sensor channel (zero delay in internal trigger mode, delay used for flash output)
u32 master_chn_set: 1; // [ 9] (0) Set 'master_chn'
u32 ts_chns: 4; // [13:10] (1) Channels to generate timestmp messages (bit mask)
u32 ts_chns_set: 1; // [ 14] (0) Set 'ts_chns'
u32 :17;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_camsync_mode_t;
// CMDFRAMESEQ mode
typedef union {
struct {
u32 interrupt_cmd: 2; // [ 1: 0] (0) Interrupt command: 0-nop, 1 - clear is, 2 - disable, 3 - enable
u32 :10;
u32 run_cmd: 2; // [13:12] (0) Run command: 0,1 - nop, 2 - stop, 3 - run
u32 reset: 1; // [ 14] (0) 1 - reset, 0 - normal operation
u32 :17;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_cmdframeseq_mode_t;
// CMDFRAMESEQ mode
typedef union {
struct {
u32 frame_num0: 4; // [ 3: 0] (0) Frame number for sensor 0
u32 frame_num1: 4; // [ 7: 4] (0) Frame number for sensor 0
u32 frame_num2: 4; // [11: 8] (0) Frame number for sensor 0
u32 frame_num3: 4; // [15:12] (0) Frame number for sensor 0
u32 is: 4; // [19:16] (0) Interrupt status: 1 bit per sensor channel
u32 im: 4; // [23:20] (0) Interrupt enable: 1 bit per sensor channel
u32 : 2;
u32 seq_num: 6; // [31:26] (0) Status sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_cmdseqmux_status_t;
// Event logger status
typedef union {
struct {
u32 sample:24; // [23: 0] (0) Logger sample number
u32 : 2;
u32 seq_num: 6; // [31:26] (0) Status sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_logger_status_t;
// Event logger register address
typedef union {
struct {
u32 addr: 5; // [ 4: 0] (0) Register address (autoincrements in 32 DWORDs (page) range
u32 page: 2; // [ 6: 5] (0) Register page: configuration: 0, IMU: 3, GPS: 1, MSG: 2
u32 :25;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_logger_address_t;
// Event logger register data
typedef union {
struct {
u32 imu_slot: 2; // [ 1: 0] (0) IMU slot
u32 imu_set: 1; // [ 2] (0) Set 'imu_slot'
u32 gps_slot: 2; // [ 4: 3] (0) GPS slot
u32 gps_invert: 1; // [ 5] (0) GPS inpert 1pps signal
u32 gps_ext: 1; // [ 6] (0) GPS sync to 1 pps signal (0 - sync to serial message)
u32 gps_set: 1; // [ 7] (0) Set 'gps_*' fields
u32 msg_input: 4; // [11: 8] (0) MSG pin: GPIO pin number to accept external signal (0xf - disable)
u32 msg_invert: 1; // [ 12] (0) MSG input polarity - 0 - active high, 1 - active low
u32 msg_set: 1; // [ 13] (0) Set 'msg_*' fields
u32 log_sync: 4; // [17:14] (0) Log frame sync events (bit per sensor channel)
u32 log_sync_set: 1; // [ 18] (0) Set 'log_sync' fields
u32 :13;
};
struct {
u32 data:32; // [31: 0] (0) Other logger register data (context-dependent)
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_logger_data_t;
// MULT_SAXI DMA addresses/lengths in 32-bit DWORDS
typedef union {
struct {
u32 addr32:30; // [29: 0] (0) SAXI sddress/length in DWORDs
u32 : 2;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_mult_saxi_al_t;
// MULTICLK reset/power down controls
typedef union {
struct {
u32 rst_clk0: 1; // [ 0] (0) Reset PLL for xclk(240MHz), hclk(150MHz)
u32 rst_clk1: 1; // [ 1] (0) Reset PLL for pclk (sensors, from ffclk0)
u32 rst_clk2: 1; // [ 2] (0) reserved
u32 rst_clk3: 1; // [ 3] (0) reserved
u32 pwrdwnclk0: 1; // [ 4] (0) Power down PLL for xclk(240MHz), hclk(150MHz)
u32 pwrdwn_clk1: 1; // [ 5] (0) Power down for pclk (sensors, from ffclk0)
u32 pwrdwn_clk2: 1; // [ 6] (0) reserved
u32 pwrdwn_clk3: 1; // [ 7] (0) reserved
u32 rst_memclk: 1; // [ 8] (0) reset memclk (external in for memory) toggle FF
u32 rst_ffclk0: 1; // [ 9] (0) reset ffclk0 (external in for sensors) toggle FF
u32 rst_ffclk1: 1; // [ 10] (0) reset ffclk1 (exteranl in, not yet used) toggle FF
u32 :21;
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_multiclk_ctl_t;
// MULTICLK status
typedef union {
struct {
u32 locked0: 1; // [ 0] (0) Locked PLL for xclk(240MHz), hclk(150MHz)
u32 locked1: 1; // [ 1] (0) Locked PLL for pclk (sensors, from ffclk0)
u32 locked2: 1; // [ 2] (0) ==1, reserved
u32 locked3: 1; // [ 3] (0) ==1, reserved
u32 tgl_memclk: 1; // [ 4] (0) memclk (external in for memory) toggle FF
u32 tgl_ffclk0: 1; // [ 5] (0) ffclk0 (external in for sensors) toggle FF
u32 tgl_ffclk1: 1; // [ 6] (0) ffclk1 (exteranl in, not yet used) toggle FF
u32 :17;
u32 idelay_rdy: 1; // [ 24] (0) idelay_ctrl_rdy (juct to prevent from optimization)
u32 : 1;
u32 seq_num: 6; // [31:26] (0) Status sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_multiclk_status_t;
// DEBUG status
typedef union {
struct {
u32 :24;
u32 tgl: 1; // [ 24] (0) Toggles for each DWORD received
u32 : 1;
u32 seq_num: 6; // [31:26] (0) Status sequence number
};
struct {
u32 d32:32; // [31: 0] (0) cast to u32
};
} x393_debug_status_t;
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/misc/ 0000775 0000000 0000000 00000000000 12703306510 0024546 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/misc/ltc3589.c 0000664 0000000 0000000 00000131465 12703306510 0026037 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : ltc3589.c
*! DESCRIPTION: control of the Linear Technology LTC3589 8-channel voltage regulator
*! Copyright (C) 2013 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! 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 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*/
#undef DEBUG /* should be before linux/module.h - enables dev_dbg at boot in this file */
#include
#include
#include
#include
#include
#include
#include
#include
#define DRV_VERSION "1.0"
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
#define CACHE_INIT 1
#define CACHE_VOLAT 2
#define LAST_REG 0x33
struct ltc3589_cache_t {
u8 flags;
u8 data;
};
struct ltc3589_data_t {
int reg_addr; /* used for raw register r/w */
int simulate; /* do not perform actual i2c writes */
struct mutex lock;
struct ltc3589_cache_t cache[LAST_REG+1];
};
static struct i2c_device_id ltc3589_id[] = {
{ "ltc3589", 0 },
{ }
};
struct named_fields_t {
char *name;
u32 awe;
};
static const struct named_fields_t status_fields[]={
{"power_good", LTC3589_AWE_PGSTAT},
{"pgood_ldo1", LTC3589_AWE_PGSTAT_LDO1},
{"pgood_sd1", LTC3589_AWE_PGSTAT_SD1},
{"pgood_sd2", LTC3589_AWE_PGSTAT_SD2},
{"pgood_sd3", LTC3589_AWE_PGSTAT_SD3},
{"pgood_bb", LTC3589_AWE_PGSTAT_BB},
{"pgood_ldo2", LTC3589_AWE_PGSTAT_LDO2},
{"pgood_ldo3", LTC3589_AWE_PGSTAT_LDO3},
{"pgood_ldo4", LTC3589_AWE_PGSTAT_LDO4},
{"irqstat", LTC3589_AWE_IRQSTAT},
{"irqstat_pgoot_timeout",LTC3589_AWE_IRQSTAT_PGOOD_TIMOUT},
{"irqstat_near_uv", LTC3589_AWE_IRQSTAT_NEAR_UV},
{"irqstat_hard_uv", LTC3589_AWE_IRQSTAT_HARD_UV},
{"irqstat_near_therm", LTC3589_AWE_IRQSTAT_NEAR_THERM},
{"irqstat_hard_therm", LTC3589_AWE_IRQSTAT_HARD_THERM},
};
static const struct named_fields_t named_fields[]={
{"ref1_sd1", LTC3589_AWE_B1DTV1_REF},
{"ref2_sd1", LTC3589_AWE_B1DTV2_REF},
{"ref1_sd2", LTC3589_AWE_B2DTV1_REF},
{"ref2_sd2", LTC3589_AWE_B2DTV2_REF},
{"ref1_sd3", LTC3589_AWE_B3DTV1_REF},
{"ref2_sd3", LTC3589_AWE_B3DTV2_REF},
{"ref1_ldo2", LTC3589_AWE_L2DTV1_REF},
{"ref2_ldo2", LTC3589_AWE_L2DTV2_REF},
{"ref_ldo4", LTC3589_AWE_B1DTV1_REF},
{"dv_dt_sd1", LTC3589_AWE_B1DTV1_DVDT},
{"pgood_mask_sd1", LTC3589_AWE_B1DTV1_PGMASK},
{"pgood_mask_sd2", LTC3589_AWE_B2DTV1_PGMASK},
{"pgood_mask_sd3", LTC3589_AWE_B3DTV1_PGMASK},
{"pgood_mask_ldo21",LTC3589_AWE_L2DTV1_PGMASK},
{"clock_rate_sd1", LTC3589_AWE_B1DTV2_CLKRATE},
{"clock_rate_sd2", LTC3589_AWE_B2DTV2_CLKRATE},
{"clock_rate_sd3", LTC3589_AWE_B3DTV2_CLKRATE},
{"clock_phase_sd1", LTC3589_AWE_B1DTV2_PHASE},
{"clock_phase_sd2", LTC3589_AWE_B2DTV2_PHASE},
{"clock_phase_sd3", LTC3589_AWE_B3DTV2_PHASE},
{"keep_alive_sd1", LTC3589_AWE_B1DTV2_KEEP_ALIVE},
{"keep_alive_sd2", LTC3589_AWE_B2DTV2_KEEP_ALIVE},
{"keep_alive_sd3", LTC3589_AWE_B3DTV2_KEEP_ALIVE},
{"keep_alive_ldo2", LTC3589_AWE_L2DTV1_KEEP_ALIVE},
{"slew_rate_sd1", LTC3589_AWE_VRRCR_SD1},
{"slew_rate_sd2", LTC3589_AWE_VRRCR_SD2},
{"slew_rate_sd3", LTC3589_AWE_VRRCR_SD3},
{"slew_rate_ldo2", LTC3589_AWE_VRRCR_LDO2},
{"oven_ldo4", LTC3589_AWE_L2DTV2_MODE_LDO4},
{"oven_only", LTC3589_AWE_OVEN_ONLY},
};
static const int volatile_registers[]={LTC3589_AWE_IRQSTAT_PGOOD_TIMOUT, LTC3589_AWE_PGSTAT_LDO1, LTC3589_AWE_VCCR,-1};
static const char * chn_names[]={"SD1","SD2","SD3","BB","LDO1","LDO2","LDO3","LDO4"};
static const char * modes[]={"continuous","burst","pulse_skip","invalid"};
static const char * pwr_states[]={"power_off","power_on"};
static const char * wait_states[]={"no_wait", "wait"};
static const char * reference_sel[]={"reference_sel1", "reference_sel2"};
/* (register_address << 8) | mask */
static const u32 register_masks[]= {
0x07ff,0x12ff,0x20ff,0x24ff,0x25ff,0x26ff,0x27ff,
0x29ff,0x2aff,0x32ff,0x33ff,0x10ff};
static int make_status_fields(struct device *dev);
static int make_bit_fields(struct device *dev);
static ssize_t invalidate_cache_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t simulate_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t simulate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_data_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_address_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_data_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_all_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_help_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t power_wait_on_off_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t power_wait_on_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t pgood_timeout_inhibit_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t pgood_timeout_inhibit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t mode_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t reference_select_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t reference_select_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t reference_select_go_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t reference_select_go_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t field_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t get_field_value (struct device *dev, const char* name, char *buf, int newline);
static ssize_t irq_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t irq_show_txt (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t pwr_bad_good_show (struct device *dev, struct device_attribute *attr, char *buf);
static int get_chn_mode(struct device *dev, char *buf, int chn); /* 0..3 */
static int get_chn_pwr(struct device *dev, char *buf, int chn); /* 0..7 */
static int get_chn_wait(struct device *dev, char *buf, int chn); /* 0..7 */
static int get_ref_sel_go(struct device *dev, char *buf, int chn); /* 0..7 */
static int no_off(const char *str);
static int read_channel_mask(const char * str);
static int read_field (struct i2c_client *client, u32 awe);
static int write_field (struct i2c_client *client, u8 data, u32 awe);
static int write_adwe(struct i2c_client *client, u32 adwe);
static int write_reg(struct i2c_client *client, u8 reg, u8 val, u8 mask);
static int read_reg(struct i2c_client *client, u8 reg);
static void invalidate_cache(struct i2c_client *client);
static int ltc3589_sysfs_register(struct device *dev);
static void ltc3589_init_of(struct i2c_client *client);
static int ltc3589_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id);
static int ltc3589_i2c_remove(struct i2c_client *client);
int ltc3589_read_field (struct i2c_client *client, u32 awe)
{
return read_field (client, awe);
}
EXPORT_SYMBOL_GPL(ltc3589_read_field);
int ltc3589_write_field (struct i2c_client *client, u8 data, u32 awe)
{
return write_field (client, data, awe);
}
EXPORT_SYMBOL_GPL(ltc3589_write_field);
int ltc3589_write_adwe(struct i2c_client *client, u32 adwe)
{
return write_adwe(client, adwe);
}
EXPORT_SYMBOL_GPL(ltc3589_write_adwe);
void ltc3589_set_simulate(struct i2c_client *client, int simulate)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(client);
clientdata->simulate=simulate;
}
EXPORT_SYMBOL_GPL(ltc3589_set_simulate);
/* raw access to i2c registers, need to set address (9 bits) first, then r/w data */
static DEVICE_ATTR(invalidate_cache, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, invalidate_cache_store);
static DEVICE_ATTR(simulate, SYSFS_PERMISSIONS, simulate_show, simulate_store);
static DEVICE_ATTR(address, SYSFS_PERMISSIONS, raw_address_show, raw_address_store);
static DEVICE_ATTR(data, SYSFS_PERMISSIONS, raw_data_show, raw_data_store);
static DEVICE_ATTR(hex_address, SYSFS_PERMISSIONS, raw_hex_address_show,raw_hex_address_store);
static DEVICE_ATTR(hex_data, SYSFS_PERMISSIONS, raw_hex_data_show, raw_hex_data_store);
static DEVICE_ATTR(hex_all, SYSFS_PERMISSIONS & SYSFS_READONLY, raw_hex_all_show, NULL);
static DEVICE_ATTR(hex_adwe, SYSFS_PERMISSIONS, raw_hex_adwe_show, raw_hex_adwe_store);
static DEVICE_ATTR(hex_adwe_help, SYSFS_PERMISSIONS & SYSFS_READONLY, raw_hex_adwe_help_show, NULL);
static struct attribute *raw_dev_attrs[] = {
&dev_attr_invalidate_cache.attr,
&dev_attr_simulate.attr,
&dev_attr_address.attr,
&dev_attr_data.attr,
&dev_attr_hex_address.attr,
&dev_attr_hex_data.attr,
&dev_attr_hex_all.attr,
&dev_attr_hex_adwe.attr,
&dev_attr_hex_adwe_help.attr,
NULL
};
static const struct attribute_group dev_attr_raw_group = {
.attrs = raw_dev_attrs,
.name = "raw",
};
//static ssize_t irq_show (struct device *dev, struct device_attribute *attr, char *buf);
//static ssize_t irq_show_txt (struct device *dev, struct device_attribute *attr, char *buf);
//static ssize_t irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
//static ssize_t pwr_bad_good_show (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(power_good, SYSFS_PERMISSIONS & SYSFS_READONLY, pwr_bad_good_show, NULL);
static DEVICE_ATTR(power_bad, SYSFS_PERMISSIONS & SYSFS_READONLY, pwr_bad_good_show, NULL);
static DEVICE_ATTR(irq, SYSFS_PERMISSIONS, irq_show, irq_store);
static DEVICE_ATTR(irq_txt, SYSFS_PERMISSIONS, irq_show_txt, irq_store);
static DEVICE_ATTR(power_off, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(power_on, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(wait, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(no_wait, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(reference_sel1, SYSFS_PERMISSIONS, reference_select_show, reference_select_store);
static DEVICE_ATTR(reference_sel2, SYSFS_PERMISSIONS, reference_select_show, reference_select_store);
static DEVICE_ATTR(reference_sel_go, SYSFS_PERMISSIONS, reference_select_go_show, reference_select_go_store);
static DEVICE_ATTR(continuous, SYSFS_PERMISSIONS, mode_show, mode_store);
static DEVICE_ATTR(burst, SYSFS_PERMISSIONS, mode_show, mode_store);
static DEVICE_ATTR(pulse_skip, SYSFS_PERMISSIONS, mode_show, mode_store);
static DEVICE_ATTR(pgood_timeout_inhibit, SYSFS_PERMISSIONS, pgood_timeout_inhibit_show, pgood_timeout_inhibit_store);
static struct attribute *control_dev_attrs[] = {
&dev_attr_power_good.attr,
&dev_attr_power_bad.attr,
&dev_attr_irq.attr,
&dev_attr_irq_txt.attr,
&dev_attr_power_off.attr,
&dev_attr_power_on.attr,
&dev_attr_wait.attr,
&dev_attr_no_wait.attr,
&dev_attr_reference_sel1.attr,
&dev_attr_reference_sel2.attr,
&dev_attr_reference_sel_go.attr,
&dev_attr_continuous.attr,
&dev_attr_burst.attr,
&dev_attr_pulse_skip.attr,
&dev_attr_pgood_timeout_inhibit.attr,
NULL
};
static const struct attribute_group dev_attr_control_group = {
.attrs = control_dev_attrs,
.name = "control",
};
//status_fields[]
static int make_status_fields(struct device *dev)
{
int retval=-1;
int index;
struct attribute **pattrs; /* array of pointers to attibutes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
pattrs = devm_kzalloc(dev,(ARRAY_SIZE(status_fields)+1)*sizeof(pattrs[0]), GFP_KERNEL);
if (!pattrs) return -ENOMEM;
dev_attrs = devm_kzalloc(dev, ARRAY_SIZE(status_fields)*sizeof(dev_attrs[0]), GFP_KERNEL);
if (!dev_attrs) return -ENOMEM;
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
if (!attr_group) return -ENOMEM;
memset(dev_attrs, 0, ARRAY_SIZE(status_fields)*sizeof(dev_attrs[0]));
memset(attr_group, 0, sizeof(*attr_group));
for (index=0;indexname = "status";
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static int make_bit_fields(struct device *dev)
{
int retval=-1;
int index;
struct attribute **pattrs; /* array of pointers to attibutes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
pattrs = devm_kzalloc(dev,(ARRAY_SIZE(named_fields)+1)*sizeof(pattrs[0]), GFP_KERNEL);
if (!pattrs) return -ENOMEM;
dev_attrs = devm_kzalloc(dev, ARRAY_SIZE(named_fields)*sizeof(dev_attrs[0]), GFP_KERNEL);
if (!dev_attrs) return -ENOMEM;
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
if (!attr_group) return -ENOMEM;
memset(dev_attrs, 0, ARRAY_SIZE(named_fields)*sizeof(dev_attrs[0]));
memset(attr_group, 0, sizeof(*attr_group));
for (index=0;indexname = "bit_fields";
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static ssize_t invalidate_cache_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
invalidate_cache(client);
return count;
}
static ssize_t simulate_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%d\n",clientdata->simulate);
}
static ssize_t simulate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%du", &clientdata->simulate);
return count;
}
//clientdata->simulate
static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%d\n",clientdata->reg_addr);
}
static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%du", &clientdata->reg_addr);
return count;
}
static ssize_t raw_data_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data= read_reg(client, clientdata->reg_addr);
return sprintf(buf, "%d\n",data);
}
static ssize_t raw_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data;
sscanf(buf, "%du", &data);
write_reg(client, clientdata->reg_addr, data, 0xff); /* write all register, it is up to user to do R-mod-W */
return count;
}
static ssize_t raw_hex_address_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "0x%02x\n",clientdata->reg_addr);
}
static ssize_t raw_hex_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%x", &clientdata->reg_addr);
return count;
}
static ssize_t raw_hex_data_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data= read_reg(client, clientdata->reg_addr);
return sprintf(buf, "0x%02x\n",data);
}
static ssize_t raw_hex_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data;
sscanf(buf, "%x", &data);
write_reg(client, clientdata->reg_addr, data, 0xff); /* write all register, it is up to user to do R-mod-W */
return count;
}
static ssize_t raw_hex_all_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int low_addr=0,reg,data,rc,len=0, count=PAGE_SIZE;
struct i2c_client *client = to_i2c_client(dev);
// struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
for (reg=low_addr;reg<=LAST_REG;reg++) if (count>10){
if ((reg & 0xf) ==0){
rc=sprintf(buf, "%02x: ",reg);
buf+=rc;
len+=rc;
count-=rc;
}
data= read_reg(client, reg); //ignore errors
if (data<0) rc=sprintf(buf, "??");
else rc=sprintf(buf, "%02x",data);
buf+=rc;
len+=rc;
count-=rc;
if (((reg & 0xf) == 0xf) || (reg==LAST_REG)){
rc=sprintf(buf, "\n");
} else {
rc=sprintf(buf, " ");
}
buf+=rc;
len+=rc;
count-=rc;
}
return len;
}
static ssize_t raw_hex_adwe_help_show (struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Setting one/multiple registers with masks in the form [0x]AADDWW, where AA is register address\n" \
"DD - data byte and WW - write enable bits ( 1 - write, 0 - keep old)\n" \
"When read, provides current register data that can be used in device tree.\n");
}
//static const u32 register_masks[]= {
static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int i,data;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
for (i=0;i>8)))<0) return data;
buf+=sprintf(buf," 0x%x",((register_masks[i] & 0x1ff00)<<8) | (register_masks[i] & 0xff) | ((data & 0xff)<<8));
if (((i+1) & 0x7)==0) buf+=sprintf(buf,"\n");
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
/*
* accepts single or multiple data, each [0x]AAADDWW - AAA - register address, DD - data byte, WW - write enable mask (1 - write, 0 - keep).
* Ignores any other characters, so same format as in dts with hex data is OK
*/
static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
const char hex_digits[]="0123456789abcdefABCDEF";
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int adwe,rc=0;
int left=count,num_bytes;
char * cp;
mutex_lock(&clientdata->lock);
while ((left>0) && ((cp=strpbrk(buf,hex_digits))) && cp[0]){
left -= (cp-buf);
buf = cp;
dev_dbg(dev,"left=%d", left);
sscanf(buf, "%x%n", &adwe,&num_bytes);
left-=num_bytes;
buf+=num_bytes;
dev_dbg(dev,"left=%d num_bytes=%d, adwe=0x%08x", left,num_bytes,adwe);
if (((rc=write_adwe(client, adwe)))<0) {
mutex_unlock(&clientdata->lock);
return rc;
}
}
mutex_unlock(&clientdata->lock);
return count;
}
//static const char * chn_names[]={"SD1","SD2","SD3","BB","LDO1","LDO2","LDO3","LDO4"};
//static const char * pwr_states[]={"power_off","power_on"};
//static const char * wait_states[]={"no_wait", "wait"};
static ssize_t power_wait_on_off_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,i,invert;
char * cp=buf;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
awe= ((strcmp(attr->attr.name,wait_states[0])==0) || (strcmp(attr->attr.name,wait_states[1])==0))?LTC3589_AWE_SCR2:LTC3589_AWE_OVEN;
invert=((strcmp(attr->attr.name,pwr_states[0])==0) || (strcmp(attr->attr.name,wait_states[0])==0))?0xff:0;
if (((rc=read_field(client,awe)))<0) return rc;
rc=((rc & 0xf) | 0x10 | ((rc & 0x70)<<1)) ^ invert;
for (i=0;i<8;i++) if (rc & (1<attr.name,wait_states[0])==0) || (strcmp(attr->attr.name,wait_states[1])==0))?LTC3589_AWE_SCR2:LTC3589_AWE_OVEN;
data=((strcmp(attr->attr.name,pwr_states[0])==0) || (strcmp(attr->attr.name,wait_states[0])==0))?0:0xff;
mask=read_channel_mask(buf);
mask=(mask & 0xf) | ((mask >> 1) & 0x70);
awe = (awe & 0xff00) | mask;
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t pgood_timeout_inhibit_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_SCR2_PGOOD_SHTDN_INH)))<0) return rc;
return sprintf(buf, "%d\n",rc);
}
static ssize_t pgood_timeout_inhibit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,data;
struct i2c_client *client = to_i2c_client(dev);
sscanf(buf, "%d", &data);
if (((rc=write_field(client,data?1:0,LTC3589_AWE_SCR2_PGOOD_SHTDN_INH)))<0) return rc;
return count;
}
static ssize_t mode_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,m,i;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_SCR1)))<0) return rc;
for (m=0;mattr.name,modes[m])==0) break;
if (m>=ARRAY_SIZE(modes)) return -EINVAL;
for (i=0;i<4;i++) if (((rc>>(2*i)) & 3) == m) {
if (buf!=cp) buf+=sprintf(buf," ");
buf+=sprintf(buf,"%s",chn_names[i]);
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,mask,m,data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (m=0;mattr.name,modes[m])==0) break;
if (m>=ARRAY_SIZE(modes)) return -EINVAL;
mask=read_channel_mask(buf);
mask=((mask & 1)? 3:0) | ((mask & 2)? 0xc:0) | ((mask & 4)? 0x30:0) | ((mask & 8)? 0x40:0);
awe = (LTC3589_AWE_SCR1 & 0xff00) | mask;
data= m | (m<<2) | (m<<4) | (m<<6);
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t reference_select_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,m,i,chn;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_VCCR)))<0) return rc;
for (m=0;mattr.name,reference_sel[m])==0) break;
if (m>=ARRAY_SIZE(reference_sel)) return -EINVAL;
for (i=0;i<4;i++) if (((rc>>(2*i+1)) & 1)==m){
chn=i;
if (i==3) chn=5 ; /* LDO2 */
if (buf!=cp) buf+=sprintf(buf," ");
buf+=sprintf(buf,"%s",chn_names[chn]);
/* if ((rc>>(2*i)) & 1){
buf+=sprintf(buf,"(slewing)");
}
*/
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
/* not raising go */
static ssize_t reference_select_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,mask,m,data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (m=0;mattr.name,reference_sel[m])==0) break;
if (m>=ARRAY_SIZE(reference_sel)) return -EINVAL;
mask=read_channel_mask(buf);
mask=((mask & 1)? 2:0) | ((mask & 2)? 0x8:0) | ((mask & 4)? 0x20:0) | ((mask & 0x20)? 0x80:0);
awe = (LTC3589_AWE_VCCR & 0xff00) | mask;
data= m?0xff:0;
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t reference_select_go_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,i,chn;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_VCCR)))<0) return rc;
for (i=0;i<4;i++) if ((rc>>(2*i)) & 1){
chn=i;
if (i==3) chn=5 ; /* LDO2 */
if (buf!=cp) buf+=sprintf(buf," ");
buf+=sprintf(buf,"%s",chn_names[chn]);
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t reference_select_go_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,mask,data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
mask=read_channel_mask(buf);
mask=((mask & 1)? 1:0) | ((mask & 2)? 0x4:0) | ((mask & 4)? 0x10:0) | ((mask & 0x20)? 0x40:0);
awe = (LTC3589_AWE_VCCR & 0xff00) | mask;
data= 0xff;
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
//--------------------
static ssize_t field_show (struct device *dev, struct device_attribute *attr, char *buf)
{
return get_field_value (dev, attr->attr.name, buf, 1); /* with newline */
}
static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,i;
int data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (i=0;iattr.name,named_fields[i].name)==0) {
awe=named_fields[i].awe;
dev_dbg(dev,"i=%d, field name=%s awe=0x%04x\n", i, named_fields[i].name, (int) awe);
break;
}
if (i>=ARRAY_SIZE(named_fields)) {
for (i=0;iattr.name,status_fields[i].name)==0) {
awe=status_fields[i].awe;
dev_dbg(dev,"i=%d, status field name=%s awe=0x%04x\n", i, status_fields[i].name, (int) awe);
break;
}
if (i>=ARRAY_SIZE(status_fields)) return -EINVAL;
}
sscanf(buf, "%du", &data);
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t get_field_value (struct device *dev, const char* name, char *buf, int newline)
{
int rc,i;
char * cp=buf;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (i=0;i=ARRAY_SIZE(named_fields)) {
for (i=0;i=ARRAY_SIZE(status_fields)) return -EINVAL;
}
if (((rc=read_field(client,awe)))<0) return rc;
buf+=sprintf(buf,"%d",rc);
if (newline) buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t irq_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_IRQSTAT)))<0) return rc;
return sprintf(buf,"%d\n",rc);
}
static ssize_t irq_show_txt (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_IRQSTAT)))<0) return rc;
buf += sprintf(buf,"0x%02x",rc);
if (rc & LTC3589_AWE_IRQSTAT_PGOOD_TIMOUT) buf += sprintf(buf,"PGOOD timeout");
if (rc & LTC3589_AWE_IRQSTAT_NEAR_UV) buf += sprintf(buf,", Near undervoltage");
if (rc & LTC3589_AWE_IRQSTAT_HARD_UV) buf += sprintf(buf,", Hard undervoltage");
if (rc & LTC3589_AWE_IRQSTAT_NEAR_THERM) buf += sprintf(buf,", Near undervoltage");
if (rc & LTC3589_AWE_IRQSTAT_HARD_THERM) buf += sprintf(buf,", Hard undervoltage");
buf += sprintf(buf,"\n");
return buf-cp;
}
static ssize_t irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=write_field (client, 0, LTC3589_AWE_CLIRQ)))<0) return rc;
return count;
}
static ssize_t pwr_bad_good_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,i,pg;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_PGSTAT)))<0) return rc;
pg=(rc & 0xe0) | ((rc>>1) & 0xff) | ((rc << 4) & 0x10);
if (strstr(attr->attr.name,"bad")){
pg^=0xff;
}
for (i=0;i<8;i++) if (pg & (1<3)) return 0;
if (((rc=read_field(client,LTC3589_AWE_SCR1)))<0) return rc;
return sprintf (buf,"%s",modes[(rc >> (chn<<1)) &3]);
}
static int get_chn_pwr(struct device *dev, char *buf, int chn) /* 0..7 */
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if ((chn<0) || (chn>7)) return 0;
if (((rc=read_field(client,LTC3589_AWE_OVEN)))<0) return rc;
rc=(rc & 0xf) | 0x10 | ((rc & 0x70)<<1);
return sprintf (buf,"%s",pwr_states[(rc >> chn) & 1]);
}
static int get_chn_wait(struct device *dev, char *buf, int chn) /* 0..7 */
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if ((chn<0) || (chn>7)) return 0;
if (((rc=read_field(client,LTC3589_AWE_SCR2)))<0) return rc;
rc=(rc & 0xf) | 0x10 | ((rc & 0x70)<<1);
return sprintf (buf,"%s",wait_states[(rc >> chn) & 1]);
}
static int get_ref_sel_go(struct device *dev, char *buf, int chn) /* 0..7 */
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if ((chn<0) || ((chn>2) && (chn!=5))) return 0;
if (chn==5) chn=3;
if (((rc=read_field(client,LTC3589_AWE_VCCR)))<0) return rc;
rc =(rc >> (2*chn)) & 3;
return sprintf (buf,"%s%s",reference_sel[(rc>>1)&1],(rc&1)?" (slewing)":"");
}
static int no_off(const char *str)
{
return strstr(str,"_off")?0:1;
}
static int read_channel_mask(const char * str)
{
int mask =0, i;
for (i=0;i>8;
mask=awe&0xff;
if (mask!=0){
nshift=0;
while (((1<> nshift;
}
return 0;
}
static int write_field (struct i2c_client *client, u8 data, u32 awe)
{
int rc,nshift;
u8 mask,reg_data;
u8 reg;
reg=awe>>8;
mask=awe&0xff;
if (mask!=0){
nshift=0;
while (((1<>8) & 0xff;
u16 reg= (adwe>>16) & 0xff;
return write_reg(client, reg, data, we);
}
static int write_reg(struct i2c_client *client, u8 reg, u8 val, u8 mask)
{
int rc;
struct ltc3589_data_t *clientdata = i2c_get_clientdata(client);
if (reg>LAST_REG) return -EINVAL;
if (mask==0) return 0;
dev_dbg(&client->dev,"reg=0x%x, val=0x%x, mask=0x%x\n", (int) reg, (int) val, (int) mask);
if (mask !=0xff){
if (((rc=read_reg(client, reg)))<0) return rc;
val=((val ^ rc) & mask)^ rc;
if ((val==rc) && !(clientdata->cache[reg].flags & CACHE_VOLAT)) {
dev_dbg(&client->dev,"No change and not volatile -> no write\n");
return 0;
}
}
clientdata->cache[reg].data= val;
clientdata->cache[reg].flags |= CACHE_INIT;
if (clientdata->simulate){
dev_info(&client->dev,">>> Simulating LTC3589 register write: 0x%02x->[0x%02x]\n",(int) reg, (int) val);
return 0;
}
return i2c_smbus_write_byte_data(client, reg, val);
}
static int read_reg(struct i2c_client *client, u8 reg)
{
int rc;
struct ltc3589_data_t *clientdata = i2c_get_clientdata(client);
if (reg>LAST_REG) return -EINVAL;
if (clientdata && (clientdata->cache[reg].flags & CACHE_INIT) && !(clientdata->cache[reg].flags & CACHE_VOLAT)){
dev_dbg(&client->dev,"Using cached register: reg=0x%x -> 0x%x\n",reg,(int) clientdata->cache[reg].data);
return clientdata->cache[reg].data;
}
rc= i2c_smbus_read_byte_data(client, reg & 0xff);
dev_dbg(&client->dev,"reading i2c device : slave=0x%x, reg=0x%x -> 0x%x\n",(int) (client->addr),reg,rc);
if (rc<0) return rc;
if (clientdata){
clientdata->cache[reg].data= (u8) rc;
clientdata->cache[reg].flags |= CACHE_INIT;
}
return rc;
}
static void invalidate_cache(struct i2c_client *client)
{
int i;
struct ltc3589_data_t *clientdata = i2c_get_clientdata(client);
for (i=0;i<=LAST_REG;i++){
clientdata->cache[i].flags&= ~CACHE_INIT;
}
}
static int ltc3589_sysfs_register(struct device *dev)
{
int retval=0;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_raw_group)))<0) return retval;
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_control_group)))<0) return retval;
if (((retval = make_status_fields (dev)))<0) return retval;
if (((retval = make_bit_fields (dev)))<0) return retval;
}
return retval;
}
static void ltc3589_init_of(struct i2c_client *client)
{
// struct device *dev=&client->dev;
const __be32 * config_data;
const char * init_type_string;
int init_type=0; /* 0 - none, 1 - always, 2 - if not running (TODO) */
struct device_node *node = client->dev.of_node;
int len,i,n;
char buf[40];
struct ltc3589_setup_data {
u8 page;
u8 reg;
u8 data;
u8 mask;
};
struct ltc3589_setup_data setup_data;
__be32 * setup_data_be32= (__be32 *) &setup_data;
/* add stuff */
#if 0
if (node) {
init_type_string = of_get_property(client->dev.of_node, "ltc3589,init", &len);
if (init_type_string){
if (strcmp(init_type_string,"always")==0) init_type=1;
else if (strcmp(init_type_string,"if off")==0) init_type=2;
else {
dev_err(&client->dev,"Unrecognized ltc3589 initialization type '%s'. Only 'always' and 'if off' are permitted\n",init_type_string);
}
}
switch (init_type){
case 2:
// static int is_set_up(struct i2c_client *client);
i=is_set_up(client);
if (i<0){
dev_err(&client->dev,"Error reading i2c register, aborting initialization\n");
return;
} else if (i>0){
init_type=0;
dev_dbg(&client->dev,"Skipping conditional initialization (some driver variables will not be initialized)\n");
return;
}
init_type=1;
/* falling to initialization */
case 1:
pre_init(client,1); // clear outputs and muxes - they will be programmed later
break;
}
config_data = of_get_property(client->dev.of_node, "ltc3589,configuration_data", &len);
if (config_data){
len /= sizeof(*config_data);
dev_dbg(&client->dev,"Read %d values\n",len);
dev_dbg(&client->dev,"Found %d items in 'ltc3589,configuration_data' in the Device Tree\n",len);
for (i=0;idev,"page_reg=0x%03x, data=0x%02x, mask=0x%02x \n",
(int) page_reg,(int)setup_data.data,(int)setup_data.mask);
if (write_reg(client, page_reg, setup_data.data, setup_data.mask)<0) return;
}
}
/* input section */
/* setting input frequency here divides (if needed) and feeds it to the PLL reference. Other variants can use raw register writes */
for (n=0;in_freq_names[n];n++){
sprintf(buf,"ltc3589,%s",in_freq_names[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
dev_dbg(&client->dev,"Found '%s', value = %d (0x%x)\n",buf,(int)(be32_to_cpup(config_data)),(int)(be32_to_cpup(config_data)));
if (set_in_frequency(client, be32_to_cpup(config_data),n)<0) return; /* 32 bits are sufficient here */
}
}
/* setting PLL for the most important output frequency, sets analog parameters accordingly. Assumes input frequency set above */
for (n=0;pll_setup_names[n];n++){
sprintf(buf,"ltc3589,%s",pll_setup_names[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
len /= sizeof(*config_data);
freq[0]=be32_to_cpup(config_data);
if (len<3){
freq[1]=0;
freq[2]=1;
} else {
freq[1]=be32_to_cpup(&config_data[1]);
freq[2]=be32_to_cpup(&config_data[2]);
}
dev_dbg(&client->dev,"Found '%s', value = %lld+(%lld/%lld)\n",buf,freq[0],freq[1],freq[2]);
if (n & 2){ /* by output */
if (set_pll_freq_by_out(client, freq, n & 1)<0) return;
} else { /* directly set PLL frequency */
if (set_pll_freq (client, freq, n & 1)<0) return;
}
if (set_pll_paremeters(client)<0) return;
/* if (set_misc_registers(client)<0) return; */ /* moved to pre_init() */
}
}
/* setting MSn dividers (same channel as output), powering them up, setting output dividers and routing outputs */
for (n=0;out_freq_setup_names[n];n++){
sprintf(buf,"ltc3589,%s",out_freq_setup_names[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
len /= sizeof(*config_data);
freq[0]=be32_to_cpup(config_data);
if (len<3){
freq[1]=0;
freq[2]=1;
} else {
freq[1]=be32_to_cpup(&config_data[1]);
freq[2]=be32_to_cpup(&config_data[2]);
}
dev_dbg(&client->dev,"Found '%s', value = %lld+(%lld/%lld)\n",buf,freq[0],freq[1],freq[2]);
if (set_out_frequency_and_route(client, freq, n&3, n>>2)<0) return;
}
}
/* configure output driver standard */
for (n=0;drv_configs[n].description;n++){
sprintf(buf,"ltc3589,%s",drv_configs[n].description);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (configure_output_driver(&client->dev, drv_configs[n].description, setup_data.mask)<0) return;
}
}
}
/* configure disabled state of the output(s) */
for (n=0;out_dis_states[n];n++){
sprintf(buf,"ltc3589,%s",out_dis_states[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (set_drv_disable(client, n, setup_data.mask)<0) return;
}
}
}
/* configure powerdown state of the output(s) */
for (n=0;out_pwr_states[n];n++){
sprintf(buf,"ltc3589,%s",out_pwr_states[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (set_drv_powerdown(client, n, setup_data.mask)<0) return;
}
}
}
/* configure output enable state of the output(s) */
for (n=0;out_en_states[n];n++){
sprintf(buf,"ltc3589,%s",out_en_states[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (set_drv_disable(client, n, setup_data.mask)<0) return;
}
}
}
/* setting spread spectrum parameters */
for (n=0;n<4;n++){
sprintf(buf,"ltc3589,spread_spectrum_%d",n);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
len /= sizeof(*config_data);
rate=get_ss_down_rate(client, n);
amp= get_ss_down_amplitude(client, n);
if (len>1) amp = be32_to_cpup(&config_data[1]);
if (len>2) rate = be32_to_cpup(&config_data[2]);
if (store_ss_down_parameters(client, rate, amp, n)==0){
dev_dbg(&client->dev,"Set spread spectrum parameters for MS%d, amplitude=%d (*0.01%%), rate=%d Hz, %s\n",
n,amp,rate,config_data[0]?"ON":"OFF");
} else {
dev_err(&client->dev,"Failed to set spread spectrum parameters for MS%d, amplitude=%d (*0.01%%), rate=%d Hz, %s\n",
n,amp,rate,config_data[0]?"ON":"OFF");
continue;
}
if (config_data[0]){ /* enable SS */
if ((set_ss_down(client, n)==0) && /* calculate and set SS registers */
(set_ss_state(client, 1, n)==0)){ // enable SS. Not using enable_spread_spectrum() as we'll reset MS later anyway
dev_dbg(&client->dev,"Spread spectrum enabled for MS%d\n",n);
} else {
dev_dbg(&client->dev,"Fail to enable spread spectrum for MS%d\n",n);
}
}
}
}
} else {
dev_info(&client->dev,"Device tree data not found for %s\n",client->name);
}
if (init_type){
if (post_init(client,INIT_TIMEOUT)<0) dev_err(&client->dev,"ltc3589 initialization failed\n");
else dev_info(&client->dev,"ltc3589 initialized\n");
}
#endif
}
static int ltc3589_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int i,rc=0;
struct ltc3589_data_t *clientdata = NULL;
/* initialize i2c ... */
if (read_field (client, LTC3589_AWE_IRQSTAT_PGOOD_TIMOUT)<0) {
dev_err(&client->dev, "%s: chip not detected\n",id->name);
return -EIO;
}
dev_info(&client->dev,
"Chip %s is found, driver version %s\n", id->name, DRV_VERSION);
clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata), GFP_KERNEL);
for (i=0;i<=LAST_REG;i++){
clientdata->cache[i].flags=0;
clientdata->cache[i].data=0;
}
for (i=0;volatile_registers[i]>=0;i++){
clientdata->cache[volatile_registers[i]>>8].flags |= CACHE_VOLAT;
}
clientdata->simulate=0;
clientdata->reg_addr=0;
//volatile_registers[]
i2c_set_clientdata(client, clientdata);
ltc3589_sysfs_register(&client->dev);
mutex_init(&clientdata->lock);
ltc3589_init_of(client);
return 0;
}
static int ltc3589_i2c_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_driver ltc3589_i2c_driver = {
.driver = {
.name = "ltc3589",
.owner = THIS_MODULE,
},
.probe = ltc3589_i2c_probe,
.remove = ltc3589_i2c_remove,
.id_table = ltc3589_id,
};
module_i2c_driver(ltc3589_i2c_driver);
MODULE_DEVICE_TABLE(i2c, ltc3589_id);
MODULE_AUTHOR("Andrey Filippov ");
MODULE_DESCRIPTION("LTC3589 I2C bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:ltc3589");
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/misc/vsc330x.c 0000664 0000000 0000000 00000145024 12703306510 0026131 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : vsc330x.c
*! DESCRIPTION: control of the VSC3304 4x4 crosspoint switch
*! Copyright (C) 2013 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! 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 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#define DRV_VERSION "1.0"
/* TODO: Descriptions from vsc3312 - check differences */
#define I2C_PAGE_CONNECTION 0x00 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf) source
(input number) bit 4 (+0x10) - turn output off, bits 3:0 - source */
#define I2C_PAGE_INPUT_ISE 0x10 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf)
ISE (equalization): Bits 5:4 ISE short: 0 - off, 1 - minimal, 2 - moderate, 3 - maximal;
bits 3:2 ISE medium, bits 1:0 ISE Long time constant */
#define I2C_PAGE_INPUT_STATE 0x11 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf) enable,
polarity and termination (default 6)
Bit 2 (+4) Terminate to VDD ( 0 - connect, 1 - do not connect) - dedicated (0..7) inputs only
Bit 1 (+2) Input power (0 - on, 1 - off)
Bit 0 (+1) Invert signal at input */
#define I2C_INPUT_STATE_DATA 0x04 /* terminated,enabled, not inverted */
#define I2C_PAGE_INPUT_LOS 0x12 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf)
LOS (loss of signal) threshold
Bits 2:0 - level in mV for dedicated(bidirectional) inputs: 0,1,6,7 - unused, 2 - 150(170),
3 - 200(230), 4 - 250(280), 5 - 300(330) */
#define I2C_PAGE_OUTPUT_PRE_LONG 0x20 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
long time constant pre-emphasis
Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB), bits 2:0 - Pre-emphasis
decay (0x0 - fastest, 0x7 - slowest) in 500..1500 ps range */
#define I2C_PAGE_OUTPUT_PRE_SHORT 0x21 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
short time constant pre-emphasis
Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 30..500 ps range */
#define I2C_PAGE_OUTPUT_LEVEL 0x22 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
short time constant pre-emphasis
Bits 3:0 - peak-to-peak 0,1,0xe,0xf - unused, 0x2-405mV,0x3-425V,0x4-455mV,0x5-485mV,0x6-520mV,
0x7-555mV,0x8-605mV,0x9-655mV,0xa-720mV,0xb-790mV,0xc-890mV,0xd-990mV (+3.3VDC required)
bit 4 (+0x10) - for 8-15 used as inputs only: terminate inputs 8..15 to VDDIO-0.7V */
#define I2C_PAGE_OUTPUT_STATE 0x23 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
OOB signaling and output polarity
bits 4:1 - operation mode: 0xa - inverted, 0x5 - normal, 0x0 - suppressed
bit 0 - OOB control: 1 - enable LOS forwarding, 0 - ignore LOS */
#define I2C_PAGE_CHANNEL_STATUS 0xf0 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf monitor corresponding input (0..0xf) LOS status
bit 0 - LOS status: 1 - LOS detected (loss of signal), 0 - signal present (input has to be enabled,
otherwise 0 is read)when reading from address 0x10 of this page:
bit 0 - value of STAT0
bit 1 - value of STAT1 */
#define I2C_PAGE_STATUS0_CONFIGURE 0x80 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control selected input LOS to be OR-ed
to STAT0 output pin (and bit)
bit 0 : 1 - OR this input channel LOS status to STAT0 */
#define I2C_PAGE_STATUS1_CONFIGURE 0x81 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control selected input LOS to be OR-ed
to STAT1 output pin (and bit)
bit 0 : 1 - OR this input channel LOS status to STAT1 */
#define I2C_PAGE_STATUS_READ 0xf0 /* Read only from reg=0x10: bit 0 - status0, bit 1 - status 1 */
#define I2C_GLOBAL_CONNECTION 0x50 /* Bit 4 (+0x10) - disable all outputs, bits 3:0 - input number to connect to all outputs */
#define I2C_GLOBAL_INPUT_ISE 0x51 /* Bits 5:4 ISE short: 0 - off, 1 - minimal, 2 - moderate, 3 - maximal; bits 3:2 ISE medium,
bits 1:0 ISE Long time constant */
#define I2C_GLOBAL_INPUT_STATE 0x52 /* Bit 2 (+4) - terminate input to VDD (0..7 only) 0-connect, 1 Normal;
Bit 1 (+2) Input power off (0 - On, 1 - Off) bit0 (+1): Input polarity: 1 - inverted, 0 - normal */
#define I2C_GLOBAL_INPUT_LOS 0x53 /* Bits 2:0 - level in mV for dedicated(bidirectional) inputs: 0,1,6,7 - unused, 2 - 150(170),
3 - 200(230), 4 - 250(280), 5 - 300(330) */
#define I2C_GLOBAL_OUTPUT_PRE_LONG 0x54 /* Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 500..1500 ps range */
#define I2C_GLOBAL_OUTPUT_PRE_SHORT 0x55 /* Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 30..500 ps range */
#define I2C_GLOBAL_OUTPUT_LEVEL 0x56 /* Bits 3:0 - peak-to-peak 0,1,0xe,0xf - unused,0x2-405mV,0x3-425V,0x4-455mV,0x5-485mV,
0x6-520mV,0x7-555mV,0x8-605mV,0x9-655mV,0xa-720mV,0xb-790mV,0xc-890mV,0xd-990mV (+3.3VDC required)
bit 4 (+0x10) terminate inputs 8..15 to VDDIO-0.7V */
#define I2C_GLOBAL_OUTPUT_STATE 0x57 /* +1 (bit 0) - LOS, +0x15 - inverted, 0xa0 - normal, +0 - "Common mode" ? */
#define I2C_GLOBAL_OUTPUT_STATE_DATA 0x0b /* No inversion, enable OOB forwarding on all channels */
#define I2C_GLOBAL_STATUS0 0x58 /* Bit 0 - selected for Status0 chanel LOS on from all channels */
#define I2C_GLOBAL_STATUS1 0x59 /* Bit 0 - selected for Status1 chanel LOS on from all channels */
#define I2C_CORE_CONFIGURATION 0x75
#define I2C_CORE_CONFIGURATION_DATA 0x18 /* default 0x18 - 0x10 - leftEn, 0x8 - rightEn, 0x4 - DNU, 0x2 - BufferForceOn, 0x1 - Config polarity */
#define I2C_CORE_CONFIGURATION_DATAF 0x19 /* default with inverted Config polarity (freeze update) */
#define I2C_SLAVE_ADDRESS 0x78 /* programmed only, not hardwired */
#define I2C_INTERFACE_MODE 0x79
#define I2C_INTERFACE_MODE_DATA 0x02 /* i2c (1 - 4-wire) */
#define I2C_SOFTWARE_RESET 0x7a
//#define I2C_SOFTWARE_RESET_DATA 0x10 /* to reset, 0 - normal */ not used - but number 4 is used instead
#define I2C_CURRENT_PAGE 0x7f
#define PORT_PEFIX "port_"
#define ALL_PORTS "all"
#define MAX_PORTS 16
#define I2C_PAGE_GLOBAL -1 /* does not use paging access */
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
static const char port_names[][8]={
PORT_PEFIX "00",PORT_PEFIX "01",PORT_PEFIX "02",PORT_PEFIX "03",PORT_PEFIX "04",
PORT_PEFIX "05",PORT_PEFIX "06",PORT_PEFIX "07",PORT_PEFIX "08",PORT_PEFIX "09",
PORT_PEFIX "10",PORT_PEFIX "11",PORT_PEFIX "12",PORT_PEFIX "13",PORT_PEFIX "14",
PORT_PEFIX "15",PORT_PEFIX "16",PORT_PEFIX "17",PORT_PEFIX "18",PORT_PEFIX "19",
PORT_PEFIX "20",PORT_PEFIX "21",PORT_PEFIX "22",PORT_PEFIX "23",PORT_PEFIX "24",
PORT_PEFIX "25",PORT_PEFIX "26",PORT_PEFIX "27",PORT_PEFIX "28",PORT_PEFIX "29",
PORT_PEFIX "30",PORT_PEFIX "31"};
static const struct i2c_device_id vsc330x_id[] = {
{ "vsc3304", 0 },
{ "vsc3308", 1 },
{ "vsc3312", 2 },
{ }
};
MODULE_DEVICE_TABLE(i2c, vsc3304_id);
struct vsc330x_data_t {
int address_mode_data; // vsc3304 needs 6 to be written, otherwise weird modification of bit 3
int last_page;
u32 in_ports;
u32 out_ports;
};
static const struct vsc330x_data_t vsc330x_data[] = {
{.address_mode_data=6,
.in_ports=0xff00, .out_ports=0xff00}, /* 3304 - all ports I/O shared*/
{.address_mode_data=-1, // No data, unknown if it is needed for 3308
.in_ports=0x00ff, .out_ports=0x00ff}, /* 3308 - no ports I/O shared */
{.address_mode_data=-1, // No data, unknown if it is needed for 3308
.in_ports=0xffff, .out_ports=0xffff} /* 3312 - some ports I/O shared*/
};
static int init_device(struct i2c_client *client);
static int read_reg(struct i2c_client *client, u8 reg);
static int write_reg(struct i2c_client *client, u8 reg, u8 val);
static int read_field(struct i2c_client *client, u8 reg, int ls_bit_num, int width);
static int read_page_field(struct i2c_client *client, int page, u8 reg, int ls_bit_num, int width);
static int write_field(struct i2c_client *client, u8 reg, u8 val, int ls_bit_num, int width);
static int write_page_field(struct i2c_client *client, int page, u8 reg, u8 val, int ls_bit_num, int width);
static ssize_t field_show(struct device *dev, struct device_attribute *attr, char *buf,
int page, int ls_bit_num, int width);
static ssize_t field_show_reg(struct device *dev, char *buf, int page, int reg, int ls_bit_num, int width);
static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,
int page, int ls_bit_num, int width);
static ssize_t field_store_reg(struct device *dev, const char *buf, size_t count,
int page, int reg, int ls_bit_num, int width);
static ssize_t connection_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_ISE_short_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_ISE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_ISE_medium_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_ISE_medium_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_ISE_long_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_ISE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_state_off_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_state_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_state_invert_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_state_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_LOS_threshold_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_LOS_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_PRE_long_level_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_PRE_long_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_PRE_long_decay_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_PRE_long_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_PRE_short_level_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_PRE_short_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_PRE_short_decay_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_PRE_short_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
/* TODO - fix for vsc3312*/
static ssize_t input_terminate_low_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_terminate_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_terminate_high_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_terminate_high_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_level_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_mode_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t forward_OOB_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t forward_OOB_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t status_0_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t status_0_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t status_1_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t status_1_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t status_show (struct device *dev, struct device_attribute *attr, char *buf);
/* global */
static ssize_t global_connection_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_ISE_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_ISE_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_input_state_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_input_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_input_LOS_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_input_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_output_PRE_long_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_output_PRE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_output_PRE_short_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_output_PRE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_output_level_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_output_state_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_output_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_status_0_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_status_0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_status_1_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_status_1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_config_word_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_config_word_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_left_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_left_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_right_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_right_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_buffer_on_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_buffer_on_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_config_pin_invert_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_config_pin_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t soft_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t address_range_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t address_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t status_combo_show (struct device *dev, struct device_attribute *attr, char *buf);
/* Global registers - writes applied to all port registers. No sense to read (so write only), but functions preserved
* Placed in "globals" directory */
static DEVICE_ATTR(connection, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_connection_show, global_connection_store);
static DEVICE_ATTR(ISE, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_ISE_show, global_ISE_store);
static DEVICE_ATTR(input_state, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_input_state_show, global_input_state_store);
static DEVICE_ATTR(input_LOS, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_input_LOS_show, global_input_LOS_store);
static DEVICE_ATTR(output_PRE_long, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_output_PRE_long_show, global_output_PRE_long_store);
static DEVICE_ATTR(output_PRE_short, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_output_PRE_short_show, global_output_PRE_short_store);
static DEVICE_ATTR(output_level, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_output_level_show, global_output_level_store);
static DEVICE_ATTR(output_state, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_output_state_show, global_output_state_store);
static DEVICE_ATTR(status_0_on_LOS, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_status_0_show, global_status_0_store);
static DEVICE_ATTR(status_1_on_LOS, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_status_1_show, global_status_1_store);
/* control/status registers , placed in "control" directory */
static DEVICE_ATTR(core_word, SYSFS_PERMISSIONS, core_config_word_show, core_config_word_store);
static DEVICE_ATTR(core_left_bias_en, SYSFS_PERMISSIONS, core_left_bias_en_show, core_left_bias_en_store);
static DEVICE_ATTR(core_right_bias_en,SYSFS_PERMISSIONS, core_right_bias_en_show, core_right_bias_en_store);
static DEVICE_ATTR(core_buffer_on, SYSFS_PERMISSIONS, core_buffer_on_show, core_buffer_on_store);
static DEVICE_ATTR(core_config_pin_invert,SYSFS_PERMISSIONS, core_config_pin_invert_show, core_config_pin_invert_store);
static DEVICE_ATTR(soft_reset, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, soft_reset_store);
static DEVICE_ATTR(address_range, SYSFS_PERMISSIONS, address_range_show, address_range_store);
static DEVICE_ATTR(status, SYSFS_PERMISSIONS & SYSFS_READONLY, status_combo_show, NULL);
static struct attribute *globals_dev_attrs[] = {
&dev_attr_connection.attr,
&dev_attr_ISE.attr,
&dev_attr_input_state.attr,
&dev_attr_input_LOS.attr,
&dev_attr_output_PRE_long.attr,
&dev_attr_output_PRE_short.attr,
&dev_attr_output_level.attr,
&dev_attr_output_state.attr,
&dev_attr_status_0_on_LOS.attr,
&dev_attr_status_1_on_LOS.attr,
NULL
};
static const struct attribute_group dev_attr_globals_group = {
.attrs = globals_dev_attrs,
.name = "globals",
};
static struct attribute *control_dev_attrs[] = {
&dev_attr_core_word.attr,
&dev_attr_core_left_bias_en.attr,
&dev_attr_core_right_bias_en.attr,
&dev_attr_core_buffer_on.attr,
&dev_attr_core_config_pin_invert.attr,
&dev_attr_soft_reset.attr,
&dev_attr_address_range.attr,
&dev_attr_status.attr,
NULL
};
static const struct attribute_group dev_attr_control_group = {
.attrs = control_dev_attrs,
.name = "control",
};
/* seems we need to INITIALIZE all structures to zero - examples use static */
static int make_group (struct device *dev, const char * name, int port_mask, mode_t mode,
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf),
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count))
{
int retval=-1;
int port,index=0,num_regs;
struct attribute **pattrs; /* array of pointers to attributes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
for (port=0,num_regs=1;portname = name;
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
index=0;
while ((*attr_group).attrs[index]){
dev_dbg(dev,"attr=%s\n",attr_group->attrs[index]->name);
index++;
}
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static int vsc330x_sysfs_register(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
int ports=clientdata->out_ports;
int retval=0;
if (&dev->kobj) {
if ((retval=make_group (dev, "connections", ports, SYSFS_PERMISSIONS, connection_show, connection_store))) return retval;
if ((retval=make_group (dev, "input_ISE_short", ports, SYSFS_PERMISSIONS, input_ISE_short_show, input_ISE_short_store))) return retval;
if ((retval=make_group (dev, "input_ISE_medium", ports, SYSFS_PERMISSIONS, input_ISE_medium_show, input_ISE_medium_store))) return retval;
if ((retval=make_group (dev, "input_ISE_long", ports, SYSFS_PERMISSIONS, input_ISE_long_show, input_ISE_long_store))) return retval;
if ((retval=make_group (dev, "input_state_off", ports, SYSFS_PERMISSIONS, input_state_off_show, input_state_off_store))) return retval;
if ((retval=make_group (dev, "input_state_invert", ports, SYSFS_PERMISSIONS, input_state_invert_show, input_state_invert_store))) return retval;
if ((retval=make_group (dev, "input_LOS_threshold", ports, SYSFS_PERMISSIONS, input_LOS_threshold_show, input_LOS_threshold_store))) return retval;
if ((retval=make_group (dev, "output_PRE_long_level", ports, SYSFS_PERMISSIONS, output_PRE_long_level_show, output_PRE_long_level_store))) return retval;
if ((retval=make_group (dev, "output_PRE_long_decay", ports, SYSFS_PERMISSIONS, output_PRE_long_decay_show, output_PRE_long_decay_store))) return retval;
if ((retval=make_group (dev, "output_PRE_short_level",ports, SYSFS_PERMISSIONS, output_PRE_short_level_show, output_PRE_short_level_store))) return retval;
if ((retval=make_group (dev, "output_PRE_short_decay",ports, SYSFS_PERMISSIONS, output_PRE_short_decay_show, output_PRE_short_decay_store))) return retval;
if ((retval=make_group (dev, "input_terminate_low", ports, SYSFS_PERMISSIONS, input_terminate_low_show, input_terminate_low_store))) return retval;
if ((retval=make_group (dev, "input_terminate_high", ports, SYSFS_PERMISSIONS, input_terminate_high_show, input_terminate_high_store))) return retval;
if ((retval=make_group (dev, "output_level", ports, SYSFS_PERMISSIONS, output_level_show, output_level_store))) return retval;
if ((retval=make_group (dev, "output_mode", ports, SYSFS_PERMISSIONS, output_mode_show, output_mode_store))) return retval;
if ((retval=make_group (dev, "forward_OOB", ports, SYSFS_PERMISSIONS, forward_OOB_show, forward_OOB_store))) return retval;
if ((retval=make_group (dev, "status_0_on_LOS", ports, SYSFS_PERMISSIONS, status_0_on_LOS_show, status_0_on_LOS_store))) return retval;
if ((retval=make_group (dev, "status_1_on_LOS", ports, SYSFS_PERMISSIONS, status_1_on_LOS_show, status_1_on_LOS_store))) return retval;
if ((retval=make_group (dev, "status", ports, SYSFS_PERMISSIONS & SYSFS_READONLY, status_show, NULL))) return retval;
if ((retval = sysfs_create_group(&dev->kobj, &dev_attr_globals_group))) return retval;
if ((retval = sysfs_create_group(&dev->kobj, &dev_attr_control_group))) return retval;
}
return retval;
}
static ssize_t field_show(struct device *dev, struct device_attribute *attr, char *buf,
int page, int ls_bit_num, int width)
{
int reg, port_mask, rc=0, len=0, count=PAGE_SIZE;
struct i2c_client *client = to_i2c_client(dev);
/* do for all ports - not used. TODO: we can try to output all of them in a row, but not sure if count will permit*/
if (strcmp(attr->attr.name,ALL_PORTS) == 0) {
port_mask=((struct vsc330x_data_t *) i2c_get_clientdata(to_i2c_client(dev)))->out_ports;
for (reg=0;reg5)) {
dev_dbg(dev, "name='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
attr->attr.name, reg, page, ls_bit_num, width);
rc = read_page_field(client, page, reg, ls_bit_num, width);
// rc=field_show_reg(dev, buf, page, reg, ls_bit_num, width);
if (rc<0) return rc;
rc=sprintf(buf, "%d ", rc);
buf+=rc;
len+=rc;
count-=rc;
}
if (len>0) {
len--;
count++;
buf--;
}
rc=sprintf(buf, "\n");
buf+=rc;
len+=rc;
count-=rc;
return len;
}
/* process single port */
sscanf(attr->attr.name+strlen(PORT_PEFIX), "%du", ®);
dev_dbg(dev, "name='%s' name+%d='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
attr->attr.name, strlen(PORT_PEFIX), ( attr->attr.name+strlen(PORT_PEFIX)), reg, page, ls_bit_num, width);
return field_show_reg(dev, buf, page, reg, ls_bit_num, width);
}
static ssize_t field_show_reg(struct device *dev, char *buf, int page, int reg, int ls_bit_num, int width)
{
struct i2c_client *client = to_i2c_client(dev);
int data=read_page_field(client, page, reg, ls_bit_num, width);
return sprintf(buf, "%d\n", data);
}
static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,
int page, int ls_bit_num, int width)
{
int reg, port_mask, rc;
/* do for all ports */
if (strcmp(attr->attr.name,ALL_PORTS) == 0) {
port_mask=((struct vsc330x_data_t *) i2c_get_clientdata(to_i2c_client(dev)))->out_ports;
for (reg=0;regattr.name, reg, page, ls_bit_num, width);
rc= field_store_reg(dev, buf, count, page, reg, ls_bit_num, width);
if (rc<0) return rc;
}
return count;
}
/* process single port */
sscanf(attr->attr.name+strlen(PORT_PEFIX), "%du", ®);
dev_dbg(dev, "name='%s' name+%d='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
attr->attr.name, strlen(PORT_PEFIX), ( attr->attr.name+strlen(PORT_PEFIX)), reg, page, ls_bit_num, width);
return field_store_reg(dev, buf, count, page, reg, ls_bit_num, width);
}
static ssize_t field_store_reg(struct device *dev, const char *buf, size_t count,
int page, int reg, int ls_bit_num, int width)
{
struct i2c_client *client = to_i2c_client(dev);
int val,rc;
sscanf(buf, "%du", &val);
rc=write_page_field(client, page, reg, val, ls_bit_num, width);
return count;
}
static ssize_t connection_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_CONNECTION, 0, 5);}
static ssize_t connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_CONNECTION, 0, 5);}
static ssize_t input_ISE_short_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_ISE, 4, 2);}
static ssize_t input_ISE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_ISE, 4, 2);}
static ssize_t input_ISE_medium_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_ISE, 2, 2);}
static ssize_t input_ISE_medium_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_ISE, 2, 2);}
static ssize_t input_ISE_long_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_ISE, 0, 2);}
static ssize_t input_ISE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_ISE, 0, 2);}
static ssize_t input_state_off_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_STATE, 1, 1);}
static ssize_t input_state_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_STATE, 1, 1);}
static ssize_t input_state_invert_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_STATE, 0, 1);}
static ssize_t input_state_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_STATE, 0, 1);}
static ssize_t input_LOS_threshold_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_LOS, 0, 3);}
static ssize_t input_LOS_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_LOS, 0, 3);}
static ssize_t output_PRE_long_level_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_LONG, 3, 4);}
static ssize_t output_PRE_long_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_LONG, 3, 4);}
static ssize_t output_PRE_long_decay_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_LONG, 0, 3);}
static ssize_t output_PRE_long_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_LONG, 0, 3);}
static ssize_t output_PRE_short_level_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_SHORT, 3, 4);}
static ssize_t output_PRE_short_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_SHORT, 3, 4);}
static ssize_t output_PRE_short_decay_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_SHORT, 0, 3);}
static ssize_t output_PRE_short_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_SHORT, 0, 3);}
/* TODO - fix for vsc3312*/
static ssize_t input_terminate_low_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_STATE, 2, 1);}
static ssize_t input_terminate_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_STATE, 2, 1);}
static ssize_t input_terminate_high_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_LEVEL, 4, 1);}
static ssize_t input_terminate_high_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_LEVEL, 4, 1);}
static ssize_t output_level_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_LEVEL, 0, 4);}
static ssize_t output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_LEVEL, 0, 4);}
static ssize_t output_mode_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_STATE, 1, 4);}
static ssize_t output_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_STATE, 1, 4);}
static ssize_t forward_OOB_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_STATE, 0, 1);}
static ssize_t forward_OOB_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_STATE, 0, 1);}
static ssize_t status_0_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_STATUS0_CONFIGURE, 0, 1);}
static ssize_t status_0_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_STATUS0_CONFIGURE, 0, 1);}
static ssize_t status_1_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_STATUS1_CONFIGURE, 0, 1);}
static ssize_t status_1_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_STATUS1_CONFIGURE, 0, 1);}
/* per-port LOS status */
static ssize_t status_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_STATUS_READ, 0, 1);}
/* combined LOS status */
static ssize_t status_combo_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg(dev, buf, I2C_PAGE_STATUS_READ, 0x10, 0, 2);}
/* Global registers use all 8 bits (and control multiple features at once, because it is not possible to read-modify-write them */
static ssize_t global_connection_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_CONNECTION, 0, 8);}
static ssize_t global_connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_CONNECTION, 0, 8);}
static ssize_t global_ISE_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_ISE, 0, 8);}
static ssize_t global_ISE_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_ISE, 0, 8);}
static ssize_t global_input_state_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_STATE, 0, 8);}
static ssize_t global_input_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_STATE, 0, 8);}
static ssize_t global_input_LOS_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_LOS, 0, 8);}
static ssize_t global_input_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_LOS, 0, 8);}
static ssize_t global_output_PRE_long_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_LONG, 0, 8);}
static ssize_t global_output_PRE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_LONG, 0, 8);}
static ssize_t global_output_PRE_short_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_SHORT, 0, 8);}
static ssize_t global_output_PRE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_SHORT, 0, 8);}
static ssize_t global_output_level_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_LEVEL, 0, 8);}
static ssize_t global_output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_LEVEL, 0, 8);}
static ssize_t global_output_state_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_STATE, 0, 8);}
static ssize_t global_output_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_STATE, 0, 8);}
static ssize_t global_status_0_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS0, 0, 8);}
static ssize_t global_status_0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS0, 0, 8);}
static ssize_t global_status_1_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS1, 0, 8);}
static ssize_t global_status_1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS1, 0, 8);}
static ssize_t core_config_word_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 8);}
static ssize_t core_config_word_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 8);} /* 0x18/ 0x19 for 3312 */
static ssize_t core_left_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 4, 1);}
static ssize_t core_left_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 4, 1);}
static ssize_t core_right_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 3, 1);}
static ssize_t core_right_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 3, 1);}
static ssize_t core_buffer_on_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 1, 1);}
static ssize_t core_buffer_on_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 1, 1);}
static ssize_t core_config_pin_invert_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 1);}
static ssize_t core_config_pin_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 1);}
static ssize_t soft_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int rc;
if (((rc=field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_SOFTWARE_RESET, 4, 1)))<0) return rc;
if (((rc=init_device(client)))<0) return rc;
return count;
}
static ssize_t address_range_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_SOFTWARE_RESET, 0, 4);}
static ssize_t address_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_SOFTWARE_RESET, 0, 4);}
/* Setup i2c, write address_mode. Needed after soft reset and power up */
static int _init_device(struct i2c_client *client, int address_mode_data)
{
int rc;
if (((rc=write_reg(client, I2C_INTERFACE_MODE, I2C_INTERFACE_MODE_DATA)))<0) return rc;
if (address_mode_data >=0){ /* only write if needed, 3304 needs, 3312 - does not, 3308 - ? */
// if (((rc=write_reg(client, I2C_SOFTWARE_RESET_DATA, address_mode_data)))<0) return rc;
// this bug caused me to assemble a new board, urgently find vsc3304 chip,spend several days trying to troubleshoot...
// Just five extra characters!
if (((rc=write_reg(client, I2C_SOFTWARE_RESET, address_mode_data)))<0) return rc;
}
if (((rc=write_reg(client, I2C_CURRENT_PAGE, 0)))<0) return rc;
return 0;
}
static int init_device(struct i2c_client *client)
{
int rc;
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
dev_info(&client->dev,"Re-initializing %s\n",client->name);
if (((rc=_init_device(client, clientdata->address_mode_data)))<0) return rc;
clientdata->last_page=0;
return 0;
}
static int bitmask(int ls_bit_num, int width)
{
return ((1 << width) -1) << ls_bit_num;
}
//address_mode_data
static int read_reg(struct i2c_client *client, u8 reg)
{
int val;
val= i2c_smbus_read_byte_data(client, reg);
dev_dbg(&client->dev,"reading i2c device : slave=0x%x, reg=0x%x -> 0x%x\n",(int) (client->addr),reg,val);
return val;
}
static int write_reg(struct i2c_client *client, u8 reg, u8 val)
{
dev_dbg(&client->dev,"device write: slave=0x%x, reg=0x%x, val=0x%x\n", (int) (client->addr),reg,val);
return i2c_smbus_write_byte_data(client, reg, val);
}
static int read_field(struct i2c_client *client, u8 reg, int ls_bit_num, int width)
{
int rc;
if (((rc=read_reg(client, reg)))<0) return rc;
rc= (rc >> ls_bit_num) & bitmask(0, width);
dev_dbg(&client->dev,"reg=0x%x, ls_bit_num=%d, width=%d -> 0x%x\n", (int) reg, ls_bit_num,width,rc);
return rc;
}
static int read_page_field(struct i2c_client *client, int page, u8 reg, int ls_bit_num, int width)
{
int rc;
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
dev_dbg(&client->dev,"page=0x%x (last was 0x%x) reg=0x%x, ls_bit_num=%d, width=%d:\n",
page, (clientdata->last_page!=page), (int) reg, ls_bit_num, width);
if ((page>=0) && (clientdata->last_page!=page)) {
if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
clientdata->last_page=page;
}
rc= read_field(client, reg, ls_bit_num, width);
dev_dbg(&client->dev,"page=0x%x (last was 0x%x) reg=0x%x, ls_bit_num=%d, width=%d -> 0x%x\n",
page, (clientdata->last_page!=page), (int) reg, ls_bit_num, width,rc);
return rc;
}
static int write_field(struct i2c_client *client, u8 reg, u8 val, int ls_bit_num, int width)
{
int rc;
dev_dbg(&client->dev,"reg=0x%x, val=0x%x, ls_bit_num=%d, width=%d \n", (int) reg, (int) val,ls_bit_num,width);
if (((rc=read_reg(client, reg)))<0) return rc;
val<<=ls_bit_num;
return write_reg(client, reg, ((rc ^ val) & bitmask(ls_bit_num, width))^ rc);
}
static int write_page_field(struct i2c_client *client, int page, u8 reg, u8 val, int ls_bit_num, int width)
{
int rc;
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
dev_dbg(&client->dev,"page=0x%x (last was 0x%x), reg=0x%x, val=0x%x, ls_bit_num=%d, width=%d \n",
page,clientdata->last_page, (int) reg, (int) val,ls_bit_num,width);
if ((page>=0) && (clientdata->last_page!=page)) {
if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
clientdata->last_page=page;
}
return write_field(client, reg, val, ls_bit_num, width);
}
static int write_with_mask(struct i2c_client *client, u8 reg, u8 val, u8 mask)
{
int rc;
dev_dbg(&client->dev,"reg=0x%x, val=0x%x, mask=0x%x\n", (int) reg, (int) val, (int) mask);
if (mask !=0xff){
if (((rc=read_reg(client, reg)))<0) return rc;
val=((val ^ rc) & mask)^ rc;
}
return write_reg(client, reg, val);
}
static int write_page_with_mask(struct i2c_client *client, int page, u8 reg, u8 val , u8 mask)
{
int rc;
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
dev_dbg(&client->dev,"page=0x%x (last was 0x%x), reg=0x%x, val=0x%x, mask=0x%x\n",
page,clientdata->last_page, (int) reg, (int) val,(int) mask);
if ((page>=0) && (clientdata->last_page!=page)) {
if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
clientdata->last_page=page;
}
return write_with_mask(client, reg, val, mask);
}
static void vsc330x_init_of(struct i2c_client *client)
{
// struct device *dev=&client->dev;
const __be32 * config_data;
struct device_node *node = client->dev.of_node;
int len,i,rc;
struct vsc330x_setup_data {
u8 page;
u8 reg;
u8 data;
u8 mask;
};
struct vsc330x_setup_data setup_data;
__be32 * setup_data_be32= (__be32 *) &setup_data;
const char * config_name;
if (node) {
config_name = of_get_property(client->dev.of_node, "vsc330x,configuration_name", &len);
if (config_name){
dev_info(&client->dev,"Initializing %s registers for \"%s\"\n",client->name,config_name);
}
config_data = of_get_property(client->dev.of_node, "vsc330x,configuration_data", &len);
if (config_data){
len /= sizeof(*config_data);
dev_dbg(&client->dev,"Read %d values\n",len);
for (i=0;idev,"0x%08x (0x%08x)\n", config_data[i],be32_to_cpup(config_data+i));
*setup_data_be32=config_data[i];
dev_dbg(&client->dev,"page=0x%02x, reg=0x%02x, data=0x%02x, mask=0x%02x \n",
(int)setup_data.page, (int)setup_data.reg,(int)setup_data.data,(int)setup_data.mask);
if (((rc=write_page_with_mask(client, (setup_data.page==0xff)?-1:setup_data.page, setup_data.reg,
setup_data.data, setup_data.mask)))<0) return;
}
} else {
dev_info(&client->dev,"'vsc330x,configuration_data' not found\n");
}
} else {
dev_info(&client->dev,"Device tree data not found for %s\n",client->name);
}
}
/*
dev_info(&client->dev,
*/
static int vsc330x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc=0;
struct vsc330x_data_t *clientdata = NULL;
/* initialize i2c mode and (if needed) address range bit field */
if (((rc=_init_device(client, vsc330x_data[id->driver_data].address_mode_data)))<0) goto wr_err;
dev_info(&client->dev,
"Chip %s found, driver version %s\n", id->name, DRV_VERSION);
clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata), GFP_KERNEL);
if (!clientdata) {
rc = -ENOMEM;
goto exit;
}
clientdata->last_page = 0;
clientdata->address_mode_data = vsc330x_data[id->driver_data].address_mode_data;
clientdata->in_ports = vsc330x_data[id->driver_data].in_ports;
clientdata->out_ports = vsc330x_data[id->driver_data].out_ports;
i2c_set_clientdata(client, clientdata);
rc = vsc330x_sysfs_register(&client->dev);
if (rc)
goto exit;
vsc330x_init_of(client);
return 0; /* found OK*/
wr_err:
rc = -EIO;
dev_err(&client->dev, "%s:%d error writing\n",__func__,__LINE__);
goto exit;
#if 0
rd_err:
rc = -EIO;
dev_err(&client->dev, "%s:%d error reading\n",__func__,__LINE__);
goto exit;
#endif
exit:
return rc;
}
static int vsc330x_i2c_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_driver vsc330x_i2c_driver = {
.driver = {
.name = "vsc330x",
.owner = THIS_MODULE,
},
.probe = vsc330x_i2c_probe,
.remove = vsc330x_i2c_remove,
.id_table = vsc330x_id,
};
module_i2c_driver(vsc330x_i2c_driver);
MODULE_AUTHOR("Andrey Filippov ");
MODULE_DESCRIPTION("VSC330x I2C bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:vsc330x");
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/mtd/ 0000775 0000000 0000000 00000000000 12703306510 0024377 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/mtd/nand/ 0000775 0000000 0000000 00000000000 12703306510 0025317 5 ustar 00root root 0000000 0000000 linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/mtd/nand/Kconfig 0000664 0000000 0000000 00000044037 12703306510 0026632 0 ustar 00root root 0000000 0000000 config MTD_NAND_ECC
tristate
config MTD_NAND_ECC_SMC
bool "NAND ECC Smart Media byte order"
depends on MTD_NAND_ECC
default n
help
Software ECC according to the Smart Media Specification.
The original Linux implementation had byte 0 and 1 swapped.
menuconfig MTD_NAND
tristate "NAND Device Support"
depends on MTD
select MTD_NAND_IDS
select MTD_NAND_ECC
help
This enables support for accessing all type of NAND flash
devices. For further information see
.
if MTD_NAND
config MTD_NAND_BCH
tristate
select BCH
depends on MTD_NAND_ECC_BCH
default MTD_NAND
config MTD_NAND_ECC_BCH
bool "Support software BCH ECC"
default n
help
This enables support for software BCH error correction. Binary BCH
codes are more powerful and cpu intensive than traditional Hamming
ECC codes. They are used with NAND devices requiring more than 1 bit
of error correction.
config MTD_NAND_OTP
bool "Support access to one-time programmable area of some Micron chips"
select HAVE_MTD_OTP
help
This enables support for reading and writing to the OTP area of some
Micron chips.
config MTD_SM_COMMON
tristate
default n
config MTD_NAND_DENALI
tristate "Support Denali NAND controller"
depends on HAS_DMA
help
Enable support for the Denali NAND controller. This should be
combined with either the PCI or platform drivers to provide device
registration.
config MTD_NAND_DENALI_PCI
tristate "Support Denali NAND controller on Intel Moorestown"
depends on PCI && MTD_NAND_DENALI
help
Enable the driver for NAND flash on Intel Moorestown, using the
Denali NAND controller core.
config MTD_NAND_DENALI_DT
tristate "Support Denali NAND controller as a DT device"
depends on HAVE_CLK && MTD_NAND_DENALI
help
Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device.
config MTD_NAND_DENALI_SCRATCH_REG_ADDR
hex "Denali NAND size scratch register address"
default "0xFF108018"
depends on MTD_NAND_DENALI_PCI
help
Some platforms place the NAND chip size in a scratch register
because (some versions of) the driver aren't able to automatically
determine the size of certain chips. Set the address of the
scratch register here to enable this feature. On Intel Moorestown
boards, the scratch register is at 0xFF108018.
config MTD_NAND_GPIO
tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB
help
This enables a NAND flash driver where control signals are
connected to GPIO pins, and commands and data are communicated
via a memory mapped interface.
config MTD_NAND_AMS_DELTA
tristate "NAND Flash device on Amstrad E3"
depends on MACH_AMS_DELTA
default y
help
Support for NAND flash on Amstrad E3 (Delta).
config MTD_NAND_OMAP2
tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
depends on ARCH_OMAP2PLUS
help
Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
platforms.
config MTD_NAND_OMAP_BCH
depends on MTD_NAND_OMAP2
bool "Support hardware based BCH error correction"
default n
select BCH
help
This config enables the ELM hardware engine, which can be used to
locate and correct errors when using BCH ECC scheme. This offloads
the cpu from doing ECC error searching and correction. However some
legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
so this is optional for them.
config MTD_NAND_OMAP_BCH_BUILD
def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
config MTD_NAND_IDS
tristate
config MTD_NAND_RICOH
tristate "Ricoh xD card reader"
default n
depends on PCI
select MTD_SM_COMMON
help
Enable support for Ricoh R5C852 xD card reader
You also need to enable ether
NAND SSFDC (SmartMedia) read only translation layer' or new
expermental, readwrite
'SmartMedia/xD new translation layer'
config MTD_NAND_AU1550
tristate "Au1550/1200 NAND support"
depends on MIPS_ALCHEMY
help
This enables the driver for the NAND flash controller on the
AMD/Alchemy 1550 SOC.
config MTD_NAND_BF5XX
tristate "Blackfin on-chip NAND Flash Controller driver"
depends on BF54x || BF52x
help
This enables the Blackfin on-chip NAND flash controller
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
This driver can also be built as a module. If so, the module
will be called bf5xx-nand.
config MTD_NAND_BF5XX_HWECC
bool "BF5XX NAND Hardware ECC"
default y
depends on MTD_NAND_BF5XX
help
Enable the use of the BF5XX's internal ECC generator when
using NAND.
config MTD_NAND_BF5XX_BOOTROM_ECC
bool "Use Blackfin BootROM ECC Layout"
default n
depends on MTD_NAND_BF5XX_HWECC
help
If you wish to modify NAND pages and allow the Blackfin on-chip
BootROM to boot from them, say Y here. This is only necessary
if you are booting U-Boot out of NAND and you wish to update
U-Boot from Linux' userspace. Otherwise, you should say N here.
If unsure, say N.
config MTD_NAND_S3C2410
tristate "NAND Flash support for Samsung S3C SoCs"
depends on ARCH_S3C24XX || ARCH_S3C64XX
help
This enables the NAND flash controller on the S3C24xx and S3C64xx
SoCs
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_S3C2410_DEBUG
bool "Samsung S3C NAND driver debug"
depends on MTD_NAND_S3C2410
help
Enable debugging of the S3C NAND driver
config MTD_NAND_S3C2410_HWECC
bool "Samsung S3C NAND Hardware ECC"
depends on MTD_NAND_S3C2410
help
Enable the use of the controller's internal ECC generator when
using NAND. Early versions of the chips have had problems with
incorrect ECC generation, and if using these, the default of
software ECC is preferable.
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on 4xx
select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
config MTD_NAND_S3C2410_CLKSTOP
bool "Samsung S3C NAND IDLE clock stop"
depends on MTD_NAND_S3C2410
default n
help
Stop the clock to the NAND controller when there is no chip
selected to save power. This will mean there is a small delay
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
depends on HAS_IOMEM
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
This is a reimplementation of M-Systems DiskOnChip 2000,
Millennium and Millennium Plus as a standard NAND device driver,
as opposed to the earlier self-contained MTD device drivers.
This should enable, among other things, proper JFFS2 operation on
these devices.
config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
depends on MTD_NAND_DISKONCHIP
help
This option allows you to specify nonstandard address at which to
probe for a DiskOnChip, or to change the detection options. You
are unlikely to need any of this unless you are using LinuxBIOS.
Say 'N'.
config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
depends on MTD_NAND_DISKONCHIP
default "0"
---help---
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option allows you to specify a single address at which to probe
for the device, which is useful if you have other devices in that
range which get upset when they are probed.
(Note that on PowerPC, the normal probe will only check at
0xE4000000.)
Normally, you should leave this set to zero, to allow the probe at
the normal addresses.
config MTD_NAND_DISKONCHIP_PROBE_HIGH
bool "Probe high addresses"
depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
help
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option changes to make it probe between 0xFFFC8000 and
0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be
useful to you. Say 'N'.
config MTD_NAND_DISKONCHIP_BBTWRITE
bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
depends on MTD_NAND_DISKONCHIP
help
On DiskOnChip devices shipped with the INFTL filesystem (Millennium
and 2000 TSOP/Alon), Linux reserves some space at the end of the
device for the Bad Block Table (BBT). If you have existing INFTL
data on your device (created by non-Linux tools such as M-Systems'
DOS drivers), your data might overlap the area Linux wants to use for
the BBT. If this is a concern for you, leave this option disabled and
Linux will not write BBT data into this area.
The downside of leaving this option disabled is that if bad blocks
are detected by Linux, they will not be recorded in the BBT, which
could cause future problems.
Once you enable this option, new filesystems (INFTL or others, created
in Linux or other operating systems) will not use the reserved area.
The only reason not to enable this option is to prevent damage to
preexisting filesystems.
Even if you leave this disabled, you can enable BBT writes at module
load time (assuming you build diskonchip as a module) with the module
parameter "inftl_bbt_write=1".
config MTD_NAND_DOCG4
tristate "Support for DiskOnChip G4"
depends on HAS_IOMEM
select BCH
select BITREVERSE
help
Support for diskonchip G4 nand flash, found in various smartphones and
PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
Portege G900, Asus P526, and O2 XDA Zinc.
With this driver you will be able to use UBI and create a ubifs on the
device, so you may wish to consider enabling UBI and UBIFS as well.
These devices ship with the Mys/Sandisk SAFTL formatting, for which
there is currently no mtd parser, so you may want to use command line
partitioning to segregate write-protected blocks. On the Treo680, the
first five erase blocks (256KiB each) are write-protected, followed
by the block containing the saftl partition table. This is probably
typical.
config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on ARCH_PXA
config MTD_NAND_CAFE
tristate "NAND support for OLPC CAFÉ chip"
depends on PCI
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
Use NAND flash attached to the CAFÉ chip designed for the OLPC
laptop.
config MTD_NAND_CS553X
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
depends on X86_32
help
The CS553x companion chips for the AMD Geode processor
include NAND flash controllers with built-in hardware ECC
capabilities; enabling this option will allow you to use
these. The driver will check the MSRs to verify that the
controller is enabled for NAND, and currently requires that
the controller be in MMIO mode.
If you say "m", the module will be called cs553x_nand.
config MTD_NAND_ATMEL
tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32"
depends on ARCH_AT91 || AVR32
help
Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 and AVR32 processors.
config MTD_NAND_PXA3xx
tristate "NAND support on PXA3xx and Armada 370/XP"
depends on PXA3xx || ARCH_MMP || PLAT_ORION
help
This enables the driver for the NAND flash device found on
PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
config MTD_NAND_SLC_LPC32XX
tristate "NXP LPC32xx SLC Controller"
depends on ARCH_LPC32XX
help
Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
chips) NAND controller. This is the default for the PHYTEC 3250
reference board which contains a NAND256R3A2CZA6 chip.
Please check the actual NAND chip connected and its support
by the SLC NAND controller.
config MTD_NAND_MLC_LPC32XX
tristate "NXP LPC32xx MLC Controller"
depends on ARCH_LPC32XX
help
Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
controller. This is the default for the WORK92105 controller
board.
Please check the actual NAND chip connected and its support
by the MLC NAND controller.
config MTD_NAND_CM_X270
tristate "Support for NAND Flash on CM-X270 modules"
depends on MACH_ARMCORE
config MTD_NAND_PASEMI
tristate "NAND support for PA Semi PWRficient"
depends on PPC_PASEMI
help
Enables support for NAND Flash interface on PA Semi PWRficient
based boards
config MTD_NAND_TMIO
tristate "NAND Flash device on Toshiba Mobile IO Controller"
depends on MFD_TMIO
help
Support for NAND flash connected to a Toshiba Mobile IO
Controller in some PDAs, including the Sharp SL6000x.
config MTD_NAND_NANDSIM
tristate "Support for NAND Flash Simulator"
help
The simulator may simulate various NAND flash chips for the
MTD nand layer.
config MTD_NAND_GPMI_NAND
tristate "GPMI NAND Flash Controller driver"
depends on MTD_NAND && MXS_DMA
help
Enables NAND Flash support for IMX23, IMX28 or IMX6.
The GPMI controller is very powerful, with the help of BCH
module, it can do the hardware ECC. The GPMI supports several
NAND flashs at the same time. The GPMI may conflicts with other
block, such as SD card. So pay attention to it when you enable
the GPMI.
config MTD_NAND_BCM47XXNFLASH
tristate "Support for NAND flash on BCM4706 BCMA bus"
depends on BCMA_NFLASH
help
BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for
NAND flash memories. For now only BCM4706 is supported.
config MTD_NAND_PLATFORM
tristate "Support for generic platform NAND driver"
depends on HAS_IOMEM
help
This implements a generic NAND driver for on-SOC platform
devices. You will need to provide platform-specific functions
via platform_data.
config MTD_NAND_ORION
tristate "NAND Flash support for Marvell Orion SoC"
depends on PLAT_ORION
help
This enables the NAND flash controller on Orion machines.
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on PPC
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
Controller Module with built-in hardware ECC capabilities.
Enabling this option will enable you to use this to control
external NAND devices.
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on MTD_NAND && FSL_SOC
select FSL_IFC
select MEMORY
help
Various Freescale chips e.g P1010, include a NAND Flash machine
with built-in hardware ECC capabilities.
Enabling this option will enable you to use this to control
external NAND devices.
config MTD_NAND_FSL_UPM
tristate "Support for NAND on Freescale UPM"
depends on PPC_83xx || PPC_85xx
select FSL_LBC
help
Enables support for NAND Flash chips wired onto Freescale PowerPC
processor localbus with User-Programmable Machine support.
config MTD_NAND_MPC5121_NFC
tristate "MPC5121 built-in NAND Flash Controller support"
depends on PPC_MPC512x
help
This enables the driver for the NAND flash controller on the
MPC5121 SoC.
config MTD_NAND_MXC
tristate "MXC NAND support"
depends on ARCH_MXC
help
This enables the driver for the NAND flash controller on the
MXC processors.
config MTD_NAND_SH_FLCTL
tristate "Support for NAND on Renesas SuperH FLCTL"
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
depends on HAS_IOMEM
depends on HAS_DMA
help
Several Renesas SuperH CPU has FLCTL. This option enables support
for NAND Flash using FLCTL.
config MTD_NAND_DAVINCI
tristate "Support NAND on DaVinci/Keystone SoC"
depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
help
Enable the driver for NAND flash chips on Texas Instruments
DaVinci/Keystone processors.
config MTD_NAND_TXX9NDFMC
tristate "NAND Flash support for TXx9 SoC"
depends on SOC_TX4938 || SOC_TX4939
help
This enables the NAND flash controller on the TXx9 SoCs.
config MTD_NAND_SOCRATES
tristate "Support for NAND on Socrates board"
depends on SOCRATES
help
Enables support for NAND Flash chips wired onto Socrates board.
config MTD_NAND_NUC900
tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
depends on ARCH_W90X900
help
This enables the driver for the NAND Flash on evaluation board based
on w90p910 / NUC9xx.
config MTD_NAND_PL35X
tristate "ARM Pl35X NAND flash driver"
depends on MTD_NAND && ARM
depends on PL35X_SMC
help
This enables access to the NAND flash device on PL351/PL353
SMC controller.
config MTD_NAND_JZ4740
tristate "Support for JZ4740 SoC NAND controller"
depends on MACH_JZ4740
help
Enables support for NAND Flash on JZ4740 SoC based boards.
config MTD_NAND_FSMC
tristate "Support for NAND on ST Micros FSMC"
depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
help
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
config MTD_NAND_XWAY
tristate "Support for NAND on Lantiq XWAY SoC"
depends on LANTIQ && SOC_TYPE_XWAY
select MTD_NAND_PLATFORM
help
Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
to the External Bus Unit (EBU).
config MTD_NAND_SUNXI
tristate "Support for NAND on Allwinner SoCs"
depends on ARCH_SUNXI
help
Enables support for NAND Flash chips on Allwinner SoCs.
config MTD_NAND_ARASAN
tristate "Support for Arasan Nand Flash controller"
depends on MTD_NAND
help
Enables the driver for the Arasan Nand Flash controller in ZynqMP SoC.
config MTD_NAND_HISI504
tristate "Support for NAND controller on Hisilicon SoC Hip04"
depends on HAS_DMA
help
Enables support for NAND controller on Hisilicon SoC Hip04.
endif # MTD_NAND
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/mtd/nand/Makefile 0000664 0000000 0000000 00000004665 12703306510 0026772 0 ustar 00root root 0000000 0000000 #
# linux/drivers/nand/Makefile
#
obj-$(CONFIG_MTD_NAND) += nand.o
obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_DENALI) += denali.o
obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o
obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o
obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
obj-$(CONFIG_MTD_NAND_PL35X) += pl35x_nand.o
obj-$(CONFIG_MTD_NAND_ARASAN) += arasan_nfc.o
obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nandchip-micron.o
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/mtd/nand/nand.h 0000664 0000000 0000000 00000000663 12703306510 0026415 0 ustar 00root root 0000000 0000000 #include
#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0)
int nand_get_device(struct mtd_info *mtd, int new_state);
void nand_release_device(struct mtd_info *mtd);
int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops);
int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops);
void nandchip_micron_init(struct mtd_info *mtd, int dev_id);
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/mtd/nand/nand_base.c 0000664 0000000 0000000 00000336714 12703306510 0027413 0 ustar 00root root 0000000 0000000 /*
* drivers/mtd/nand.c
*
* Overview:
* This is the generic MTD driver for NAND flash devices. It should be
* capable of working with almost all NAND chips currently available.
*
* Additional technical information is available on
* http://www.linux-mtd.infradead.org/doc/nand.html
*
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
* 2002-2006 Thomas Gleixner (tglx@linutronix.de)
*
* Credits:
* David Woodhouse for adding multichip support
*
* Aleph One Ltd. and Toby Churchill Ltd. for supporting the
* rework for 2K page size chips
*
* TODO:
* Enable cached programming for 2k page size chips
* Check, if mtd->ecctype should be set to MTD_ECC_HW
* if we have HW ECC support.
* BBT table is not serialized, has to be fixed
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "nand.h"
/* Define default oob placement schemes for large and small page devices */
static struct nand_ecclayout nand_oob_8 = {
.eccbytes = 3,
.eccpos = {0, 1, 2},
.oobfree = {
{.offset = 3,
.length = 2},
{.offset = 6,
.length = 2} }
};
static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 6, 7},
.oobfree = {
{.offset = 8,
. length = 8} }
};
static struct nand_ecclayout nand_oob_64 = {
.eccbytes = 24,
.eccpos = {
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {
{.offset = 2,
.length = 38} }
};
static struct nand_ecclayout nand_oob_128 = {
.eccbytes = 48,
.eccpos = {
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127},
.oobfree = {
{.offset = 2,
.length = 78} }
};
int nand_get_device(struct mtd_info *mtd, int new_state);
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops);
/*
* For devices which display every fart in the system on a separate LED. Is
* compiled away when LED support is disabled.
*/
DEFINE_LED_TRIGGER(nand_led_trigger);
static int check_offs_len(struct mtd_info *mtd,
loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd->priv;
int ret = 0;
/* Start address must align on block boundary */
if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) {
pr_debug("%s: unaligned address\n", __func__);
ret = -EINVAL;
}
/* Length must align on block boundary */
if (len & ((1ULL << chip->phys_erase_shift) - 1)) {
pr_debug("%s: length not block aligned\n", __func__);
ret = -EINVAL;
}
return ret;
}
/**
* nand_release_device - [GENERIC] release chip
* @mtd: MTD device structure
*
* Release chip lock and wake up anyone waiting on the device.
*/
void nand_release_device(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
/* Release the controller and the chip */
spin_lock(&chip->controller->lock);
chip->controller->active = NULL;
chip->state = FL_READY;
wake_up(&chip->controller->wq);
spin_unlock(&chip->controller->lock);
}
/**
* nand_read_byte - [DEFAULT] read one byte from the chip
* @mtd: MTD device structure
*
* Default read function for 8bit buswidth
*/
static uint8_t nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
return readb(chip->IO_ADDR_R);
}
/**
* nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
* @mtd: MTD device structure
*
* Default read function for 16bit buswidth with endianness conversion.
*
*/
static uint8_t nand_read_byte16(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
}
/**
* nand_read_word - [DEFAULT] read one word from the chip
* @mtd: MTD device structure
*
* Default read function for 16bit buswidth without endianness conversion.
*/
static u16 nand_read_word(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
return readw(chip->IO_ADDR_R);
}
/**
* nand_select_chip - [DEFAULT] control CE line
* @mtd: MTD device structure
* @chipnr: chipnumber to select, -1 for deselect
*
* Default select function for 1 chip devices.
*/
static void nand_select_chip(struct mtd_info *mtd, int chipnr)
{
struct nand_chip *chip = mtd->priv;
switch (chipnr) {
case -1:
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
break;
case 0:
break;
default:
BUG();
}
}
/**
* nand_write_byte - [DEFAULT] write single byte to chip
* @mtd: MTD device structure
* @byte: value to write
*
* Default function to write a byte to I/O[7:0]
*/
static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
{
struct nand_chip *chip = mtd->priv;
chip->write_buf(mtd, &byte, 1);
}
/**
* nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
* @mtd: MTD device structure
* @byte: value to write
*
* Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
*/
static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
{
struct nand_chip *chip = mtd->priv;
uint16_t word = byte;
/*
* It's not entirely clear what should happen to I/O[15:8] when writing
* a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
*
* When the host supports a 16-bit bus width, only data is
* transferred at the 16-bit width. All address and command line
* transfers shall use only the lower 8-bits of the data bus. During
* command transfers, the host may place any value on the upper
* 8-bits of the data bus. During address transfers, the host shall
* set the upper 8-bits of the data bus to 00h.
*
* One user of the write_byte callback is nand_onfi_set_features. The
* four parameters are specified to be written to I/O[7:0], but this is
* neither an address nor a command transfer. Let's assume a 0 on the
* upper I/O lines is OK.
*/
chip->write_buf(mtd, (uint8_t *)&word, 2);
}
/**
* nand_write_buf - [DEFAULT] write buffer to chip
* @mtd: MTD device structure
* @buf: data buffer
* @len: number of bytes to write
*
* Default write function for 8bit buswidth.
*/
static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
struct nand_chip *chip = mtd->priv;
iowrite8_rep(chip->IO_ADDR_W, buf, len);
}
/**
* nand_read_buf - [DEFAULT] read chip data into buffer
* @mtd: MTD device structure
* @buf: buffer to store date
* @len: number of bytes to read
*
* Default read function for 8bit buswidth.
*/
static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct nand_chip *chip = mtd->priv;
ioread8_rep(chip->IO_ADDR_R, buf, len);
}
/**
* nand_write_buf16 - [DEFAULT] write buffer to chip
* @mtd: MTD device structure
* @buf: data buffer
* @len: number of bytes to write
*
* Default write function for 16bit buswidth.
*/
static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
{
struct nand_chip *chip = mtd->priv;
u16 *p = (u16 *) buf;
iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
}
/**
* nand_read_buf16 - [DEFAULT] read chip data into buffer
* @mtd: MTD device structure
* @buf: buffer to store date
* @len: number of bytes to read
*
* Default read function for 16bit buswidth.
*/
static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct nand_chip *chip = mtd->priv;
u16 *p = (u16 *) buf;
ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
}
/**
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
* @mtd: MTD device structure
* @ofs: offset from device start
* @getchip: 0, if the chip is already selected
*
* Check, if the block is bad.
*/
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
{
int page, chipnr, res = 0, i = 0;
struct nand_chip *chip = mtd->priv;
u16 bad;
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
ofs += mtd->erasesize - mtd->writesize;
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
if (getchip) {
chipnr = (int)(ofs >> chip->chip_shift);
nand_get_device(mtd, FL_READING);
/* Select the NAND device */
chip->select_chip(mtd, chipnr);
}
do {
if (chip->options & NAND_BUSWIDTH_16) {
chip->cmdfunc(mtd, NAND_CMD_READOOB,
chip->badblockpos & 0xFE, page);
bad = cpu_to_le16(chip->read_word(mtd));
if (chip->badblockpos & 0x1)
bad >>= 8;
else
bad &= 0xFF;
} else {
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
page);
bad = chip->read_byte(mtd);
}
if (likely(chip->badblockbits == 8))
res = bad != 0xFF;
else
res = hweight8(bad) < chip->badblockbits;
ofs += mtd->writesize;
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
i++;
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
if (getchip) {
chip->select_chip(mtd, -1);
nand_release_device(mtd);
}
return res;
}
/**
* nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
* @mtd: MTD device structure
* @ofs: offset from device start
*
* This is the default implementation, which can be overridden by a hardware
* specific driver. It provides the details for writing a bad block marker to a
* block.
*/
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
struct nand_chip *chip = mtd->priv;
struct mtd_oob_ops ops;
uint8_t buf[2] = { 0, 0 };
int ret = 0, res, i = 0;
ops.datbuf = NULL;
ops.oobbuf = buf;
ops.ooboffs = chip->badblockpos;
if (chip->options & NAND_BUSWIDTH_16) {
ops.ooboffs &= ~0x01;
ops.len = ops.ooblen = 2;
} else {
ops.len = ops.ooblen = 1;
}
ops.mode = MTD_OPS_PLACE_OOB;
/* Write to first/last page(s) if necessary */
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
ofs += mtd->erasesize - mtd->writesize;
do {
res = nand_do_write_oob(mtd, ofs, &ops);
if (!ret)
ret = res;
i++;
ofs += mtd->writesize;
} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
return ret;
}
/**
* nand_block_markbad_lowlevel - mark a block bad
* @mtd: MTD device structure
* @ofs: offset from device start
*
* This function performs the generic NAND bad block marking steps (i.e., bad
* block table(s) and/or marker(s)). We only allow the hardware driver to
* specify how to write bad block markers to OOB (chip->block_markbad).
*
* We try operations in the following order:
* (1) erase the affected block, to allow OOB marker to be written cleanly
* (2) write bad block marker to OOB area of affected block (unless flag
* NAND_BBT_NO_OOB_BBM is present)
* (3) update the BBT
* Note that we retain the first error encountered in (2) or (3), finish the
* procedures, and dump the error in the end.
*/
static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
{
struct nand_chip *chip = mtd->priv;
int res, ret = 0;
if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
struct erase_info einfo;
/* Attempt erase before marking OOB */
memset(&einfo, 0, sizeof(einfo));
einfo.mtd = mtd;
einfo.addr = ofs;
einfo.len = 1ULL << chip->phys_erase_shift;
nand_erase_nand(mtd, &einfo, 0);
/* Write bad block marker to OOB */
nand_get_device(mtd, FL_WRITING);
ret = chip->block_markbad(mtd, ofs);
nand_release_device(mtd);
}
/* Mark block bad in BBT */
if (chip->bbt) {
res = nand_markbad_bbt(mtd, ofs);
if (!ret)
ret = res;
}
if (!ret)
mtd->ecc_stats.badblocks++;
return ret;
}
/**
* nand_check_wp - [GENERIC] check if the chip is write protected
* @mtd: MTD device structure
*
* Check, if the device is write protected. The function expects, that the
* device is already selected.
*/
static int nand_check_wp(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
/* Broken xD cards report WP despite being writable */
if (chip->options & NAND_BROKEN_XD)
return 0;
/* Check the WP bit */
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
}
/**
* nand_block_isreserved - [GENERIC] Check if a block is marked reserved.
* @mtd: MTD device structure
* @ofs: offset from device start
*
* Check if the block is marked as reserved.
*/
static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
{
struct nand_chip *chip = mtd->priv;
if (!chip->bbt)
return 0;
/* Return info from the table */
return nand_isreserved_bbt(mtd, ofs);
}
/**
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
* @mtd: MTD device structure
* @ofs: offset from device start
* @getchip: 0, if the chip is already selected
* @allowbbt: 1, if its allowed to access the bbt area
*
* Check, if the block is bad. Either by reading the bad block table or
* calling of the scan function.
*/
static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
int allowbbt)
{
struct nand_chip *chip = mtd->priv;
if (!chip->bbt)
return chip->block_bad(mtd, ofs, getchip);
/* Return info from the table */
return nand_isbad_bbt(mtd, ofs, allowbbt);
}
/**
* panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
* @mtd: MTD device structure
* @timeo: Timeout
*
* Helper function for nand_wait_ready used when needing to wait in interrupt
* context.
*/
static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
{
struct nand_chip *chip = mtd->priv;
int i;
/* Wait for the device to get ready */
for (i = 0; i < timeo; i++) {
if (chip->dev_ready(mtd))
break;
touch_softlockup_watchdog();
mdelay(1);
}
}
/* Wait for the ready pin, after a command. The timeout is caught later. */
void nand_wait_ready(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
unsigned long timeo = jiffies + msecs_to_jiffies(20);
/* 400ms timeout */
if (in_interrupt() || oops_in_progress)
return panic_nand_wait_ready(mtd, 400);
led_trigger_event(nand_led_trigger, LED_FULL);
/* Wait until command is processed or timeout occurs */
do {
if (chip->dev_ready(mtd))
break;
touch_softlockup_watchdog();
} while (time_before(jiffies, timeo));
led_trigger_event(nand_led_trigger, LED_OFF);
}
EXPORT_SYMBOL_GPL(nand_wait_ready);
/**
* nand_command - [DEFAULT] Send command to NAND device
* @mtd: MTD device structure
* @command: the command to be sent
* @column: the column address for this command, -1 if none
* @page_addr: the page address for this command, -1 if none
*
* Send command to NAND device. This function is used for small page devices
* (512 Bytes per page).
*/
static void nand_command(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
register struct nand_chip *chip = mtd->priv;
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
/* Write out the command to the device */
if (command == NAND_CMD_SEQIN) {
int readcmd;
if (column >= mtd->writesize) {
/* OOB area */
column -= mtd->writesize;
readcmd = NAND_CMD_READOOB;
} else if (column < 256) {
/* First 256 bytes --> READ0 */
readcmd = NAND_CMD_READ0;
} else {
column -= 256;
readcmd = NAND_CMD_READ1;
}
chip->cmd_ctrl(mtd, readcmd, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
}
chip->cmd_ctrl(mtd, command, ctrl);
/* Address cycle, when necessary */
ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
/* Serially input address */
if (column != -1) {
/* Adjust columns for 16 bit buswidth */
if (chip->options & NAND_BUSWIDTH_16 &&
!nand_opcode_8bits(command))
column >>= 1;
chip->cmd_ctrl(mtd, column, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
}
if (page_addr != -1) {
chip->cmd_ctrl(mtd, page_addr, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
/* One more address cycle for devices > 32MiB */
if (chip->chipsize > (32 << 20))
chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
}
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/*
* Program and erase have their own busy handlers status and sequential
* in needs no delay
*/
switch (command) {
case NAND_CMD_PAGEPROG:
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_STATUS:
return;
case NAND_CMD_RESET:
if (chip->dev_ready)
break;
udelay(chip->chip_delay);
chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd,
NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
while (!(chip->read_byte(mtd) & NAND_STATUS_READY))
;
return;
/* This applies to read commands */
default:
/*
* If we don't have access to the busy pin, we apply the given
* command delay
*/
if (!chip->dev_ready) {
udelay(chip->chip_delay);
return;
}
}
/*
* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine.
*/
ndelay(100);
nand_wait_ready(mtd);
}
/**
* nand_command_lp - [DEFAULT] Send command to NAND large page device
* @mtd: MTD device structure
* @command: the command to be sent
* @column: the column address for this command, -1 if none
* @page_addr: the page address for this command, -1 if none
*
* Send command to NAND device. This is the version for the new large page
* devices. We don't have the separate regions as we have in the small page
* devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
*/
static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
register struct nand_chip *chip = mtd->priv;
/* Emulate NAND_CMD_READOOB */
if (command == NAND_CMD_READOOB) {
column += mtd->writesize;
command = NAND_CMD_READ0;
}
/* Command latch cycle */
chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
if (column != -1 || page_addr != -1) {
int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
/* Serially input address */
if (column != -1) {
/* Adjust columns for 16 bit buswidth */
if (chip->options & NAND_BUSWIDTH_16 &&
!nand_opcode_8bits(command))
column >>= 1;
chip->cmd_ctrl(mtd, column, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
chip->cmd_ctrl(mtd, column >> 8, ctrl);
}
if (page_addr != -1) {
chip->cmd_ctrl(mtd, page_addr, ctrl);
chip->cmd_ctrl(mtd, page_addr >> 8,
NAND_NCE | NAND_ALE);
/* One more address cycle for devices > 128MiB */
if (chip->chipsize > (128 << 20))
chip->cmd_ctrl(mtd, page_addr >> 16,
NAND_NCE | NAND_ALE);
}
}
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/*
* Program and erase have their own busy handlers status, sequential
* in and status need no delay.
*/
switch (command) {
case NAND_CMD_CACHEDPROG:
case NAND_CMD_PAGEPROG:
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
return;
case NAND_CMD_RESET:
if (chip->dev_ready)
break;
udelay(chip->chip_delay);
chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
while (!(chip->read_byte(mtd) & NAND_STATUS_READY))
;
return;
case NAND_CMD_RNDOUT:
/* No ready / busy check necessary */
chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
return;
case NAND_CMD_READ0:
chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
/* This applies to read commands */
default:
/*
* If we don't have access to the busy pin, we apply the given
* command delay.
*/
if (!chip->dev_ready) {
udelay(chip->chip_delay);
return;
}
}
/*
* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine.
*/
ndelay(100);
nand_wait_ready(mtd);
}
/**
* panic_nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
* @mtd: MTD device structure
* @new_state: the state which is requested
*
* Used when in panic, no locks are taken.
*/
static void panic_nand_get_device(struct nand_chip *chip,
struct mtd_info *mtd, int new_state)
{
/* Hardware controller shared among independent devices */
chip->controller->active = chip;
chip->state = new_state;
}
/**
* nand_get_device - [GENERIC] Get chip for selected access
* @mtd: MTD device structure
* @new_state: the state which is requested
*
* Get the device and lock it for exclusive access
*/
int nand_get_device(struct mtd_info *mtd, int new_state)
{
struct nand_chip *chip = mtd->priv;
spinlock_t *lock = &chip->controller->lock;
wait_queue_head_t *wq = &chip->controller->wq;
DECLARE_WAITQUEUE(wait, current);
retry:
spin_lock(lock);
/* Hardware controller shared among independent devices */
if (!chip->controller->active)
chip->controller->active = chip;
if (chip->controller->active == chip && chip->state == FL_READY) {
chip->state = new_state;
spin_unlock(lock);
return 0;
}
if (new_state == FL_PM_SUSPENDED) {
if (chip->controller->active->state == FL_PM_SUSPENDED) {
chip->state = FL_PM_SUSPENDED;
spin_unlock(lock);
return 0;
}
}
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(wq, &wait);
spin_unlock(lock);
schedule();
remove_wait_queue(wq, &wait);
goto retry;
}
/**
* panic_nand_wait - [GENERIC] wait until the command is done
* @mtd: MTD device structure
* @chip: NAND chip structure
* @timeo: timeout
*
* Wait for command done. This is a helper function for nand_wait used when
* we are in interrupt context. May happen when in panic and trying to write
* an oops through mtdoops.
*/
static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
unsigned long timeo)
{
int i;
for (i = 0; i < timeo; i++) {
if (chip->dev_ready) {
if (chip->dev_ready(mtd))
break;
} else {
if (chip->read_byte(mtd) & NAND_STATUS_READY)
break;
}
mdelay(1);
}
}
/**
* nand_wait - [DEFAULT] wait until the command is done
* @mtd: MTD device structure
* @chip: NAND chip structure
*
* Wait for command done. This applies to erase and program only. Erase can
* take up to 400ms and program up to 20ms according to general NAND and
* SmartMedia specs.
*/
static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
int status, state = chip->state;
unsigned long timeo = (state == FL_ERASING ? 400 : 20);
led_trigger_event(nand_led_trigger, LED_FULL);
/*
* Apply this short delay always to ensure that we do wait tWB in any
* case on any machine.
*/
ndelay(100);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
if (in_interrupt() || oops_in_progress)
panic_nand_wait(mtd, chip, timeo);
else {
timeo = jiffies + msecs_to_jiffies(timeo);
while (time_before(jiffies, timeo)) {
if (chip->dev_ready) {
if (chip->dev_ready(mtd))
break;
} else {
if (chip->read_byte(mtd) & NAND_STATUS_READY)
break;
}
cond_resched();
}
}
led_trigger_event(nand_led_trigger, LED_OFF);
status = (int)chip->read_byte(mtd);
/* This can happen if in case of timeout or buggy dev_ready */
WARN_ON(!(status & NAND_STATUS_READY));
return status;
}
/**
* __nand_unlock - [REPLACEABLE] unlocks specified locked blocks
* @mtd: mtd info
* @ofs: offset to start unlock from
* @len: length to unlock
* @invert: when = 0, unlock the range of blocks within the lower and
* upper boundary address
* when = 1, unlock the range of blocks outside the boundaries
* of the lower and upper boundary address
*
* Returs unlock status.
*/
static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
uint64_t len, int invert)
{
int ret = 0;
int status, page;
struct nand_chip *chip = mtd->priv;
/* Submit address of first page to unlock */
page = ofs >> chip->page_shift;
chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask);
/* Submit address of last page to unlock */
page = (ofs + len) >> chip->page_shift;
chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1,
(page | invert) & chip->pagemask);
/* Call wait ready function */
status = chip->waitfunc(mtd, chip);
/* See if device thinks it succeeded */
if (status & NAND_STATUS_FAIL) {
pr_debug("%s: error status = 0x%08x\n",
__func__, status);
ret = -EIO;
}
return ret;
}
/**
* nand_unlock - [REPLACEABLE] unlocks specified locked blocks
* @mtd: mtd info
* @ofs: offset to start unlock from
* @len: length to unlock
*
* Returns unlock status.
*/
int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret = 0;
int chipnr;
struct nand_chip *chip = mtd->priv;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
__func__, (unsigned long long)ofs, len);
if (check_offs_len(mtd, ofs, len))
ret = -EINVAL;
/* Align to last block address if size addresses end of the device */
if (ofs + len == mtd->size)
len -= mtd->erasesize;
nand_get_device(mtd, FL_UNLOCKING);
/* Shift to get chip number */
chipnr = ofs >> chip->chip_shift;
chip->select_chip(mtd, chipnr);
/*
* Reset the chip.
* If we want to check the WP through READ STATUS and check the bit 7
* we must reset the chip
* some operation can also clear the bit 7 of status register
* eg. erase/program a locked block
*/
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
pr_debug("%s: device is write protected!\n",
__func__);
ret = -EIO;
goto out;
}
ret = __nand_unlock(mtd, ofs, len, 0);
out:
chip->select_chip(mtd, -1);
nand_release_device(mtd);
return ret;
}
EXPORT_SYMBOL(nand_unlock);
/**
* nand_lock - [REPLACEABLE] locks all blocks present in the device
* @mtd: mtd info
* @ofs: offset to start unlock from
* @len: length to unlock
*
* This feature is not supported in many NAND parts. 'Micron' NAND parts do
* have this feature, but it allows only to lock all blocks, not for specified
* range for block. Implementing 'lock' feature by making use of 'unlock', for
* now.
*
* Returns lock status.
*/
int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret = 0;
int chipnr, status, page;
struct nand_chip *chip = mtd->priv;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
__func__, (unsigned long long)ofs, len);
if (check_offs_len(mtd, ofs, len))
ret = -EINVAL;
nand_get_device(mtd, FL_LOCKING);
/* Shift to get chip number */
chipnr = ofs >> chip->chip_shift;
chip->select_chip(mtd, chipnr);
/*
* Reset the chip.
* If we want to check the WP through READ STATUS and check the bit 7
* we must reset the chip
* some operation can also clear the bit 7 of status register
* eg. erase/program a locked block
*/
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
pr_debug("%s: device is write protected!\n",
__func__);
status = MTD_ERASE_FAILED;
ret = -EIO;
goto out;
}
/* Submit address of first page to lock */
page = ofs >> chip->page_shift;
chip->cmdfunc(mtd, NAND_CMD_LOCK, -1, page & chip->pagemask);
/* Call wait ready function */
status = chip->waitfunc(mtd, chip);
/* See if device thinks it succeeded */
if (status & NAND_STATUS_FAIL) {
pr_debug("%s: error status = 0x%08x\n",
__func__, status);
ret = -EIO;
goto out;
}
ret = __nand_unlock(mtd, ofs, len, 0x1);
out:
chip->select_chip(mtd, -1);
nand_release_device(mtd);
return ret;
}
EXPORT_SYMBOL(nand_lock);
/**
* nand_read_page_raw - [INTERN] read raw page data without ecc
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
chip->read_buf(mtd, buf, mtd->writesize);
if (oob_required)
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
/**
* nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* We need a special oob layout and handling even when OOB isn't used.
*/
static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
uint8_t *oob = chip->oob_poi;
int steps, size;
for (steps = chip->ecc.steps; steps > 0; steps--) {
chip->read_buf(mtd, buf, eccsize);
buf += eccsize;
if (chip->ecc.prepad) {
chip->read_buf(mtd, oob, chip->ecc.prepad);
oob += chip->ecc.prepad;
}
chip->read_buf(mtd, oob, eccbytes);
oob += eccbytes;
if (chip->ecc.postpad) {
chip->read_buf(mtd, oob, chip->ecc.postpad);
oob += chip->ecc.postpad;
}
}
size = mtd->oobsize - (oob - chip->oob_poi);
if (size)
chip->read_buf(mtd, oob, size);
return 0;
}
/**
* nand_read_page_swecc - [REPLACEABLE] software ECC based page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*/
static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *ecc_calc = chip->buffers->ecccalc;
uint8_t *ecc_code = chip->buffers->ecccode;
uint32_t *eccpos = chip->ecc.layout->eccpos;
unsigned int max_bitflips = 0;
chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];
eccsteps = chip->ecc.steps;
p = buf;
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return max_bitflips;
}
/**
* nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @data_offs: offset of requested data within the page
* @readlen: data length
* @bufpoi: buffer to store read data
* @page: page number to read
*/
static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
int page)
{
int start_step, end_step, num_steps;
uint32_t *eccpos = chip->ecc.layout->eccpos;
uint8_t *p;
int data_col_addr, i, gaps = 0;
int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
int index;
unsigned int max_bitflips = 0;
/* Column address within the page aligned to ECC size (256bytes) */
start_step = data_offs / chip->ecc.size;
end_step = (data_offs + readlen - 1) / chip->ecc.size;
num_steps = end_step - start_step + 1;
index = start_step * chip->ecc.bytes;
/* Data size aligned to ECC ecc.size */
datafrag_len = num_steps * chip->ecc.size;
eccfrag_len = num_steps * chip->ecc.bytes;
data_col_addr = start_step * chip->ecc.size;
/* If we read not a page aligned data */
if (data_col_addr != 0)
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
p = bufpoi + data_col_addr;
chip->read_buf(mtd, p, datafrag_len);
/* Calculate ECC */
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);
/*
* The performance is faster if we position offsets according to
* ecc.pos. Let's make sure that there are no gaps in ECC positions.
*/
for (i = 0; i < eccfrag_len - 1; i++) {
if (eccpos[i + index] + 1 != eccpos[i + index + 1]) {
gaps = 1;
break;
}
}
if (gaps) {
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
} else {
/*
* Send the command to read the particular ECC bytes take care
* about buswidth alignment in read_buf.
*/
aligned_pos = eccpos[index] & ~(busw - 1);
aligned_len = eccfrag_len;
if (eccpos[index] & (busw - 1))
aligned_len++;
if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
aligned_len++;
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
mtd->writesize + aligned_pos, -1);
chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
}
for (i = 0; i < eccfrag_len; i++)
chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]];
p = bufpoi + data_col_addr;
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
int stat;
stat = chip->ecc.correct(mtd, p,
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return max_bitflips;
}
/**
* nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Not for syndrome calculating ECC controllers which need a special oob layout.
*/
static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *ecc_calc = chip->buffers->ecccalc;
uint8_t *ecc_code = chip->buffers->ecccode;
uint32_t *eccpos = chip->ecc.layout->eccpos;
unsigned int max_bitflips = 0;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
}
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];
eccsteps = chip->ecc.steps;
p = buf;
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return max_bitflips;
}
/**
* nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Hardware ECC for large page chips, require OOB to be read first. For this
* ECC mode, the write_page method is re-used from ECC_HW. These methods
* read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with
* multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
* the data area, by overwriting the NAND manufacturer bad block markings.
*/
static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *ecc_code = chip->buffers->ecccode;
uint32_t *eccpos = chip->ecc.layout->eccpos;
uint8_t *ecc_calc = chip->buffers->ecccalc;
unsigned int max_bitflips = 0;
/* Read the OOB area first */
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return max_bitflips;
}
/**
* nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* The hw generator calculates the error syndrome automatically. Therefore we
* need a special oob layout and handling.
*/
static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *oob = chip->oob_poi;
unsigned int max_bitflips = 0;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
if (chip->ecc.prepad) {
chip->read_buf(mtd, oob, chip->ecc.prepad);
oob += chip->ecc.prepad;
}
chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
chip->read_buf(mtd, oob, eccbytes);
stat = chip->ecc.correct(mtd, p, oob, NULL);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
oob += eccbytes;
if (chip->ecc.postpad) {
chip->read_buf(mtd, oob, chip->ecc.postpad);
oob += chip->ecc.postpad;
}
}
/* Calculate remaining oob bytes */
i = mtd->oobsize - (oob - chip->oob_poi);
if (i)
chip->read_buf(mtd, oob, i);
return max_bitflips;
}
/**
* nand_transfer_oob - [INTERN] Transfer oob to client buffer
* @chip: nand chip structure
* @oob: oob destination address
* @ops: oob ops structure
* @len: size of oob to transfer
*/
static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
struct mtd_oob_ops *ops, size_t len)
{
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
case MTD_OPS_RAW:
memcpy(oob, chip->oob_poi + ops->ooboffs, len);
return oob + len;
case MTD_OPS_AUTO_OOB: {
struct nand_oobfree *free = chip->ecc.layout->oobfree;
uint32_t boffs = 0, roffs = ops->ooboffs;
size_t bytes = 0;
for (; free->length && len; free++, len -= bytes) {
/* Read request not from offset 0? */
if (unlikely(roffs)) {
if (roffs >= free->length) {
roffs -= free->length;
continue;
}
boffs = free->offset + roffs;
bytes = min_t(size_t, len,
(free->length - roffs));
roffs = 0;
} else {
bytes = min_t(size_t, len, free->length);
boffs = free->offset;
}
memcpy(oob, chip->oob_poi + boffs, bytes);
oob += bytes;
}
return oob;
}
default:
BUG();
}
return NULL;
}
/**
* nand_setup_read_retry - [INTERN] Set the READ RETRY mode
* @mtd: MTD device structure
* @retry_mode: the retry mode to use
*
* Some vendors supply a special command to shift the Vt threshold, to be used
* when there are too many bitflips in a page (i.e., ECC error). After setting
* a new threshold, the host should retry reading the page.
*/
static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
{
struct nand_chip *chip = mtd->priv;
pr_debug("setting READ RETRY mode %d\n", retry_mode);
if (retry_mode >= chip->read_retries)
return -EINVAL;
if (!chip->setup_read_retry)
return -EOPNOTSUPP;
return chip->setup_read_retry(mtd, retry_mode);
}
/**
* nand_do_read_ops - [INTERN] Read data with ECC
* @mtd: MTD device structure
* @from: offset to read from
* @ops: oob ops structure
*
* Internal function. Called with chip held.
*/
int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
int chipnr, page, realpage, col, bytes, aligned, oob_required;
struct nand_chip *chip = mtd->priv;
int ret = 0;
uint32_t readlen = ops->len;
uint32_t oobreadlen = ops->ooblen;
uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?
mtd->oobavail : mtd->oobsize;
uint8_t *bufpoi, *oob, *buf;
int use_bufpoi;
unsigned int max_bitflips = 0;
int retry_mode = 0;
bool ecc_fail = false;
chipnr = (int)(from >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
realpage = (int)(from >> chip->page_shift);
page = realpage & chip->pagemask;
col = (int)(from & (mtd->writesize - 1));
buf = ops->datbuf;
oob = ops->oobbuf;
oob_required = oob ? 1 : 0;
while (1) {
unsigned int ecc_failures = mtd->ecc_stats.failed;
bytes = min(mtd->writesize - col, readlen);
aligned = (bytes == mtd->writesize);
if (!aligned)
use_bufpoi = 1;
else if (chip->options & NAND_USE_BOUNCE_BUFFER)
use_bufpoi = !virt_addr_valid(buf);
else
use_bufpoi = 0;
/* Is the current page in the buffer? */
if (realpage != chip->pagebuf || oob) {
bufpoi = use_bufpoi ? chip->buffers->databuf : buf;
if (use_bufpoi && aligned)
pr_debug("%s: using read bounce buffer for buf@%p\n",
__func__, buf);
read_retry:
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
/*
* Now read the page into the buffer. Absent an error,
* the read methods return max bitflips per ecc step.
*/
if (unlikely(ops->mode == MTD_OPS_RAW))
ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
oob_required,
page);
else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
!oob)
ret = chip->ecc.read_subpage(mtd, chip,
col, bytes, bufpoi,
page);
else
ret = chip->ecc.read_page(mtd, chip, bufpoi,
oob_required, page);
if (ret < 0) {
if (use_bufpoi)
/* Invalidate page cache */
chip->pagebuf = -1;
break;
}
max_bitflips = max_t(unsigned int, max_bitflips, ret);
/* Transfer not aligned data */
if (use_bufpoi) {
if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
!(mtd->ecc_stats.failed - ecc_failures) &&
(ops->mode != MTD_OPS_RAW)) {
chip->pagebuf = realpage;
chip->pagebuf_bitflips = ret;
} else {
/* Invalidate page cache */
chip->pagebuf = -1;
}
memcpy(buf, chip->buffers->databuf + col, bytes);
}
if (unlikely(oob)) {
int toread = min(oobreadlen, max_oobsize);
if (toread) {
oob = nand_transfer_oob(chip,
oob, ops, toread);
oobreadlen -= toread;
}
}
if (chip->options & NAND_NEED_READRDY) {
/* Apply delay or wait for ready/busy pin */
if (!chip->dev_ready)
udelay(chip->chip_delay);
else
nand_wait_ready(mtd);
}
if (mtd->ecc_stats.failed - ecc_failures) {
if (retry_mode + 1 < chip->read_retries) {
retry_mode++;
ret = nand_setup_read_retry(mtd,
retry_mode);
if (ret < 0)
break;
/* Reset failures; retry */
mtd->ecc_stats.failed = ecc_failures;
goto read_retry;
} else {
/* No more retry modes; real failure */
ecc_fail = true;
}
}
buf += bytes;
} else {
memcpy(buf, chip->buffers->databuf + col, bytes);
buf += bytes;
max_bitflips = max_t(unsigned int, max_bitflips,
chip->pagebuf_bitflips);
}
readlen -= bytes;
/* Reset to retry mode 0 */
if (retry_mode) {
ret = nand_setup_read_retry(mtd, 0);
if (ret < 0)
break;
retry_mode = 0;
}
if (!readlen)
break;
/* For subsequent reads align to page boundary */
col = 0;
/* Increment page address */
realpage++;
page = realpage & chip->pagemask;
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
chip->select_chip(mtd, -1);
chip->select_chip(mtd, chipnr);
}
}
chip->select_chip(mtd, -1);
ops->retlen = ops->len - (size_t) readlen;
if (oob)
ops->oobretlen = ops->ooblen - oobreadlen;
if (ret < 0)
return ret;
if (ecc_fail)
return -EBADMSG;
return max_bitflips;
}
/**
* nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
*
* Get hold of the chip and call nand_do_read.
*/
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf)
{
struct mtd_oob_ops ops;
int ret;
nand_get_device(mtd, FL_READING);
ops.len = len;
ops.datbuf = buf;
ops.oobbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_read_ops(mtd, from, &ops);
*retlen = ops.retlen;
nand_release_device(mtd);
return ret;
}
/**
* nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to read
*/
static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
/**
* nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
* with syndromes
* @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to read
*/
static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
int length = mtd->oobsize;
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size;
uint8_t *bufpoi = chip->oob_poi;
int i, toread, sndrnd = 0, pos;
chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
for (i = 0; i < chip->ecc.steps; i++) {
if (sndrnd) {
pos = eccsize + i * (eccsize + chunk);
if (mtd->writesize > 512)
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);
else
chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);
} else
sndrnd = 1;
toread = min_t(int, length, chunk);
chip->read_buf(mtd, bufpoi, toread);
bufpoi += toread;
length -= toread;
}
if (length > 0)
chip->read_buf(mtd, bufpoi, length);
return 0;
}
/**
* nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to write
*/
static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
int status = 0;
const uint8_t *buf = chip->oob_poi;
int length = mtd->oobsize;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
chip->write_buf(mtd, buf, length);
/* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
}
/**
* nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
* with syndrome - only for large page flash
* @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to write
*/
static int nand_write_oob_syndrome(struct mtd_info *mtd,
struct nand_chip *chip, int page)
{
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size, length = mtd->oobsize;
int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
const uint8_t *bufpoi = chip->oob_poi;
/*
* data-ecc-data-ecc ... ecc-oob
* or
* data-pad-ecc-pad-data-pad .... ecc-pad-oob
*/
if (!chip->ecc.prepad && !chip->ecc.postpad) {
pos = steps * (eccsize + chunk);
steps = 0;
} else
pos = eccsize;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
for (i = 0; i < steps; i++) {
if (sndcmd) {
if (mtd->writesize <= 512) {
uint32_t fill = 0xFFFFFFFF;
len = eccsize;
while (len > 0) {
int num = min_t(int, len, 4);
chip->write_buf(mtd, (uint8_t *)&fill,
num);
len -= num;
}
} else {
pos = eccsize + i * (eccsize + chunk);
chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);
}
} else
sndcmd = 1;
len = min_t(int, length, chunk);
chip->write_buf(mtd, bufpoi, len);
bufpoi += len;
length -= len;
}
if (length > 0)
chip->write_buf(mtd, bufpoi, length);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
}
/**
* nand_do_read_oob - [INTERN] NAND read out-of-band
* @mtd: MTD device structure
* @from: offset to read from
* @ops: oob operations description structure
*
* NAND read out-of-band data from the spare area.
*/
static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
int page, realpage, chipnr;
struct nand_chip *chip = mtd->priv;
struct mtd_ecc_stats stats;
int readlen = ops->ooblen;
int len;
uint8_t *buf = ops->oobbuf;
int ret = 0;
pr_debug("%s: from = 0x%08Lx, len = %i\n",
__func__, (unsigned long long)from, readlen);
stats = mtd->ecc_stats;
if (ops->mode == MTD_OPS_AUTO_OOB)
len = chip->ecc.layout->oobavail;
else
len = mtd->oobsize;
if (unlikely(ops->ooboffs >= len)) {
pr_debug("%s: attempt to start read outside oob\n",
__func__);
return -EINVAL;
}
/* Do not allow reads past end of device */
if (unlikely(from >= mtd->size ||
ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
(from >> chip->page_shift)) * len)) {
pr_debug("%s: attempt to read beyond end of device\n",
__func__);
return -EINVAL;
}
chipnr = (int)(from >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
/* Shift to get page */
realpage = (int)(from >> chip->page_shift);
page = realpage & chip->pagemask;
while (1) {
if (ops->mode == MTD_OPS_RAW)
ret = chip->ecc.read_oob_raw(mtd, chip, page);
else
ret = chip->ecc.read_oob(mtd, chip, page);
if (ret < 0)
break;
len = min(len, readlen);
buf = nand_transfer_oob(chip, buf, ops, len);
if (chip->options & NAND_NEED_READRDY) {
/* Apply delay or wait for ready/busy pin */
if (!chip->dev_ready)
udelay(chip->chip_delay);
else
nand_wait_ready(mtd);
}
readlen -= len;
if (!readlen)
break;
/* Increment page address */
realpage++;
page = realpage & chip->pagemask;
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
chip->select_chip(mtd, -1);
chip->select_chip(mtd, chipnr);
}
}
chip->select_chip(mtd, -1);
ops->oobretlen = ops->ooblen - readlen;
if (ret < 0)
return ret;
if (mtd->ecc_stats.failed - stats.failed)
return -EBADMSG;
return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
}
/**
* nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
* @mtd: MTD device structure
* @from: offset to read from
* @ops: oob operation description structure
*
* NAND read data and/or out-of-band data.
*/
static int nand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
int ret = -ENOTSUPP;
ops->retlen = 0;
/* Do not allow reads past end of device */
if (ops->datbuf && (from + ops->len) > mtd->size) {
pr_debug("%s: attempt to read beyond end of device\n",
__func__);
return -EINVAL;
}
nand_get_device(mtd, FL_READING);
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
case MTD_OPS_AUTO_OOB:
case MTD_OPS_RAW:
break;
default:
goto out;
}
if (!ops->datbuf)
ret = nand_do_read_oob(mtd, from, ops);
else
ret = nand_do_read_ops(mtd, from, ops);
out:
nand_release_device(mtd);
return ret;
}
/**
* nand_write_page_raw - [INTERN] raw page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
chip->write_buf(mtd, buf, mtd->writesize);
if (oob_required)
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
/**
* nand_write_page_raw_syndrome - [INTERN] raw page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*
* We need a special oob layout and handling even when ECC isn't checked.
*/
static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
uint8_t *oob = chip->oob_poi;
int steps, size;
for (steps = chip->ecc.steps; steps > 0; steps--) {
chip->write_buf(mtd, buf, eccsize);
buf += eccsize;
if (chip->ecc.prepad) {
chip->write_buf(mtd, oob, chip->ecc.prepad);
oob += chip->ecc.prepad;
}
chip->write_buf(mtd, oob, eccbytes);
oob += eccbytes;
if (chip->ecc.postpad) {
chip->write_buf(mtd, oob, chip->ecc.postpad);
oob += chip->ecc.postpad;
}
}
size = mtd->oobsize - (oob - chip->oob_poi);
if (size)
chip->write_buf(mtd, oob, size);
return 0;
}
/**
* nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*/
static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
uint32_t *eccpos = chip->ecc.layout->eccpos;
/* Software ECC calculation */
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
for (i = 0; i < chip->ecc.total; i++)
chip->oob_poi[eccpos[i]] = ecc_calc[i];
return chip->ecc.write_page_raw(mtd, chip, buf, 1);
}
/**
* nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*/
static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
uint32_t *eccpos = chip->ecc.layout->eccpos;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
chip->write_buf(mtd, p, eccsize);
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
}
for (i = 0; i < chip->ecc.total; i++)
chip->oob_poi[eccpos[i]] = ecc_calc[i];
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
/**
* nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write
* @mtd: mtd info structure
* @chip: nand chip info structure
* @offset: column address of subpage within the page
* @data_len: data length
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*/
static int nand_write_subpage_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint32_t offset,
uint32_t data_len, const uint8_t *buf,
int oob_required)
{
uint8_t *oob_buf = chip->oob_poi;
uint8_t *ecc_calc = chip->buffers->ecccalc;
int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes;
int ecc_steps = chip->ecc.steps;
uint32_t *eccpos = chip->ecc.layout->eccpos;
uint32_t start_step = offset / ecc_size;
uint32_t end_step = (offset + data_len - 1) / ecc_size;
int oob_bytes = mtd->oobsize / ecc_steps;
int step, i;
for (step = 0; step < ecc_steps; step++) {
/* configure controller for WRITE access */
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
/* write data (untouched subpages already masked by 0xFF) */
chip->write_buf(mtd, buf, ecc_size);
/* mask ECC of un-touched subpages by padding 0xFF */
if ((step < start_step) || (step > end_step))
memset(ecc_calc, 0xff, ecc_bytes);
else
chip->ecc.calculate(mtd, buf, ecc_calc);
/* mask OOB of un-touched subpages by padding 0xFF */
/* if oob_required, preserve OOB metadata of written subpage */
if (!oob_required || (step < start_step) || (step > end_step))
memset(oob_buf, 0xff, oob_bytes);
buf += ecc_size;
ecc_calc += ecc_bytes;
oob_buf += oob_bytes;
}
/* copy calculated ECC for whole page to chip->buffer->oob */
/* this include masked-value(0xFF) for unwritten subpages */
ecc_calc = chip->buffers->ecccalc;
for (i = 0; i < chip->ecc.total; i++)
chip->oob_poi[eccpos[i]] = ecc_calc[i];
/* write OOB buffer to NAND device */
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
/**
* nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*
* The hw generator calculates the error syndrome automatically. Therefore we
* need a special oob layout and handling.
*/
static int nand_write_page_syndrome(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
const uint8_t *p = buf;
uint8_t *oob = chip->oob_poi;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
chip->write_buf(mtd, p, eccsize);
if (chip->ecc.prepad) {
chip->write_buf(mtd, oob, chip->ecc.prepad);
oob += chip->ecc.prepad;
}
chip->ecc.calculate(mtd, p, oob);
chip->write_buf(mtd, oob, eccbytes);
oob += eccbytes;
if (chip->ecc.postpad) {
chip->write_buf(mtd, oob, chip->ecc.postpad);
oob += chip->ecc.postpad;
}
}
/* Calculate remaining oob bytes */
i = mtd->oobsize - (oob - chip->oob_poi);
if (i)
chip->write_buf(mtd, oob, i);
return 0;
}
/**
* nand_write_page - [REPLACEABLE] write one page
* @mtd: MTD device structure
* @chip: NAND chip descriptor
* @offset: address offset within the page
* @data_len: length of actual data to be written
* @buf: the data to write
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
* @cached: cached programming
* @raw: use _raw version of write_page
*/
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw)
{
int status, subpage;
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
chip->ecc.write_subpage)
subpage = offset || (data_len < mtd->writesize);
else
subpage = 0;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (unlikely(raw))
status = chip->ecc.write_page_raw(mtd, chip, buf,
oob_required);
else if (subpage)
status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
buf, oob_required);
else
status = chip->ecc.write_page(mtd, chip, buf, oob_required);
if (status < 0)
return status;
/*
* Cached progamming disabled for now. Not sure if it's worth the
* trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).
*/
cached = 0;
if (!cached || !NAND_HAS_CACHEPROG(chip)) {
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
/*
* See if operation failed and additional status checks are
* available.
*/
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
status = chip->errstat(mtd, chip, FL_WRITING, status,
page);
if (status & NAND_STATUS_FAIL)
return -EIO;
} else {
chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
}
return 0;
}
/**
* nand_fill_oob - [INTERN] Transfer client buffer to oob
* @mtd: MTD device structure
* @oob: oob data buffer
* @len: oob data write length
* @ops: oob ops structure
*/
static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
struct mtd_oob_ops *ops)
{
struct nand_chip *chip = mtd->priv;
/*
* Initialise to all 0xFF, to avoid the possibility of left over OOB
* data from a previous OOB read.
*/
memset(chip->oob_poi, 0xff, mtd->oobsize);
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
case MTD_OPS_RAW:
memcpy(chip->oob_poi + ops->ooboffs, oob, len);
return oob + len;
case MTD_OPS_AUTO_OOB: {
struct nand_oobfree *free = chip->ecc.layout->oobfree;
uint32_t boffs = 0, woffs = ops->ooboffs;
size_t bytes = 0;
for (; free->length && len; free++, len -= bytes) {
/* Write request not from offset 0? */
if (unlikely(woffs)) {
if (woffs >= free->length) {
woffs -= free->length;
continue;
}
boffs = free->offset + woffs;
bytes = min_t(size_t, len,
(free->length - woffs));
woffs = 0;
} else {
bytes = min_t(size_t, len, free->length);
boffs = free->offset;
}
memcpy(chip->oob_poi + boffs, oob, bytes);
oob += bytes;
}
return oob;
}
default:
BUG();
}
return NULL;
}
/**
* nand_do_write_ops - [INTERN] NAND write with ECC
* @mtd: MTD device structure
* @to: offset to write to
* @ops: oob operations description structure
*
* NAND write with ECC.
*/
int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
int chipnr, realpage, page, blockmask, column;
struct nand_chip *chip = mtd->priv;
uint32_t writelen = ops->len;
uint32_t oobwritelen = ops->ooblen;
uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?
mtd->oobavail : mtd->oobsize;
uint8_t *oob = ops->oobbuf;
uint8_t *buf = ops->datbuf;
int ret;
int oob_required = oob ? 1 : 0;
ops->retlen = 0;
if (!writelen)
return 0;
/* Reject writes, which are not page aligned */
if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
pr_notice("%s: attempt to write non page aligned data\n",
__func__);
return -EINVAL;
}
column = to & (mtd->writesize - 1);
chipnr = (int)(to >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
ret = -EIO;
goto err_out;
}
realpage = (int)(to >> chip->page_shift);
page = realpage & chip->pagemask;
blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
/* Invalidate the page cache, when we write to the cached page */
if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len))
chip->pagebuf = -1;
/* Don't allow multipage oob writes with offset */
if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
ret = -EINVAL;
goto err_out;
}
while (1) {
int bytes = mtd->writesize;
int cached = writelen > bytes && page != blockmask;
uint8_t *wbuf = buf;
int use_bufpoi;
int part_pagewr = (column || writelen < (mtd->writesize - 1));
if (part_pagewr)
use_bufpoi = 1;
else if (chip->options & NAND_USE_BOUNCE_BUFFER)
use_bufpoi = !virt_addr_valid(buf);
else
use_bufpoi = 0;
/* Partial page write?, or need to use bounce buffer */
if (use_bufpoi) {
pr_debug("%s: using write bounce buffer for buf@%p\n",
__func__, buf);
cached = 0;
if (part_pagewr)
bytes = min_t(int, bytes - column, writelen);
chip->pagebuf = -1;
memset(chip->buffers->databuf, 0xff, mtd->writesize);
memcpy(&chip->buffers->databuf[column], buf, bytes);
wbuf = chip->buffers->databuf;
}
if (unlikely(oob)) {
size_t len = min(oobwritelen, oobmaxlen);
oob = nand_fill_oob(mtd, oob, len, ops);
oobwritelen -= len;
} else {
/* We still need to erase leftover OOB data */
memset(chip->oob_poi, 0xff, mtd->oobsize);
}
ret = chip->write_page(mtd, chip, column, bytes, wbuf,
oob_required, page, cached,
(ops->mode == MTD_OPS_RAW));
if (ret)
break;
writelen -= bytes;
if (!writelen)
break;
column = 0;
buf += bytes;
realpage++;
page = realpage & chip->pagemask;
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
chip->select_chip(mtd, -1);
chip->select_chip(mtd, chipnr);
}
}
ops->retlen = ops->len - writelen;
if (unlikely(oob))
ops->oobretlen = ops->ooblen;
err_out:
chip->select_chip(mtd, -1);
return ret;
}
/**
* panic_nand_write - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure
* @to: offset to write to
* @len: number of bytes to write
* @retlen: pointer to variable to store the number of written bytes
* @buf: the data to write
*
* NAND write with ECC. Used when performing writes in interrupt context, this
* may for example be called by mtdoops when writing an oops while in panic.
*/
static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
struct mtd_oob_ops ops;
int ret;
/* Wait for the device to get ready */
panic_nand_wait(mtd, chip, 400);
/* Grab the device */
panic_nand_get_device(chip, mtd, FL_WRITING);
ops.len = len;
ops.datbuf = (uint8_t *)buf;
ops.oobbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_write_ops(mtd, to, &ops);
*retlen = ops.retlen;
return ret;
}
/**
* nand_write - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure
* @to: offset to write to
* @len: number of bytes to write
* @retlen: pointer to variable to store the number of written bytes
* @buf: the data to write
*
* NAND write with ECC.
*/
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf)
{
struct mtd_oob_ops ops;
int ret;
nand_get_device(mtd, FL_WRITING);
ops.len = len;
ops.datbuf = (uint8_t *)buf;
ops.oobbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_write_ops(mtd, to, &ops);
*retlen = ops.retlen;
nand_release_device(mtd);
return ret;
}
/**
* nand_do_write_oob - [MTD Interface] NAND write out-of-band
* @mtd: MTD device structure
* @to: offset to write to
* @ops: oob operation description structure
*
* NAND write out-of-band.
*/
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
int chipnr, page, status, len;
struct nand_chip *chip = mtd->priv;
pr_debug("%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int)to, (int)ops->ooblen);
if (ops->mode == MTD_OPS_AUTO_OOB)
len = chip->ecc.layout->oobavail;
else
len = mtd->oobsize;
/* Do not allow write past end of page */
if ((ops->ooboffs + ops->ooblen) > len) {
pr_debug("%s: attempt to write past end of page\n",
__func__);
return -EINVAL;
}
if (unlikely(ops->ooboffs >= len)) {
pr_debug("%s: attempt to start write outside oob\n",
__func__);
return -EINVAL;
}
/* Do not allow write past end of device */
if (unlikely(to >= mtd->size ||
ops->ooboffs + ops->ooblen >
((mtd->size >> chip->page_shift) -
(to >> chip->page_shift)) * len)) {
pr_debug("%s: attempt to write beyond end of device\n",
__func__);
return -EINVAL;
}
chipnr = (int)(to >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
/* Shift to get page */
page = (int)(to >> chip->page_shift);
/*
* Reset the chip. Some chips (like the Toshiba TC5832DC found in one
* of my DiskOnChip 2000 test units) will clear the whole data page too
* if we don't do this. I have no clue why, but I seem to have 'fixed'
* it in the doc2000 driver in August 1999. dwmw2.
*/
/*
* Nand onfi compatible devices may support different data interface
* modes like SDR, NVDDR and NVDDR2. Giving reset to device places the
* device in to power-up state and places the target in the SDR data
* interface mode. This will be the problem for devices configured for
* NVDDR modes. So, limiting the reset operation to Toshiba devices.
*/
if (chip->onfi_params.jedec_id == NAND_MFR_TOSHIBA)
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
chip->select_chip(mtd, -1);
return -EROFS;
}
/* Invalidate the page cache, if we write to the cached page */
if (page == chip->pagebuf)
chip->pagebuf = -1;
nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
if (ops->mode == MTD_OPS_RAW)
status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
else
status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
chip->select_chip(mtd, -1);
if (status)
return status;
ops->oobretlen = ops->ooblen;
return 0;
}
/**
* nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
* @mtd: MTD device structure
* @to: offset to write to
* @ops: oob operation description structure
*/
static int nand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
int ret = -ENOTSUPP;
ops->retlen = 0;
/* Do not allow writes past end of device */
if (ops->datbuf && (to + ops->len) > mtd->size) {
pr_debug("%s: attempt to write beyond end of device\n",
__func__);
return -EINVAL;
}
nand_get_device(mtd, FL_WRITING);
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
case MTD_OPS_AUTO_OOB:
case MTD_OPS_RAW:
break;
default:
goto out;
}
if (!ops->datbuf)
ret = nand_do_write_oob(mtd, to, ops);
else
ret = nand_do_write_ops(mtd, to, ops);
out:
nand_release_device(mtd);
return ret;
}
/**
* single_erase - [GENERIC] NAND standard block erase command function
* @mtd: MTD device structure
* @page: the page address of the block which will be erased
*
* Standard erase command for NAND chips. Returns NAND status.
*/
static int single_erase(struct mtd_info *mtd, int page)
{
struct nand_chip *chip = mtd->priv;
/* Send commands to erase a block */
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
return chip->waitfunc(mtd, chip);
}
/**
* nand_erase - [MTD Interface] erase block(s)
* @mtd: MTD device structure
* @instr: erase instruction
*
* Erase one ore more blocks.
*/
static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
{
return nand_erase_nand(mtd, instr, 0);
}
/**
* nand_erase_nand - [INTERN] erase block(s)
* @mtd: MTD device structure
* @instr: erase instruction
* @allowbbt: allow erasing the bbt area
*
* Erase one ore more blocks.
*/
int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt)
{
int page, status, pages_per_block, ret, chipnr;
struct nand_chip *chip = mtd->priv;
loff_t len;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
__func__, (unsigned long long)instr->addr,
(unsigned long long)instr->len);
if (check_offs_len(mtd, instr->addr, instr->len))
return -EINVAL;
/* Grab the lock and see if the device is available */
nand_get_device(mtd, FL_ERASING);
/* Shift to get first page */
page = (int)(instr->addr >> chip->page_shift);
chipnr = (int)(instr->addr >> chip->chip_shift);
/* Calculate pages in each block */
pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
/* Select the NAND device */
chip->select_chip(mtd, chipnr);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
pr_debug("%s: device is write protected!\n",
__func__);
instr->state = MTD_ERASE_FAILED;
goto erase_exit;
}
/* Loop through the pages */
len = instr->len;
instr->state = MTD_ERASING;
while (len) {
/* Check if we have a bad block, we do not erase bad blocks! */
if (nand_block_checkbad(mtd, ((loff_t) page) <<
chip->page_shift, 0, allowbbt)) {
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
__func__, page);
instr->state = MTD_ERASE_FAILED;
goto erase_exit;
}
/*
* Invalidate the page cache, if we erase the block which
* contains the current cached page.
*/
if (page <= chip->pagebuf && chip->pagebuf <
(page + pages_per_block))
chip->pagebuf = -1;
status = chip->erase(mtd, page & chip->pagemask);
/*
* See if operation failed and additional status checks are
* available
*/
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
status = chip->errstat(mtd, chip, FL_ERASING,
status, page);
/* See if block erase succeeded */
if (status & NAND_STATUS_FAIL) {
pr_debug("%s: failed erase, page 0x%08x\n",
__func__, page);
instr->state = MTD_ERASE_FAILED;
instr->fail_addr =
((loff_t)page << chip->page_shift);
goto erase_exit;
}
/* Increment page address and decrement length */
len -= (1ULL << chip->phys_erase_shift);
page += pages_per_block;
/* Check, if we cross a chip boundary */
if (len && !(page & chip->pagemask)) {
chipnr++;
chip->select_chip(mtd, -1);
chip->select_chip(mtd, chipnr);
}
}
instr->state = MTD_ERASE_DONE;
erase_exit:
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
/* Deselect and wake up anyone waiting on the device */
chip->select_chip(mtd, -1);
nand_release_device(mtd);
/* Do call back function */
if (!ret)
mtd_erase_callback(instr);
/* Return more or less happy */
return ret;
}
/**
* nand_sync - [MTD Interface] sync
* @mtd: MTD device structure
*
* Sync is actually a wait for chip ready function.
*/
static void nand_sync(struct mtd_info *mtd)
{
pr_debug("%s: called\n", __func__);
/* Grab the lock and see if the device is available */
nand_get_device(mtd, FL_SYNCING);
/* Release it and go back */
nand_release_device(mtd);
}
/**
* nand_block_isbad - [MTD Interface] Check if block at offset is bad
* @mtd: MTD device structure
* @offs: offset relative to mtd start
*/
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
{
return nand_block_checkbad(mtd, offs, 1, 0);
}
/**
* nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
* @mtd: MTD device structure
* @ofs: offset relative to mtd start
*/
static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
int ret;
ret = nand_block_isbad(mtd, ofs);
if (ret) {
/* If it was bad already, return success and do nothing */
if (ret > 0)
return 0;
return ret;
}
return nand_block_markbad_lowlevel(mtd, ofs);
}
/**
* nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
* @mtd: MTD device structure
* @chip: nand chip info structure
* @addr: feature address.
* @subfeature_param: the subfeature parameters, a four bytes array.
*/
static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param)
{
int status;
int i;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
chip->write_byte(mtd, subfeature_param[i]);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
/**
* nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
* @mtd: MTD device structure
* @chip: nand chip info structure
* @addr: feature address.
* @subfeature_param: the subfeature parameters, a four bytes array.
*/
static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param)
{
int i;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
/* clear the sub feature parameters */
memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
*subfeature_param++ = chip->read_byte(mtd);
return 0;
}
/**
* nand_suspend - [MTD Interface] Suspend the NAND flash
* @mtd: MTD device structure
*/
static int nand_suspend(struct mtd_info *mtd)
{
return nand_get_device(mtd, FL_PM_SUSPENDED);
}
/**
* nand_resume - [MTD Interface] Resume the NAND flash
* @mtd: MTD device structure
*/
static void nand_resume(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
if (chip->state == FL_PM_SUSPENDED)
nand_release_device(mtd);
else
pr_err("%s called for a chip which is not in suspended state\n",
__func__);
}
/**
* nand_shutdown - [MTD Interface] Finish the current NAND operation and
* prevent further operations
* @mtd: MTD device structure
*/
static void nand_shutdown(struct mtd_info *mtd)
{
nand_get_device(mtd, FL_SHUTDOWN);
}
/* Set default functions */
static void nand_set_defaults(struct nand_chip *chip, int busw)
{
/* check for proper chip_delay setup, set 20us if not */
if (!chip->chip_delay)
chip->chip_delay = 20;
/* check, if a user supplied command function given */
if (chip->cmdfunc == NULL)
chip->cmdfunc = nand_command;
/* check, if a user supplied wait function given */
if (chip->waitfunc == NULL)
chip->waitfunc = nand_wait;
if (!chip->select_chip)
chip->select_chip = nand_select_chip;
/* set for ONFI nand */
if (!chip->onfi_set_features)
chip->onfi_set_features = nand_onfi_set_features;
if (!chip->onfi_get_features)
chip->onfi_get_features = nand_onfi_get_features;
/* If called twice, pointers that depend on busw may need to be reset */
if (!chip->read_byte || chip->read_byte == nand_read_byte)
chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
if (!chip->read_word)
chip->read_word = nand_read_word;
if (!chip->block_bad)
chip->block_bad = nand_block_bad;
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
if (!chip->write_buf || chip->write_buf == nand_write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
if (!chip->write_byte || chip->write_byte == nand_write_byte)
chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
if (!chip->read_buf || chip->read_buf == nand_read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
spin_lock_init(&chip->controller->lock);
init_waitqueue_head(&chip->controller->wq);
}
}
/* Sanitize ONFI strings so we can safely print them */
static void sanitize_string(uint8_t *s, size_t len)
{
ssize_t i;
/* Null terminate */
s[len - 1] = 0;
/* Remove non printable chars */
for (i = 0; i < len - 1; i++) {
if (s[i] < ' ' || s[i] > 127)
s[i] = '?';
}
/* Remove trailing spaces */
strim(s);
}
static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
{
int i;
while (len--) {
crc ^= *p++ << 8;
for (i = 0; i < 8; i++)
crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
}
return crc;
}
/* Parse the Extended Parameter Page. */
static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
struct nand_chip *chip, struct nand_onfi_params *p)
{
struct onfi_ext_param_page *ep;
struct onfi_ext_section *s;
struct onfi_ext_ecc_info *ecc;
uint8_t *cursor;
int ret = -EINVAL;
int len;
int i;
len = le16_to_cpu(p->ext_param_page_length) * 16;
ep = kmalloc(len, GFP_KERNEL);
if (!ep)
return -ENOMEM;
/* Send our own NAND_CMD_PARAM. */
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
/* Use the Change Read Column command to skip the ONFI param pages. */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
sizeof(*p) * p->num_of_param_pages , -1);
/* Read out the Extended Parameter Page. */
chip->read_buf(mtd, (uint8_t *)ep, len);
if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
!= le16_to_cpu(ep->crc))) {
pr_debug("fail in the CRC.\n");
goto ext_out;
}
/*
* Check the signature.
* Do not strictly follow the ONFI spec, maybe changed in future.
*/
if (strncmp(ep->sig, "EPPS", 4)) {
pr_debug("The signature is invalid.\n");
goto ext_out;
}
/* find the ECC section. */
cursor = (uint8_t *)(ep + 1);
for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
s = ep->sections + i;
if (s->type == ONFI_SECTION_TYPE_2)
break;
cursor += s->length * 16;
}
if (i == ONFI_EXT_SECTION_MAX) {
pr_debug("We can not find the ECC section.\n");
goto ext_out;
}
/* get the info we want. */
ecc = (struct onfi_ext_ecc_info *)cursor;
if (!ecc->codeword_size) {
pr_debug("Invalid codeword size\n");
goto ext_out;
}
chip->ecc_strength_ds = ecc->ecc_bits;
chip->ecc_step_ds = 1 << ecc->codeword_size;
ret = 0;
ext_out:
kfree(ep);
return ret;
}
static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
{
struct nand_chip *chip = mtd->priv;
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
feature);
}
/*
* Configure chip properties from Micron vendor-specific ONFI table
*/
static void nand_onfi_detect_micron(struct nand_chip *chip,
struct nand_onfi_params *p)
{
struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
if (le16_to_cpu(p->vendor_revision) < 1)
return;
chip->read_retries = micron->read_retry_options;
chip->setup_read_retry = nand_setup_read_retry_micron;
}
/*
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
*/
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
int *busw)
{
struct nand_onfi_params *p = &chip->onfi_params;
int i, j;
int val;
/* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */
if (chip->options & NAND_BUSWIDTH_16) {
pr_err("Trying ONFI probe in 16 bits mode, aborting !\n");
return 0;
}
/* Try ONFI for unknown chip or LP */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
return 0;
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
for (i = 0; i < 3; i++) {
for (j = 0; j < sizeof(*p); j++)
((uint8_t *)p)[j] = chip->read_byte(mtd);
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
le16_to_cpu(p->crc)) {
break;
}
}
if (i == 3) {
pr_err("Could not find valid ONFI parameter page; aborting\n");
return 0;
}
/* Check version */
val = le16_to_cpu(p->revision);
if (val & (1 << 5))
chip->onfi_version = 23;
else if (val & (1 << 4))
chip->onfi_version = 22;
else if (val & (1 << 3))
chip->onfi_version = 21;
else if (val & (1 << 2))
chip->onfi_version = 20;
else if (val & (1 << 1))
chip->onfi_version = 10;
if (!chip->onfi_version) {
pr_info("unsupported ONFI version: %d\n", val);
return 0;
}
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
if (!mtd->name)
mtd->name = p->model;
mtd->writesize = le32_to_cpu(p->byte_per_page);
/*
* pages_per_block and blocks_per_lun may not be a power-of-2 size
* (don't ask me who thought of this...). MTD assumes that these
* dimensions will be power-of-2, so just truncate the remaining area.
*/
mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
mtd->erasesize *= mtd->writesize;
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
/* See erasesize comment */
chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
chip->bits_per_cell = p->bits_per_cell;
if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
*busw = NAND_BUSWIDTH_16;
else
*busw = 0;
if (p->ecc_bits != 0xff) {
chip->ecc_strength_ds = p->ecc_bits;
chip->ecc_step_ds = 512;
} else if (chip->onfi_version >= 21 &&
(onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
/*
* The nand_flash_detect_ext_param_page() uses the
* Change Read Column command which maybe not supported
* by the chip->cmdfunc. So try to update the chip->cmdfunc
* now. We do not replace user supplied command function.
*/
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
/* The Extended Parameter Page is supported since ONFI 2.1. */
if (nand_flash_detect_ext_param_page(mtd, chip, p))
pr_warn("Failed to detect ONFI extended param page\n");
} else {
pr_warn("Could not retrieve ONFI ECC requirements\n");
}
if (p->jedec_id == NAND_MFR_MICRON)
nand_onfi_detect_micron(chip, p);
return 1;
}
/*
* Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
*/
static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
int *busw)
{
struct nand_jedec_params *p = &chip->jedec_params;
struct jedec_ecc_info *ecc;
int val;
int i, j;
/* Try JEDEC for unknown chip or LP */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' ||
chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' ||
chip->read_byte(mtd) != 'C')
return 0;
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
for (i = 0; i < 3; i++) {
for (j = 0; j < sizeof(*p); j++)
((uint8_t *)p)[j] = chip->read_byte(mtd);
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
le16_to_cpu(p->crc))
break;
}
if (i == 3) {
pr_err("Could not find valid JEDEC parameter page; aborting\n");
return 0;
}
/* Check version */
val = le16_to_cpu(p->revision);
if (val & (1 << 2))
chip->jedec_version = 10;
else if (val & (1 << 1))
chip->jedec_version = 1; /* vendor specific version */
if (!chip->jedec_version) {
pr_info("unsupported JEDEC version: %d\n", val);
return 0;
}
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
if (!mtd->name)
mtd->name = p->model;
mtd->writesize = le32_to_cpu(p->byte_per_page);
/* Please reference to the comment for nand_flash_detect_onfi. */
mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
mtd->erasesize *= mtd->writesize;
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
/* Please reference to the comment for nand_flash_detect_onfi. */
chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
chip->bits_per_cell = p->bits_per_cell;
if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
*busw = NAND_BUSWIDTH_16;
else
*busw = 0;
/* ECC info */
ecc = &p->ecc_info[0];
if (ecc->codeword_size >= 9) {
chip->ecc_strength_ds = ecc->ecc_bits;
chip->ecc_step_ds = 1 << ecc->codeword_size;
} else {
pr_warn("Invalid codeword size\n");
}
return 1;
}
/*
* nand_id_has_period - Check if an ID string has a given wraparound period
* @id_data: the ID string
* @arrlen: the length of the @id_data array
* @period: the period of repitition
*
* Check if an ID string is repeated within a given sequence of bytes at
* specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
* period of 3). This is a helper function for nand_id_len(). Returns non-zero
* if the repetition has a period of @period; otherwise, returns zero.
*/
static int nand_id_has_period(u8 *id_data, int arrlen, int period)
{
int i, j;
for (i = 0; i < period; i++)
for (j = i + period; j < arrlen; j += period)
if (id_data[i] != id_data[j])
return 0;
return 1;
}
/*
* nand_id_len - Get the length of an ID string returned by CMD_READID
* @id_data: the ID string
* @arrlen: the length of the @id_data array
* Returns the length of the ID string, according to known wraparound/trailing
* zero patterns. If no pattern exists, returns the length of the array.
*/
static int nand_id_len(u8 *id_data, int arrlen)
{
int last_nonzero, period;
/* Find last non-zero byte */
for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
if (id_data[last_nonzero])
break;
/* All zeros */
if (last_nonzero < 0)
return 0;
/* Calculate wraparound period */
for (period = 1; period < arrlen; period++)
if (nand_id_has_period(id_data, arrlen, period))
break;
/* There's a repeated pattern */
if (period < arrlen)
return period;
/* There are trailing zeros */
if (last_nonzero < arrlen - 1)
return last_nonzero + 1;
/* No pattern detected */
return arrlen;
}
/* Extract the bits of per cell from the 3rd byte of the extended ID */
static int nand_get_bits_per_cell(u8 cellinfo)
{
int bits;
bits = cellinfo & NAND_CI_CELLTYPE_MSK;
bits >>= NAND_CI_CELLTYPE_SHIFT;
return bits + 1;
}
/*
* Many new NAND share similar device ID codes, which represent the size of the
* chip. The rest of the parameters must be decoded according to generic or
* manufacturer-specific "extended ID" decoding patterns.
*/
static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
u8 id_data[8], int *busw)
{
int extid, id_len;
/* The 3rd id byte holds MLC / multichip data */
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
/* The 4th id byte is the important one */
extid = id_data[3];
id_len = nand_id_len(id_data, 8);
/*
* Field definitions are in the following datasheets:
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
* Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
*
* Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
* ID to decide what to do.
*/
if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
!nand_is_slc(chip) && id_data[5] != 0x00) {
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
case 1:
mtd->oobsize = 128;
break;
case 2:
mtd->oobsize = 218;
break;
case 3:
mtd->oobsize = 400;
break;
case 4:
mtd->oobsize = 436;
break;
case 5:
mtd->oobsize = 512;
break;
case 6:
mtd->oobsize = 640;
break;
case 7:
default: /* Other cases are "reserved" (unknown) */
mtd->oobsize = 1024;
break;
}
extid >>= 2;
/* Calc blocksize */
mtd->erasesize = (128 * 1024) <<
(((extid >> 1) & 0x04) | (extid & 0x03));
*busw = 0;
} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
!nand_is_slc(chip)) {
unsigned int tmp;
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
case 0:
mtd->oobsize = 128;
break;
case 1:
mtd->oobsize = 224;
break;
case 2:
mtd->oobsize = 448;
break;
case 3:
mtd->oobsize = 64;
break;
case 4:
mtd->oobsize = 32;
break;
case 5:
mtd->oobsize = 16;
break;
default:
mtd->oobsize = 640;
break;
}
extid >>= 2;
/* Calc blocksize */
tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
if (tmp < 0x03)
mtd->erasesize = (128 * 1024) << tmp;
else if (tmp == 0x03)
mtd->erasesize = 768 * 1024;
else
mtd->erasesize = (64 * 1024) << tmp;
*busw = 0;
} else {
/* Calc pagesize */
mtd->writesize = 1024 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
mtd->oobsize = (8 << (extid & 0x01)) *
(mtd->writesize >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB */
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information */
*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
/*
* Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
* 512B page. For Toshiba SLC, we decode the 5th/6th byte as
* follows:
* - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
* 110b -> 24nm
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
*/
if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
nand_is_slc(chip) &&
(id_data[5] & 0x7) == 0x6 /* 24nm */ &&
!(id_data[4] & 0x80) /* !BENAND */) {
mtd->oobsize = 32 * mtd->writesize >> 9;
}
}
}
/*
* Old devices have chip data hardcoded in the device ID table. nand_decode_id
* decodes a matching ID table entry and assigns the MTD size parameters for
* the chip.
*/
static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_flash_dev *type, u8 id_data[8],
int *busw)
{
int maf_id = id_data[0];
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
*busw = type->options & NAND_BUSWIDTH_16;
/* All legacy ID NAND are small-page, SLC */
chip->bits_per_cell = 1;
/*
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
* some Spansion chips have erasesize that conflicts with size
* listed in nand_ids table.
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
*/
if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00
&& id_data[6] == 0x00 && id_data[7] == 0x00
&& mtd->writesize == 512) {
mtd->erasesize = 128 * 1024;
mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
}
}
/*
* Set the bad block marker/indicator (BBM/BBI) patterns according to some
* heuristic patterns using various detected parameters (e.g., manufacturer,
* page size, cell-type information).
*/
static void nand_decode_bbm_options(struct mtd_info *mtd,
struct nand_chip *chip, u8 id_data[8])
{
int maf_id = id_data[0];
/* Set the bad block position */
if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
else
chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
/*
* Bad block marker is stored in the last page of each block on Samsung
* and Hynix MLC devices; stored in first two pages of each block on
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
* AMD/Spansion, and Macronix. All others scan only the first page.
*/
if (!nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
else if ((nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX ||
maf_id == NAND_MFR_TOSHIBA ||
maf_id == NAND_MFR_AMD ||
maf_id == NAND_MFR_MACRONIX)) ||
(mtd->writesize == 2048 &&
maf_id == NAND_MFR_MICRON))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
}
static inline bool is_full_id_nand(struct nand_flash_dev *type)
{
return type->id_len;
}
static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_flash_dev *type, u8 *id_data, int *busw)
{
if (!strncmp(type->id, id_data, type->id_len)) {
mtd->writesize = type->pagesize;
mtd->erasesize = type->erasesize;
mtd->oobsize = type->oobsize;
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
chip->chipsize = (uint64_t)type->chipsize << 20;
chip->options |= type->options;
chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
chip->ecc_step_ds = NAND_ECC_STEP(type);
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;
*busw = type->options & NAND_BUSWIDTH_16;
if (!mtd->name)
mtd->name = type->name;
return true;
}
return false;
}
/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
struct nand_chip *chip,
int *maf_id, int *dev_id,
struct nand_flash_dev *type)
{
int busw;
int i, maf_idx;
u8 id_data[8];
/* Select the device */
chip->select_chip(mtd, 0);
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* after power-up.
*/
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
*maf_id = chip->read_byte(mtd);
*dev_id = chip->read_byte(mtd);
/*
* Try again to make sure, as some systems the bus-hold or other
* interface concerns can cause random data which looks like a
* possibly credible NAND flash to appear. If the two results do
* not match, ignore the device completely.
*/
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read entire ID string */
for (i = 0; i < 8; i++)
id_data[i] = chip->read_byte(mtd);
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
*maf_id, *dev_id, id_data[0], id_data[1]);
return ERR_PTR(-ENODEV);
}
if (!type)
type = nand_flash_ids;
for (; type->name != NULL; type++) {
if (is_full_id_nand(type)) {
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
goto ident_done;
} else if (*dev_id == type->dev_id) {
break;
}
}
chip->onfi_version = 0;
if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
if (nand_flash_detect_onfi(mtd, chip, &busw))
goto ident_done;
/* Check if the chip is JEDEC compliant */
if (nand_flash_detect_jedec(mtd, chip, &busw))
goto ident_done;
}
if (!type->name)
return ERR_PTR(-ENODEV);
if (!mtd->name)
mtd->name = type->name;
chip->chipsize = (uint64_t)type->chipsize << 20;
if (!type->pagesize && chip->init_size) {
/* Set the pagesize, oobsize, erasesize by the driver */
busw = chip->init_size(mtd, chip, id_data);
} else if (!type->pagesize) {
/* Decode parameters from extended ID */
nand_decode_ext_id(mtd, chip, id_data, &busw);
} else {
nand_decode_id(mtd, chip, type, id_data, &busw);
}
/* Get chip options */
chip->options |= type->options;
/*
* Check if chip is not a Samsung device. Do not clear the
* options for chips which do not have an extended id.
*/
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
ident_done:
/* Try to identify manufacturer */
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
if (nand_manuf_ids[maf_idx].id == *maf_id)
break;
}
if (chip->options & NAND_BUSWIDTH_AUTO) {
WARN_ON(chip->options & NAND_BUSWIDTH_16);
chip->options |= busw;
nand_set_defaults(chip, busw);
} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
/*
* Check, if buswidth is correct. Hardware drivers should set
* chip correct!
*/
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
*maf_id, *dev_id);
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
pr_warn("bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
return ERR_PTR(-EINVAL);
}
nand_decode_bbm_options(mtd, chip, id_data);
/* Calculate the address shift from the page size */
chip->page_shift = ffs(mtd->writesize) - 1;
/* Convert chipsize to number of pages per chip -1 */
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
chip->bbt_erase_shift = chip->phys_erase_shift =
ffs(mtd->erasesize) - 1;
if (chip->chipsize & 0xffffffff)
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
else {
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
chip->chip_shift += 32 - 1;
}
chip->badblockbits = 8;
chip->erase = single_erase;
/* Do not replace user supplied command function! */
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
if (*maf_id == NAND_MFR_MICRON) nandchip_micron_init(mtd, *dev_id);
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
*maf_id, *dev_id);
if (chip->onfi_version)
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
chip->onfi_params.model);
else if (chip->jedec_version)
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
chip->jedec_params.model);
else
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
type->name);
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
return type;
}
/**
* nand_scan_ident - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
* @maxchips: number of chips to scan for
* @table: alternative NAND ID table
*
* This is the first phase of the normal nand_scan() function. It reads the
* flash ID and sets up MTD fields accordingly.
*
* The mtd->owner field must be set to the module of the caller.
*/
int nand_scan_ident(struct mtd_info *mtd, int maxchips,
struct nand_flash_dev *table)
{
int i, nand_maf_id, nand_dev_id;
struct nand_chip *chip = mtd->priv;
struct nand_flash_dev *type;
/* Set the default functions */
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
/* Read the flash type */
type = nand_get_flash_type(mtd, chip, &nand_maf_id,
&nand_dev_id, table);
if (IS_ERR(type)) {
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
pr_warn("No NAND device found\n");
chip->select_chip(mtd, -1);
return PTR_ERR(type);
}
chip->select_chip(mtd, -1);
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
/* See comment in nand_get_flash_type for reset */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
if (nand_maf_id != chip->read_byte(mtd) ||
nand_dev_id != chip->read_byte(mtd)) {
chip->select_chip(mtd, -1);
break;
}
chip->select_chip(mtd, -1);
}
if (i > 1)
pr_info("%d chips detected\n", i);
/* Store the number of chips and calc total size for mtd */
chip->numchips = i;
mtd->size = i * chip->chipsize;
return 0;
}
EXPORT_SYMBOL(nand_scan_ident);
/*
* Check if the chip configuration meet the datasheet requirements.
* If our configuration corrects A bits per B bytes and the minimum
* required correction level is X bits per Y bytes, then we must ensure
* both of the following are true:
*
* (1) A / B >= X / Y
* (2) A >= X
*
* Requirement (1) ensures we can correct for the required bitflip density.
* Requirement (2) ensures we can correct even when all bitflips are clumped
* in the same sector.
*/
static bool nand_ecc_strength_good(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct nand_ecc_ctrl *ecc = &chip->ecc;
int corr, ds_corr;
if (ecc->size == 0 || chip->ecc_step_ds == 0)
/* Not enough information */
return true;
/*
* We get the number of corrected bits per page to compare
* the correction density.
*/
corr = (mtd->writesize * ecc->strength) / ecc->size;
ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds;
return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
}
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
*
* This is the second phase of the normal nand_scan() function. It fills out
* all the uninitialized function pointers with the defaults and scans for a
* bad block table if appropriate.
*/
int nand_scan_tail(struct mtd_info *mtd)
{
int i;
struct nand_chip *chip = mtd->priv;
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct nand_buffers *nbuf;
/* New bad blocks should be marked in OOB, flash-based BBT, or both */
BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
!(chip->bbt_options & NAND_BBT_USE_FLASH));
if (!(chip->options & NAND_OWN_BUFFERS)) {
nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
+ mtd->oobsize * 3, GFP_KERNEL);
if (!nbuf)
return -ENOMEM;
nbuf->ecccalc = (uint8_t *)(nbuf + 1);
nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
nbuf->databuf = nbuf->ecccode + mtd->oobsize;
chip->buffers = nbuf;
} else {
if (!chip->buffers)
return -ENOMEM;
}
/* Set the internal oob buffer location, just after the page data */
chip->oob_poi = chip->buffers->databuf + mtd->writesize;
/*
* If no default placement scheme is given, select an appropriate one.
*/
if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
switch (mtd->oobsize) {
case 8:
ecc->layout = &nand_oob_8;
break;
case 16:
ecc->layout = &nand_oob_16;
break;
case 64:
ecc->layout = &nand_oob_64;
break;
case 128:
ecc->layout = &nand_oob_128;
break;
default:
pr_warn("No oob scheme defined for oobsize %d\n",
mtd->oobsize);
BUG();
}
}
if (!chip->write_page)
chip->write_page = nand_write_page;
/*
* Check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
*/
switch (ecc->mode) {
case NAND_ECC_HW_OOB_FIRST:
/* Similar to NAND_ECC_HW, but a separate read_page handle */
if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
pr_warn("No ECC functions supplied; hardware ECC not possible\n");
BUG();
}
if (!ecc->read_page)
ecc->read_page = nand_read_page_hwecc_oob_first;
case NAND_ECC_HW:
/* Use standard hwecc read page function? */
if (!ecc->read_page)
ecc->read_page = nand_read_page_hwecc;
if (!ecc->write_page)
ecc->write_page = nand_write_page_hwecc;
if (!ecc->read_page_raw)
ecc->read_page_raw = nand_read_page_raw;
if (!ecc->write_page_raw)
ecc->write_page_raw = nand_write_page_raw;
if (!ecc->read_oob)
ecc->read_oob = nand_read_oob_std;
if (!ecc->write_oob)
ecc->write_oob = nand_write_oob_std;
if (!ecc->read_subpage)
ecc->read_subpage = nand_read_subpage;
if (!ecc->write_subpage)
ecc->write_subpage = nand_write_subpage_hwecc;
case NAND_ECC_HW_SYNDROME:
if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
(!ecc->read_page ||
ecc->read_page == nand_read_page_hwecc ||
!ecc->write_page ||
ecc->write_page == nand_write_page_hwecc)) {
pr_warn("No ECC functions supplied; hardware ECC not possible\n");
BUG();
}
/* Use standard syndrome read/write page function? */
if (!ecc->read_page)
ecc->read_page = nand_read_page_syndrome;
if (!ecc->write_page)
ecc->write_page = nand_write_page_syndrome;
if (!ecc->read_page_raw)
ecc->read_page_raw = nand_read_page_raw_syndrome;
if (!ecc->write_page_raw)
ecc->write_page_raw = nand_write_page_raw_syndrome;
if (!ecc->read_oob)
ecc->read_oob = nand_read_oob_syndrome;
if (!ecc->write_oob)
ecc->write_oob = nand_write_oob_syndrome;
if (mtd->writesize >= ecc->size) {
if (!ecc->strength) {
pr_warn("Driver must set ecc.strength when using hardware ECC\n");
BUG();
}
break;
}
pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
ecc->size, mtd->writesize);
ecc->mode = NAND_ECC_SOFT;
case NAND_ECC_SOFT:
ecc->calculate = nand_calculate_ecc;
ecc->correct = nand_correct_data;
ecc->read_page = nand_read_page_swecc;
ecc->read_subpage = nand_read_subpage;
ecc->write_page = nand_write_page_swecc;
ecc->read_page_raw = nand_read_page_raw;
ecc->write_page_raw = nand_write_page_raw;
ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std;
if (!ecc->size)
ecc->size = 256;
ecc->bytes = 3;
ecc->strength = 1;
break;
case NAND_ECC_SOFT_BCH:
if (!mtd_nand_has_bch()) {
pr_warn("CONFIG_MTD_NAND_ECC_BCH not enabled\n");
BUG();
}
ecc->calculate = nand_bch_calculate_ecc;
ecc->correct = nand_bch_correct_data;
ecc->read_page = nand_read_page_swecc;
ecc->read_subpage = nand_read_subpage;
ecc->write_page = nand_write_page_swecc;
ecc->read_page_raw = nand_read_page_raw;
ecc->write_page_raw = nand_write_page_raw;
ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std;
/*
* Board driver should supply ecc.size and ecc.strength values
* to select how many bits are correctable. Otherwise, default
* to 4 bits for large page devices.
*/
if (!ecc->size && (mtd->oobsize >= 64)) {
ecc->size = 512;
ecc->strength = 4;
}
/* See nand_bch_init() for details. */
ecc->bytes = DIV_ROUND_UP(
ecc->strength * fls(8 * ecc->size), 8);
ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
&ecc->layout);
if (!ecc->priv) {
pr_warn("BCH ECC initialization failed!\n");
BUG();
}
break;
case NAND_ECC_NONE:
pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
ecc->read_page = nand_read_page_raw;
ecc->write_page = nand_write_page_raw;
ecc->read_oob = nand_read_oob_std;
ecc->read_page_raw = nand_read_page_raw;
ecc->write_page_raw = nand_write_page_raw;
ecc->write_oob = nand_write_oob_std;
ecc->size = mtd->writesize;
ecc->bytes = 0;
ecc->strength = 0;
break;
default:
pr_warn("Invalid NAND_ECC_MODE %d\n", ecc->mode);
BUG();
}
/* For many systems, the standard OOB write also works for raw */
if (!ecc->read_oob_raw)
ecc->read_oob_raw = ecc->read_oob;
if (!ecc->write_oob_raw)
ecc->write_oob_raw = ecc->write_oob;
/*
* The number of bytes available for a client to place data into
* the out of band area.
*/
ecc->layout->oobavail = 0;
for (i = 0; ecc->layout->oobfree[i].length
&& i < ARRAY_SIZE(ecc->layout->oobfree); i++)
ecc->layout->oobavail += ecc->layout->oobfree[i].length;
mtd->oobavail = ecc->layout->oobavail;
/* ECC sanity check: warn if it's too weak */
if (!nand_ecc_strength_good(mtd))
pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
mtd->name);
/*
* Set the number of read / write steps for one page depending on ECC
* mode.
*/
ecc->steps = mtd->writesize / ecc->size;
if (ecc->steps * ecc->size != mtd->writesize) {
pr_warn("Invalid ECC parameters\n");
BUG();
}
ecc->total = ecc->steps * ecc->bytes;
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
switch (ecc->steps) {
case 2:
mtd->subpage_sft = 1;
break;
case 4:
case 8:
case 16:
mtd->subpage_sft = 2;
break;
}
}
chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
/* Initialize state */
chip->state = FL_READY;
/* Invalidate the pagebuffer reference */
chip->pagebuf = -1;
/* Large page NAND with SOFT_ECC should support subpage reads */
switch (ecc->mode) {
case NAND_ECC_SOFT:
case NAND_ECC_SOFT_BCH:
if (chip->page_shift > 9)
chip->options |= NAND_SUBPAGE_READ;
break;
default:
break;
}
/* Fill in remaining MTD driver data */
mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
MTD_CAP_NANDFLASH;
mtd->_erase = nand_erase;
mtd->_point = NULL;
mtd->_unpoint = NULL;
mtd->_read = nand_read;
mtd->_write = nand_write;
mtd->_panic_write = panic_nand_write;
mtd->_read_oob = nand_read_oob;
mtd->_write_oob = nand_write_oob;
mtd->_sync = nand_sync;
mtd->_lock = NULL;
mtd->_unlock = NULL;
mtd->_suspend = nand_suspend;
mtd->_resume = nand_resume;
mtd->_reboot = nand_shutdown;
mtd->_block_isreserved = nand_block_isreserved;
mtd->_block_isbad = nand_block_isbad;
mtd->_block_markbad = nand_block_markbad;
mtd->writebufsize = mtd->writesize;
/* propagate ecc info to mtd_info */
mtd->ecclayout = ecc->layout;
mtd->ecc_strength = ecc->strength;
mtd->ecc_step_size = ecc->size;
/*
* Initialize bitflip_threshold to its default prior scan_bbt() call.
* scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
* properly set.
*/
if (!mtd->bitflip_threshold)
mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
/* Check, if we should skip the bad block table scan */
if (chip->options & NAND_SKIP_BBTSCAN)
return 0;
/* Build bad block table */
return chip->scan_bbt(mtd);
}
EXPORT_SYMBOL(nand_scan_tail);
/*
* is_module_text_address() isn't exported, and it's mostly a pointless
* test if this is a module _anyway_ -- they'd have to try _really_ hard
* to call us from in-kernel code if the core NAND support is modular.
*/
#ifdef MODULE
#define caller_is_module() (1)
#else
#define caller_is_module() \
is_module_text_address((unsigned long)__builtin_return_address(0))
#endif
/**
* nand_scan - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
* @maxchips: number of chips to scan for
*
* This fills out all the uninitialized function pointers with the defaults.
* The flash ID is read and the mtd/chip structures are filled with the
* appropriate values. The mtd->owner field must be set to the module of the
* caller.
*/
int nand_scan(struct mtd_info *mtd, int maxchips)
{
int ret;
/* Many callers got this wrong, so check for it for a while... */
if (!mtd->owner && caller_is_module()) {
pr_crit("%s called with NULL mtd->owner!\n", __func__);
BUG();
}
ret = nand_scan_ident(mtd, maxchips, NULL);
if (!ret)
ret = nand_scan_tail(mtd);
return ret;
}
EXPORT_SYMBOL(nand_scan);
/**
* nand_release - [NAND Interface] Free resources held by the NAND device
* @mtd: MTD device structure
*/
void nand_release(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
mtd_device_unregister(mtd);
/* Free bad block table memory */
kfree(chip->bbt);
if (!(chip->options & NAND_OWN_BUFFERS))
kfree(chip->buffers);
/* Free bad block descriptor memory */
if (chip->badblock_pattern && chip->badblock_pattern->options
& NAND_BBT_DYNAMICSTRUCT)
kfree(chip->badblock_pattern);
}
EXPORT_SYMBOL_GPL(nand_release);
static int __init nand_base_init(void)
{
led_trigger_register_simple("nand-disk", &nand_led_trigger);
return 0;
}
static void __exit nand_base_exit(void)
{
led_trigger_unregister_simple(nand_led_trigger);
}
module_init(nand_base_init);
module_exit(nand_base_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steven J. Hill ");
MODULE_AUTHOR("Thomas Gleixner ");
MODULE_DESCRIPTION("Generic NAND flash driver code");
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/mtd/nand/nandchip-micron.c 0000664 0000000 0000000 00000012474 12703306510 0030544 0 ustar 00root root 0000000 0000000 #include
#include
#include
#include
#include
#include "nand.h"
#define MICRON_SETFEATURE_ARRAYOP 0x90
#define MICRON_SETFEATURE_ARRAYOP_NORMAL ((uint8_t[]){0,0,0,0})
#define MICRON_SETFEATURE_ARRAYOP_OTP ((uint8_t[]){1,0,0,0})
#define MICRON_SETFEATURE_ARRAYOP_OTPPROTECT ((uint8_t[]){3,0,0,0})
#define MICRON_NUM_OTP_FIRSTPAGE 2
#define MICRON_NUM_OTP_PAGES 30
static int mt29f_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
size_t len)
{
int i;
if (len < MICRON_NUM_OTP_PAGES * sizeof(*buf))
return -ENOSPC;
for (i = 0; i < MICRON_NUM_OTP_PAGES; ++i) {
buf->start = i * mtd->writesize;
buf->length = mtd->writesize;
/*
* XXX: don't know how to find out, if a page is locked
*/
buf->locked = 0;
buf++;
}
return MICRON_NUM_OTP_PAGES * sizeof(*buf);
}
static int mt29f_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
size_t len, size_t *retlen, uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
struct mtd_oob_ops ops;
int ret;
u8 get_feature,i;
/* Valid pages in otp are 02h-1Fh. */
if (from > MICRON_NUM_OTP_PAGES << chip->page_shift)
return -EIO;
if (from + len > MICRON_NUM_OTP_PAGES << chip->page_shift)
len = (MICRON_NUM_OTP_PAGES << chip->page_shift) - from;
from += MICRON_NUM_OTP_FIRSTPAGE << chip->page_shift;
/* XXX: FL_READING? */
nand_get_device(mtd, FL_READING);
chip->select_chip(mtd, 0);
ret = chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,MICRON_SETFEATURE_ARRAYOP_OTP);
ndelay(1000);
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, MICRON_SETFEATURE_ARRAYOP, -1);
get_feature = readb(chip->IO_ADDR_R);
pr_debug("Feature on: 0x%02x\n",get_feature);
if (ret)
goto out;
ops.len = len;
ops.datbuf = buf;
ops.oobbuf = NULL;
ops.mode = 0;
/*
* XXX: some things in nand_do_read_ops might be wrong for OTP. e.g.
* chip->pagemask, chip->pagebuf handling, caching
*/
ret = nand_do_read_ops(mtd, from, &ops);
*retlen = ops.retlen;
/* nand_do_read_ops deselects the chip so reselect here */
chip->select_chip(mtd, 0);
chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,MICRON_SETFEATURE_ARRAYOP_NORMAL);
ndelay(1000);
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, MICRON_SETFEATURE_ARRAYOP, -1);
get_feature = readb(chip->IO_ADDR_R);
pr_debug("Feature off: 0x%02x\n",get_feature);
out:
nand_release_device(mtd);
return ret;
}
static int mt29f_write_user_prot_reg(struct mtd_info *mtd, loff_t to,
size_t len, size_t *retlen, uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
struct mtd_oob_ops ops;
int ret;
pr_debug("mt29f_write_user_prot_reg start!!!");
/* Valid pages in otp are 02h-1Fh. */
if (to > MICRON_NUM_OTP_PAGES << chip->page_shift)
return -EIO;
if (to + len > MICRON_NUM_OTP_PAGES << chip->page_shift)
len = (MICRON_NUM_OTP_PAGES << chip->page_shift) - to;
to += MICRON_NUM_OTP_FIRSTPAGE << chip->page_shift;
nand_get_device(mtd, FL_WRITING);
chip->select_chip(mtd, 0);
ret = chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,
MICRON_SETFEATURE_ARRAYOP_OTP);
if (ret)
goto out;
ops.len = len;
ops.datbuf = buf;
ops.oobbuf = NULL;
ops.mode = 0;
/*
* some things in nand_do_write_ops might be wrong for OTP. e.g.
* chip->pagemask, chip->pagebuf handling
*/
ret = nand_do_write_ops(mtd, to, &ops);
*retlen = ops.retlen;
/* nand_do_write_ops deselects the chip so reselect here */
chip->select_chip(mtd, 0);
chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,
MICRON_SETFEATURE_ARRAYOP_NORMAL);
out:
nand_release_device(mtd);
return ret;
}
static int mt29f_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
size_t len)
{
struct nand_chip *chip = mtd->priv;
int ret;
int i;
/* assert from and len are aligned */
if (NOTALIGNED(from) || NOTALIGNED(len)) {
pr_notice("%s: attempt to lock non page aligned data\n",
__func__);
return -EINVAL;
}
if (!len)
return 0;
if (from > MICRON_NUM_OTP_PAGES << chip->page_shift)
return -EINVAL;
if (from + len > MICRON_NUM_OTP_PAGES << chip->page_shift)
return -EINVAL;
from += MICRON_NUM_OTP_FIRSTPAGE << chip->page_shift;
nand_get_device(mtd, FL_WRITING);
chip->select_chip(mtd, 0);
ret = chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,
MICRON_SETFEATURE_ARRAYOP_OTPPROTECT);
if (ret)
goto out;
for (i = 0; i < len << chip->page_shift; ++i) {
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0,
(from << chip->page_shift) + i);
chip->write_byte(mtd, 0);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
}
chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,
MICRON_SETFEATURE_ARRAYOP_NORMAL);
out:
nand_release_device(mtd);
return ret;
}
void nandchip_micron_init(struct mtd_info *mtd, int dev_id)
{
/*
* OTP is available on (at least) Micron's MT29F2G{08,16}AB[AB]EA,
* MT29F[48]G{08,16}AB[AB]DA, MT29F16G08AJADA having device IDs:
* 0xda, 0xca, 0xaa, 0xba;
* 0xdc, 0xcc, 0xac, 0xbc, 0xa3, 0xb3, 0xd3, 0xc3;
* 0xd3
*/
if (IS_ENABLED(CONFIG_MTD_NAND_OTP) &&
((dev_id + 0x20) & 0xc0) == 0xc0 &&
((dev_id & 0x09) == 8 || (dev_id & 0x0f) == 3)) {
mtd->_get_user_prot_info = mt29f_get_user_prot_info;
mtd->_read_user_prot_reg = mt29f_read_user_prot_reg;
mtd->_write_user_prot_reg = mt29f_write_user_prot_reg;
mtd->_lock_user_prot_reg = mt29f_lock_user_prot_reg;
}
}
linux-elphel-023fb0af7f4e09caba49cdc9d2996b2e261658fe/src/drivers/mtd/nand/pl35x_nand.c 0000664 0000000 0000000 00000107043 12703306510 0027443 0 ustar 00root root 0000000 0000000 /*
* ARM PL35X NAND Flash Controller Driver
*
* Copyright (C) 2009 - 2014 Xilinx, Inc.
*
* This driver is based on plat_nand.c and mxc_nand.c drivers
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include
#include
#include
#include
#include