pax_global_header 0000666 0000000 0000000 00000000064 12677012326 0014520 g ustar 00root root 0000000 0000000 52 comment=f632965fb219afe5dc368fab4a3b70cd21365b17
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/ 0000775 0000000 0000000 00000000000 12677012326 0021205 5 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/.gitignore 0000664 0000000 0000000 00000000464 12677012326 0023201 0 ustar 00root root 0000000 0000000 bin
tmp
Debug
Release
linux
sysroots
.project
.cproject
.externalToolBuilders
.settings
.pydevproject
# below files were autogenerated and should not be tracked
src/drivers/elphel/x393.c
src/drivers/elphel/x393.h
src/include/elphel/x393_defs.h
src/include/elphel/x393_map.h
src/include/elphel/x393_types.h
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/README.md 0000664 0000000 0000000 00000003622 12677012326 0022467 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-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/ 0000775 0000000 0000000 00000000000 12677012326 0025577 5 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.cproject 0000664 0000000 0000000 00000337203 12677012326 0027421 0 ustar 00root root 0000000 0000000
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.externalToolBuilders/ 0000775 0000000 0000000 00000000000 12677012326 0032027 5 ustar 00root root 0000000 0000000 bitbake compile -f [Builder].launch 0000664 0000000 0000000 00000001372 12677012326 0040303 0 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.externalToolBuilders
bitbake compile [Builder].launch 0000664 0000000 0000000 00000001552 12677012326 0040020 0 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.externalToolBuilders
bitbake deploy [Builder].launch 0000664 0000000 0000000 00000001762 12677012326 0037667 0 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.externalToolBuilders
kernel modules [Builder].launch 0000664 0000000 0000000 00000001257 12677012326 0037721 0 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.externalToolBuilders
org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder.launch 0000664 0000000 0000000 00000001361 12677012326 0046046 0 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.externalToolBuilders
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.project 0000664 0000000 0000000 00000005211 12677012326 0027245 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-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.pydevproject 0000664 0000000 0000000 00000000456 12677012326 0030323 0 ustar 00root root 0000000 0000000
Default
python 2.7
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.settings/ 0000775 0000000 0000000 00000000000 12677012326 0027515 5 ustar 00root root 0000000 0000000 language.settings.xml 0000664 0000000 0000000 00000001117 12677012326 0033602 0 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/eclipse_project_setup/.settings
org.eclipse.cdt.codan.core.prefs 0000664 0000000 0000000 00000024130 12677012326 0035474 0 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/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 12677012326 0034412 0 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/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-f632965fb219afe5dc368fab4a3b70cd21365b17/run_bitbake.sh 0000775 0000000 0000000 00000000330 12677012326 0024025 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-f632965fb219afe5dc368fab4a3b70cd21365b17/src/ 0000775 0000000 0000000 00000000000 12677012326 0021774 5 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/ 0000775 0000000 0000000 00000000000 12677012326 0023452 5 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/Makefile 0000664 0000000 0000000 00000011376 12677012326 0025122 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-y += net/
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/ata/ 0000775 0000000 0000000 00000000000 12677012326 0024217 5 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/ata/Kconfig 0000664 0000000 0000000 00000062003 12677012326 0025523 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-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/ata/Makefile 0000664 0000000 0000000 00000011503 12677012326 0025657 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-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/ata/ahci_elphel.c 0000664 0000000 0000000 00000021651 12677012326 0026625 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-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/clk/ 0000775 0000000 0000000 00000000000 12677012326 0024223 5 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/clk/clk-si5338.c 0000664 0000000 0000000 00000550572 12677012326 0026112 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-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/ 0000775 0000000 0000000 00000000000 12677012326 0024723 5 ustar 00root root 0000000 0000000 linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/Kconfig 0000664 0000000 0000000 00000002213 12677012326 0026224 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 circbuf as external module"
default m
help
If unsure, say Y.
endmenu
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/Makefile 0000664 0000000 0000000 00000002477 12677012326 0026375 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) += framepars.o
obj-$(CONFIG_ELPHEL393) += sensor_common.o x393.o
obj-$(CONFIG_ELPHEL393) += quantization_tables.o
obj-$(CONFIG_ELPHEL393) += circbuf.o jpeghead.o
#fpars-y := framepars.o sensor_common.o
#sc-y := sensor_common.o quantization_tables.o framepars.o
#cbuf-y := circbuf.o fpars.o sc.o jpeghead.o
#obj-$(CONFIG_ELPHEL393_EXTERNAL) += fpars.o
#obj-$(CONFIG_ELPHEL393_EXTERNAL) += sc.o
#obj-$(CONFIG_ELPHEL393_EXTERNAL) += cbuf.o
#obj-$(CONFIG_ELPHEL393_EXTERNAL) += circbuf.o jpeghead.o quantization_tables.o linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/circbuf.c 0000664 0000000 0000000 00000071627 12677012326 0026521 0 ustar 00root root 0000000 0000000 /** @file circbuf.c
*
* @brief drivers to manipulate large circular buffer that holds compressed
* images/video. Buffer frame data is filled in by the FPGA, frame pointers and
* essential frames metadata filled during servicing of the interrupts.
*
* 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 .
* -----------------------------------------------------------------------------**
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
//#include
//#include obsolete
#include
/*#include
#include
#include
#include
#include
*/
#include
#include
#include
#include
#include
#include
#include
#include "framepars.h" // just for ELPHEL_DEBUG bit mask
#include "sensor_common.h"
#include "jpeghead.h"
#include "circbuf.h"
#include "exif.h"
#include "x393_macro.h"
#include "x393.h"
#if ELPHEL_DEBUG
#define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;}
#define D19(x) { if (GLOBALPARS(G_DEBUG) & (1 <<19)) {x; } ; }
#define MDF19(x) { if (GLOBALPARS(G_DEBUG) & (1 <<19)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
#define D20(x) { if (GLOBALPARS(G_DEBUG) & (1 <<20)) {x; } ; }
#define MDF20(x) { if (GLOBALPARS(G_DEBUG) & (1 <<20)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
#else
#define MDF(x)
#define D19(x)
#define MDF19(x)
#define D20(x)
#define MDF20(x)
#endif
#define MD12(x)
#define D(x)
//#define MD7(x) printk("%s:%d:",__FILE__,__LINE__);x
#define MD7(x)
//#define MD10(x) printk("%s:%d:",__FILE__,__LINE__);x
#define MD10(x)
//#define MD11(x) printk("%s:%d:",__FILE__,__LINE__);x
#define MD11(x)
static const struct of_device_id elphel393_circbuf_of_match[];
/* really huge static DMA buffer (1288+8)*1032/3=445824 long-s */
// DMA_SIZE - in 32-bit words, not bytes
//static unsigned long ccam_dma_buf[CCAM_DMA_SIZE + (PAGE_SIZE>>2)] __attribute__ ((aligned (PAGE_SIZE)));
static unsigned long *ccam_dma_buf = NULL;
//!Without "static" system hangs after "Uncompressing Linux...
unsigned long * ccam_dma_buf_ptr = NULL;
//EXPORT_SYMBOL_GPL(ccam_dma_buf_ptr);
//unsigned long * ccam_dma = NULL; //! still used in autoexposure or something - why is in needed there?
int init_ccam_dma_buf_ptr(struct platform_device *pdev) {
dma_addr_t dma_handle;
const size_t dma_size = (CCAM_DMA_SIZE + (PAGE_SIZE >> 2)) * sizeof(int);
struct device *dev = &pdev->dev;
//ccam_dma_buf_ptr = ccam_dma_buf;
//ccam_dma = ccam_dma_buf; //&ccam_dma_buf[0]; Use in autoexposure
// use Elphel_buf if it was allocated
if (pElphel_buf != NULL) {
ccam_dma_buf_ptr = pElphel_buf->vaddr;
dma_handle = pElphel_buf->paddr;
dev_info(dev, "using %d bytes of DMA memory from pElphel_buf at address 0x%08p", pElphel_buf->size * PAGE_SIZE, dma_handle);
} else {
ccam_dma_buf_ptr = dmam_alloc_coherent(dev, dma_size, &dma_handle, GFP_KERNEL);
if (!ccam_dma_buf_ptr) {
dev_err(dev, "unable to allocate DMA buffer\n");
return -ENOMEM;
} else {
dev_info(dev, "%d bytes of DMA memory allocated at address 0x%08p", dma_size , dma_handle);
}
}
ccam_dma_buf = ccam_dma_buf_ptr;
return 0;
}
//extern struct interframe_params_t frame_params; // cc353.c
/*!======================================================================================
*! Wait queue for the processes waiting for a new frame to appear in the circular buffer
*!======================================================================================*/
wait_queue_head_t circbuf_wait_queue;
/*!=========================================================================================================
*! circbuf top level device drivers. Minors are the same as before
*! CMOSCAM_MINOR_CIRCBUF, CMOSCAM_MINOR_JPEAGHEAD - just a new major
*!========================================================================================================*/
#define CIRCBUF_DRIVER_NAME "Elphel (R) Model 353 video buffer device driver"
static struct file_operations circbuf_fops = {
owner: THIS_MODULE,
llseek: circbuf_all_lseek,
read: circbuf_all_read,
write: circbuf_all_write,
//ioctl: circbuf_all_ioctl,
open: circbuf_all_open,
mmap: circbuf_all_mmap,
poll: circbuf_all_poll,
release: circbuf_all_release
};
// Read/write to circular buffer. Needed to find out what Axis DMA is doing
// also - jpeg header
struct circbuf_pd {
int minor; /// should be the first, same as in jpeghead_pd
int daemon_bit; /// poll() will produce POLLHUP if this bit is >=0 (set through lseek (, LSEEK_DAEMON_CIRCBUF,SEEK_END)
/// and the corresponding bit in P_DAEMON_EN goes 0
int imageWidth; /// image width to compare to current. G_SKIP_DIFF_FRAME
int imageHeight; /// image height to compare to current. G_SKIP_DIFF_FRAME
int tolerated; /// number of frames with different size tolerated
struct wait_queue *circbuf_wait_queue; ///NOTE: not used at all?
// something else to be added here?
};
// CMOSCAM_MINOR_HUFFMAN // huffman tables R/W
int circbuf_all_open(struct inode *inode, struct file *filp) {
int res;
MD10(printk("circbuf_all_open, minor=0x%x\n",MINOR(inode->i_rdev)));
switch (MINOR(inode->i_rdev)) {
case CMOSCAM_MINOR_CIRCBUF :
res=circbuf_open(inode,filp);
break;
case CMOSCAM_MINOR_JPEAGHEAD :
res=jpeghead_open(inode,filp);
break;
case CMOSCAM_MINOR_HUFFMAN :
res=huffman_open(inode,filp);
break;
default:
// kfree(filp->private_data); // already allocated
return -EINVAL;
}
return res;
}
int circbuf_all_release(struct inode *inode, struct file *filp) {
int res=0;
int p = MINOR(inode->i_rdev);
MD10(printk("circbuf_all_release, minor=0x%x\n",p));
switch ( p ) {
case CMOSCAM_MINOR_CIRCBUF :
// res=circbuf_release(inode,filp);
break;
case CMOSCAM_MINOR_JPEAGHEAD :
// res=jpeghead_release(inode,filp);
break;
case CMOSCAM_MINOR_HUFFMAN :
// res=huffman_release(inode,filp);
break;
default:
return -EINVAL; //! do not need to free anything - "wrong number"
}
if (filp->private_data) kfree(filp->private_data);
return res;
}
loff_t circbuf_all_lseek(struct file * file, loff_t offset, int orig) {
struct circbuf_pd * privData;
privData = (struct circbuf_pd *) file->private_data;
struct interframe_params_t *fp = NULL;
int rp;
MD10(printk("circbuf_all_lseek, minor=0x%x\n",privData-> minor));
switch (privData->minor) {
case CMOSCAM_MINOR_CIRCBUF : return circbuf_lseek (file, offset, orig);
case CMOSCAM_MINOR_JPEAGHEAD :
if (orig == SEEK_END && offset > 0) {
rp= (offset >>2) & (~7); // convert to index to long, align to 32-bytes
fp = (struct interframe_params_t *) &ccam_dma_buf_ptr[X313_BUFFSUB(rp, 8)]; //! 32 bytes before the frame pointer, may roll-over to the end of ccam_dma_buf_ptr
}
return jpeghead_lseek (file, offset, orig, fp);
case CMOSCAM_MINOR_HUFFMAN : return huffman_lseek (file, offset, orig);
default: return -EINVAL;
}
}
ssize_t circbuf_all_read(struct file * file, char * buf, size_t count, loff_t *off) {
struct circbuf_pd * privData;
privData = (struct circbuf_pd *) file->private_data;
MD10(printk("circbuf_all_read, minor=0x%x\n",privData-> minor));
switch (privData->minor) {
case CMOSCAM_MINOR_CIRCBUF : return circbuf_read (file, buf, count, off);
case CMOSCAM_MINOR_JPEAGHEAD : return jpeghead_read (file, buf, count, off);
case CMOSCAM_MINOR_HUFFMAN : return huffman_read (file, buf, count, off);
default: return -EINVAL;
}
}
ssize_t circbuf_all_write(struct file * file, const char * buf, size_t count, loff_t *off) {
struct circbuf_pd * privData;
privData = (struct circbuf_pd *) file->private_data;
MD10(printk("circbuf_all_write, minor=0x%x, count=%d, off=%d\n",privData-> minor, (int) count,(int)*off));
switch (privData->minor) {
case CMOSCAM_MINOR_CIRCBUF : return circbuf_write (file, buf, count, off);
// case CMOSCAM_MINOR_JPEAGHEAD : return jpeghead_write (file, buf, count, off); // same as other - write header
case CMOSCAM_MINOR_HUFFMAN : return huffman_write (file, buf, count, off);
default: return -EINVAL;
}
}
int circbuf_all_mmap (struct file *file, struct vm_area_struct *vma) {
struct circbuf_pd * privData;
privData = (struct circbuf_pd *) file->private_data;
MD10(printk("circbuf_all_mmap, minor=0x%x\n",privData-> minor));
switch (privData->minor) {
case CMOSCAM_MINOR_CIRCBUF : return circbuf_mmap (file, vma);
default: return -EINVAL;
}
}
unsigned int circbuf_all_poll (struct file *file, poll_table *wait) {
struct circbuf_pd * privData;
privData = (struct circbuf_pd *) file->private_data;
MD10(printk("circbuf_all_poll, minor=0x%x\n",privData-> minor));
switch (privData->minor) {
case CMOSCAM_MINOR_CIRCBUF :
return circbuf_poll (file, wait);
default: return -EINVAL;
}
}
int circbuf_all_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) {
struct circbuf_pd * privData;
privData = (struct circbuf_pd *) filp->private_data;
printk("\n========== IOCTL is not implemented in circbuf_all_ioctl, minor=0x%x, cmd=0x%x, _IOC_NR(cmd)=0x%x, arg=0x%x\n",privData-> minor, (int) cmd, _IOC_NR(cmd), (int) arg);
return -EINVAL;
}
int circbuf_open(struct inode *inode, struct file *filp) { // set filesize
struct circbuf_pd * privData;
privData= (struct circbuf_pd *) kmalloc(sizeof(struct circbuf_pd),GFP_KERNEL);
if (!privData) return -ENOMEM;
filp->private_data = privData;
privData-> minor=MINOR(inode->i_rdev);
inode->i_size = ((CCAM_DMA_SIZE) << 2);
MD10(printk("circbuf_open, inode->i_size=0x%x\n", (int)inode->i_size));
//!should be removed (or else you can not ftp file - it will start from WP)
// circbuf_lseek(filp, LSEEK_CIRC_LAST, SEEK_END); //! position at last acquired frame, ignore result
return 0;
}
/*!=============================================================================================
*! Overloading lseek with additional functionality (to avoid ioctls)
*! with orig==SEEK_END lseek will treat (offset>0) as a command
*! to manipulate frame pointer(s) or wait for the image to be ready
*! using these commands
*! LSEEK_CIRC_TORP .- set filepointer to global (shared) read pointer
*! LSEEK_CIRC_TOWP - set filepointer to FPGA write pointer (next frame to be acquired)
*! LSEEK_CIRC_PREV - move pointer to the previous frame, return -EOVERFLOW if there are none
*! LSEEK_CIRC_NEXT - advance pointer to the next frame, return -EOVERFLOW if was already
*! at the last
*! LSEEK_CIRC_LAST - move pointer to the last acquired frame (default after open)
*! (it is combination of 2+3)
*! LSEEK_CIRC_FIRST - move pointer to the first acquired frame. It s not safe to rely
*! on this pointer if more frames are expected - next incoming frame
*! can overwrite this one.
*! LSEEK_CIRC_SCND - move pointer to the second oldest acquired frame. A slightly safer
*! to use instead of LSEEK_CIRC_FIRST when constant acquisition is on
*! and sensor provides new frames - this frame will likely survive longer
*! LSEEK_CIRC_SETP - save current pointer to global read pointer
*! LSEEK_CIRC_VALID - verify that the frame at current location is valid (not overrun in the buffer)
*! Returns file pointer if valid, else - -1
*! LSEEK_CIRC_READY - verify frame at current loacation is available (valid and acquired)
*! Returns file pointer if ready, else - -1
*! LSEEK_CIRC_WAIT - sleep until next frame is acquired
*! All commands but (LSEEK_CIRC_TOWP,LSEEK_CIRC_LAST,LSEEK_CIRC_FIRST) will return -EINVAL if read
*! pointer is not valid (i.e buffer was overrun and data pointed is lost). if success they return
*! the current (byte *) to the start of the frame data (parameters are at
*! offsett =-32 from it)
*! (0, SEEK_CUR) also verifies that the header is not overwritten. It can be used
*! after buffering frame data to verify you got it all correctly
*! SEEK_CUR also supports the circular nature of the buffer and rolls over if needed
*! Additional commands for SEEK_END (they _DO_ modify the current file pointer !)
*! LSEEK_CIRC_FREE - returnes remaining memory in circbuf from the current file pointer,
*! or -EINVAL if the pointer is invalid. As this command uses the buffer write pointer
*! that is updated only when the complete frame is in the buffer, the actual
*! free memory may be less by a whole frame if compressor is running.
*! LSEEK_CIRC_USED - returnes memory used in the in circbuf from the current file pointer,
*! or -EINVAL if the pointer is invalid
*!=============================================================================================*/
//!returns 0 if rp is a valid read ponter
//! returns 1 if there is a frame at this address
//! returns 0 if the pointer is for the frame yet to be acquired
//! returns -1 if there is no frame at this index
//! returns -2 if the rp is not 32-bytes aligned
//!sets *fpp to the frame header, including signature and length
int circbufValidPointer(int rp, struct interframe_params_t ** fpp) {
if (rp & 0x1f) { //!rp is not 32-bytes aligned
MD10(printk("circbufValidPointer: misaligned pointer\n"));
return -2;
}
int wp=camSeqGetJPEG_wp();
int p= rp >> 2; // index inccam_dma_buf
struct interframe_params_t * fp;
fp = (struct interframe_params_t *) &ccam_dma_buf[X313_BUFFSUB(p, 8)]; //! 32 bytes before the frame pointer, may roll-over to the end of ccam_dma_buf
MD10(printk("rp=0x%x (0x%x), offset=0x%x\n",rp,p,(int)&ccam_dma_buf[p]-(int)fp); dumpFrameParams(fp, "in circbufValidPointer:"));
*fpp=fp;
MD11(printk("p=0x%x , wp==0x%x\n",p,wp));
if (p == wp) {
return 0; // frame not yet acquired, fp - not valid
}
if (fp->signffff != 0xffff) { //! signature is overwritten
MD10(printk("circbufValidPointer: signanure overwritten\n"));
return -1;
}
if ((fp->timestamp_sec) & X313_LENGTH_MASK) {
MDF(printk ("Should not get here - fp->timestamp_sec=0x%x\n",(int) fp->timestamp_sec));
return 0; //! should not get here - should be caught by (p==wp)
}
return 1;
}
loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
// orig 0: position from begning
// orig 1: relative from current
// orig 2: position from last address
int l = (CCAM_DMA_SIZE << 2);
int fl=0;// frame length
struct interframe_params_t * fp;
int fvld=-1;
int rp, bp, prev_p, preprev_p; //, p;
int nf; //! number of frames;
int nz=1; //! number of crossing of start of the circular buffer (counter to prevent looping forever)
MD12(int dbg_i);
// int pf; // previous frame
MD11(printk("circbuf_lseek, offset=0x%x, orig=0x%x\n",(int) offset, (int) orig));
switch(orig) {
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
if (offset) file->f_pos += offset;
else if (circbufValidPointer(file->f_pos, &fp) <0 ) return -EINVAL; //!no frames at the specified location or pointer is not 32-byte aligned
break;
case SEEK_END:
if (offset <= 0) {
file->f_pos = l + offset;
} else { //! New functionality
//!verify the frame pointer
switch (offset) {
case LSEEK_CIRC_TORP:
file->f_pos=camSeqGetJPEG_rp()<<2; //! set file pointer to global read pointer, and proceed
case LSEEK_CIRC_PREV:
case LSEEK_CIRC_NEXT:
case LSEEK_CIRC_SETP:
case LSEEK_CIRC_VALID:
case LSEEK_CIRC_READY:
case LSEEK_CIRC_FREE:
case LSEEK_CIRC_USED:
if (((fvld=circbufValidPointer(file->f_pos, &fp))) <0 )
return -EINVAL; //!no frames at the specified location
}
switch (offset) {
case LSEEK_CIRC_FREE:
bp=(file->f_pos - (camSeqGetJPEG_wp()<<2));
// return (bp>0)?bp:(bp+l); //!will return full buffer size if current pointer is a write pointer (waiting for the next frame)
return (file->f_pos=(bp>0)?bp:(bp+l)); //!Has a side effect of moving a file pointer!
case LSEEK_CIRC_USED:
bp=((camSeqGetJPEG_wp()<<2) - file->f_pos);
// return (bp>=0)?bp:(bp+l); //!will return 0 if current pointer is a write pointer (waiting for the next frame)
return (file->f_pos=(bp>0)?bp:(bp+l)); //!Has a side effect of moving a file pointer!
case LSEEK_CIRC_TORP:
break;
case LSEEK_CIRC_TOWP:
file->f_pos=camSeqGetJPEG_wp()<<2; // no checking if it is valid
break;
case LSEEK_CIRC_LAST:
file->f_pos=camSeqGetJPEG_wp()<<2;
fvld=circbufValidPointer(file->f_pos, &fp); //!set fp
case LSEEK_CIRC_PREV:
rp= file->f_pos >> 2;
fl=ccam_dma_buf[X313_BUFFSUB(rp, 9)] ^ X313_LENGTH_MASK;
MD11(printk("LSEEK_CIRC_PREV: rp=0x%x, fvld=%d, fl=0x%x\n", rp, fvld,fl));
if (fl & X313_LENGTH_MASK) {
if (offset==LSEEK_CIRC_LAST) break; // just don't move pointer, leave it at write pointer and return no error
return -EOVERFLOW; //! no frames before current
}
bp = (X313_BUFFSUB(rp, X313_PADDED_FRAME(fl))<<2); // in bytes
MD11(printk("LSEEK_CIRC_PREV: bp=0x%x (0x%x), circbufValidPointer=%d\n", bp, bp>>2,circbufValidPointer(rp>>2, &fp)));
if (circbufValidPointer(bp, &fp) < 0 ) { //! no valid frames before current
if (offset==LSEEK_CIRC_LAST) break; // just don't move pointer, leave it at write pointer and return no error
return -EOVERFLOW; //! no frames before current
}
//! move frame pointer only if there is a valid frame there
file->f_pos=bp;
break;
case LSEEK_CIRC_NEXT:
MD11(printk("LSEEK_CIRC_NEXT: rp=0x%x, fvld=%d, fp->timestamp_sec=0x%x\n", file->f_pos >> 2, fvld, fp->timestamp_sec));
if (fvld <=0)
return -EOVERFLOW; //! no frames after current
file->f_pos = X313_BUFFADD(file->f_pos >> 2, X313_PADDED_FRAME(fp->timestamp_sec)) <<2 ;// do it even if the next frame does not yet exist
break;
case LSEEK_CIRC_FIRST:
case LSEEK_CIRC_SCND:
//! Starting from the write pointer do be able to count all the frames in the buffer
rp=camSeqGetJPEG_wp();
prev_p=rp;
preprev_p=prev_p; // for second
nf=0;
nz=1;
file->f_pos=rp<<2;
while ((((fvld=circbufValidPointer(rp<<2, &fp))) >= 0) & (nz>=0)) {
nf++;
// file->f_pos=rp<<2;
preprev_p=prev_p; //! second known good (at least first one)
prev_p=rp; //!now - current, known good
fl=ccam_dma_buf[X313_BUFFSUB(rp, 9)] ^ X313_LENGTH_MASK;
MD11(printk("\nf=%d, rp=0x%x, fvld=%d, fl=0x%x\n",nf, rp, fvld, fl));
if (fl & X313_LENGTH_MASK) break; //! no frames before rp (==prev_p)
//! move rp to the previous frame
rp= X313_BUFFSUB(rp, X313_PADDED_FRAME(fl));
if (rp > prev_p) nz-- ; // rolled through zero - make sure we'll not stuck in this loop forever
}
MD11(printk("after while{}: nf=%d, rp=0x%x, fvld=%d, fl=0x%x\n",nf, rp, fvld, fl));
file->f_pos=((offset==LSEEK_CIRC_SCND)?preprev_p:prev_p) << 2;
break;
case LSEEK_CIRC_SETP:
camSeqSetJPEG_rp(file->f_pos>>2);
break;
case LSEEK_CIRC_VALID:
break;
case LSEEK_CIRC_READY:
if (fvld <=0) return -EINVAL; //! no frame is available better code?
break;
case LSEEK_CIRC_WAIT:
while (((fvld=circbufValidPointer(file->f_pos, &fp)))==0) { //! only while not ready, ready or BAD - return
wait_event_interruptible(circbuf_wait_queue,(camSeqGetJPEG_wp()<<2)!=file->f_pos);
}
if (fvld < 0) return -ESPIPE; //!invalid seek - have better code?
return file->f_pos ; //! data already available, return file pointer
default:
if ((offset & ~0x1f)==LSEEK_DAEMON_CIRCBUF) {
wait_event_interruptible(circbuf_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
}
}
return ( file->f_pos ); //! file position >=0
}
break;
default:
return -EINVAL;
}
// roll-over position
while (file->f_pos < 0) file->f_pos+=l;
while (file->f_pos > l) file->f_pos-=l;
if ((orig !=SEEK_END) && (file->f_pos == l)) file->f_pos=0; //!only for lseek (fd,0,SEEK_END) the result will be file size, others will roll to 0
return file->f_pos ;
}
/**
* @brief This function handles write operations for circbuf file
* @param[in] file pointer to struct file
* @param[in] buf pointer to buffer containing data
* @param[in] count number of bytes in buffer
* @param[in] off offset
* @return number of bytes read form \e buf
*/
ssize_t circbuf_write(struct file * file, const char * buf, size_t count, loff_t *off) {
void __iomem *mmio;
x393_afimux_status_t val;
int port;
unsigned long p;
char *char_pb = (char *)ccam_dma_buf;
struct circbuf_pd *priv = file->private_data;
// convert char to number
port = buf[0] - 0x30;
/*mmio = ioremap(0x40002060, 16);
if (!mmio) {
printk(KERN_DEBUG "ERROR: can not ioremap region");
return count;
}*/
if (init_mmio_ptr() < 0) {
printk(KERN_DEBUG "ERROR: can not remap IO region\n");
}
if (port >= 0 && port < 4) {
val = x393_afimux0_status(port);
//val.d32 = readl((void*) (0x40002060 + 0x4 * port));
//val.d32 = ioread32(mmio + 0x4 * port);
} else {
printk(KERN_DEBUG "Unrecognized port number\n");
}
printk(KERN_DEBUG "AFI MUX0 port: %d, AFI MUX0 offset: 0x%x, AFI MUX0 sequence number: %d\n", port, val.offset256 * 32, val.seq_num);
printk(KERN_DEBUG "AFI MUX0 raw value: 0x%x\n", val.d32);
printk(KERN_DEBUG "AFI MUX0 offset265: 0x%x, seq_num: 0x%x\n", val.offset256, val.seq_num);
iounmap(mmio);
mmio = NULL;
return count;
D(printk("circbuf_write\n"));
/// ************* NOTE: Never use file->f_pos in write() and read() !!!
p = *off;
if(p >= (CCAM_DMA_SIZE << 2))
p = (CCAM_DMA_SIZE << 2);
if((p + count) > (CCAM_DMA_SIZE << 2)) { // truncate count
count = (CCAM_DMA_SIZE << 2) - p;
}
if(count) {
if(copy_from_user(&char_pb[p], buf, count))
return -EFAULT;
*off += count;
}
return count;
}
/**
* @brief This function handles read operations for circbuf file
* @param[in] file pointer to struct file
* @param[in] buf pointer to buffer where data will be written to
* @param[in] count number of bytes written to \e buf
* @param[in] off offset
* @return number of bytes written to \e buf
*/
ssize_t circbuf_read(struct file * file, char * buf, size_t count, loff_t *off) {
unsigned long p;
char * char_pb = (char *) ccam_dma_buf;
struct circbuf_pd *priv = file->private_data;
printk(KERN_DEBUG "%s\n", __func__);
p = *off;
D(printk("circbuf_read pos=%d,count=%d, off=%d\r\n",p,count,off ));
if (p >= (CCAM_DMA_SIZE<<2)) p = (CCAM_DMA_SIZE<<2);
if( (p + count) > (CCAM_DMA_SIZE<<2)) { // truncate count
count = (CCAM_DMA_SIZE<<2) - p;
}
if (count) {
if (copy_to_user(buf, &char_pb[p], count)) return -EFAULT;
// file->f_pos+=count;
*off+=count;
}
return count;
}
int circbuf_mmap (struct file *file, struct vm_area_struct *vma) {
int rslt;
MD7(printk("vm_start=%lx\r\n",vma->vm_start));
MD7(printk("vm_end=%lx\r\n",vma->vm_end));
MD7(printk("vm_pgoff=%lx\r\n",vma->vm_pgoff));
MD7(printk("vm_file=%lx\r\n",(unsigned long) (vma->vm_file)));
MD7(printk("ccam_dma_buf=%lx\r\n",(unsigned long) (virt_to_phys (&ccam_dma_buf[0]))));
/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
rslt=remap_pfn_range(vma,
vma->vm_start,
// ((unsigned long)(&ccam_dma_buf[0])) >> PAGE_SHIFT, // Should be page-aligned
((unsigned long) virt_to_phys(&ccam_dma_buf[0])) >> PAGE_SHIFT, // Should be page-aligned
vma->vm_end-vma->vm_start,
vma->vm_page_prot);
MD7(printk("remap_pfn_range returned=%x\r\n",rslt));
if (rslt) return -EAGAIN;
// vma->vm_ops = &simple_remap_vm_ops;
// simple_vma_open(vma);
return 0;
}
/*!===========================================================================
*! If the current read pointer is invalid, circbuf_poll returns POLLHUP
*! as no data will be ever available until file poinetr is reset.
*! if it is valid, wait is setup and the blocking condition occurs
*! ifthe current file pointer is equal to the FPGA write pointer
*!===========================================================================*/
unsigned int circbuf_poll (struct file *file, poll_table *wait) {
struct interframe_params_t * fp;
struct circbuf_pd * privData;
privData = (struct circbuf_pd *) file->private_data;
int rslt; //!result of testing read poinetr
MD10(printk("circbuf_poll\n"));
rslt= circbufValidPointer(file->f_pos, &fp);
if (rslt < 0) { //! not a valid read pointer, probable buffer overrun
MD10(printk("circbuf_poll:invalid pointer\n"));
return POLLHUP ;
} else if (rslt > 0) {
return POLLIN | POLLRDNORM; //! there was frame already available
} else { //! pointer valid, no frame yet
poll_wait(file, &circbuf_wait_queue, wait);
//! Frame might become available during call to poll_wait so nobody will wake us up.
//! Let's see if there is stillno frame
if ((camSeqGetJPEG_wp()<<2)!=file->f_pos) return POLLIN | POLLRDNORM; //! we are lucky - got it
}
return 0; // nothing ready
}
/**
* @brief cirbuf driver probing function
* @param[in] pdev pointer to \b platform_device structure
* @return 0 on success or negative error code otherwise
*/
static int circbuf_all_init(struct platform_device *pdev)
{
int res;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
/* sanity check */
match = of_match_device(elphel393_circbuf_of_match, dev);
if (!match)
return -EINVAL;
MDF19(printk("\n"));
res = register_chrdev(CIRCBUF_MAJOR, "circbuf_operations", &circbuf_fops);
if(res < 0) {
printk(KERN_ERR "\ncircbuf_all_init: couldn't get a major number %d.\n",CIRCBUF_MAJOR);
return res;
}
res = init_ccam_dma_buf_ptr(pdev);
if (res < 0) {
dev_err(dev, "ERROR allocating coherent DMA buffer\n");
return -ENOMEM;
}
MDF19(printk("init_waitqueue_head()\n"));
init_waitqueue_head(&circbuf_wait_queue);
MDF19(printk("jpeg_htable_init()\n"));
jpeg_htable_init (); /// set default Huffman table, encode it for the FPGA
dev_info(dev, "registered MAJOR: %d\n", CIRCBUF_MAJOR);
return 0;
}
static int circbuf_remove(struct platform_device *pdev)
{
unregister_chrdev(CIRCBUF_MAJOR, "circbuf_operations");
return 0;
}
static const struct of_device_id elphel393_circbuf_of_match[] = {
{ .compatible = "elphel,elphel393-circbuf-1.00" },
{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, elphel393_circbuf_of_match);
static struct platform_driver elphel393_circbuf = {
.probe = circbuf_all_init,
.remove = circbuf_remove,
.driver = {
.name = CIRCBUF_DRIVER_NAME,
.of_match_table = elphel393_circbuf_of_match,
},
};
module_platform_driver(elphel393_circbuf);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov .");
MODULE_DESCRIPTION(CIRCBUF_DRIVER_NAME);
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/circbuf.h 0000664 0000000 0000000 00000003517 12677012326 0026517 0 ustar 00root root 0000000 0000000 // FILE NAME : cxsdma.h
// read/write image and FPN buffers from SDRAM
#ifndef _CIRCBUF_H
#define _CIRCBUF_H
#include
int circbuf_all_open (struct inode *inode, struct file *filp); // set filesize
int circbuf_all_release(struct inode *inode, struct file *filp);
loff_t circbuf_all_lseek (struct file * file, loff_t offset, int orig);
ssize_t circbuf_all_write (struct file * file, const char * buf, size_t count, loff_t *off);
ssize_t circbuf_all_read (struct file * file, char * buf, size_t count, loff_t *off);
int circbuf_all_mmap (struct file *file, struct vm_area_struct *vma);
unsigned int circbuf_all_poll (struct file *file, poll_table *wait);
//!just to notify it is not implemented
int circbuf_all_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
int circbuf_open (struct inode *inode, struct file *filp); // set filesize
loff_t circbuf_lseek (struct file * file, loff_t offset, int orig);
ssize_t circbuf_write (struct file * file, const char * buf, size_t count, loff_t *off);
ssize_t circbuf_read (struct file * file, char * buf, size_t count, loff_t *off);
int circbuf_mmap (struct file *file, struct vm_area_struct *vma);
unsigned int circbuf_poll (struct file *file, poll_table *wait);
//int init_ccam_dma_buf_ptr(void);
/*!======================================================================================
*! Wait queue for the processes waiting for a new frame to appear in the circular buffer
*!======================================================================================*/
extern wait_queue_head_t circbuf_wait_queue;
extern unsigned long *ccam_dma_buf_ptr;
//unsigned long *circbuf_get_ccam_ptr(void);
#endif /* _CIRCBUF_H */
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/elphel393-init.c 0000664 0000000 0000000 00000027417 12677012326 0027553 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-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/elphel393-mem.c 0000664 0000000 0000000 00000041123 12677012326 0027354 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 .
*!****************************************************************************/
#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)
{
printk("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.paddr) {
printk("Allocated %u pages for DMA at address 0x%x\n", (u32)_elphel_buf.size, (u32)_elphel_buf.paddr);
} else {
printk("ERROR allocating coherent DMA memory buffer");
}
_elphel_buf.h2d_vaddr = kzalloc((_elphel_buf.h2d_size*PAGE_SIZE) ,GFP_KERNEL);
if (!_elphel_buf.h2d_vaddr){
_elphel_buf.h2d_size = 0;
printk("ERROR allocating H2D DMA memory buffer");
}
_elphel_buf.d2h_vaddr = kzalloc((_elphel_buf.d2h_size*PAGE_SIZE) ,GFP_KERNEL);
if (!_elphel_buf.d2h_vaddr){
_elphel_buf.d2h_size = 0;
printk("ERROR allocating D2H DMA memory buffer");
}
_elphel_buf.bidir_vaddr = kzalloc((_elphel_buf.bidir_size*PAGE_SIZE) ,GFP_KERNEL);
if (!_elphel_buf.bidir_vaddr){
_elphel_buf.bidir_size = 0;
printk("ERROR allocating Bidirectional DMA memory buffer");
}
printk("Coherent buffer vaddr: 0x%08X\n",(u32) pElphel_buf -> vaddr);
printk("Coherent buffer paddr: 0x%08X\n",(u32) pElphel_buf -> paddr);
printk("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)
{
printk("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;
}
printk("\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;
}
printk("\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;
}
printk("\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;
}
printk("\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;
}
printk("\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);
dev_info(&pdev->dev,"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){
printk("ERROR in dma_map_single() for bidirectional buffer");
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){
printk("ERROR in dma_map_single() for bidirectional buffer");
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){
printk("ERROR in dma_map_single() for bidirectional buffer");
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)
{
dev_info(&pdev->dev,"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_mem_of_match);
static struct platform_driver elphel393_mem = {
.probe = elphel393_mem_probe,
.remove = elphel393_mem_remove,
.driver = {
.name = "elphel393-mem",
.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");
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/elphel393-pwr.c 0000664 0000000 0000000 00000130717 12677012326 0027416 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-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/exif.h 0000664 0000000 0000000 00000001776 12677012326 0026042 0 ustar 00root root 0000000 0000000 #ifndef __F_EXIF__H_
#define __F_EXIF__H_
extern unsigned char exif_header[];
int exif_header_length(void);
#define EXIF_OFFSET 4
#define EXIF_FIRMWARE 0xC4
#define EXIF_FIRMWARE_LEN 27
//#define EXIF_DATE_TIME 0x7A
#define EXIF_DATE_TIME 0xE0
#define EXIF_DATE_TIME_LEN 20
//#define EXIF_ARTIST 0x8E
#define EXIF_ARTIST 0xF4
#define EXIF_ARTIST_LEN 18
//#define EXIF_DATE_TIME_OR 0xCA
#define EXIF_DATE_TIME_OR 0x0138
#define EXIF_DATE_TIME_OR_LEN 20
//#define EXIF_SUBSEC_OR 0xDE
#define EXIF_SUBSEC_OR 0x014C
#define EXIF_SUBSEC_OR_LEN 7
//#define EXIF_EXP 0xE6
#define EXIF_EXP 0x0130
#define EXIF_EXP_LEN 8
#define EXIF_IMAGE_ID 0x6E
#define EXIF_IMAGE_ID_LEN 64
struct exif_desc_t {
unsigned char date_time[EXIF_DATE_TIME_LEN];
unsigned char date_time_or[EXIF_DATE_TIME_OR_LEN];
unsigned char subsec[EXIF_SUBSEC_OR_LEN];
unsigned char artist[EXIF_ARTIST_LEN];
unsigned char firmware[EXIF_FIRMWARE_LEN];
unsigned long exp[2];
};
extern struct exif_desc_t exif_desc;
#endif //__F_EXIF__H_
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/framepars.c 0000664 0000000 0000000 00000176307 12677012326 0027065 0 ustar 00root root 0000000 0000000 /** @file framepars.c */
/*!********************************************************************************
*! FILE NAME : framepars.c
*! DESCRIPTION: Handling of frame parameters, making use of FPGA i2c
*! and command sequencer that accepts commands up to 6 frames ahead.
*! This module includes parameter storage, code called from ISR,
*! from other kernel drivers as well as from the user space
*! Copyright (C) 2008 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.
*!senssensor_common.hor_common.h
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*! -----------------------------------------------------------------------------**
*! $Log: framepars.c,v $
*! Revision 1.14 2011/12/22 05:39:07 elphel
*! catching up after some missed interrupts
*!
*! Revision 1.13 2010/08/10 21:10:41 elphel
*! portrait mode now includes all 4 rotations (2 bits)
*!
*! Revision 1.12 2010/08/03 23:37:34 elphel
*! rev 8.0.8.37, portrait mode support
*!
*! Revision 1.11 2010/05/25 00:52:23 elphel
*! 8.0.8.20, working on multi-sensor
*!
*! Revision 1.10 2010/05/21 06:12:16 elphel
*! continue working on multi-sensor software
*!
*! Revision 1.9 2010/05/16 02:03:47 elphel
*! 8.0.8.4 - driver working with individual/broadcast sensor registers
*!
*! Revision 1.8 2010/05/13 03:39:31 elphel
*! 8.0.8.12 - drivers modified for multi-sensor operation
*!
*! Revision 1.7 2010/04/28 02:34:33 elphel
*! 8.0.6.6 - added support for linescan mode (also useful for high fps small images). 2.5K full line pairs/second with 5MPix sensor
*!
*! Revision 1.6 2010/04/06 20:35:42 elphel
*! 8.0.7.5 - made the fpgaclock driver program 10359 clock in addition to the system one
*!
*! Revision 1.5 2010/01/27 22:51:52 elphel
*! turned off ELPHEL_DEBUG, fixed errors caused by that.
*!
*! Revision 1.4 2008/12/02 19:08:54 elphel
*! Bug fixin setFramePar()
*!
*! Revision 1.3 2008/11/30 05:01:03 elphel
*! Changing gains/scales behavior
*!
*! Revision 1.2 2008/11/28 08:17:09 elphel
*! keeping Doxygen a little happier
*!
*! Revision 1.1.1.1 2008/11/27 20:04:00 elphel
*!
*!
*! Revision 1.41 2008/11/17 06:42:37 elphel
*! added SETFRAMEREL - skipping specified number of frames from current (through lseek)
*!
*! Revision 1.40 2008/11/14 07:09:48 elphel
*! additional test to prevent "JUST_THIS" parameters to be written to the future-most frame (otherwise it can get stuck)
*!
*! Revision 1.39 2008/11/13 05:40:45 elphel
*! 8.0.alpha16 - modified histogram storage, profiling
*!
*! Revision 1.38 2008/11/05 02:01:25 elphel
*! Added bit field manipulation in parameters
*!
*! Revision 1.37 2008/11/02 00:31:25 elphel
*! reduced required initialization steps
*!
*! Revision 1.36 2008/10/29 04:18:28 elphel
*! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
*!
*! Revision 1.35 2008/10/25 19:59:48 elphel
*! added lseek() calls to enable/disable daemons at events (compressed frame available, any frame available, histogram-Y and histograms-C available)
*!
*! Revision 1.34 2008/10/23 18:25:40 elphel
*! removed unneeded test condition before calling wait_event_interruptible()
*!
*! Revision 1.33 2008/10/23 08:03:38 elphel
*! cleanup
*!
*! Revision 1.32 2008/10/21 21:28:26 elphel
*! minor bug fix
*!
*! Revision 1.31 2008/10/20 18:46:36 elphel
*! all the functions for the same target frame are processed in the order regardless of latencies
*!
*! Revision 1.30 2008/10/19 06:51:51 elphel
*! rearranged initialization, added frame number reset (to avoid unlikely integer overflow)
*!
*! Revision 1.29 2008/10/17 05:44:48 elphel
*! fixing latencies
*!
*! Revision 1.28 2008/10/15 22:28:56 elphel
*! snapshot 8.0.alpha2
*!
*! Revision 1.27 2008/10/12 06:13:10 elphel
*! snapshot
*!
*! Revision 1.26 2008/10/11 18:46:07 elphel
*! snapshot
*!
*! Revision 1.25 2008/10/10 17:06:59 elphel
*! just a snapshot
*!
*! Revision 1.24 2008/10/08 21:26:25 elphel
*! snapsot 7.2.0.pre4 - first images (actually - second)
*!
*! Revision 1.23 2008/10/06 08:31:08 elphel
*! snapshot, first images
*!
*! Revision 1.22 2008/10/05 05:13:33 elphel
*! snapshot003
*!
*! Revision 1.21 2008/10/04 16:10:12 elphel
*! snapshot
*!
*! Revision 1.20 2008/09/28 00:31:57 elphel
*! snapshot
*!
*! Revision 1.19 2008/09/25 00:58:11 elphel
*! snapshot
*!
*! Revision 1.18 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.17 2008/09/19 04:37:25 elphel
*! snapshot
*!
*! Revision 1.16 2008/09/16 00:49:31 elphel
*! snapshot
*!
*! Revision 1.15 2008/09/12 20:40:11 elphel
*! snapshot
*!
*! Revision 1.14 2008/09/12 00:28:54 elphel
*! typo fixed
*!
*! Revision 1.13 2008/09/12 00:23:59 elphel
*! removed cc353.c, cc353.h
*!
*! Revision 1.12 2008/09/07 19:48:08 elphel
*! snapshot
*!
*! Revision 1.11 2008/09/05 23:20:26 elphel
*! just a snapshot
*!
*! Revision 1.10 2008/09/04 17:37:13 elphel
*! documenting
*!
*! Revision 1.9 2008/09/02 21:01:06 elphel
*! just next...
*!
*! Revision 1.8 2008/07/27 04:27:49 elphel
*! next snapshot
*!
*! Revision 1.7 2008/06/24 00:43:44 elphel
*! just a snapshot
*!
*! Revision 1.6 2008/06/20 03:54:19 elphel
*! another snapshot
*!
*! Revision 1.5 2008/06/19 02:17:36 elphel
*! continuing work - just a snapshot
*!
*! Revision 1.4 2008/06/16 06:51:21 elphel
*! work in progress, intermediate commit
*!
*! Revision 1.3 2008/06/10 00:03:14 elphel
*! storing past frame data - subset of the frame parameters
*!
*! Revision 1.2 2008/06/08 23:48:39 elphel
*! minor cleanup
*!
*! Revision 1.1 2008/05/26 23:33:00 elphel
*! Added driver to handle multi-frame parameters
*!
*!
*/
//copied from cxi2c.c - TODO:remove unneeded
#include /// div for 64
#include /// div for 64
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
//#include
#include // endians
#include
#include
#include
#include
#include
#include
#include
//#include "fpgactrl.h" // defines port_csp0_adsensor_common.hdr, port_csp4_addr
//#include "cc3x3.h"
//#include "x3x3.h" // hardware definitions
#include "sensor_common.h"
#include "framepars.h"
#include "param_depend.h" // specifies what functions should be called for different parameters changed
/// needed for lseek commands
//#include "cxdma.h" // x313_dma_init
//#include "cci2c.h" // to use void i2c_reset_wait(void), reset shadow static 'i2c_hardware_on'
#include "x393_macro.h"
/**
* \def MDF1(x) optional debug output
*/
#if ELPHEL_DEBUG
#define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;}
#define MDF2(x) { if (GLOBALPARS(G_DEBUG) & (1 <<2)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
/// setFrameParsAtomic
#define MDF5(x) { if (GLOBALPARS(G_DEBUG) & (1 <<5)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
#define D5(x) { if (GLOBALPARS(G_DEBUG) & (1 <<5)) {x ;} }
/// processPars
#define MDF6(x) { if (GLOBALPARS(G_DEBUG) & (1 <<6)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
#define D6(x) { if (GLOBALPARS(G_DEBUG) & (1 <<6)) {x ;} }
///update FramePars
#define MDF7(x) { if (GLOBALPARS(G_DEBUG) & (1 <<7)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
#define D7(x) { if (GLOBALPARS(G_DEBUG) & (1 <<7)) {x ;} }
/// setFramePar[s]
#define MDF8(x) { if (GLOBALPARS(G_DEBUG) & (1 <<8)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
#define D8(x) { if (GLOBALPARS(G_DEBUG) & (1 <<8)) {x ;} }
#define ELPHEL_DEBUG_THIS 0
// #define ELPHEL_DEBUG_THIS 1
#else
#define MDF(x)
#define MDF2(x)
#define MDF5(x)
#define D5(x)
#define MDF6(x)
#define D6(x)
#define MDF7(x)
#define D7(x)
#define MDF8(x)
#define D8(x)
#define ELPHEL_DEBUG_THIS 0
#endif
#if ELPHEL_DEBUG_THIS
#define MDD1(x) printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__); x ; udelay (ELPHEL_DEBUG_DELAY)
#define MDF1(x) printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__); x
#define D1(x) x
#define D1I(x)
#else
#define MDD1(x)
#define MDF1(x)
#define D1(x)
#define D1I(x) x
#endif
//#define ELP_KERR(x) printk("%s:%d:%s: ERROR ",__FILE__,__LINE__,__FUNCTION__); x
/**
* \def FRAMEPARS_DRIVER_NAME driver name to display
*/
#define FRAMEPARS_DRIVER_NAME "Elphel (R) Model 393 Frame Parameters device driver"
static const struct of_device_id elphel393_framepars_of_match[];
static struct framepars_all_t sFrameParsAll __attribute__ ((aligned (PAGE_SIZE))); ///< Sensor Parameters, currently 8 pages all and 2048 pages some, static struct
unsigned long frameParsInitialized; /// set to 0 at startup, 1 after initialization that is triggered by setParsAtomic()
#define thisFrameNumber GLOBALPARS(G_THIS_FRAME) // Current frame number (may lag from the hardware)
//#define THISFRAMENUMBER GLOBALPARS(G_THIS_FRAME) // Current frame number (may lag from the hardware)
struct framepars_all_t *frameparsall=NULL; /// - will be mmap-ed
struct framepars_t *framepars= NULL; ///< getting rid of static to be able to use extern
struct framepars_past_t *pastpars= NULL; ///< getting rid of static to be able to use extern
unsigned long *funcs2call= NULL; /// sFrameParsAll.func2call.pars; - each parameter has a 32-bit mask of what pgm_function to call - other fields not used
unsigned long *globalPars= NULL; /// parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
unsigned long *multiSensIndex= NULL; /// index for per-sensor alternatives
unsigned long *multiSensRvrsIndex=NULL; /// reverse index (to parent) for the multiSensIndex
wait_queue_head_t framepars_wait_queue; /// used to wait for the frame to be acquired
/**
* @brief file private data
*/
struct framepars_pd {
int minor; ///< file minor value
struct wait_queue *framepars_wait_queue; ///< wait queue (waiting for file number to increase) ///NOTE: not used at all?
// something else to be added here?
};
/**
* @brief assign non-static pointers to static data to be used as extern
*/
void init_framepars_ptr(void) {
frameparsall= &sFrameParsAll; /// - will be mmap-ed
framepars = sFrameParsAll.framePars;
pastpars = sFrameParsAll.pastPars;
funcs2call = sFrameParsAll.func2call.pars; /// each parameter has a 32-bit mask of what pgm_function to call - other fields not used
globalPars = sFrameParsAll.globalPars; /// parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
multiSensIndex= sFrameParsAll.multiSensIndex; /// indexes of individual sensor register shadows (first of 3) - now for all parameters, not just sensor ones
multiSensRvrsIndex= sFrameParsAll.multiSensRvrsIndex; /// reverse index (to parent) for the multiSensIndex
}
int framepars_open (struct inode *inode, struct file *filp);
int framepars_release(struct inode *inode, struct file *filp);
loff_t framepars_lseek (struct file * file, loff_t offset, int orig);
ssize_t framepars_write (struct file * file, const char * buf, size_t count, loff_t *off);
int framepars_mmap (struct file *file, struct vm_area_struct *vma);
/**
* @brief Reset hardware sequencers (i2c, command) and initialize framepars structure
*/
void initSequencers(void) {
unsigned long flags;
MDF2(printk ("\n"));
printk ("initSequencers:resetting both sequencers\n");
#ifdef TEST_DISABLE_CODE
local_irq_save(flags);
X3X3_SEQ_RESET;
i2c_reset_wait();
local_irq_restore(flags);
initFramePars();
#endif
}
/**
* @brief reset absolute frame number \b thisFrameNumber to \b frame8
*/
void resetFrameNumber(void) {
int i;
#ifdef TEST_DISABLE_CODE
thisFrameNumber= X3X3_I2C_FRAME;
#endif
MDF2(printk (" thisFrameNumber=0x%lx\n",thisFrameNumber));
// write absolute frame numbers
for (i=thisFrameNumber; i<(thisFrameNumber+PARS_FRAMES); i++) framepars[i & PARS_FRAMES_MASK].pars[P_FRAME]=i;
/// initialize frameParsDeps.pars masks:
}
/**
* @brief initialize all parameters, set \b thisFrameNumber to \b frame number read from hardware hardware ( 0 after resetting i2c and cmd_seq)
*/
void initFramePars(void) {
int i;
memset(framepars, 0, sizeof(framepars));
resetFrameNumber();
/// initialize frameParsDeps.pars masks:
for (i=0; i < (sizeof(param_depend_tab)/8); i++) {
funcs2call[param_depend_tab[2*i] & 0xffff]=param_depend_tab[2*i+1]; /// remove possible flags
MDF2(printk("funcs2call[0x%lx]=0x%08lx\n",param_depend_tab[2*i] & 0xffff,param_depend_tab[2*i+1]));
}
for (i=0; i < P_SENSOR_NUMREGS; i++) funcs2call[P_SENSOR_REGS+i] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
/// Same for 10359 registers - will not change anything if there is no 10359 - these registers will not be chnaged, and if will be it wil cause no action
for (i=0; i < P_M10359_NUMREGS; i++) funcs2call[P_M10359_REGS+i] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
initMultiPars(); /// initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
frameParsInitialized=1;
}
/**
* @brief reset all global parameters, set default for debug mask (if ELPHEL_DEBUG)
*/
void initGlobalPars(void) {
memset(&globalPars[GLOBALS_PRESERVE], 0, sizeof(globalPars)-GLOBALS_PRESERVE*sizeof(globalPars[0]));
/// MDF(GLOBALPARS(G_DEBUG) = ELPHEL_DEBUG_STARTUP;// removed - add write to fpga init script
MDF(printk("GLOBALPARS(G_DEBUG)=%lx\n",GLOBALPARS(G_DEBUG)));
}
/**
* @brief initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
* @return number of multi-regs
*/
int initMultiPars(void) {
int i,j,n;
int ireg=P_MULTI_REGS; /// multi-reg shadows start index
unsigned long m;
memset(multiSensIndex, 0, sizeof(multiSensIndex));
memset(multiSensRvrsIndex, 0, sizeof(multiSensRvrsIndex));
GLOBALPARS(G_MULTI_NUM)=0;
for (i=0;i<8;i++) {
m=GLOBALPARS(G_MULTI_REGSM+i); /// 1 bit per register that need individual shadows
// MDF(printk("i=%d, m=0x%lx\n",i,m));
for (j= P_SENSOR_REGS +(i<<5); m && (GLOBALPARS(G_MULTI_NUM)>= 1) {
if (m & 1) {
multiSensIndex[j]=ireg;
// MDF(printk("j=0x%x ireg=0x%x\n",j,ireg));
for (n=0;nheight= framepars[findex_this].pars[P_ACTUAL_HEIGHT]; /// NOTE: P_ACTUAL_WIDTH,P_QUALITY copied with memcpy
interframe_pars->color= framepars[findex_this].pars[P_COLOR];
interframe_pars->byrshift=framepars[findex_this].pars[P_COMPMOD_BYRSH];
interframe_pars->quality2 |= (framepars[findex_this].pars[P_PORTRAIT] & 1) << 7;
}
/// copy parameters from findex_future (old "fartherst in the future") to findex_prev (new "fartherst in the future") if it was changed since
if ((bmask32=framepars[findex_prev].modsince32)) {
MDF7(printk("framepars[%d].modsince32=0x%lx\n",findex_prev,bmask32));
for (index32=0; bmask32; index32++, bmask32 >>= 1) {
if (bmask32 & 1) {
for (index=(index32<<5),bmask=framepars[findex_prev].modsince[index32]; bmask; index++, bmask >>= 1)
if (bmask & 1) {
framepars[findex_prev].pars[index] = framepars[findex_future].pars[index];
MDF7(printk("hw=%d framepars[%d].pars[%d]=framepars[%d].pars[%d]=0x%lx\n",frame8, findex_prev,index,findex_future,index,framepars[findex_future].pars[index]));
}
framepars[findex_prev].modsince[index32]=0; /// mark as not "modified since" (yet)
}
}
framepars[findex_prev].modsince32=0;/// mark as not "modified since" super index
}
/// clear "modified" and flags on the brand new future frame
if (framepars[findex_prev].mod32) memset(framepars[findex_prev].mod, 0, 32*4); /// .mod[0]-.mod[30], .mod32
framepars[findex_prev].functions=0; /// No functions yet needed on the brand new frame
framepars[findex_prev].pars[P_FRAME]=thisFrameNumber+7; /// that will be the full frame number
/// NOTE: Handle past due - copy functions, and mod if functions were non-zero
if (framepars[findex_this].functions) { /// Some functions were not yet processed (past due)
if (!(get_globalParam(G_TASKLET_CTL) & (1 << TASKLET_CTL_IGNPAST))) {
framepars[findex_next].functions |= framepars[findex_this].functions;
if ((bmask32=framepars[findex_this].mod32)) {
for (index32=0; bmask32; index32++, bmask32 >>= 1) {
if (bmask32 & 1) {
framepars[findex_next].mod[index32] |= framepars[findex_this].mod[index32];
}
framepars[findex_next].mod32 |= framepars[findex_this].mod32;
}
}
MDF7(printk ("resubmitting past due functions = 0x%lx for frame=%ld (0x%x)\n",framepars[findex_this].functions,thisFrameNumber,findex_this));
} else {
MDF(printk ("Ignored past due functions = 0x%lx for frame=%ld (0x%x)\n",framepars[findex_this].functions,thisFrameNumber,findex_this));
}
}
thisFrameNumber++;
}
}
/**
* @brief process parameters that are overdue or due in ASAP mode (not through the sequencer)
* Called twice from processPars - at the beginning and at the end to finish off any derivatives (needed?)
* @param sensorproc
* @param frame8
*/
inline void processParsASAP (struct sensorproc_t * sensorproc, int frame8) {
unsigned long todo, mask , remain;
int pars_ahead; /// considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8
int frame_proc; /// current frame for which parameters are considered
struct framepars_t * procpars;
struct framepars_t * prevpars ; /// maybe - drop calculation for each function, move it to pgm_* where needed?
unsigned long * p_nasap=& GLOBALPARS(G_CALLNASAP);
int i;
int rslt;
#if ELPHEL_DEBUG
unsigned long allfunctions=framepars[0].functions | framepars[1].functions | framepars[2].functions | framepars[3].functions |
framepars[4].functions | framepars[5].functions | framepars[6].functions | framepars[7].functions;
if (allfunctions) MDF6(printk("frame8=%d, functions: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", frame8, framepars[0].functions,framepars[1].functions,framepars[2].functions,framepars[3].functions,framepars[4].functions,framepars[5].functions,framepars[6].functions,framepars[7].functions));
#endif
/// do all ASAP tasks (they should not be done ahead of the corresponding interrupt!)
/// Now try overdue functions with latencies >=1 and try them in ASAP mode
for (pars_ahead=0; pars_ahead <= 4; pars_ahead++ ) {
frame_proc=(frame8 + pars_ahead) & PARS_FRAMES_MASK;
procpars = &framepars[frame_proc];
prevpars = &framepars[(frame_proc-1) & PARS_FRAMES_MASK];
i=0;
mask=1;
remain=0xffffffff;
while ((todo=(pars_ahead)?
(p_nasap[pars_ahead] & (procpars->functions) & remain):
(procpars->functions & remain) )) { ///none, *1, *2,*3,*4
while (!(todo & mask)) { /// skip zeros - todo will stay current (.functions will not change
i++;
mask <<=1;
remain <<=1;
}
/// now (todo & mask) !=0
MDF6(printk(" todo=0x%08lx (curr=0x%08lx) frame8=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx\n", todo, procpars->functions, frame8,pars_ahead,frame_proc,i,mask));
MDF6(printk(" %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", framepars[0].functions,framepars[1].functions,framepars[2].functions,framepars[3].functions,framepars[4].functions,framepars[5].functions,framepars[6].functions,framepars[7].functions));
if (sensorproc->pgm_func[i]) {
rslt=sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, -1);
} else rslt=0; /// only sensor-specific function, nothing to do common to all sensors
if ((rslt >= 0) && (sensorproc->pgm_func[i+32])) { /// sensor - specific functions, called after the main ones
rslt=sensorproc->pgm_func[i+32] ( &(sensorproc->sensor), procpars, prevpars, -1);
}
/// Nothing to do with errors here - just report?
if (rslt<0) printk("%s:%d:%s - error=%d",__FILE__,__LINE__,__FUNCTION__, rslt);
procpars->functions &= ~mask;
MDF6(printk(".functions=0x%08lx)\n", procpars->functions));
i++;
mask <<=1;
remain <<=1;
}
}
}
/// Next 5 should go in that sequence
//#define G_CALLNASAP 119 // bitmask - what functions can be used not only in the current frame (ASAP) mode
//#define G_CALLNEXT1 120 // bitmask of actions to be one or more frames ahead of the programmed one (OR-ed with G_CALLNEXT2..G_CALLNEXT4)
//#define G_CALLNEXT2 121 // bitmask of actions to be two or more frames ahead of the programmed one (OR-ed with G_CALLNEXT3..G_CALLNEXT4)
//#define G_CALLNEXT3 122 // bitmask of actions to be three or more frames ahead of the programmed one (OR-ed with G_CALLNEXT4)
//#define G_CALLNEXT4 123 // bitmask of actions to be four or more frames ahead of the programmed one
inline void processParsSeq (struct sensorproc_t * sensorproc, int frame8, int maxahead) {
unsigned long todo, mask , remain;
int job_ahead; /// doing job "job_ahead" ahead of needed
int pars_ahead; /// considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8
int frame_proc; /// current frame for which parameters are considered
struct framepars_t * procpars;
struct framepars_t * prevpars ; /// maybe - drop calculation fpr each function, move it to pgm_* where needed?
unsigned long * p_nasap=& GLOBALPARS(G_CALLNASAP);
int seq_frame; /// sequencer frame for which pgm_* function should schedule data
int i;
int rslt;
int max_par_ahead;
int this_ahead;
if (maxahead > (PARS_FRAMES-3)) maxahead = PARS_FRAMES-3; /// use 5 if maxahead >5
/// commands that use FPGA queues for the i2c/sequencer commands, executed at frame syncs
/// Modifying - as soon as found the frame to process with non-zero masked .functions - process all functions for that
/// frame with appropriate sequencer frame.
/// For now - scan p_nasap[i] to find latency - improve that later
for (job_ahead=0; job_ahead <= maxahead; job_ahead++ ) {
max_par_ahead=min(5,(PARS_FRAMES-3) -job_ahead);
for (pars_ahead=0; pars_ahead < max_par_ahead; pars_ahead++ ) {
frame_proc=(frame8 + job_ahead + pars_ahead +1) & PARS_FRAMES_MASK; ///
procpars = &framepars[frame_proc];
/// Check if at least one function is needed for frame_proc
if (procpars->functions &
p_nasap[pars_ahead] & ///all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice
p_nasap[0]) {
prevpars = &framepars[(frame_proc-1) & PARS_FRAMES_MASK];
// seq_frame= (frame8+job_ahead+1) & PARS_FRAMES_MASK;
i=0;
mask=1;
remain=0xffffffff;
while ((todo=procpars->functions &
/// p_nasap[pars_ahead] & ///all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice
p_nasap[0] & remain)) { /// eliminate ASAP-only function
while (!(todo & mask)) { /// skip zeros - todo will stay current (.functions will not change)
i++;
mask <<=1;
remain <<=1;
}
/// now (todo & mask) !=0
/// find the right latency
for (this_ahead=1; (p_nasap[this_ahead] & todo & mask) && (this_ahead <=4); this_ahead++); /// this_ahead==1..5
// seq_frame= (frame8 + job_ahead + this_ahead) & PARS_FRAMES_MASK;
seq_frame= (frame_proc+1-this_ahead) & PARS_FRAMES_MASK;
MDF6(printk(" todo=0x%08lx (curr=0x%08lx) frame8=%d, frame_proc=%d, seq_frame=%d, i=%d, mask=0x%08lx\n", todo, procpars->functions, frame8,frame_proc,seq_frame,i,mask));
MDF6(printk(" %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", framepars[0].functions,framepars[1].functions,framepars[2].functions,framepars[3].functions,framepars[4].functions,framepars[5].functions,framepars[6].functions,framepars[7].functions));
if (sensorproc->pgm_func[i]) {
/// NOTE: Was (frame8+job_ahead +1) & PARS_FRAMES_MASK
rslt=sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, seq_frame);
} else rslt=0; /// only sensor-specific function, nothing to do common to all sensors
if ((rslt >= 0) && (sensorproc->pgm_func[i+32])) { /// sensor - specific functions, called after the main ones
rslt=sensorproc->pgm_func[i+32] ( &(sensorproc->sensor), procpars, prevpars, seq_frame);
}
if (rslt >= 0) {
procpars->functions &= ~mask; /// mark it done
} else {
MDF6(printk("Error - function result was %d\n", rslt));
}
i++;
mask <<=1;
remain <<=1;
}
}
}
}
}
/**
* @brief Program image acquisition, according to the parameters changed
* Called from ISR?
* @param sensorproc pointer to sensor static parameters and functions
* @param frame8 current hardware frame number
* @param maxahead maximal number of frames to program ahead of the current (make it P_* parameter ?)
* @return always 0 ?
*/
//TODO: "Do it later" should be the only reason not to erase todo bit
//#define P_CALLASAP 107 // bitmask - what functions work only in the current frame (ASAP) mode
void processPars (struct sensorproc_t * sensorproc, int frame8, int maxahead) {
frame8 &= PARS_FRAMES_MASK;
/// first - do all ASAP tasks (they should not be done ahead of the corresponding interrupt!)
// MDF6(printk("before first processParsASAP\n"));
processParsASAP (sensorproc, frame8);
/// now - the rest commands that use FPGA queues for the i2c/sequencer commands, executed at frame syncs
/// for jobahead =0 it is still possible to have some functions in ASAP mode with non-zero latency
// MDF6(printk("before processParsSeq\n"));
processParsSeq (sensorproc, frame8, maxahead);
/// re-test ASAP tasks - they might appear as a result of other commands executed
// MDF6(printk("before second processParsASAP\n"));
processParsASAP (sensorproc, frame8);
}
/**
* @brief schedule pgm_func to be executed for selected frame (frame8)
* @param frame8 frame number (3-bit) to schedule a function for
* @param func_num function number to schedule
*/
void schedule_pgm_func(int frame8, int func_num) {
MDF1(printk(" frame8=%d, func_num=%d\n", frame8, func_num));
framepars[frame8 & PARS_FRAMES_MASK].functions |= 1 << func_num;
}
/**
* @brief schedule pgm_func to be executed for this_framepars->pars[P_FRAME] & PARS_FRAMES_MASK
* @param this_framepars pointer to frame parameters structure
* @param func_num number of function to schedule
*/
void schedule_this_pgm_func(struct framepars_t * this_framepars, int func_num) {
int frame8=this_framepars->pars[P_FRAME] & PARS_FRAMES_MASK;
MDF1(printk(" frame8=%d, func_num=%d\n", frame8, func_num));
framepars[frame8].functions |= 1 << func_num;
}
/**
* @brief just return current thisFrameNumber
* @return current value of thisFrameNumber
*/
unsigned long getThisFrameNumber(void) {
return thisFrameNumber;
}
/**
* @brief Set parameters that will never change (usually after sensor discovery)
* @param numPars number of parameters to set
* @param pars array of parameters (number/value pairs)
* @return always 0
*/
int setFrameParsStatic(int numPars, struct frameparspair_t * pars) {
int npar,nframe,index;
for (npar=0; npar < numPars; npar++) {
index=pars[npar].num;
if (index > P_MAX_PAR) return -ERR_FRAMEPARS_BADINDEX;
for (nframe=0; nframe < PARS_FRAMES; nframe++) {
framepars[nframe].pars[index]=pars[npar].val;
}
}
return 0;
}
/**
* @brief set parameters for the specified frame (atomic, with interrupts off). Used from applications through driver write
* @param frameno absolute (full) frame number parameters should be applied to
* @param maxLatency maximal command latency (parameters should be set not less than maxLatency ahead of the current frame)
* maxLatency < 0 - don't check latency (i.e.only commands that are not releted to particular frames)
* @param numPars number of parameters to set (0 is OK to just test if it is too early/too late)
* @param pars array of parameters (number/value pairs). FRAMEPAIR_FORCE_NEW modifier to parameter number
* @return 0 - OK, -ERR_FRAMEPARS_TOOEARLY, -ERR_FRAMEPARS_TOOLATE
*/
///TODO: Check that writes never to the future or past frame (only 6 of 8 are allowed). Have seen just_this to flood all
int setFrameParsAtomic(unsigned long frameno, int maxLatency, int numPars, struct frameparspair_t * pars) {
unsigned long flags;
int npar,nframe;
unsigned long val, bmask, bmask32;
int index,bindex;
if (!frameParsInitialized) {
initSequencers(); /// Will call initFramePars(); and initialize functions
}
int findex_this= thisFrameNumber & PARS_FRAMES_MASK;
int findex_prev= (findex_this-1) & PARS_FRAMES_MASK;
int findex_future=(findex_this-2) & PARS_FRAMES_MASK; /// actually - fartherst in the future??
// int frame8= frameno & PARS_FRAMES_MASK;
int frame8;
MDF2(printk (": frameno=0x%lx, findex_this=%d (0x%lx) maxLatency=%d, numPars=%d\n",frameno, findex_this, thisFrameNumber, maxLatency, numPars));
D1I(local_irq_save(flags));
PROFILE_NOW(6);
if (maxLatency>=0) {
if (frameno <= (thisFrameNumber+maxLatency)) {
D1I(local_irq_restore(flags));
return -ERR_FRAMEPARS_TOOLATE;
}
else if (frameno >= (thisFrameNumber+ (PARS_FRAMES-1))) {
D1I(local_irq_restore(flags));
return -ERR_FRAMEPARS_TOOEARLY;
}
}
/// not too late, not too early, go ahead
for (npar=0; npar < numPars; npar++) {
D5(printk(" --pars[%d].num=0x%lx, pars[%d].val=0x%lx",npar,pars[npar].num, npar, pars[npar].val));
// frame8= (pars[npar].num & FRAMEPAR_GLOBALS)? -1: (frameno & PARS_FRAMES_MASK);
frame8= frameno & PARS_FRAMES_MASK;
val=pars[npar].val;
index= pars[npar].num & 0xffff;
if (index> ((index >= FRAMEPAR_GLOBALS)? (P_MAX_GPAR+FRAMEPAR_GLOBALS): P_MAX_PAR)) {
D1I(local_irq_restore(flags));
return -ERR_FRAMEPARS_BADINDEX;
}
D5(printk(" index=0x%x, val=0x%lx",index, val));
if (index >= FRAMEPAR_GLOBALS) { /// ignore frame logic, set "static" parameters to frame 0
if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, GLOBALPARS(index), val);
}
GLOBALPARS(index)=val;
D5(printk(" set GLOBALPARS(0x%x)=0x%lx\n",index,val));
} else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) {
funcs2call[index] = val;
D5(printk(" set funcs2call[0x%x]=0x%lx\n",index,val));
// } else if ((frameno !=findex_prev) && (frameno != findex_future)) { /// do not write parameters in the future otherwise
} else if ((frame8 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick
if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame8].pars[index], val);
}
//TODO: optimize to use mask several parameters together
D5(printk(" frame8=0x%x\n",frame8));
if ((framepars[frame8].pars[index]!= val) || (pars[npar].num & FRAMEPAIR_FORCE_NEW)){
bmask= 1 << (index & 31);
bindex = index >> 5;
bmask32= 1 << bindex;
/// Set this parameter for specified frame
framepars[frame8].pars[index] = val;
framepars[frame8].mod[bindex] |= bmask;
framepars[frame8].mod32 |= bmask32;
framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters
D5(printk(" bindex=0x%x, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",bindex, bmask, bmask32, framepars[frame8].functions));
/// Write parameter to the next frames up to the one that have the same parameter already modified (only if not FRAMEPAIR_JUST_THIS)
if ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0) {
MDF5(printk (": --- setting next frames"));
for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
framepars[nframe].pars[index] = val;
D5(printk (" %d",nframe));
}
frame8=(frame8-1) & PARS_FRAMES_MASK;/// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
D5(printk ("\n"));
}
/// Mark this parameter in all previous frames as "modified since"
/// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
for (nframe=frame8; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here
framepars[nframe].modsince[bindex] |= bmask;
framepars[nframe].modsince32 |= bmask32;
}
}
} else { /// error - trying to write "just this" to the "future" - that would stick if allowed
D1I(local_irq_restore(flags));
ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num));
return -ERR_FRAMEPARS_TOOEARLY;
}
}
/// Try to process parameters immediately after written. If 0, only non-ASAP will be processed to prevent
/// effects of uncertainty of when was it called relative to frame sync
/// Changed to all (don't care about uncertainty - they will trigger only if it is too late or during sensor detection/initialization)
if (!(get_globalParam(G_TASKLET_CTL) & (1<< TASKLET_CTL_NOSAME))) {
// processParsSeq (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet
MDF5(printk ("\n"));
processPars (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet
}
PROFILE_NOW(7);
D1I(local_irq_restore(flags));
return 0;
}
//#define FRAMEPAIR_JUST_THIS 0x40000 // write only to this frame, don't propagate
// (like "single frame" - compressor, sensor) first write "stop", then - "single" with FRAMEPAIR_JUST_THIS
/**
* @brief set a single output (calculated) parameter for the frame referenced by this_framepars structure.
* Shedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in mindex
* @param this_framepars pointer to the current parameters structure
* @param mindex parameter number (with optional modifiers in high bits)
* @param val parameter value to set
* @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
*/
int setFramePar(struct framepars_t * this_framepars, unsigned long mindex, unsigned long val) {
int frame8= (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK;
unsigned long flags;
int nframe;
unsigned long bmask, bmask32 , bindex;
int findex_this= thisFrameNumber & PARS_FRAMES_MASK;
int findex_prev= (findex_this-1) & PARS_FRAMES_MASK;
int findex_future=(findex_this-2) & PARS_FRAMES_MASK;
int index= mindex & 0xffff;
MDF8(printk (": thisFrameNumber=0x%lx frame8=%d index= %d (0x%lx), val=0x%lx\n", thisFrameNumber, frame8, index, mindex, val));
D1I(local_irq_save(flags));
// if (index > P_MAX_PAR) {
if (index> ((index >= FRAMEPAR_GLOBALS)? (P_MAX_GPAR+FRAMEPAR_GLOBALS): P_MAX_PAR)) {
D1I(local_irq_restore(flags));
return -ERR_FRAMEPARS_BADINDEX;
}
//TODO: optimize to use mask several parameters together
if (index >= FRAMEPAR_GLOBALS) { /// ignore frame logic, set "static" parameters to frame 0
if (mindex & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
val= FRAMEPAIR_FRAME_MASK_NEW(mindex, GLOBALPARS(index), val);
}
GLOBALPARS(index)=val;
} else if (mindex & FRAMEPAIR_FRAME_FUNC) { /// write to func_proc[] instead
funcs2call[index] = val;
// } else {
} else if ((frame8 != findex_future) || ((mindex & FRAMEPAIR_JUST_THIS)==0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick
if (mindex & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
val= FRAMEPAIR_FRAME_MASK_NEW(mindex, framepars[frame8].pars[index], val);
}
if ((framepars[frame8].pars[index]!= val) || (mindex & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))){
bmask= 1 << (index & 31);
bindex = index >> 5;
bmask32= 1 << bindex;
/// Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED!
framepars[frame8].pars[index] = val;
framepars[frame8].mod[bindex] |= bmask;
framepars[frame8].mod32 |= bmask32;
if (mindex & FRAMEPAIR_FORCE_PROC){
framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters
}
MDF8(printk(" bindex=0x%lx, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",bindex, bmask, bmask32, framepars[frame8].functions));
/// Write parameter to the next frames up to the one that have the same parameter already modified
if ((mindex & FRAMEPAIR_JUST_THIS)==0) {
MDF8(printk (": --- setting next frames"));
// for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[frame8].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
framepars[nframe].pars[index] = val;
D8(printk (" %d",nframe));
}
frame8=(frame8-1) & PARS_FRAMES_MASK; /// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
}
// MDF1(printk("\n"));
/// Mark this parameter in all previous frames as "modified since"
/// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
MDF8(printk (": >>> setting modsince"));
// for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) {
for (nframe=frame8; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here
framepars[nframe].modsince[bindex] |= bmask;
framepars[nframe].modsince32 |= bmask32;
D8(printk (" %d",nframe));
}
D8(printk ("\n"));
}
} else { /// error - trying to write "just this" to the "future" - that would stick if allowed
D1I(local_irq_restore(flags));
ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex));
return -ERR_FRAMEPARS_TOOEARLY;
}
D1I(local_irq_restore(flags));
return 0;
}
/**
* @brief set multiple output (calculated) parameters for the frame referenced by this_framepars structure.
* Shedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in the particular parameter index
* @param this_framepars pointer to the current parameters structure
* @param numPars number of parameters to set
* @param pars array of parameters (number/value pairs). Parameter numbers accept modifiers
* @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
*/
int setFramePars(struct framepars_t * this_framepars, int numPars, struct frameparspair_t * pars) {
int frame8;
unsigned long flags;
int npar,nframe;
unsigned long val, bmask, bmask32;
int index,bindex;
int findex_this= thisFrameNumber & PARS_FRAMES_MASK;
int findex_prev= (findex_this-1) & PARS_FRAMES_MASK;
int findex_future=(findex_this-2) & PARS_FRAMES_MASK;
MDF8(printk (": this_framepars=0x%x numPars=%d\n",(int) this_framepars, numPars));
D1I(local_irq_save(flags));
for (npar=0; npar < numPars; npar++) {
frame8= (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK;
val=pars[npar].val;
index= pars[npar].num & 0xffff;
MDF8(printk (": --- frame8=%d index=%d (0x%x) val=0x%x\n", frame8, index, (int) pars[npar].num, (int) val));
if (index> ((index >= FRAMEPAR_GLOBALS)? (P_MAX_GPAR+FRAMEPAR_GLOBALS): P_MAX_PAR)) {
D1I(local_irq_restore(flags));
ELP_KERR(printk(" bad index=%d > %d\n", index, P_MAX_PAR));
return -ERR_FRAMEPARS_BADINDEX;
}
if (index >= FRAMEPAR_GLOBALS) { /// ignore frame logic, set "static" parameters to frame 0
if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, GLOBALPARS(index), val);
}
GLOBALPARS(index)=val;
} else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) {
funcs2call[index] = val;
// } else {
} else if ((frame8 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick
if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame8].pars[index], val);
}
//TODO: optimize to use mask several parameters together
if ((framepars[frame8].pars[index]!= val) || (pars[npar].num & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))){
bmask= 1 << (index & 31);
bindex = index >> 5;
bmask32= 1 << bindex;
/// Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED!
framepars[frame8].pars[index] = val;
framepars[frame8].mod[bindex] |= bmask;
framepars[frame8].mod32 |= bmask32;
if (pars[npar].num & FRAMEPAIR_FORCE_PROC){
framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters
}
/// Write parameter to the next frames up to the one that have the same parameter already modified (only if not FRAMEPAIR_JUST_THIS)
if ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0) {
MDF8(printk (": --- setting next frames"));
for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
D8(printk (" %d",nframe));
framepars[nframe].pars[index] = val;
}
frame8=(frame8-1) & PARS_FRAMES_MASK; /// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
D8(printk ("\n"));
}
/// Mark this parameter in all previous frames as "modified since"
/// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
// for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) {
for (nframe=frame8; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here
framepars[nframe].modsince[bindex] |= bmask;
framepars[nframe].modsince32 |= bmask32;
}
}
} else { /// error - trying to write "just this" to the "future" - that would stick if allowed
D1I(local_irq_restore(flags));
ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num));
return -ERR_FRAMEPARS_TOOEARLY;
}
}
D1I(local_irq_restore(flags));
return 0;
}
///TODO: make some parameters readonly (prohibited from modification from the userland)
/// File operations:
/// open, release - nop
/// read - none
/// write -> setFrameParsAtomic (first 4 bytes - absolute frame number, next 4 bytes - latency, then each 8 bytes - index/value)
/// can use current file pointer or special indexes (0x****ff01 - set frame number, 0x****ff02 - set latency) that should come before actual parameters
/// file pointer - absolute frame number
/// lseek (SEEK_SET, value) - set absolute frame number
/// lseek (SEEK_CUR, value) - set frame number relative to the current frame number (thisFrameNumber),
/// lseek (SEEK_CUR, 0) - (used by ftell()) also modifies file pointer - set it to thisFrameNumber,
/// lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
/// lseek (SEEK_END, value > 0) - execute commands, do not modify file pointer (and actually use it - frame number the command applies to)
/// mmap (should be used read only)
static struct file_operations framepars_fops = {
owner: THIS_MODULE,
llseek: framepars_lseek,
write: framepars_write,
open: framepars_open,
mmap: framepars_mmap,
release: framepars_release
};
/**
* @brief Driver OPEN method
* @param inode inode
* @param filp file pointer
* @return OK - 0, -EINVAL for wrong minor
*/
int framepars_open(struct inode *inode, struct file *filp) {
int res;
struct framepars_pd * privData;
privData= (struct framepars_pd *) kmalloc(sizeof(struct framepars_pd),GFP_KERNEL);
if (!privData) return -ENOMEM;
filp->private_data = privData;
privData-> minor=MINOR(inode->i_rdev);
MDF1(printk(": minor=0x%x\n",privData-> minor));
switch (privData-> minor) {
case CMOSCAM_MINOR_FRAMEPARS :
inode->i_size = 0; //or return 8 - number of frame pages?
return 0;
default:
kfree(filp->private_data); // already allocated
return -EINVAL;
}
return res;
}
/**
* @brief Driver RELEASE method
* @param inode inode
* @param filp file pointer
* @return OK - 0, -EINVAL for wrong minor
*/
int framepars_release(struct inode *inode, struct file *filp) {
int res=0;
int p = MINOR(inode->i_rdev);
MDF1(printk(": minor=0x%x\n",p));
switch ( p ) {
case CMOSCAM_MINOR_FRAMEPARS :
break;
default:
return -EINVAL; //! do not need to free anything - "wrong number"
}
kfree(filp->private_data);
return res;
}
/**
* @brief Driver LSEEK method (and execute commands)
* - lseek (SEEK_SET, value) - set absolute frame number
* - lseek (SEEK_CUR, value) - set frame number relative to the current frame number (thisFrameNumber),
* - lseek (SEEK_CUR, 0) - (used by ftell()) DOES NOT modify file pointer, returns thisFrameNumber,
* - lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
* - lseek (SEEK_END, value > 0) - execute commands, do not modify file pointer (and actually use it - frame number the command applies to)
* - no commands yet
* @param file
* @param offset
* @param orig SEEK_SET, SEEK_CUR or SEEK_SET END
* @return file position (absolute frame number)
*/
loff_t framepars_lseek (struct file * file, loff_t offset, int orig) {
unsigned long target_frame;
MDF1(printk(" offset=0x%x, orig=0x%x\n",(int) offset, (int) orig));
switch(orig) {
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
if (offset==0) return getThisFrameNumber(); /// do not modify frame number
file->f_pos = getThisFrameNumber() + offset; /// modifies frame number, but it is better to use absolute SEEK SET
break;
case SEEK_END:
if (offset <= 0) {
break;
} else if (offset >= LSEEK_FRAME_WAIT_REL) {
if (offset >=LSEEK_FRAME_WAIT_ABS) target_frame=offset-LSEEK_FRAME_WAIT_ABS; /// Wait for absolute frame number
else target_frame=getThisFrameNumber()+offset-LSEEK_FRAME_WAIT_REL; /// Skip 0..255 frames
wait_event_interruptible (framepars_wait_queue,getThisFrameNumber()>=target_frame);
// if (getThisFrameNumber()=target_frame);
return getThisFrameNumber(); /// Does not modify current frame pointer? lseek (,0,SEEK_CUR) anyway returns getThisFrameNumber()
} else { //! Other lseek commands
switch (offset & ~0x1f) {
case LSEEK_DAEMON_FRAME: /// wait the daemon enabled and a new frame interrupt (sensor frame sync)
wait_event_interruptible (framepars_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
break;
default:
switch (offset) {
case LSEEK_GET_FPGA_TIME:
//X313_GET_FPGA_TIME( GLOBALPARS(G_SECONDS), GLOBALPARS(G_MICROSECONDS) );
MDF2(printk("X313_GET_FPGA_TIME\n"));
break;
case LSEEK_SET_FPGA_TIME: /// better to use write, not lseek to set FPGA time
//X313_SET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) );
MDF2(printk("X313_SET_FPGA_TIME\n"));
break;
case LSEEK_FRAMEPARS_INIT: /// reset hardware sequencers, init framepars structure
MDF2(printk("LSEEK_FRAMEPARS_INIT\n"));
initGlobalPars();/// reset all global parameters but the first 32
initSequencers();
break;
case LSEEK_FRAME_RESET: /// reset absoulte frame number to avoid integer frame number overflow
MDF2(printk("LSEEK_FRAME_RESET\n"));
resetFrameNumber();
break;
case LSEEK_SENSORPROC: /// process modified parameters in frame 0 (to start sensor detection)
MDF2(printk("LSEEK_SENSORPROC: framepars[0].functions=0x%08lx\n",framepars[0].functions));
processPars (sensorproc, 0, 8); ///frame0, all 8 frames (maxAhead==8)
break;
case LSEEK_DMA_INIT: /// initialize ETRAX DMA (normally done in sensor_common.c at driver init
MDF2(printk("LSEEK_DMA_INIT\n"));
//x313_dma_init();
break;
case LSEEK_DMA_STOP: /// stop DMA
MDF2(printk("LSEEK_DMA_STOP\n"));
//x313_dma_stop(); ///
break;
case LSEEK_DMA_START: /// start DMA
MDF2(printk("LSEEK_DMA_START\n"));
//x313_dma_start(); ///
break;
case LSEEK_COMPRESSOR_RESET: /// reset compressor and buffer pointers
MDF2(printk("LSEEK_COMPRESSOR_RESET\n"));
reset_compressor();
break;
case LSEEK_INTERRUPT_OFF: /// disable camera interrupts
MDF2(printk ("LSEEK_INTERRUPT_OFF\n"));
camera_interrupts (0);
break;
case LSEEK_INTERRUPT_ON: /// enable camera interrupts
MDF2(printk ("LSEEK_INTERRUPT_ON\n"));
camera_interrupts (1);
break;
}
}
break;
}
break;
default:
return -EINVAL;
}
return file->f_pos ;
}
/**
* @brief Driver WRITE method
* writes all at once, no provisions to continue in the next call
* @param file
* @param buf
* @param count
* @param off
* @return OK - number of bytes written, negative - errors
*/
ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff_t *off) {
struct frameparspair_t pars_static[256];/// will be sufficient for most calls
struct frameparspair_t * pars = pars_static;
struct framepars_pd * privData = (struct framepars_pd *) file->private_data;
unsigned long frame=*off; /// ************* NOTE: Never use file->f_pos in write() and read() !!!
int latency=-1;
int first=0;
int last;
int result;
MDF1(printk(": file->f_pos=0x%x, *off=0x%x, count=0x%x\n", (int) file->f_pos, (int) *off, (int) count));
count &= ~7; /// sizeof (struct frameparspair_t)==8
switch (privData->minor) {
case CMOSCAM_MINOR_FRAMEPARS :
if (count>sizeof(pars_static)) /// only allocate if static is not enough
pars = (struct frameparspair_t *) kmalloc(count, GFP_KERNEL);
if (!pars) return -ENOMEM;
count >>=3; /// divide by sizeof(struct frameparspair_t); // 8
if(count) {
if(copy_from_user((char *) pars, buf, count<<3)) {
if (count>sizeof(pars_static)) kfree(pars);
return -EFAULT;
}
while (first sizeof(pars_static)) kfree(pars);
return -EFAULT;
}
first=last;
}
}
if (count>sizeof(pars_static)) kfree(pars);
return count<<3; /// *sizeof(struct frameparspair_t);
default: return -EINVAL;
}
}
/**
* @brief Driver MMAP method (should be used read only)
* provides access to both 8-frame parameters (including future ones), frame - 0 - some static ones too and
* much longer retained pastparameters - subset of all parameters
* @param file
* @param vma
* @return OK - 0, negative - errors
*/
int framepars_mmap (struct file *file, struct vm_area_struct *vma) {
int result;
struct framepars_pd * privData = (struct framepars_pd *) file->private_data;
MDF1(printk(": minor=0x%x\n",privData-> minor));
switch (privData->minor) {
case CMOSCAM_MINOR_FRAMEPARS :
result=remap_pfn_range(vma,
vma->vm_start,
((unsigned long) virt_to_phys(frameparsall)) >> PAGE_SHIFT, // Should be page-aligned
vma->vm_end-vma->vm_start,
vma->vm_page_prot);
MDF1(printk("remap_pfn_range returned=%x\r\n",result));
if (result) return -EAGAIN;
return 0;
default: return -EINVAL;
}
}
/**
* @brief framepars driver probing function
* @param[in] pdev pointer to \b platform_device structure
* @return 0 on success or negative error code otherwise
*/
static int framepars_init(struct platform_device *pdev)
{
int res;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
/* sanity check */
match = of_match_device(elphel393_framepars_of_match, dev);
if (!match)
return -EINVAL;
init_framepars_ptr();
initGlobalPars(); /// sets default debug if enabled - not anymore. Add here?
initMultiPars(); /// just clear - needs to be called again when sensor is recognized
frameParsInitialized=0;
res = register_chrdev(FRAMEPARS_MAJOR, "framepars_operations", &framepars_fops);
if(res < 0) {
printk(KERN_ERR "\nframepars_init: couldn't get a major number %d.\n",FRAMEPARS_MAJOR);
return res;
}
init_waitqueue_head(&framepars_wait_queue);
dev_info(dev, "registered MAJOR: %d\n", FRAMEPARS_MAJOR);
return 0;
}
static int framepars_remove(struct platform_device *pdev)
{
unregister_chrdev(FRAMEPARS_MAJOR, "framepars_operations");
return 0;
}
static const struct of_device_id elphel393_framepars_of_match[] = {
{ .compatible = "elphel,elphel393-framepars-1.00" },
{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, elphel393_framepars_of_match);
static struct platform_driver elphel393_framepars = {
.probe = framepars_init,
.remove = framepars_remove,
.driver = {
.name = FRAMEPARS_DRIVER_NAME,
.of_match_table = elphel393_framepars_of_match,
},
};
module_platform_driver(elphel393_framepars);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov .");
MODULE_DESCRIPTION(X3X3_FRAMEPARS_DRIVER_NAME);
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/framepars.h 0000664 0000000 0000000 00000010075 12677012326 0027057 0 ustar 00root root 0000000 0000000 #ifndef _FRAMEPARS_H
#define _FRAMEPARS_H
//extern struct framepars_t (*framepars)[PARS_FRAMES];
extern struct framepars_t *framepars;
extern struct framepars_past_t *pastpars;
extern unsigned long *globalPars;
extern unsigned long *multiSensIndex;
extern unsigned long *multiSensRvrsIndex;
extern wait_queue_head_t framepars_wait_queue;
///TODO: init framepars (zero parameters) before initscripts (not when detecting the sensors) - then initscript will be able to overwrite some
void init_framepars_ptr(void);
void initSequencers(void); ///Move to sensorcommon? currently it is used through frameparsall file (lseek)
void initGlobalPars(void); /// resets all global parameters but debug mask (if ELPHEL_DEBUG)
int initMultiPars(void); /// initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called aftre/during sensor detection
void initFramePars(void); ///initialize all parameters, set thisFrameNumber to frame8 (read from hardware, usually 0 after resetting i2c and cmd_seq)
void resetFrameNumber(void); /// reset this frame number (called from initFramePars(), also can be used to avoid frame number integer overflow)
unsigned long get_imageParamsThis (int n);
unsigned long get_imageParamsPrev (int n);
void set_imageParamsThis (int n,unsigned long d);
unsigned long get_globalParam (int n);
void set_globalParam (int n, unsigned long d);
void set_imageParamsR_all(int n, unsigned long d);
void updateFramePars(int frame8, struct interframe_params_t * frame_pars); /// called from ISR - advance thisFrameNumber to match hardware frame8, copy parameters as needed.
/// frame8 usually is just next after thisFrameNumber
/// frame_pars - pointer to structure (between frames in the frame buffer) to save a pointer to past parameters
int setFrameParsStatic(int numPars, struct frameparspair_t * pars);
unsigned long getThisFrameNumber(void); /// just return current thisFrameNumber
/// set parameters for the frame number frameno, knowing that they should be set not less than maxLatency ahead (may be sensor - dependent)
/// Parameters (numPars of them) will be updated all at once, with interrupts disabled
/// Return - 0 if OK, -ERR_FRAMEPARS_TOOEARLY or -ERR_FRAMEPARS_TOOLATE if it is too early or too late to set parameters (numPars may be 0 to just test)
///
/// NOTE: When writing parameter to P_SENSOR_RUN or P_COMPRESSOR_RUN "*_RUN_SINGLE", first write "*SENSOR_RUN_STOP" (it will propagate to all next frames) and then
/// write "*_RUN_SINGLE", to (P_*_RUN | FRAMEPAIR_JUST_THIS) - then this *_RUN_SINGLE will not propagate to the next frames (they will stay stopped)
/// TODO: Make (an "unlimited") future commands que based on lists and a tree frame index
int setFrameParsAtomic(unsigned long frameno, int maxLatency, int numPars, struct frameparspair_t * pars);
/// set output/calculated parameter and propogate changes - will not trigger any actions
int setFramePar(struct framepars_t * this_framepars, unsigned long mindex, unsigned long val);
///same for several pars at once
int setFramePars(struct framepars_t * this_framepars, int numPars, struct frameparspair_t * pars);
/// schedule pgm_func to be executed for selected frame
void schedule_pgm_func(int frame8, int func_num);
/// schedule pgm_func to be executed for the current frame
void schedule_this_pgm_func(struct framepars_t * this_framepars, int func_num);
/// program acquisition, according to the parameters changed.
/// maxahead - how many frames ahead of time (start with most urgent, then 1 ahead, ...)
/// make maxahead - P_* parameter?
inline void processParsASAP (struct sensorproc_t * sensorproc, int frame8);
inline void processParsSeq (struct sensorproc_t * sensorproc, int frame8, int maxahead);
void processPars (struct sensorproc_t * sensorproc, int frame8, int maxahead);
///*** TODO: Add option (flag?) to write "single" (like single compress, single sensor) so it will not make all the next frames "single"
#endif
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/jpeghead.c 0000664 0000000 0000000 00000077031 12677012326 0026646 0 ustar 00root root 0000000 0000000 /** @file jpeghead.c
*
* @brief This file contains methods for JPEG tables and headers generation and
* JPEG files composition from data compressed by FPGA.
*
* 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
//#include
//#include
//#include obsolete
#include
/*#include
#include
#include
#include
#include
*/
#include
#include
#include
#include
#include
//#include "fpga_io.h"//fpga_table_write_nice
#include "jpeghead.h"
//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
#include "framepars.h" // extern pastpars
#include "quantization_tables.h" // get_gtables()
//#include "x3x3.h"
//#include "cc3x3.h"
//#include "cxdma.h"
//#include "circbuf.h"
//#include "sensor_common.h"
#include "exif.h"
#include "x393_macro.h"
#if ELPHEL_DEBUG
#define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;}
#define D17(x) { if (GLOBALPARS(G_DEBUG) & (1 <<17)) {x; } ; }
#define MDF17(x) { if (GLOBALPARS(G_DEBUG) & (1 <<17)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
#define D18(x) { if (GLOBALPARS(G_DEBUG) & (1 <<18)) {x; } ; }
#define MDF18(x) { if (GLOBALPARS(G_DEBUG) & (1 <<18)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
#define ELPHEL_DEBUG_THIS 1
#else
#define MDF(x)
#define D17(x)
#define MDF17(x)
#define D18(x)
#define MDF18(x)
#define ELPHEL_DEBUG_THIS 0
#endif
#define JPEG_HEADER_MAX_SIZE 0x300
static int huffman_fpga_programmed=0;
/// All huffman tabels data to be read/written from the application
static struct huff_tables_t {
struct huffman_encoded_t header_huffman_tables[4];
unsigned long fpga_huffman_table[512];
union {
unsigned char dht_all[20];
struct {
unsigned char dht_dc0[5]; /// DHT DC0 header (all constants but the length)
unsigned char dht_ac0[5]; /// DHT AC0 header (all constants but the length)
unsigned char dht_dc1[5]; /// DHT DC1 header (all constants but the length)
unsigned char dht_ac1[5]; /// DHT AC1 header (all constants but the length)
};
};
} huff_tables;
#define HEADER_COPY_SOF(x) {buf[bpl]=sizeof( x )+8 ; \
buf[bp++]=sizeof( x)/3; \
memcpy((void *) &buf[bp], (void *) ( x ), sizeof ( x )); \
bp+=sizeof ( x );}
#define HEADER_COPY_SOS(x) {buf[bp++]=sizeof( x )+6 ; \
buf[bp++]=sizeof( x)/2; \
memcpy((void *) &buf[bp], (void *) ( x ), sizeof ( x )); \
bp+=sizeof ( x );}
/**
* @brief just copy two quantization tables for the current frame (for the RTP streamer)
* @param params pointer to an array of parameters stored for the frame
* @param buf buffer to put the header to
* @return header length if successful, <0 - error
*/
int qtables_create(struct interframe_params_t * params, unsigned char * buf) {
MDF18(printk("params->quality2=0x%x",params->quality2));
int rslt=get_qtable(params->quality2, &buf[0], &buf[64]); /// will copy both quantization tables
if (rslt <0) return rslt; /// bad quality table
return 128;
}
/**
* @brief create JPEG header for the frame acquired earlier
* @param params pointer to an array of parameters stored for the frame
* @param buf buffer to put the header to
* @return header length if successful, <0 - error
*/
int jpegheader_create(struct interframe_params_t * params, unsigned char * buf) {
int bp=0; ///buffer pointer
int bpl; /// pointer to length word in the buffer
int rslt;
int len;
int header_sos; /// start of SOS (varaible)
const int header_yqtable= 0x19;
const int header_cqtable_hd= 0x59;
const int header_cqtable= 0x5e;
const int header_sof= 0x9e;
/// first constant part of the header - 0x19 bytes
const unsigned char jfif1[0x19]={0xff, 0xd8, /// SOI start of image
0xff, 0xe0, /// APP0
0x00, 0x10, /// (16 bytes long)
0x4a, 0x46, 0x49, 0x46, 0x00, /// JFIF null terminated
0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00,
0xff, 0xdb, /// DQT (define quantization table)
0x00, 0x43, /// 0x43 bytes long
0x00 }; /// table number + (bytes-1)<<4 (0ne byte - 0, 2 bytes - 0x10)
/// second constant part of the header (starting from byte 0x59 - 0x5 bytes)
const unsigned char jfif2[0x5]= {0xff, 0xdb, /// DQT (define quantization table)
0x00, 0x43, /// 0x43 bytes long
0x01 }; /// table number + (bytes-1)<<4 (0ne byte - 0, 2 bytes - 0x10)
const unsigned char sof_color6[]= {0x01, 0x22, 0x00, /// id , freqx/freqy, q
0x02, 0x11, 0x01,
0x03, 0x11, 0x01};
const unsigned char sos_color6[]= {0x01, 0x00, /// id, hufftable_dc/htable_ac
0x02, 0x11,
0x03, 0x11};
const unsigned char sof_jp46dc[]= {0x01, 0x11, 0x00, /// id , freqx/freqy, q
0x02, 0x11, 0x00,
0x03, 0x11, 0x00,
0x04, 0x11, 0x00,
0x05, 0x11, 0x01,
0x06, 0x11, 0x01};
const unsigned char sos_jp46dc[]= {0x01, 0x00, /// id, hufftable_dc/htable_ac
0x02, 0x00,
0x03, 0x00,
0x04, 0x00,
0x05, 0x11,
0x06, 0x11};
const unsigned char sof_mono4[]= {0x01, 0x22, 0x00}; /// id , freqx/freqy, q
const unsigned char sos_mono4[]= {0x01, 0x00}; /// id, hufftable_dc/htable_ac
const unsigned char sof_jp4[]= {0x04, 0x22, 0x00}; /// id , freqx/freqy, q
const unsigned char sos_jp4[]= {0x04, 0x00}; /// id, hufftable_dc/htable_ac
const unsigned char sof_jp4dc[]= {0x04, 0x11, 0x00, /// id , freqx/freqy, q
0x05, 0x11, 0x00,
0x06, 0x11, 0x00,
0x07, 0x11, 0x00};
const unsigned char sos_jp4dc[]= {0x04, 0x00, /// id, hufftable_dc/htable_ac
0x05, 0x00,
0x06, 0x00,
0x07, 0x00};
const unsigned char sof_jp4diff[]={0x04, 0x11, 0x11, /// will be adjusted to bayer shift, same for jp4hdr
0x05, 0x11, 0x11,
0x06, 0x11, 0x11,
0x07, 0x11, 0x11};
const unsigned char sos_jp4diff[]={0x04, 0x11, /// id, hufftable_dc/htable_ac
0x05, 0x11,
0x06, 0x11,
0x07, 0x11};
if (buf==NULL) return -1; /// buffer is not provided
MDF17(printk("\n"));
MDF18(unsigned char * p= (char *) params; for (len=0;len<32;len++) {if ((len & 0x0f)==0) printk("\n%03x: ",len); printk(" %02x", (int) p[len]);} printk("\n"););
memcpy((void *) &buf[0], (void *) jfif1, sizeof (jfif1)); /// including DQT0 header
memcpy((void *) &buf[header_cqtable_hd], (void *) jfif2, sizeof (jfif2)); /// DQT1 header
rslt=get_qtable(params->quality2, &buf[header_yqtable], &buf[header_cqtable]); /// will copy both quantization tables
if (rslt <0) return rslt; /// bad quality table
bp=header_sof;
buf[bp++]=0xff; buf[bp++]=0xc0;
buf[bp++]=0; /// high byte length - always 0
bpl=bp; /// save pointer to length (low byte)
bp++;
buf[bp++]=0x8; /// 8bpp
buf[bp++]=params->height >> 8; buf[bp++]=params->height; /// big endian height
buf[bp++]=params->width >> 8; buf[bp++]=params->width; /// big endian width
/// copy SOF0 (constants combined with bayer shift for jp4diff/jp4hdr)
switch (params->color) {
case COLORMODE_MONO6: /// monochrome, (4:2:0),
case COLORMODE_COLOR: /// color, 4:2:0, 18x18(old)
case COLORMODE_COLOR20: /// color, 4:2:0, 20x20, middle of the tile (not yet implemented)
case COLORMODE_JP46: /// jp4, original (4:2:0)
HEADER_COPY_SOF(sof_color6);
break;
case COLORMODE_MONO4: /// monochrome, 4 blocks (but still with 2x2 macroblocks)
HEADER_COPY_SOF(sof_mono4);
break;
case COLORMODE_JP4: /// jp4, 4 blocks
HEADER_COPY_SOF(sof_jp4);
break;
case COLORMODE_JP46DC: /// jp4, dc -improved (4:2:0)
HEADER_COPY_SOF(sof_jp46dc);
break;
case COLORMODE_JP4DC: /// jp4, 4 blocks, dc -improved
HEADER_COPY_SOF(sof_jp4dc);
break;
case COLORMODE_JP4DIFF: /// jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
case COLORMODE_JP4DIFF2: /// jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
HEADER_COPY_SOF(sof_jp4diff);
//header_sof
//bshift
buf[header_sof+12+3*((4-params->byrshift) & 3)]=0; /// set quantization table 0 for the "base color"
break;
case COLORMODE_JP4HDR: /// jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
case COLORMODE_JP4HDR2: /// jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2)
HEADER_COPY_SOF(sof_jp4diff); /// same as for COLORMODE_JP4DIFF
buf[header_sof+12+3*((4-params->byrshift) & 3)]=0; /// set quantization table 0 for the "base color"
buf[header_sof+12+3*((6-params->byrshift) & 3)]=0; /// set quantization table 0 for the HDR color
break;
}
/// Include 4 huffman tables
memcpy((void *) &buf[bp], (void *) huff_tables.dht_dc0, 5); /// DHT DC0 header
bp+=5;
len= (huff_tables.dht_dc0[2]<<8)+huff_tables.dht_dc0[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[0], len);
bp+=len;
memcpy((void *) &buf[bp], (void *) huff_tables.dht_ac0, 5); /// DHT AC0 header
bp+=5;
len= (huff_tables.dht_ac0[2]<<8)+huff_tables.dht_ac0[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[1], len);
bp+=len;
memcpy((void *) &buf[bp], (void *) huff_tables.dht_dc1, 5); /// DHT DC1 header
bp+=5;
len= (huff_tables.dht_dc1[2]<<8)+huff_tables.dht_dc1[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[2], len);
bp+=len;
memcpy((void *) &buf[bp], (void *) huff_tables.dht_ac1, 5); /// DHT AC1 header
bp+=5;
len= (huff_tables.dht_ac1[2]<<8)+huff_tables.dht_ac1[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[3], len);
bp+=len;
/// copy SOS0 (constants combined with bayer shift for jp4diff/jp4hdr)
header_sos=bp;
buf[bp++]=0xff; buf[bp++]=0xda; /// SOS tag
buf[bp++]=0; /// high byte length - always 0
switch (params->color) {
case COLORMODE_MONO6: /// monochrome, (4:2:0),
case COLORMODE_COLOR: /// color, 4:2:0, 18x18(old)
case COLORMODE_COLOR20: /// color, 4:2:0, 20x20, middle of the tile (not yet implemented)
case COLORMODE_JP46: /// jp4, original (4:2:0)
HEADER_COPY_SOS(sos_color6);
break;
case COLORMODE_MONO4: /// monochrome, 4 blocks (but still with 2x2 macroblocks)
HEADER_COPY_SOS(sos_mono4);
break;
case COLORMODE_JP4: /// jp4, 4 blocks
HEADER_COPY_SOS(sos_jp4);
break;
case COLORMODE_JP46DC: /// jp4, dc -improved (4:2:0)
HEADER_COPY_SOS(sos_jp46dc);
break;
case COLORMODE_JP4DC: /// jp4, 4 blocks, dc -improved
HEADER_COPY_SOS(sos_jp4dc);
break;
case COLORMODE_JP4DIFF: /// jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
case COLORMODE_JP4DIFF2: /// jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
HEADER_COPY_SOS(sos_jp4diff);
buf[header_sos+6+2*((4-params->byrshift) & 3)]=0; /// set huffman table 0 for the "base color"
break;
case COLORMODE_JP4HDR: /// jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
case COLORMODE_JP4HDR2: /// jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2)
HEADER_COPY_SOS(sos_jp4diff); /// same as for COLORMODE_JP4DIFF
buf[header_sos+6+2*((4-params->byrshift) & 3)]=0; /// set huffman table 0 for the "base color"
buf[header_sos+6+2*((6-params->byrshift) & 3)]=0; /// set huffman table 0 for the HDR color
break;
}
buf[bp++]=0x00; /// Spectral selection start
buf[bp++]=0x3f; /// Spectral selection end
buf[bp++]=0x00; /// Successive approximation (2 values 0..13)
MDF17(printk("JPEG header length=%d\n",bp));
MDF18(for (len=0;lenprivate_data = privData;
privData-> minor=MINOR(inode->i_rdev);
privData-> size=0; ///undefined yet
inode->i_size=JPEG_HEADER_MAXSIZE; /// not the actual size
return 0;
}
EXPORT_SYMBOL_GPL(jpeghead_open);
/*!=================================================================
*! Overloading lseek with additional functionality (to avoid ioctls)
*! with orig==SEEK_END lseek will treat (offset>0) as a byte pointer
*! in (char *)ccam_dma_buf_ptr of a frame pointer and use quality,
*! width and height to regenerate header.
*! frame pointers are 32-bytes aligned, so adding 1 to offest
*! will make sure it is always >0 (as offset=0, orig=SEEK_END
*! will just move pointer to the end and return file length.
*!
*! When called with orig==SEEK_END, offset>0 lseek will position
*! file at the very beginning and return 0 if OK, -EINVAL if
*! frame header is not found for the specified offset
*!================================================================*/
loff_t jpeghead_lseek(struct file * file, loff_t offset, int orig,
struct interframe_params_t *fp){
int rp;
struct jpeghead_pd * privData;
//struct interframe_params_t * fp;
privData = (struct jpeghead_pd *) file->private_data;
MDF17(printk("orig=%d, offst=0x%x\n",orig,(int) offset));
switch (orig)
{
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
file->f_pos += offset;
break;
case SEEK_END:
if (offset <= 0) {
file->f_pos = privData->size + offset;
} else { //! New functionality
file->f_pos=0; // anyway reset it to 0
/*
* move below two lines to circbuf_all_lseek to remove ccam_dma_buf_ptr and simplify dependencies
rp= (offset >>2) & (~7); // convert to index to long, align to 32-bytes
fp = (struct interframe_params_t *) &ccam_dma_buf_ptr[X313_BUFFSUB(rp, 8)]; //! 32 bytes before the frame pointer, may roll-over to the end of ccam_dma_buf_ptr
*/
if ((fp->signffff != 0xffff) || //! signature is overwritten
((fp->timestamp_sec) & X313_LENGTH_MASK)) return -EINVAL; //! acquisition of this frame is not done yet - length word high byte is non-zero
///FIXME: pp_index=fp->past_index; /// unsigned short
/// if (pp_index>=PASTPARS_SAVE_ENTRIES) return -EINVAL; /// wrong index
/// privData->size= jpegheader_create( pastpars[pp_index].past_pars, privData->header);
if ((offset & 0x1f)==0x2) privData->size= qtables_create(fp, privData->header); /// just qunatization tables (128 bytes) - for the streamer
else privData->size= jpegheader_create(fp, privData->header); /// full JPEG header
if (privData->size <0 ) {
privData->size=0;
return -EINVAL; /// error in header
}
return ( file->f_pos ); //! it is 0
}
break;
default:
return -EINVAL;
}
/// truncate position
if (file->f_pos < 0) {
file->f_pos = 0;
return(-EOVERFLOW);
}
if (file->f_pos > privData->size) {
file->f_pos = privData->size;
}
return ( file->f_pos );
}
EXPORT_SYMBOL_GPL(jpeghead_lseek);
ssize_t jpeghead_read(struct file * file, char * buf, size_t count, loff_t *off) {
unsigned long p;
struct jpeghead_pd * privData;
privData = (struct jpeghead_pd *) file->private_data;
MDF17(printk("\n"));
p = *off;
if(p >= privData->size)
p = privData->size;
if((p + count) > privData->size) { /// truncate count
count = privData->size - p;
}
if(count) {
if(copy_to_user(buf, &privData->header[p], count)) return -EFAULT;
*off += count;
}
return count;
}
EXPORT_SYMBOL_GPL(jpeghead_read);
/**huffman_* file operations
* write, read Huffman tables, initialize tables to default ones, program FPGA with the Huffman tables
* file structure is the same as the struct huff_tables_t:
* - 4 tables of 16+256 elements (16 frequencies followed by symbols)
* - 2048 bytes (512 unsigned long) FPGA-encoded data - it is recalculated from the tables above
* - 4 bytes - number of symbols in each table (calculated)
*/
int huffman_open(struct inode *inode, struct file *filp) { // set filesize
struct huffman_pd * privData;
privData= (struct huffman_pd *) kmalloc(sizeof(struct huffman_pd),GFP_KERNEL);
if (!privData) return -ENOMEM;
filp->private_data = privData;
privData-> minor=MINOR(inode->i_rdev);
inode->i_size = sizeof(huff_tables);
return 0;
}
EXPORT_SYMBOL_GPL(huffman_open);
/*!=================================================================
*! Overloading lseek with additional functionality
*! with orig==SEEK_END , offset==LSEEK_HUFFMAN_DC0 - position at Huffman DC0
*! with orig==SEEK_END , offset==LSEEK_HUFFMAN_AC0 - position at Huffman DC0
*! with orig==SEEK_END , offset==LSEEK_HUFFMAN_DC1 - position at Huffman DC0
*! with orig==SEEK_END , offset==LSEEK_HUFFMAN_AC1 - position at Huffman DC0
*! with orig==SEEK_END , offset==LSEEK_HUFFMAN_FPGATAB - position at FPGA table
*! with orig==SEEK_END , offset==LSEEK_HUFFMAN_DEFAULT - fill in default tables
*! with orig==SEEK_END , offset==LSEEK_HUFFMAN_FPGACALC - calculate FPGA table
*! with orig==SEEK_END , offset==LSEEK_HUFFMAN_FPGAPGM - program FPGA table
*! those commands do not move the file pointer (return current),
*! or negative in the case of error (calculate FPGA table)
*!================================================================*/
loff_t huffman_lseek(struct file * file, loff_t offset, int orig){
// orig 0: position from begning
// orig 1: relative from current position
// orig 2: position from last address
switch (orig)
{
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
file->f_pos += offset;
break;
case SEEK_END:
if (offset <= 0) {
file->f_pos = sizeof(huff_tables) + offset;
} else { //! New functionality
switch (offset) {
case LSEEK_HUFFMAN_DC0: file->f_pos=0; break;
case LSEEK_HUFFMAN_AC0: file->f_pos=1*sizeof(struct huffman_encoded_t);break;
case LSEEK_HUFFMAN_DC1: file->f_pos=2*sizeof(struct huffman_encoded_t);break;
case LSEEK_HUFFMAN_AC1: file->f_pos=3*sizeof(struct huffman_encoded_t);break;
case LSEEK_HUFFMAN_FPGATAB: file->f_pos=4*sizeof(struct huffman_encoded_t);break;
case LSEEK_HUFFMAN_DEFAULT: jpeg_htable_init(); break; // no change to file pointer
case LSEEK_HUFFMAN_FPGACALC:
if (jpeg_htable_fpga_encode () <0) return -EINVAL;
break;
case LSEEK_HUFFMAN_FPGAPGM: jpeg_htable_fpga_pgm (); break;
default: return -EINVAL;
}
return ( file->f_pos );
}
break;
default:
return -EINVAL;
}
// truncate position
if (file->f_pos < 0) {
file->f_pos = 0;
return(-EOVERFLOW);
}
if (file->f_pos > sizeof(huff_tables)) file->f_pos = sizeof(huff_tables);
return ( file->f_pos );
}
EXPORT_SYMBOL_GPL(huffman_lseek);
ssize_t huffman_read(struct file * file, char * buf, size_t count, loff_t *off) {
unsigned long p;
unsigned char * uc_huff_tables= (unsigned char *) &huff_tables;
MDF17(printk("\n"));
p = *off;
if(p >= sizeof(huff_tables)) p = sizeof(huff_tables);
if((p + count) > sizeof(huff_tables)) count = sizeof(huff_tables) - p; /// truncate count
if(count) {
if(copy_to_user(buf, &uc_huff_tables[p], count)) return -EFAULT;
*off += count;
}
return count;
}
EXPORT_SYMBOL_GPL(huffman_read);
ssize_t huffman_write(struct file * file, const char * buf, size_t count, loff_t *off) {
unsigned long p;
unsigned char * uc_huff_tables= (unsigned char *) &huff_tables;
MDF17(printk("\n"));
p = *off;
if (p >= sizeof(huff_tables)) p = sizeof(huff_tables);
if( (p + count) > sizeof(huff_tables)) count = sizeof(huff_tables) - p; /// truncate count
if (count) {
if (copy_from_user(&uc_huff_tables[p],buf, count)) return -EFAULT;
}
return count;
}
EXPORT_SYMBOL_GPL(huffman_write);
/**
* @brief Initialize Huffman tables with default data
*/
void jpeg_htable_init (void) {
unsigned char dc0[]={0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///. number of codes of each length 1..16 (12 total)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /// symbols encoded (12)
0x08, 0x09, 0x0a, 0x0b};
unsigned char ac0[]={0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, /// - counts of codes of each length - 1..16 - total a2
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, /// symbols encoded (0xa2)
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa};
unsigned char dc1[]={0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b};
unsigned char ac1[]={0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa};
MDF17(printk(" started\n"));
memset ((void*) &huff_tables,0, sizeof(huff_tables));
memcpy ((void*) huff_tables.header_huffman_tables[0].bits,dc0, sizeof(dc0));
memcpy ((void*) huff_tables.header_huffman_tables[1].bits,ac0, sizeof(ac0));
memcpy ((void*) huff_tables.header_huffman_tables[2].bits,dc1, sizeof(dc1));
memcpy ((void*) huff_tables.header_huffman_tables[3].bits,ac1, sizeof(ac1));
MDF17(printk("jpeg_htable_fpga_encode ()\n"));
jpeg_htable_fpga_encode ();
}
EXPORT_SYMBOL_GPL(jpeg_htable_init);
/**
* @brief encode all 4 Huffman tables into FPGA format
* additionally calculates number of symbols in each table
* @return OK - 0, -1 - too many symbols, -2 bad table, -3 - bad table number
*/
int jpeg_htable_fpga_encode (void) {
int ntab, i, rslt, a, length;
const unsigned char dht_headers[20]={ /// length will be inserted later
0xff, 0xc4, 0x00, 0x00, 0x00,
0xff, 0xc4, 0x00, 0x00, 0x10,
0xff, 0xc4, 0x00, 0x00, 0x01,
0xff, 0xc4, 0x00, 0x00, 0x11 };
struct huffman_fpga_code_t codes[256];
unsigned long * icodes = (unsigned long *) codes;
huffman_fpga_programmed=0; /// mark FPGA table as needed to be programmed
MDF17(printk(" started\n"));
/// Fill in the table headers:
memcpy ((void*) huff_tables.dht_all, (void*) dht_headers, sizeof(dht_headers)); /// all 4 headers (with zero length)
for (ntab=0; ntab<4; ntab++) {
MDF17(printk("ntab=%d\n", ntab));
memset (codes,0,sizeof(codes));
if ((rslt=jpeg_prep_htable (&(huff_tables.header_huffman_tables[ntab]), codes)) < 0 ) return rslt;
if (ntab & 1) {
a=((ntab & 2)<<7);
for (i=0; i<256;i+=16) {
memcpy ((void*) &(huff_tables.fpga_huffman_table[a]), (void*) &codes[i], 60); /// all but DC column
a+=16;
}
} else {
a=((ntab & 2)<<7)+0x0f; /// in FPGA DC use spare parts of AC table
for (i=0; i<16;i++) {
huff_tables.fpga_huffman_table[a]= icodes[i];
a+=16;
}
}
/// Fill in the table headers:
length=19; /// 2 length bytes, 1 type byte, 16 lengths bytes
for (i=0; i<16; i++) length += huff_tables.header_huffman_tables[ntab].bits[i]; /// first 16 bytes in each table number of symbols
huff_tables.dht_all[(5*ntab)+2]=length >> 8; /// high byte (usually 0)
huff_tables.dht_all[(5*ntab)+3]=length& 0xff; /// low byte
}
MDF17(printk("\nFPGA Huffman table\n");for (i=0;i<512;i++){printk (" %06x",(int)huff_tables.fpga_huffman_table[i]); if ((i & 0x0f)==0x0f) printk("\n");});
return 0;
}
/**
* @brief check if the FPGA is programmed to the new Huffman table
* @return 1 - programmed, 0 - not programmed
*/
int jpeg_htable_is_programmed(void) {
return huffman_fpga_programmed;
}
/**
* @brief program FPGA Huffman table (fram static array)
*/
void jpeg_htable_fpga_pgm (void) {
#ifdef TEST_DISABLE_CODE
fpga_table_write_nice (CX313_FPGA_TABLES_HUFF, 512, huff_tables.fpga_huffman_table);
#endif
huffman_fpga_programmed=1;
}
/// Code below is based on jdhuff.c (from libjpeg)
/**
* @brief Calculate huffman table (1 of 4) from the JPEG header to code lengh/value (for FPGA)
* @param htable encoded Huffman table - 16 length bytes followed by up to 256 symbols
* @param hcodes combined (length<<16) | code table for each symbol
* @return OK- 0, -1 - too many symbols, -2 bad table
*/
///Does it depend on no missing symbols?
int jpeg_prep_htable (struct huffman_encoded_t * htable, struct huffman_fpga_code_t * hcodes) {
int p, i, l, si, numsymbols;
unsigned int code;
MDF17(printk(" started\n"));
/// Figure C.1: make table of Huffman code length for each symbol
p = 0;
for (l = 1; l <= 16; l++) {
i = htable->bits[l-1];
if (i < 0 || p + i > 256) {
MDF17(printk("protect against table overrun\n"));
return -1 ; /// protect against table overrun
}
while (i--) hcodes[htable->huffval[p++]].length=l;
}
numsymbols = p;
/// Figure C.2: generate the codes themselves
/// We also validate that the counts represent a legal Huffman code tree.
code = 0;
si = hcodes[htable->huffval[0]].length;
p = 0;
///htable->huffval[N] - N-th symbol value
while (p < numsymbols) {
if ((hcodes[htable->huffval[p]].length < si) || (si>16)) {
ELP_KERR(printk("Bad table/bug\n"));
return -3; ///Bad table
}
while (hcodes[htable->huffval[p]].length == si) {
hcodes[htable->huffval[p++]].value = code;
code++;
}
/** code is now 1 more than the last code used for codelength si; but
* it must still fit in si bits, since no code is allowed to be all ones.
*/
if ( code >= (1 << si)) {
ELP_KERR(printk("Bad code\n"));
return -2; ///Bad code
}
code <<= 1;
si++;
}
return 0;
}
MODULE_LICENSE("GPL");
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/jpeghead.h 0000664 0000000 0000000 00000003567 12677012326 0026656 0 ustar 00root root 0000000 0000000 // FILE NAME : jpeghead.h
///Structure used for FPGA data - lower 16 bits - code value, next 5 - code length (1..16).
///Actually FPGA only uses 20 bits, length 0 is interpreted as 16
#ifndef _JPEGHEAD
#define _JPEGHEAD
struct huffman_fpga_code_t {
unsigned short value; /// code value
unsigned short length; /// code length
};
int qtables_create (struct interframe_params_t * params, unsigned char * buf);
int jpegheader_create(struct interframe_params_t * params, unsigned char * buf);
int jpeghead_open (struct inode *inode, struct file *filp); // set filesize
loff_t jpeghead_lseek (struct file * file, loff_t offset, int orig, struct interframe_params_t *fp);
ssize_t jpeghead_read (struct file * file, char * buf, size_t count, loff_t *off);
int huffman_open (struct inode *inode, struct file *filp); // set filesize
int huffman_release(struct inode *inode, struct file *filp);
loff_t huffman_lseek (struct file * file, loff_t offset, int orig);
ssize_t huffman_read (struct file * file, char * buf, size_t count, loff_t *off);
ssize_t huffman_write (struct file * file, const char * buf, size_t count, loff_t *off);
//extern unsigned long * ccam_dma_buf_ptr;
//void init_ccam_dma_buf_ptr(void);
#define JPEG_HEADER_MAXSIZE 0x300
struct jpeghead_pd {
int minor;/// should be the first, same as in circbuf_pd
unsigned long size; /// JPEG header size (no Exif)
unsigned char header[JPEG_HEADER_MAXSIZE];
};
struct huffman_pd {
int minor;/// should be the first, same as in circbuf_pd
};
int jpeg_htable_is_programmed(void);
void jpeg_htable_init (void);
int jpeg_htable_fpga_encode (void);
void jpeg_htable_fpga_pgm (void);
int jpeg_prep_htable (struct huffman_encoded_t * htable, struct huffman_fpga_code_t * hcodes);
#endif /* _JPEGHEAD */
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/param_depend.h 0000664 0000000 0000000 00000065720 12677012326 0027525 0 ustar 00root root 0000000 0000000 /*!********************************************************************************
*! FILE NAME : param_depend.h
*! DESCRIPTION: Specifies, which actions should be performed when some acquisition
*! parameters are changed
*! Copyright (C) 2008 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: param_depend.h,v $
*! Revision 1.12 2010/08/03 23:37:34 elphel
*! rev 8.0.8.37, portrait mode support
*!
*! Revision 1.11 2010/08/01 19:29:24 elphel
*! files updated to support coring function for noise filtering
*!
*! Revision 1.10 2010/06/02 16:31:04 elphel
*! Added P_MULTI_SELECTED parameter
*!
*! Revision 1.9 2010/06/01 08:30:36 elphel
*! support for the FPGA code 03534022 with optional master time stamp over the inter-camera sync line(s)
*!
*! Revision 1.8 2010/05/25 00:52:23 elphel
*! 8.0.8.20, working on multi-sensor
*!
*! Revision 1.7 2010/05/21 06:12:16 elphel
*! continue working on multi-sensor software
*!
*! Revision 1.6 2010/05/16 02:03:47 elphel
*! 8.0.8.4 - driver working with individual/broadcast sensor registers
*!
*! Revision 1.5 2010/05/13 03:39:31 elphel
*! 8.0.8.12 - drivers modified for multi-sensor operation
*!
*! Revision 1.4 2010/04/28 16:00:09 elphel
*! Changing PF_HEIGHT now triggers window recalculation
*!
*! Revision 1.3 2008/12/03 17:17:23 elphel
*! added limitfps function to exposure change - otherwise indicated period/fps was not updated when exposure time was reduced (from above minimal frame period)
*!
*! Revision 1.2 2008/11/30 05:01:03 elphel
*! Changing gains/scales behavior
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.20 2008/11/27 09:27:31 elphel
*! Support fro new parameters (vignetting correction related)
*!
*! Revision 1.19 2008/11/13 05:40:45 elphel
*! 8.0.alpha16 - modified histogram storage, profiling
*!
*! Revision 1.18 2008/10/29 04:18:28 elphel
*! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
*!
*! Revision 1.17 2008/10/18 06:14:21 elphel
*! 8.0.alpha4 - removed some obsolete parameters, renumbered others, split P_FLIP into P_FLIPH and P_FLIPV (different latencies because of bad frames), pgm_window-> pgm_window, pgm_window_safe
*!
*! Revision 1.16 2008/10/10 17:06:59 elphel
*! just a snapshot
*!
*! Revision 1.15 2008/10/08 21:26:25 elphel
*! snapsot 7.2.0.pre4 - first images (actually - second)
*!
*! Revision 1.14 2008/10/06 08:31:08 elphel
*! snapshot, first images
*!
*! Revision 1.13 2008/10/04 16:10:12 elphel
*! snapshot
*!
*! Revision 1.12 2008/09/28 00:31:57 elphel
*! snapshot
*!
*! Revision 1.11 2008/09/25 00:58:12 elphel
*! snapshot
*!
*! Revision 1.10 2008/09/22 22:55:49 elphel
*! snapshot
*!
*! Revision 1.9 2008/09/16 00:49:32 elphel
*! snapshot
*!
*! Revision 1.8 2008/08/11 19:17:01 elphel
*! reduced syntax complaints by KDevelop
*!
*! Revision 1.7 2008/07/29 01:15:06 elphel
*! another snapshot
*!
*! Revision 1.6 2008/07/27 23:25:07 elphel
*! next snapshot
*!
*! Revision 1.5 2008/07/27 04:27:49 elphel
*! next snapshot
*!
*! Revision 1.4 2008/06/24 00:43:44 elphel
*! just a snapshot
*!
*! Revision 1.3 2008/06/20 03:54:20 elphel
*! another snapshot
*!
*! Revision 1.2 2008/06/19 02:17:36 elphel
*! continuing work - just a snapshot
*!
*! Revision 1.1 2008/06/16 06:51:21 elphel
*! work in progress, intermediate commit
*!
*!
*/
#ifndef _PARAM_DEPEND_H
#define _PARAM_DEPEND_H
#define ONCHANGE_MULTISENS (1 << onchange_multisens ) /// changes related to multiplexed sensors
#define ONCHANGE_RECALCSEQ (1 << onchange_recalcseq ) /// recalculate sequences/latencies, according to P_SKIP, P_TRIG
#define ONCHANGE_DETECTSENSOR (1 << onchange_detectsensor ) /// detect sensor type, sets sensor structure (capabilities), function pointers
#define ONCHANGE_SENSORPHASE (1 << onchange_sensorphase ) /// program sensor clock/phase
#define ONCHANGE_I2C (1 << onchange_i2c ) /// program i2c speed/bytes
#define ONCHANGE_INITSENSOR (1 << onchange_initsensor ) /// resets sensor, reads sensor registers, schedules "secret" manufacturer's corrections to the registers (stops/re-enables hardware i2c)
#define ONCHANGE_AFTERINIT (1 << onchange_afterinit ) /// restore image size, decimation,... after sensor reset or set them according to sensor capabilities if none were specified
#define ONCHANGE_WINDOW (1 << onchange_window ) /// program sensor WOI - with 1 bad frame to be skipped by the compressor
#define ONCHANGE_WINDOW_SAFE (1 << onchange_window_safe ) /// program sensor WOI - zero bad frames to be skipped by the compressor
#define ONCHANGE_EXPOSURE (1 << onchange_exposure ) /// program exposure
#define ONCHANGE_GAINS (1 << onchange_gains ) /// program analog gains
#define ONCHANGE_TRIGGERMODE (1 << onchange_triggermode ) /// program sensor trigger mode
#define ONCHANGE_SENSORIN (1 << onchange_sensorin ) /// program sensor input in FPGA (Bayer, 8/16 bits, ??)
#define ONCHANGE_SENSORSTOP (1 << onchange_sensorstop) /// Stop acquisition from the sensor to the FPGA (start has latency of 2)
#define ONCHANGE_SENSORRUN (1 << onchange_sensorrun) /// Start/single acquisition from the sensor to the FPGA (stop has latency of 1)
#define ONCHANGE_GAMMA (1 << onchange_gamma ) /// program gamma table
#define ONCHANGE_HIST (1 << onchange_hist ) /// program histogram window
#define ONCHANGE_AEXP (1 << onchange_aexp ) /// program autoexposure mode
#define ONCHANGE_QUALITY (1 << onchange_quality ) /// program quantization table(s)
#define ONCHANGE_MEMSENSOR (1 << onchange_memsensor ) /// program memory channels 0 (sensor->memory) and 1 (memory->FPN)
#define ONCHANGE_MEMCOMPRESSOR (1 << onchange_memcompressor ) /// program memory channel 2 (memory->compressor)
#define ONCHANGE_LIMITFPS (1 << onchange_limitfps ) /// check compressor will keep up, limit sensor FPS if needed
#define ONCHANGE_COMPMODE (1 << onchange_compmode ) /// program compressor modes
#define ONCHANGE_FOCUSMODE (1 << onchange_focusmode ) /// program focus modes
#define ONCHANGE_TRIGSEQ (1 << onchange_trigseq ) /// program sequencer (int/ext)
#define ONCHANGE_IRQ (1 << onchange_irq ) /// program smart IRQ mode (needs to be on)
#define ONCHANGE_COMPRESTART (1 << onchange_comprestart ) /// restart after changing geometry (recognizes ASAP and programs memory channel 2 then)
#define ONCHANGE_COMPSTOP (1 << onchange_compstop ) /// stop compressor when changing geometry
#define ONCHANGE_COMPCTL (1 << onchange_compctl ) /// only start/stop/single (after explicitly changed, not when geometry was changed)
#define ONCHANGE_GAMMALOAD (1 << onchange_gammaload ) /// write gamma tables (should be prepared). Maybe - just last byte, to activate?
#define ONCHANGE_SENSORREGS (1 << onchange_sensorregs ) /// write sensor registers (only changed from outside the driver as they may have different latencies)?
#define ONCHANGE_PRESCAL (1 << onchange_prescal ) /// change scales for per-color digital gains, apply vignetting correction
const unsigned long param_depend_tab[]=
{
P_SENSOR_RUN, ONCHANGE_SENSORSTOP | ONCHANGE_SENSORRUN | ONCHANGE_MEMCOMPRESSOR,
P_SENSOR, ONCHANGE_DETECTSENSOR | ONCHANGE_RECALCSEQ | ONCHANGE_INITSENSOR | ONCHANGE_AFTERINIT | ONCHANGE_MULTISENS | \
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
P_BAYER , ONCHANGE_SENSORIN ,
P_CLK_FPGA, ONCHANGE_I2C | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
/// not need ONCHANGE_INITSENSOR | ONCHANGE_AFTERINIT - they will be scheduled by pgm_sensorphase if needed for the sensor
P_CLK_SENSOR, ONCHANGE_SENSORPHASE | \
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
P_SENSOR_PHASE, ONCHANGE_SENSORPHASE | ONCHANGE_EXPOSURE | ONCHANGE_LIMITFPS | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
P_FPGA_XTRA, ONCHANGE_LIMITFPS ,
P_TRIG, ONCHANGE_RECALCSEQ | ONCHANGE_TRIGGERMODE | ONCHANGE_TRIGSEQ | ONCHANGE_LIMITFPS | /// Next to call with afterinit
ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
// P_VIRT_WIDTH, ONCHANGE_LIMITFPS ,
P_VIRT_WIDTH, ONCHANGE_LIMITFPS | ONCHANGE_EXPOSURE , ///after limitFPS
P_VIRT_HEIGHT, ONCHANGE_LIMITFPS ,
P_WOI_LEFT, ONCHANGE_WINDOW_SAFE ,
// P_WOI_TOP, ONCHANGE_WINDOW_SAFE ,
P_WOI_TOP, ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
P_WOI_WIDTH, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
P_WOI_HEIGHT, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
///P_WOI_HEIGHT-> number of lines to acquire. Or move it to memsensor so other changes (decimation, binning) will lead to recalc number of lines?
///FLIP_H is safe, FLIPV produces bad frame
P_FLIPH, ONCHANGE_WINDOW_SAFE | ONCHANGE_EXPOSURE | ONCHANGE_SENSORIN , /// bit 0 - horizontal (ONCHANGE_SENSORIN for Bayer)
P_FLIPV, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_SENSORIN | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART, /// bit 1 - vertical (ONCHANGE_SENSORIN for Bayer)
P_FPSFLAGS, ONCHANGE_LIMITFPS ,
P_DCM_HOR, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
/// Multisensor is called without any verification of [P_DCM_VERT] (it is needed to adjust gaps between frames)
P_DCM_VERT, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_BIN_HOR, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
P_BIN_VERT, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_COLOR, ONCHANGE_COMPMODE | ONCHANGE_LIMITFPS ,
// P_PF_HEIGHT, ONCHANGE_RECALCSEQ | ONCHANGE_SENSORIN | ONCHANGE_LIMITFPS | ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
P_PF_HEIGHT, ONCHANGE_RECALCSEQ | ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_BITS, ONCHANGE_SENSORIN | ONCHANGE_LIMITFPS | ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
P_FPGATEST, ONCHANGE_SENSORIN ,
P_FPNS, ONCHANGE_SENSORIN ,
P_FPNM, ONCHANGE_SENSORIN ,
P_VIRTTRIG, ONCHANGE_SENSORIN ,
P_COMPMOD_BYRSH, ONCHANGE_COMPMODE,
P_COMPMOD_TILSH, ONCHANGE_COMPMODE,
P_COMPMOD_DCSUB, ONCHANGE_COMPMODE,
P_COMPMOD_QTAB, ONCHANGE_COMPMODE, // to be written not directly,but by pgm_quality ? (pgm_gamma to be used by pgm_gammaload - wrong)
P_FP1000SLIM, ONCHANGE_LIMITFPS ,
P_COLOR_SATURATION_BLUE, ONCHANGE_COMPMODE ,
P_COLOR_SATURATION_RED, ONCHANGE_COMPMODE ,
P_CORING_PAGE, ONCHANGE_COMPMODE ,
P_AUTOEXP_ON, ONCHANGE_AEXP ,
P_HISTWND_RWIDTH, ONCHANGE_HIST | ONCHANGE_AEXP ,
P_HISTWND_RHEIGHT, ONCHANGE_HIST | ONCHANGE_AEXP ,
P_HISTWND_RLEFT, ONCHANGE_HIST | ONCHANGE_AEXP ,
P_HISTWND_RTOP, ONCHANGE_HIST | ONCHANGE_AEXP ,
P_AUTOEXP_EXP_MAX, ONCHANGE_AEXP ,
P_AUTOEXP_OVEREXP_MAX, ONCHANGE_AEXP ,
P_AUTOEXP_S_PERCENT, ONCHANGE_AEXP ,
P_AUTOEXP_S_INDEX, ONCHANGE_AEXP ,
P_AUTOEXP_SKIP_PMIN, ONCHANGE_AEXP ,
P_AUTOEXP_SKIP_PMAX, ONCHANGE_AEXP ,
P_AUTOEXP_SKIP_T, ONCHANGE_AEXP ,
P_FOCUS_SHOW, ONCHANGE_COMPMODE , /// ONCHANGE_COMPMODE, not ONCHANGE_FOCUSMODE (it only can be done w/o the sequencer)
P_FOCUS_SHOW1, ONCHANGE_FOCUSMODE ,
P_RFOCUS_LEFT, ONCHANGE_FOCUSMODE ,
P_RFOCUS_WIDTH, ONCHANGE_FOCUSMODE ,
P_RFOCUS_TOP, ONCHANGE_FOCUSMODE ,
P_RFOCUS_HEIGHT, ONCHANGE_FOCUSMODE ,
P_FOCUS_FILTER, ONCHANGE_FOCUSMODE ,
P_TRIG_CONDITION, ONCHANGE_TRIGSEQ ,
P_TRIG_DELAY, ONCHANGE_TRIGSEQ ,
P_TRIG_OUT, ONCHANGE_TRIGSEQ ,
P_TRIG_PERIOD, ONCHANGE_TRIGSEQ ,
P_SKIP_FRAMES, ONCHANGE_RECALCSEQ ,
P_I2C_QPERIOD, ONCHANGE_I2C ,
P_I2C_BYTES, ONCHANGE_I2C ,
P_IRQ_SMART, ONCHANGE_IRQ ,
P_EXTERN_TIMESTAMP, ONCHANGE_TRIGSEQ ,
P_TRIG_BITLENGTH, ONCHANGE_TRIGSEQ ,
P_XMIT_TIMESTAMP, ONCHANGE_TRIGSEQ ,
P_OVERSIZE, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
P_QUALITY, ONCHANGE_QUALITY ,
P_PORTRAIT, ONCHANGE_QUALITY ,
P_CORING_INDEX, ONCHANGE_QUALITY ,
P_TESTSENSOR, ONCHANGE_GAINS , /// sensor test mode - now processed together with sensor gains
P_GAINR, ONCHANGE_GAINS | ONCHANGE_PRESCAL , /// Set digital gain after adjusting analog gain
P_GAING, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
P_GAINGB, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
P_RSCALE_ALL, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
P_GSCALE_ALL, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
P_BSCALE_ALL, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
P_GAINB, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
P_GAIN_CTRL, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
P_GAIN_MIN, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
P_GAIN_MAX, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
P_EXPOS, ONCHANGE_EXPOSURE | ONCHANGE_LIMITFPS, /// Otherwise it only increase period/decr. indicated FP1000S, but does not chnage when exposure is decreased
P_VEXPOS, ONCHANGE_EXPOSURE | ONCHANGE_LIMITFPS, /// Otherwise it only increase period/decr. indicated FP1000S, but does not chnage when exposure is decreased
P_GTAB_R, ONCHANGE_GAMMA | ONCHANGE_GAMMALOAD,
P_GTAB_G, ONCHANGE_GAMMA | ONCHANGE_GAMMALOAD,
P_GTAB_GB, ONCHANGE_GAMMA | ONCHANGE_GAMMALOAD,
P_GTAB_B, ONCHANGE_GAMMA | ONCHANGE_GAMMALOAD,
P_COMPRESSOR_RUN, ONCHANGE_COMPCTL,
P_VIGNET_AX, ONCHANGE_PRESCAL,
P_VIGNET_AY, ONCHANGE_PRESCAL,
P_VIGNET_BX, ONCHANGE_PRESCAL,
P_VIGNET_BY, ONCHANGE_PRESCAL,
P_VIGNET_C, ONCHANGE_PRESCAL,
P_VIGNET_SHL, ONCHANGE_PRESCAL,
P_SCALE_ZERO_IN, ONCHANGE_PRESCAL,
P_SCALE_ZERO_OUT, ONCHANGE_PRESCAL,
P_DGAINR, ONCHANGE_PRESCAL,
P_DGAING, ONCHANGE_PRESCAL,
P_DGAINGB, ONCHANGE_PRESCAL,
P_DGAINB, ONCHANGE_PRESCAL,
P_MULTISENS_EN, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_PHASE_SDRAM, ONCHANGE_SENSORPHASE,
P_MULTI_PHASE1, ONCHANGE_SENSORPHASE,
P_MULTI_PHASE2, ONCHANGE_SENSORPHASE,
P_MULTI_PHASE3, ONCHANGE_SENSORPHASE,
P_MULTI_SEQUENCE, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_SELECTED, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_FLIPH, ONCHANGE_WINDOW_SAFE | ONCHANGE_EXPOSURE | ONCHANGE_SENSORIN , /// bit 0 - horizontal (ONCHANGE_SENSORIN for Bayer)
P_MULTI_FLIPV, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_SENSORIN | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
P_MULTI_MODE, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_HBLANK, ONCHANGE_MULTISENS, /// not needed ? Calculated?)
P_MULTI_VBLANK, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_HEIGHT1, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_HEIGHT2, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_HEIGHT3, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
/*
P_MULTI_CWIDTH, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
P_MULTI_CHEIGHT, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_CLEFT, ONCHANGE_MULTISENS | ONCHANGE_WINDOW_SAFE ,
P_MULTI_CTOP, ONCHANGE_MULTISENS | ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
*/
P_MULTI_VBLANK, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_WIDTH1, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
P_MULTI_WIDTH2, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
P_MULTI_WIDTH3, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
P_MULTI_HEIGHT1, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_HEIGHT2, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_HEIGHT3, ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
P_MULTI_LEFT1, ONCHANGE_MULTISENS | ONCHANGE_WINDOW_SAFE,
P_MULTI_LEFT2, ONCHANGE_MULTISENS | ONCHANGE_WINDOW_SAFE,
P_MULTI_LEFT3, ONCHANGE_MULTISENS | ONCHANGE_WINDOW_SAFE,
P_MULTI_TOP1, ONCHANGE_MULTISENS |ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
P_MULTI_TOP2, ONCHANGE_MULTISENS |ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
P_MULTI_TOP3, ONCHANGE_MULTISENS |ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
/// These two below are changed in multisensor
P_SENSOR_WIDTH, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
P_SENSOR_HEIGHT, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN
};
#endif
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/quantization_tables.c 0000664 0000000 0000000 00000166616 12677012326 0031167 0 ustar 00root root 0000000 0000000 /*!********************************************************************************
*! FILE NAME : quantization_tables.c
*! DESCRIPTION: Generation and handling quantization tables:
*! - direct - to be included in the JPEG headers and
*! - reverse - to go to the FPGA. Reverse are calculated as 0x10000/direct
*! Based on standard JPEG quality quantization tables, with the following differences
*! - FPGA uses multiplication by 65536/x instead of division by x
*! - (to better handle JP4 flavors) it is possible to use Y tables for other components
*! possibly with different quality.
*!
*! Quality is represented by 2-byte value. Each byte uses Y table if the value is Q<128,
*! and C table with (Q-128) if it is Q>=128.
*! If the High byte is zero, it is treated as Q^0x80 (Q|=(Q^0x80)<<8) for compatibility
*! with a standard single-byte Q value
*! FPGA table accomodates 8 pairs of quantization coefficients, so software tries
*! to reuse loaded tables when possible
*!
*! Copyright (C) 2008 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: quantization_tables.c,v $
*! Revision 1.4 2010/08/03 23:37:34 elphel
*! rev 8.0.8.37, portrait mode support
*!
*! Revision 1.3 2010/08/01 19:29:24 elphel
*! files updated to support coring function for noise filtering
*!
*! Revision 1.2 2010/05/31 21:47:21 elphel
*! Fixed old bug that effectively disabled FPGA and file headers quantization tables caching
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.8 2008/10/29 04:18:28 elphel
*! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
*!
*! Revision 1.7 2008/10/23 08:08:41 elphel
*! reenabled irq in debug mode
*!
*! Revision 1.6 2008/10/05 05:13:33 elphel
*! snapshot003
*!
*! Revision 1.5 2008/09/12 00:24:00 elphel
*! removed cc353.c, cc353.h
*!
*! Revision 1.4 2008/09/11 01:05:32 elphel
*! snapshot
*!
*! Revision 1.3 2008/09/05 23:20:26 elphel
*! just a snapshot
*!
*! Revision 1.2 2008/07/27 23:25:07 elphel
*! next snapshot
*!
*! Revision 1.1 2008/06/08 23:46:45 elphel
*! added drivers files for handling quantization tables, gamma tables and the histograms
*!
*!
*/
//copied from cxi2c.c - TODO:remove unneeded
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include // endians
#include
#include
#include
#include
#include
#include
//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
//#include "cc3x3.h"
//#include "fpga_io.h"
//#include "x3x3.h" // just for FPGA_NQTAB
#include "framepars.h"
//#include "fpga_io.h"//fpga_table_write_nice
#include "quantization_tables.h"
/**
* @brief optional debug output
*/
#if ELPHEL_DEBUG
#define D15(x) { if (GLOBALPARS(G_DEBUG) & (1 <<15)) { x ;} }
#define MDF15(x) { if (GLOBALPARS(G_DEBUG) & (1 <<15)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
#define D14(x) { if (GLOBALPARS(G_DEBUG) & (1 <<14)) { x ;} }
#define MDF14(x) { if (GLOBALPARS(G_DEBUG) & (1 <<14)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
#define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;}
// #define D1I(x)
#define D1I(x) x
#else
#define D1I(x) x
#define D15(x)
#define MDF15(x)
#define D14(x)
#define MDF14(x)
#define MDF(x)
#endif
#define QTABLE_SIZE 64 /// number of elements in quantization table
#define QTABLE_HEAD_CACHE 8 /// number of quantization pairs in cache (just for generation of JPEG headers)
static unsigned int std_quant_tbls[4 * QTABLE_SIZE] = { /// make it possible to modify runtime later?
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99,
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
///transposed for portrait mode
16, 12, 14, 14, 18, 24, 49, 72,
11, 12, 13, 17, 22, 35, 64, 92,
10, 14, 16, 22, 37, 55, 78, 95,
16, 19, 24, 29, 56, 64, 87, 98,
24, 26, 40, 51, 68, 81, 103, 112,
40, 58, 57, 87, 109, 104, 121, 100,
51, 60, 69, 80, 103, 113, 120, 103,
61, 55, 56, 62, 77, 92, 101, 99,
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
/// with a number of programmed tables equal to PARS_FRAMES, and that "this" table is not needed it will always be possible to find an unused table slot
/// LRU cache for JPEG headers
static unsigned char qtable_cache [QTABLE_SIZE * 2 * QTABLE_HEAD_CACHE]; ///quantization tables cache
static int qtable_cache_values [QTABLE_HEAD_CACHE]; /// quality values for the tables in cache
static int qtable_cache_next[QTABLE_HEAD_CACHE] ; /// index of the next (not used longer than this) slot
static int qtable_cache_mre; ///index of most recently used slot
#define FPGA_NQTAB 8 /* got from x353.h */
static int qtable_fpga_values [FPGA_NQTAB]; /// quality values for the tables in FPGA
static int qtable_fpga_next[FPGA_NQTAB] ; /// index of the next (not used longer than this) slot in FPGA quantization tables
static int qtable_fpga_mre; ///index of most recently used slot
static int qtable_cache_initialized;
static int qtable_fpga_initialized;
// Coring function table, 256 4-bit values per function
// min=0, max=10, step=0.1
//static char * coring_tables;
static unsigned long coring_tables[];
/**
* @brief force (re-)initialization of quantization tables cache and FPGA quantization table (in FPGA) when next used.
*/
void reset_qtables(void) {
qtable_cache_initialized=0;
qtable_fpga_initialized=0;
}
//EXPORT_SYMBOL_GPL(reset_qtables);
/**
* @brief initialization of quantization tables (direct - JPEG header ones) cache
* \n TODO: add \b init_qtable_head_cache to module initialization
*/
void init_qtable_head_cache (void) {
D1I(unsigned long flags);
int i;
MDF(printk("\n"));
D1I(local_irq_save(flags));
/// needs to turn off IRQ
for (i=0; i < QTABLE_HEAD_CACHE; i++) {
qtable_cache_values[i]=-1; /// undefined
qtable_cache_next[i]=i+1; /// last value is invalid, but that's OK - it should not be used
qtable_cache_mre=0;
}
qtable_cache_initialized=1;
D1I(local_irq_restore(flags));
}
/**
* @brief calculates a pair of direct (JPEG header) tables for the specified quality (2-bytes )
* @param quality2 single byte (standard) or a pair of bytes (see file header description)
* @param y_tab caller-provided pointer to a 64-byte Y (intensity) quantization table (NULL - don't copy)
* @param c_tab caller-provided pointer to a 64-byte C (color) quantization table (NULL - don't copy)
* @return 0 - cache hit, 1 - cache miss (recalculated), -1 - invalid quality
*/
int get_qtable (int quality2, unsigned char *y_tab, unsigned char *c_tab) {
D1I(unsigned long flags);
int i,transpose,cache_index,cache_index_prev,q_type,quality,temp,tstart;
int rslt=0;
unsigned char * tab;
const unsigned int zig_zag[QTABLE_SIZE] = {
0, 1, 5, 6,14,15,27,28,
2, 4, 7,13,16,26,29,42,
3, 8,12,17,25,30,41,43,
9,11,18,24,31,40,44,53,
10,19,23,32,39,45,52,54,
20,22,33,38,46,51,55,60,
21,34,37,47,50,56,59,61,
35,36,48,49,57,58,62,63
};
if (qtable_cache_initialized==0) init_qtable_head_cache();
MDF14(printk("quality2=0x%x\n",quality2));
if (quality2<0) return -1;
// transpose=(quality2>>7) & 1; /// 0 - landscape mode, 1 - portrait mode
// if (quality2<256) quality2 |= (quality2^0x80)<<8;
if (quality2<256) quality2 |= (quality2 & 0x7f)<<8;
// else (quality
MDF14(printk("quality2=0x%x\n",quality2));
D1I(local_irq_save(flags));
/// look if such q value is already in cache
cache_index=qtable_cache_mre;
cache_index_prev=-1;
for (i=0; (i=0); i++) {
cache_index_prev=cache_index;
cache_index=qtable_cache_next[cache_index];
D14(printk(" ---i=%d, cache_index_prev=%d, cache_index=%d\n",i, cache_index_prev, cache_index));
}
/// cache_index is invalid if (i==FPGA_NQTAB), but cache_index_prev is OK
/// End of cache?
if (i==QTABLE_HEAD_CACHE) { /// yes, re-use the LRE slot
qtable_cache_next[cache_index_prev]=qtable_cache_mre;
qtable_cache_mre=cache_index_prev;
MDF14(printk("qtable_cache_mre=%d\n",qtable_cache_mre));
} else if (cache_index_prev>=0){ /// no, hit or never used so far, and not the first - anyway use this slot
qtable_cache_next[cache_index_prev]=qtable_cache_next[cache_index]; /// bypass this
qtable_cache_next[cache_index]=qtable_cache_mre; /// this points to the old mre
qtable_cache_mre=cache_index; /// this is now mre
MDF14(printk("qtable_cache_mre=%d\n",qtable_cache_mre));
}
/// is it a hit or a miss?
if (qtable_cache_values[qtable_cache_mre] != quality2) { /// miss, calculate the table and save it to cache first
qtable_cache_values[qtable_cache_mre] = quality2; /// this operator was missing !!!
rslt=1;
transpose=(quality2>>7) & 1; /// 0 - landscape mode, 1 - portrait mode
for (q_type=0;q_type<2;q_type++) { //Y/C
// quality=(quality2>>(q_type?8:0)) & 0xff;
quality= q_type?((quality2>>8)^0x80):(quality2 & 0x7f);
tstart=((quality & 0x80)?QTABLE_SIZE:0)+(transpose*(QTABLE_SIZE*2));
tab = & qtable_cache [QTABLE_SIZE * (2 * qtable_cache_mre + q_type)];
quality &= 0x7f;
MDF14(printk("transpose=%d tstart=%d, quality=%d\n",transpose,tstart,quality));
/// Safety limit on quality factor. Convert 0 to 1 to avoid zero divide.
if(quality <= 0)
quality = 1;
if(quality > 100)
quality = 100;
/** The basic table is used as-is (scaling 100) for a quality of 50.
* Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
* note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
* to make all the table entries 1 (hence, minimum quantization loss).
* Qualities 1..50 are converted to scaling percentage 5000/Q.
*/
if(quality < 50)
quality = 5000 / quality;
else
quality = 200 - quality * 2;
MDF14(printk("q_type=%d, quality=%d\n",q_type,quality));
for(i = 0; i < QTABLE_SIZE; i++) {
temp = (std_quant_tbls[i+tstart] * quality + 50) / 100;
/// limit the values to the valid range
if(temp <= 0) temp = 1;
if(temp > 255) temp = 255;
tab[zig_zag[i]]=temp;
}
}
} /// now table pair is calculated and stored in cache
/// copy tables to the output
if (y_tab) memcpy (y_tab, & qtable_cache [QTABLE_SIZE * (2 * qtable_cache_mre + 0)],QTABLE_SIZE) ;
if (c_tab) memcpy (c_tab, & qtable_cache [QTABLE_SIZE * (2 * qtable_cache_mre + 1)],QTABLE_SIZE) ;
D1I(local_irq_restore(flags));
MDF14(printk("y_tab=0x%x, c_tab=0x%x, rslt=%d\n",(int) y_tab, (int) c_tab, rslt));
MDF15(if (y_tab) {printk("y_tab\n"); for (i=0;i<64;i++){if ((i & 7)==0) printk("\n");printk(" %02x",(int) y_tab[i]);} printk("\n");});
MDF15(if (c_tab) {printk("c_tab\n"); for (i=0;i<64;i++){if ((i & 7)==0) printk("\n");printk(" %02x",(int) c_tab[i]);} printk("\n");});
return rslt;
}
//EXPORT_SYMBOL_GPL(get_qtable);
/**
* @brief initialization of quantization tables (reverse, for the FPGA) cache
* \n TODO: add \b init_qtable_fpga to module initialization
*/
void init_qtable_fpga(void) {
D1I(unsigned long flags);
int i;
MDF14(printk("\n"));
D1I(local_irq_save(flags)); /// needs to turn off IRQ
for (i=0; i < FPGA_NQTAB; i++) {
qtable_fpga_values[i]=-1; // undefined
qtable_fpga_next[i]=i+1; // last value is invalid, but that's OK - it should not be used
qtable_fpga_mre=0;
}
qtable_fpga_initialized=1;
D1I(local_irq_restore(flags));
}
/**
* @brief Finds an already programmed FPGA page or calculates (and programms FPGA with) a new one
* @param quality2 single byte (standard) or a pair of bytes (see file header description)
* @return table page number used (0..7) or -1 - invalid q
*/
int set_qtable_fpga(int quality2) {
D1I(unsigned long flags);
int i,transpose,fpga_index,fpga_index_prev,q_type,quality,temp,tstart;
unsigned short qtable_fpga[QTABLE_SIZE *2];
unsigned short * tab;
if (qtable_fpga_initialized==0) init_qtable_fpga();
if (quality2<0) return -1;
// if (quality2<256) quality2 |= (quality2 ^ 0x80)<<8;
if (quality2<256) quality2 |= (quality2 & 0x7f)<<8;
MDF14(printk("quality2=0x%x\n",quality2)); // d050
D1I(local_irq_save(flags));
/// look if such q value is already in cache
fpga_index=qtable_fpga_mre;
fpga_index_prev=-1;
for (i=0; (i=0); i++) {
fpga_index_prev=fpga_index;
fpga_index=qtable_fpga_next[fpga_index];
D14(printk(" ---i=%d, fpga_index_prev=%d, fpga_index=%d\n",i, fpga_index_prev, fpga_index)); ///NOTE: never - fixed!
}
/// fpga_index is invalid if (i==FPGA_NQTAB), but fpga_index_prev is OK
/// End of cache?
if (i==FPGA_NQTAB) { /// yes, re-use the LRE slot
qtable_fpga_next[fpga_index_prev]=qtable_fpga_mre;
qtable_fpga_mre=fpga_index_prev;
MDF14(printk("qtable_fpga_mre=%d\n",qtable_fpga_mre)); ///NOTE: never
} else if (fpga_index_prev>=0) { /// no, hit or never used so far, and not the latest - anyway use this slot
qtable_fpga_next[fpga_index_prev]=qtable_fpga_next[fpga_index]; /// bypass this
qtable_fpga_next[fpga_index]=qtable_fpga_mre; /// this points to the old mre
qtable_fpga_mre=fpga_index; /// this is now mre
MDF14(printk("qtable_fpga_mre=%d\n",qtable_fpga_mre)); ///NOTE: never
}
/// is it a hit or miss?
if (qtable_fpga_values[qtable_fpga_mre] != quality2) { /// miss, calculate the table and send it to the FPGA
qtable_fpga_values[qtable_fpga_mre] = quality2;
transpose=(quality2>>7) & 1; /// 0 - landscape mode, 1 - portrait mode
for (q_type=0;q_type<2;q_type++) { //Y/C
// quality=(quality2>>(q_type?8:0)) & 0xff;
quality= q_type?((quality2>>8)^0x80):(quality2 & 0x7f);
MDF14(printk("transpose=%d q_type=%d, quality=%d quality2=0x%x\n",transpose, q_type,quality,quality2));
tstart=((quality & 0x80)?QTABLE_SIZE:0)+(transpose*(QTABLE_SIZE*2));
tab = &qtable_fpga [QTABLE_SIZE * q_type];
quality &= 0x7f;
MDF14(printk("tstart=%d, quality=%d\n",tstart,quality)); //0, 1 - both times
/// Safety limit on quality factor. Convert 0 to 1 to avoid zero divide.
if(quality <= 0)
quality = 1;
if(quality > 100)
quality = 100;
/** The basic table is used as-is (scaling 100) for a quality of 50.
* Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
* note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
* to make all the table entries 1 (hence, minimum quantization loss).
* Qualities 1..50 are converted to scaling percentage 5000/Q.
*/
if(quality < 50)
quality = 5000 / quality;
else
quality = 200 - quality * 2;
MDF14(printk("q_type=%d, quality=%d\n",q_type,quality));
for(i = 0; i < QTABLE_SIZE; i++) {
temp = (std_quant_tbls[i+tstart] * quality + 50) / 100;
D15(if ((i & 7)==0) printk("\n");if (i==0) printk("\n");printk(" %08x",(int) temp));
/// limit the values to the valid range
if(temp <= 0) temp = 1;
if(temp > 255) temp = 255;
temp = ((0x20000/temp) + 1) >> 1;
if(temp > 0xffff) temp = 0xffff;
tab[i]=temp;
}
}
D15(printk("\n"));
#ifdef TEST_DISABLE_CODE
fpga_table_write_nice (CX313_FPGA_TABLES_QUANT+qtable_fpga_mre*QTABLE_SIZE, QTABLE_SIZE, (unsigned long *) qtable_fpga);
#endif /* TEST_DISABLE_CODE */
MDF15(for (i=0;i<128;i++){if ((i & 7)==0) printk("\n");if ((i & 63)==0) printk("\n");printk(" %04x",(int) qtable_fpga[i]);} printk("\n"));
MDF15(for (i=0;i<128;i++){if ((i & 7)==0) printk("\n");if ((i & 63)==0) printk("\n");printk(" %04x",std_quant_tbls[i]);} printk("\n"));
} /// now table pair is calculated and stored in cache
/// copy tables to the FPGA
D1I(local_irq_restore(flags));
MDF14(printk("qtable_fpga_mre=%d\n",qtable_fpga_mre));
return qtable_fpga_mre;
}
// Coring function table, 256 4-bit values per function
// min=0, max=10, step=0.1
// See coring_filter_setup.php to generate this table (with parameter '?C')
static unsigned long coring_tables[]= {
// filter=0
0x00000000, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=0.1
0x00000000, 0x11111110, 0x11111111, 0x22222222, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=0.2
0x00000000, 0x11111110, 0x11111111, 0x22222222, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=0.3
0x00000000, 0x11111110, 0x11111111, 0x22222221, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=0.4
0x00000000, 0x11111100, 0x11111111, 0x22222221, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=0.5
0x00000000, 0x11111000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444444,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=0.6
0x00000000, 0x11111000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444444,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=0.7
0x00000000, 0x11110000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444444,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=0.8
0x00000000, 0x11100000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=0.9
0x00000000, 0x11000000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1
0x00000000, 0x10000000, 0x11111111, 0x22222211, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1.1
0x00000000, 0x00000000, 0x11111111, 0x22222111, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1.2
0x00000000, 0x00000000, 0x11111110, 0x22221111, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1.3
0x00000000, 0x00000000, 0x11111110, 0x22211111, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1.4
0x00000000, 0x00000000, 0x11111100, 0x22211111, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1.5
0x00000000, 0x00000000, 0x11111000, 0x22111111, 0x22222222, 0x33333322, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1.6
0x00000000, 0x00000000, 0x11110000, 0x21111111, 0x22222222, 0x33333322, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1.7
0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22222222, 0x33333222, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1.8
0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22222221, 0x33332222, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=1.9
0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x22222211, 0x33322222, 0x33333333, 0x44444443,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2
0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x22222111, 0x33322222, 0x33333333, 0x44444433,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888888,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2.1
0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x22221111, 0x33222222, 0x33333333, 0x44444433,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2.2
0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x22211111, 0x32222222, 0x33333333, 0x44444433,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2.3
0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x22111111, 0x22222222, 0x33333333, 0x44444333,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2.4
0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x21111111, 0x22222222, 0x33333332, 0x44443333,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2.5
0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x11111111, 0x22222222, 0x33333322, 0x44443333,
0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2.6
0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x22222221, 0x33333222, 0x44433333,
0x44444444, 0x55555544, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2.7
0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x22222221, 0x33332222, 0x44333333,
0x44444444, 0x55555544, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2.8
0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22222211, 0x33322222, 0x43333333,
0x44444444, 0x55555544, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=2.9
0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22222111, 0x33222222, 0x33333333,
0x44444444, 0x55555444, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3
0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x22221111, 0x32222222, 0x33333333,
0x44444444, 0x55555444, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3.1
0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x22211111, 0x22222222, 0x33333333,
0x44444443, 0x55554444, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3.2
0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x22111111, 0x22222222, 0x33333333,
0x44444433, 0x55544444, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3.3
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x21111111, 0x22222222, 0x33333332,
0x44444333, 0x55544444, 0x55555555, 0x66666655, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3.4
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x11111111, 0x22222222, 0x33333322,
0x44443333, 0x55444444, 0x55555555, 0x66666655, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3.5
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x11111111, 0x22222221, 0x33333222,
0x44433333, 0x54444444, 0x55555555, 0x66666555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3.6
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x11111111, 0x22222211, 0x33332222,
0x44333333, 0x44444444, 0x55555555, 0x66666555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3.7
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x22222111, 0x33322222,
0x43333333, 0x44444444, 0x55555554, 0x66665555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3.8
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x22222111, 0x33222222,
0x33333333, 0x44444444, 0x55555554, 0x66665555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=3.9
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x22221111, 0x32222222,
0x33333333, 0x44444443, 0x55555544, 0x66655555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22211111, 0x22222222,
0x33333333, 0x44444433, 0x55555444, 0x66655555, 0x66666666, 0x77777766, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4.1
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x22111111, 0x22222222,
0x33333332, 0x44444333, 0x55554444, 0x66555555, 0x66666666, 0x77777766, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4.2
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x21111111, 0x22222222,
0x33333322, 0x44443333, 0x55544444, 0x65555555, 0x66666666, 0x77777666, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4.3
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x11111111, 0x22222222,
0x33333222, 0x44433333, 0x55444444, 0x55555555, 0x66666666, 0x77777666, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4.4
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111, 0x22222221,
0x33332222, 0x44333333, 0x54444444, 0x55555555, 0x66666666, 0x77777666, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4.5
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111, 0x22222211,
0x33322222, 0x43333333, 0x44444444, 0x55555555, 0x66666665, 0x77776666, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4.6
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x11111111, 0x22222111,
0x33222222, 0x33333333, 0x44444444, 0x55555554, 0x66666655, 0x77766666, 0x77777777, 0x88888887,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4.7
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x11111111, 0x22221111,
0x32222222, 0x33333333, 0x44444443, 0x55555544, 0x66666555, 0x77766666, 0x77777777, 0x88888877,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4.8
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x22211111,
0x22222222, 0x33333333, 0x44444433, 0x55555444, 0x66665555, 0x77666666, 0x77777777, 0x88888877,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=4.9
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x22211111,
0x22222222, 0x33333332, 0x44444333, 0x55554444, 0x66655555, 0x77666666, 0x77777777, 0x88888877,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x22111111,
0x22222222, 0x33333322, 0x44443333, 0x55544444, 0x66655555, 0x76666666, 0x77777777, 0x88888777,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5.1
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x21111111,
0x22222222, 0x33333222, 0x44433333, 0x55444444, 0x66555555, 0x66666666, 0x77777777, 0x88888777,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5.2
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x11111111,
0x22222222, 0x33332222, 0x44333333, 0x55444444, 0x65555555, 0x66666666, 0x77777776, 0x88887777,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5.3
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x11111111,
0x22222221, 0x33322222, 0x43333333, 0x54444444, 0x55555555, 0x66666666, 0x77777776, 0x88887777,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5.4
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x11111111,
0x22222211, 0x33222222, 0x33333333, 0x44444444, 0x55555555, 0x66666665, 0x77777766, 0x88877777,
0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5.5
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111,
0x22222111, 0x32222222, 0x33333333, 0x44444443, 0x55555554, 0x66666655, 0x77777666, 0x88877777,
0x88888888, 0x99999988, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5.6
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111,
0x22221111, 0x22222222, 0x33333333, 0x44444433, 0x55555444, 0x66666555, 0x77776666, 0x88777777,
0x88888888, 0x99999988, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5.7
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x11111111,
0x22211111, 0x22222222, 0x33333332, 0x44444333, 0x55554444, 0x66665555, 0x77766666, 0x88777777,
0x88888888, 0x99999988, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5.8
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x11111111,
0x22111111, 0x22222222, 0x33333322, 0x44443333, 0x55544444, 0x66655555, 0x77666666, 0x87777777,
0x88888888, 0x99999888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=5.9
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111,
0x21111111, 0x22222222, 0x33333222, 0x44433333, 0x55444444, 0x66555555, 0x77666666, 0x77777777,
0x88888888, 0x99999888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111,
0x11111111, 0x22222222, 0x33332222, 0x44333333, 0x54444444, 0x65555555, 0x76666666, 0x77777777,
0x88888888, 0x99999888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6.1
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111,
0x11111111, 0x22222221, 0x33322222, 0x43333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777,
0x88888887, 0x99998888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6.2
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111,
0x11111111, 0x22222211, 0x33222222, 0x33333333, 0x44444444, 0x55555554, 0x66666665, 0x77777776,
0x88888877, 0x99998888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6.3
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111,
0x11111111, 0x22222111, 0x32222222, 0x33333333, 0x44444443, 0x55555544, 0x66666655, 0x77777766,
0x88888777, 0x99988888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6.4
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111,
0x11111111, 0x22222111, 0x22222222, 0x33333333, 0x44444433, 0x55555444, 0x66666555, 0x77777666,
0x88887777, 0x99988888, 0x99999999, 0xaaaaaa99, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6.5
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111,
0x11111111, 0x22221111, 0x22222222, 0x33333332, 0x44444333, 0x55554444, 0x66665555, 0x77776666,
0x88887777, 0x99888888, 0x99999999, 0xaaaaaa99, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6.6
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111,
0x11111111, 0x22211111, 0x22222222, 0x33333322, 0x44443333, 0x55544444, 0x66655555, 0x77766666,
0x88877777, 0x98888888, 0x99999999, 0xaaaaaa99, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6.7
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110,
0x11111111, 0x22111111, 0x22222222, 0x33333222, 0x44433333, 0x55444444, 0x66555555, 0x77666666,
0x88777777, 0x98888888, 0x99999999, 0xaaaaaa99, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6.8
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100,
0x11111111, 0x21111111, 0x22222222, 0x33332222, 0x44333333, 0x54444444, 0x65555555, 0x76666666,
0x87777777, 0x88888888, 0x99999999, 0xaaaaa999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=6.9
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100,
0x11111111, 0x11111111, 0x22222222, 0x33322222, 0x43333333, 0x44444444, 0x55555555, 0x66666666,
0x77777777, 0x88888888, 0x99999998, 0xaaaaa999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000,
0x11111111, 0x11111111, 0x22222221, 0x33222222, 0x33333333, 0x44444444, 0x55555554, 0x66666665,
0x77777776, 0x88888887, 0x99999998, 0xaaaa9999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7.1
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000,
0x11111111, 0x11111111, 0x22222211, 0x32222222, 0x33333333, 0x44444433, 0x55555544, 0x66666655,
0x77777766, 0x88888877, 0x99999988, 0xaaaa9999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7.2
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000,
0x11111111, 0x11111111, 0x22222111, 0x22222222, 0x33333332, 0x44444333, 0x55555444, 0x66666555,
0x77777666, 0x88888877, 0x99999888, 0xaaa99999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7.3
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000,
0x11111111, 0x11111111, 0x22221111, 0x22222222, 0x33333322, 0x44443333, 0x55554444, 0x66665555,
0x77776666, 0x88888777, 0x99998888, 0xaaa99999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7.4
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000,
0x11111111, 0x11111111, 0x22211111, 0x22222222, 0x33333222, 0x44433333, 0x55544444, 0x66655555,
0x77766666, 0x88887777, 0x99998888, 0xaa999999, 0xaaaaaaaa, 0xbbbbbbaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7.5
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000,
0x11111111, 0x11111111, 0x22111111, 0x22222222, 0x33332222, 0x44333333, 0x54444444, 0x66555555,
0x77666666, 0x88877777, 0x99988888, 0xaa999999, 0xaaaaaaaa, 0xbbbbbbaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7.6
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x11111111, 0x11111111, 0x21111111, 0x22222222, 0x33322222, 0x43333333, 0x44444444, 0x65555555,
0x76666666, 0x88777777, 0x99888888, 0xa9999999, 0xaaaaaaaa, 0xbbbbbbaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7.7
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x11111110, 0x11111111, 0x11111111, 0x22222222, 0x33222222, 0x33333333, 0x44444444, 0x55555554,
0x66666665, 0x87777777, 0x98888888, 0x99999999, 0xaaaaaaaa, 0xbbbbbbaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7.8
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x11111100, 0x11111111, 0x11111111, 0x22222211, 0x32222222, 0x33333333, 0x44444443, 0x55555544,
0x66666655, 0x77777776, 0x88888888, 0x99999999, 0xaaaaaaaa, 0xbbbbbaaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=7.9
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x11111000, 0x11111111, 0x11111111, 0x22222111, 0x22222222, 0x33333333, 0x44444433, 0x55555444,
0x66666555, 0x77777766, 0x88888887, 0x99999998, 0xaaaaaaa9, 0xbbbbbaaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x11110000, 0x11111111, 0x11111111, 0x22221111, 0x22222222, 0x33333332, 0x44443333, 0x55554444,
0x66665555, 0x77777666, 0x88888877, 0x99999998, 0xaaaaaa99, 0xbbbbbaaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8.1
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x11100000, 0x11111111, 0x11111111, 0x22211111, 0x22222222, 0x33333322, 0x44433333, 0x55544444,
0x66655555, 0x77776666, 0x88888777, 0x99999988, 0xaaaaaa99, 0xbbbbaaaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8.2
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x11000000, 0x11111111, 0x11111111, 0x22111111, 0x22222222, 0x33332222, 0x44333333, 0x55444444,
0x66555555, 0x77766666, 0x88887777, 0x99999888, 0xaaaaa999, 0xbbbbaaaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8.3
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x11000000, 0x11111111, 0x11111111, 0x21111111, 0x22222222, 0x33322222, 0x43333333, 0x44444444,
0x65555555, 0x77666666, 0x88877777, 0x99998888, 0xaaaa9999, 0xbbbaaaaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8.4
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x10000000, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x33222222, 0x33333333, 0x44444444,
0x55555554, 0x76666666, 0x88777777, 0x99988888, 0xaaa99999, 0xbbbaaaaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8.5
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x11111111, 0x11111111, 0x11111111, 0x22222221, 0x32222222, 0x33333333, 0x44444443,
0x55555544, 0x66666665, 0x87777777, 0x99888888, 0xaaa99999, 0xbbaaaaaa, 0xbbbbbbbb, 0xcccccccb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8.6
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x11111110, 0x11111111, 0x11111111, 0x22222211, 0x22222222, 0x33333333, 0x44444333,
0x55555444, 0x66666555, 0x77777776, 0x98888888, 0xaa999999, 0xbaaaaaaa, 0xbbbbbbbb, 0xccccccbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8.7
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x11111100, 0x11111111, 0x11111111, 0x22222111, 0x22222222, 0x33333332, 0x44443333,
0x55554444, 0x66665555, 0x77777666, 0x88888887, 0xa9999999, 0xbaaaaaaa, 0xbbbbbbbb, 0xccccccbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8.8
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x11111000, 0x11111111, 0x11111111, 0x22221111, 0x22222222, 0x33333222, 0x44433333,
0x55544444, 0x66655555, 0x77776666, 0x88888877, 0x99999998, 0xaaaaaaaa, 0xbbbbbbbb, 0xccccccbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=8.9
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x11110000, 0x11111111, 0x11111111, 0x22111111, 0x22222222, 0x33332222, 0x44333333,
0x54444444, 0x66555555, 0x77766666, 0x88888777, 0x99999988, 0xaaaaaaa9, 0xbbbbbbba, 0xcccccbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=9
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x11100000, 0x11111111, 0x11111111, 0x21111111, 0x22222222, 0x33322222, 0x43333333,
0x44444444, 0x65555555, 0x77666666, 0x88887777, 0x99999888, 0xaaaaaa99, 0xbbbbbbba, 0xcccccbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=9.1
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x11000000, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x33222222, 0x33333333,
0x44444443, 0x55555554, 0x76666666, 0x88877777, 0x99998888, 0xaaaaaa99, 0xbbbbbbaa, 0xcccccbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=9.2
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x10000000, 0x11111111, 0x11111111, 0x11111111, 0x22222221, 0x32222222, 0x33333333,
0x44444433, 0x55555544, 0x66666655, 0x87777777, 0x99988888, 0xaaaaa999, 0xbbbbbaaa, 0xccccbbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=9.3
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x11111111, 0x11111111, 0x11111111, 0x22222211, 0x22222222, 0x33333332,
0x44444333, 0x55555444, 0x66666555, 0x77777776, 0x99888888, 0xaaaa9999, 0xbbbbbaaa, 0xccccbbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=9.4
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x11111110, 0x11111111, 0x11111111, 0x22222111, 0x22222222, 0x33333322,
0x44443333, 0x55544444, 0x66665555, 0x77777666, 0x98888887, 0xaaa99999, 0xbbbbaaaa, 0xcccbbbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=9.5
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x11111100, 0x11111111, 0x11111111, 0x22211111, 0x22222222, 0x33333222,
0x44433333, 0x55444444, 0x66655555, 0x77776666, 0x88888877, 0xaa999999, 0xbbbaaaaa, 0xcccbbbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=9.6
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x11111111, 0x22111111, 0x22222222, 0x33332222,
0x43333333, 0x54444444, 0x66555555, 0x77766666, 0x88888777, 0xa9999998, 0xbbaaaaaa, 0xccbbbbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=9.7
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x11111111, 0x21111111, 0x22222222, 0x33222222,
0x33333333, 0x44444444, 0x55555555, 0x77666666, 0x88887777, 0x99999988, 0xbaaaaaaa, 0xccbbbbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
// filter=9.8
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x32222222,
0x33333333, 0x44444443, 0x55555544, 0x76666665, 0x88877777, 0x99999888, 0xbaaaaaa9, 0xcbbbbbbb,
0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xfffffffe, 0xffffffff, 0xffffffff,
// filter=9.9
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x11111111, 0x11111111, 0x22222211, 0x22222222,
0x33333333, 0x44444333, 0x55555444, 0x66666655, 0x88777777, 0x99998888, 0xaaaaaa99, 0xbbbbbbbb,
0xcccccccc, 0xddddddcc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xfffffffe, 0xffffffff, 0xffffffff,
// filter=10
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111, 0x11111111, 0x22222111, 0x22222222,
0x33333332, 0x44443333, 0x55554444, 0x66666555, 0x77777766, 0x99988888, 0xaaaaa999, 0xbbbbbbba,
0xcccccccc, 0xddddddcc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xfffffffe, 0xffffffff, 0xffffffff
};
/**
* @brief Temporary function to directly set one of the coring LUTs (currently 100 0.0 to 9.9 with 0.1 step)
* to one of 16 FPGA tables (even - for Y,odd - for C)
* @param coring_number 0..99 - function number
* @param fpga_number 0.. 15 - fpga table number
* @return table page number used (0..7) or -1 - invalid q
*/
#define CORING_SIZE 32 // longs
void set_coring_fpga(int coring_number, int fpga_number) {
if (coring_number<0) coring_number=0;
if (coring_number>=sizeof(coring_tables)/(4*CORING_SIZE)) coring_number=sizeof(coring_tables)/(4*CORING_SIZE);
D15(printk("coring_number=0x%x, fpga_number=0x%x\n",coring_number, fpga_number));
#ifdef TEST_DISABLE_CODE
fpga_table_write_nice (CX313_FPGA_TABLES_CORING+(fpga_number *CORING_SIZE) , CORING_SIZE, (unsigned long *) &coring_tables[coring_number*CORING_SIZE]);
#endif /* TEST_DISABLE_CODE */
MDF15(int i; for (i=0;i<32;i++) {if ((i & 7)==0) printk("\n");printk(" %08x",(int) coring_tables[coring_number*CORING_SIZE +i]);} printk("\n"));
}
MODULE_LICENSE("GPL");
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/quantization_tables.h 0000664 0000000 0000000 00000003312 12677012326 0031153 0 ustar 00root root 0000000 0000000 /// @file quantization_tables.h
#ifndef _QUANTIZATION_TABLES_H
#define _QUANTIZATION_TABLES_H
/**
* @brief initialization of quantization tables (direct - JPEG header ones) cache
* \n TODO: add \b init_qtable_head_cache to module initialization
*/
void init_qtable_head_cache(void);
/**
* @brief calculates a pair of direct (JPEG header) tables for the specified quality (2-bytes )
* @param quality2 single byte (standard) or a pair of bytes (see file header description)
* @param y_tab caller-provided pointer to a 64-byte Y (intensity) quantization table (NULL - don't copy)
* @param c_tab caller-provided pointer to a 64-byte C (color) quantization table (NULL - don't copy)
* @return 0 - cache hit, 1 - cache miss (recalculated), -1 - invalid quality
*/
int get_qtable(int quality2, unsigned char *y_tab, unsigned char *c_tab);
/**
* @brief initialization of quantization tables (reverse, for the FPGA) cache
* \n TODO: add \b init_qtable_fpga to module initialization
*/
void init_qtable_fpga(void);
/**
* @brief Finds an already programmed FPGA page or calculates (an programms FPGA with) a new one
* @param quality2 single byte (standard) or a pair of bytes (see file header description)
* @return table page number used (0..7) or -1 - invalid q
*/
int set_qtable_fpga(int quality2);
/**
* @brief Temporary function to directly set one of the coring LUTs (currently 100 0.0 to 9.9 with 0.1 step)
* to one of 16 FPGA tables (even - for Y,odd - for C)
* @param coring_number 0..99 - function number
* @param fpga_number 0.. 15 - fpga table number
* @return table page number used (0..7) or -1 - invalid q
*/
void set_coring_fpga(int coring_number, int fpga_number);
void reset_qtables(void);
#endif
linux-elphel-f632965fb219afe5dc368fab4a3b70cd21365b17/src/drivers/elphel/sensor_common.c 0000664 0000000 0000000 00000067027 12677012326 0027764 0 ustar 00root root 0000000 0000000 /** @file sensor_common.h
* @brief This module handles sensor discovery, initialization and programming tasks
* common for all sensors. Task that are implemented:
* - system initialization (?)
* - compressor write (and global read) pointers
* - populating 32-byte interframe data
* - interrupts handling
* - tasklets
* - device driver that includes waiting for the next frame regardless of compression
*
* 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 .
*/
//copied from cxi2c.c - TODO:remove unneeded
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
//#include
#include // endians
#include
//#include /// ETRAX interrupt registers
#include
#include
#include
#include
#include
//#include
#include
//#include
#include "x393.h"
//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
//#include "fpga_sdram.h" // use a single fpga_initSDRAM(void)
//#include "x3x3.h"
//#include "cc3x3.h"
//#include "cxdma.h"
#include "framepars.h"
#include "sensor_common.h"
//#include "pgm_functions.h"
#include "circbuf.h"
//#include "exif353.h"
//#include "histograms.h"
//#include "gamma_tables.h"
#include "quantization_tables.h"
#include "x393_macro.h"
#if ELPHEL_DEBUG
#define ELPHEL_DEBUG_THIS 0
#else
#define ELPHEL_DEBUG_THIS 0
#endif
#if ELPHEL_DEBUG_THIS
#define MDF2(x) printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__); x
#define MDD1(x) printk("%s:%d:",__FILE__,__LINE__); x ; udelay (ELPHEL_DEBUG_DELAY)
#define MD1(x) printk("%s:%d:",__FILE__,__LINE__);x
//#define MD1(x)
#define MD12(x) printk("%s:%d:",__FILE__,__LINE__);x
//#define MD12(x)
#define MD13(x) printk("%s:%d:",__FILE__,__LINE__);x
//#define MD13(x)
#else
#define MDF2(x)
#define MD1(x)
#define MDD1(x)
#define MD12(x)
#define MD13(x)
#endif
/**@struct jpeg_ptr_t
* @brief \e jpeg_ptr_t structure contains read and write pointers along with
* IRQ number for a single channel
* @var jpeg_ptr_t::jpeg_wr
* JPEG write pointer
* @var jpeg_ptr_t::jpeg_rp
* JPEG read pointer
* @var jpeg_ptr_t::fpga_cntr_prev
* This field contains previous value of the FPGA transfer counter which is used
* to find out if it has changed
* @var jpeg_ptr_t::irq_num_comp
* IRQ number associated with compressor
* @var jpeg_ptr_t::irq_num_sens
* IRQ number associated with sensor
*/
struct jpeg_ptr_t {
volatile int jpeg_wp;
volatile int jpeg_rp;
int fpga_cntr_prev;
unsigned int irq_num_comp;
unsigned int irq_num_sens;
};
/**@struct image_acq_pd_t
* @brief \e image_acq_pd contains private data for the image acquisition driver
*/
struct image_acq_pd_t {
int minor;
struct jpeg_ptr_t jpeg_ptr[IMAGE_CHN_NUM];
};
static struct image_acq_pd_t image_acq_priv;
static volatile int JPEG_wp;
static volatile int JPEG_rp;
static int fpga_counter_prev=0; /// Previous value of the FPGA transfer counter (to find out if it did change)
static struct meta_offsets_t { // works like a cache to time save on looking for tags in the directory (forced to recalcualte if does not match)
int Image_DateTime; // will have offset of the Exif_Image_DateTime data in meta page (Exif_Photo_SubSecTime should go immediately after in meta page)
int Photo_DateTimeOriginal;
int Photo_ExposureTime;
int Image_FrameNumber;
int Image_Orientation;
int Photo_MakerNote;
} meta_offsets;
int camSeqGetJPEG_wp(void) {return JPEG_wp;}
int camSeqGetJPEG_rp(void) {return JPEG_rp;}
void camSeqSetJPEG_rp(int p) {
JPEG_rp=p;
set_globalParam(G_CIRCBUFRP, p<< 2);
set_globalParam(G_FREECIRCBUF,
(((get_globalParam(G_CIRCBUFRP) <= get_globalParam(G_CIRCBUFWP))?
get_globalParam(G_CIRCBUFSIZE):0)+ get_globalParam(G_CIRCBUFRP))
- get_globalParam(G_CIRCBUFWP));
}
/*!
End of compressor-related code - TODO: move to a separate file?
*/
/**
* @brief driver name to display in log messages
*/
#define IMAGEACQ_DRIVER_NAME "Elphel (R) Model 393 Image Acquisition device driver"
static const struct of_device_id elphel393_sensor_of_match[];
static struct sensorproc_t s_sensorproc; // sensor parameters and functions to call
struct sensorproc_t * sensorproc = NULL;
//EXPORT_SYMBOL_GPL(sensorproc);
//wait_queue_head_t image_acq_wait_queue; /// queue for the sensor frame interrupts
void tasklet_fpga_function(unsigned long arg);
/**
* @brief Copy #sensorproc structure, needed for multisensor board to be able
* to replace some of the functions
* @param[in] copy pointer to a copy structure
* @return pointer to a \b copy structure
*/
struct sensorproc_t * copy_sensorproc (struct sensorproc_t * copy)
{
/** copy sensor functions */
memcpy(copy, sensorproc, sizeof(struct sensorproc_t));
return copy;
}
//#ifdef TEST_DISABLE_CODE
/// When should it be called?
//int init_sensor(void);
/// Not yet used??
/**
* @brief Check FPGA version and initialize SDRAM (if not done yet)
* TODO: when should it be called?
* @return <0 error, 0 - just checked, nothing done,1 - needs sensor initialization
*/
int init_FPGA(void) { //will check FPGA version, init SDRAM (if needed) and sensor
int i;
// int f1,f2;
// Should be initial
if ((fpga_state & FPGA_STATE_LOADED) == 0) return -1; /// fpga is not configured
if ((i=port_csp0_addr[X313__RA__MODEL]) < X313_MINMODREV) {
printk ("too old fpga rev - found %x, software wants >= %x\n",i,X313_MINMODREV);
return -1; // too old FPGA
}
if (i > X313_MAXMODREV) {
printk ("too new fpga rev - found %x, software wants <= %x\n",i,X313_MAXMODREV);
return -1; // too new FPGA
}
fpga_state |= FPGA_STATE_INITIALIZED; /// what this initialization really mean?
if (!X313_IS_SDRAM_ON) fpga_initSDRAM();
// Was sensor initialized? (What if SDRAM was initialized by some application?)
MD1(printk("init_FPGA, fpga_state=0x%x\n",fpga_state));
if (X313_CHN0_USED!=0) return 0;
return 1;
}
///
/// initializes structures for the image acquisition parameter
/// initializes hardware i2c controller and the command sequencer (leaves them stopped to ignore any frame syncs)
/// sets some default acquisition parameters
/// Maybe - set up DMA also?
/// TODO: Take care while turning off reset on i2c and cmd_sequencer so there will be no sensor vsync lost
/// (easier to do in FPGA)
/// Done:
///#define CCAM_VSYNC_ON port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,0)
///#define CCAM_VSYNC_OFF port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,1)
///
int init_acq_sensor(void);
DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); /// 0 - no arguments for now
/**
* @brief reads FPGA transfer pointer to update JPEG_wp
* NOTE: should be called before compressor is reset - that would zero out that hardware register
* @return 0 if compressor was off (no advance), 1 if write pointer did actually advance
*/
inline int updateIRQJPEG_wp(void) {
int xferred; /// number of 32-byte chunks transferred since compressor was reset
int fpga_cntr= X313_XFERCNTR; /// using macro defined in x353.h that makes a dummy read (reads after writes can be wrong)
xferred= fpga_cntr-fpga_counter_prev; /// Transferred since last JPEG_wp update (or counter reset)
#if 0 /// ELPHEL_DEBUG_THIS- address changed !!!
set_globalParam (0x300,get_globalParam (0x300)+1);
set_globalParam (0x302,fpga_cntr);
if (xferred==0) set_globalParam (0x305,get_globalParam (0x305)+1);
#endif
if (xferred==0) return 0; /// no advance (compressor was off?)
fpga_counter_prev= fpga_cntr;
if (xferred <0) xferred+= (1 <<24) ; /// Hardware counter is 24 bits - rolled over
JPEG_wp+= (xferred << 3); //! counts in 32-byte ( 8 of 32bit words) chunks
int circbuf_size=get_globalParam (G_CIRCBUFSIZE)>>2; //G_CIRCBUFSIZE G_CIRCBUFRP
if (JPEG_wp > circbuf_size) JPEG_wp-=circbuf_size;
#if 0 ///ELPHEL_DEBUG_THIS - address changed !!!
set_globalParam (0x301,get_globalParam (0x301)+1);
set_globalParam (0x303,xferred);
set_globalParam (0x304,JPEG_wp);
#endif
return 1;
}
/**
* @brief Calculate/update CIRCBUF parameters available after compressor interrupt
*/
inline void updateIRQCircbuf(void) {
set_globalParam (G_CIRCBUFWP, JPEG_wp<<2);
set_globalParam (G_FREECIRCBUF, (((get_globalParam (G_CIRCBUFRP) <= get_globalParam (G_CIRCBUFWP))? get_globalParam (G_CIRCBUFSIZE):0)+
get_globalParam (G_CIRCBUFRP)) - get_globalParam (G_CIRCBUFWP));
}
/**
* @brief Calculate/update focus parameters available after compressor interrupt
* NOTE: currently global (latest), not per-frame
*/
inline void updateIRQFocus(void) {
set_globalParam (G_GFOCUS_VALUE, X313_HIGHFREQ);
set_imageParamsThis (P_FOCUS_VALUE, X313_HIGHFREQ);
}
/**
* @brief Locate area between frames in the circular buffer
* @return pointer to interframe parameters structure
*/
inline struct interframe_params_t* updateIRQ_interframe(void) {
int circbuf_size=get_globalParam (G_CIRCBUFSIZE)>>2;
int alen = JPEG_wp-9; if (alen<0) alen+=circbuf_size;
int jpeg_len=ccam_dma_buf_ptr[alen] & 0xffffff;
set_globalParam(G_FRAME_SIZE,jpeg_len);
int aframe_params=(alen & 0xfffffff8)-
(((jpeg_len + CCAM_MMAP_META + 3) & 0xffffffe0)>>2) /// multiple of 32-byte chunks to subtract
-8; /// size of the storage area to be filled before the frame
if(aframe_params < 0) aframe_params += circbuf_size;
struct interframe_params_t* interframe= (struct interframe_params_t*) &ccam_dma_buf_ptr[aframe_params];
/// should we use memcpy as before here?
interframe->frame_length=jpeg_len;
interframe->signffff=0xffff;
#if ELPHEL_DEBUG_THIS
set_globalParam (0x306,get_globalParam (0x306)+1);
#endif
return interframe;
}
/**
* @brief Fill exif data with the current frame data, save pointer to Exif page in the interframe area
* @param interframe pointer to interframe parameters structure
*/
inline void updateIRQ_Exif(struct interframe_params_t* interframe) {
int index_time = JPEG_wp-11; if (index_time<0) index_time+=get_globalParam (G_CIRCBUFSIZE)>>2;
/// calculates datetime([20] and subsec[7], returns pointer to char[27]
char * exif_meta_time_string=encode_time(ccam_dma_buf_ptr[index_time], ccam_dma_buf_ptr[index_time+1]);
/// may be split in datetime/subsec - now it will not notice missing subseq field in template
write_meta_irq(exif_meta_time_string, &meta_offsets.Photo_DateTimeOriginal, Exif_Photo_DateTimeOriginal, 27);
write_meta_irq(exif_meta_time_string, &meta_offsets.Image_DateTime, Exif_Image_DateTime, 20); // may use 27 if room is provided
putlong_meta_irq(get_imageParamsThis(P_EXPOS), &meta_offsets.Photo_ExposureTime, Exif_Photo_ExposureTime);
putlong_meta_irq(get_imageParamsThis(P_FRAME), &meta_offsets.Image_FrameNumber, Exif_Image_FrameNumber);
//Exif_Photo_MakerNote
int global_flips=(get_imageParamsThis(P_FLIPH) & 1) | ((get_imageParamsThis(P_FLIPV)<<1) & 2);
int extra_flips=0;
if (get_imageParamsThis(P_MULTI_MODE)!=0) {
extra_flips=get_imageParamsThis(P_MULTI_MODE_FLIPS);
global_flips=extra_flips & 3;
}
/* unsigned char orientations[]={1,6,3,8,
2,7,4,5,
4,5,2,7,
3,8,1,6};
*/
unsigned char orientations[]="1638274545273816";
unsigned char orientation_short[2];
orientation_short[0]=0;
orientation_short[1]=0xf & orientations[(get_imageParamsThis(P_PORTRAIT)&3) | (global_flips<<2)];
write_meta_irq(orientation_short, &meta_offsets.Image_Orientation, Exif_Image_Orientation, 2);
//TODO - use memcpy
int maker_offset;
maker_offset=putlong_meta_irq(get_imageParamsThis(P_GAINR), &meta_offsets.Photo_MakerNote, Exif_Photo_MakerNote);
if (maker_offset>0) {
putlong_meta_raw_irq(get_imageParamsThis(P_GAING), maker_offset+4);
putlong_meta_raw_irq(get_imageParamsThis(P_GAINGB), maker_offset+8);
putlong_meta_raw_irq(get_imageParamsThis(P_GAINB), maker_offset+12);
putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_R), maker_offset+16);
putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_G), maker_offset+20);
putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_GB), maker_offset+24);
putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_B), maker_offset+28);
putlong_meta_raw_irq(get_imageParamsThis(P_WOI_LEFT) | (get_imageParamsThis(P_WOI_WIDTH)<<16), maker_offset+32);
putlong_meta_raw_irq(get_imageParamsThis(P_WOI_TOP) | (get_imageParamsThis(P_WOI_HEIGHT)<<16), maker_offset+36);
putlong_meta_raw_irq( global_flips |
((get_imageParamsThis(P_BAYER)<<2) & 0xc) |
((get_imageParamsThis(P_COLOR)<<4) & 0xF0) |
((get_imageParamsThis(P_DCM_HOR)<<8) & 0xF00) |
((get_imageParamsThis(P_DCM_VERT)<<12) & 0xF000) |
((get_imageParamsThis(P_BIN_HOR)<<16) & 0xF0000) |
((get_imageParamsThis(P_BIN_VERT)<<20) & 0xF00000) |
(extra_flips <<24) , maker_offset+40);
putlong_meta_raw_irq(get_imageParamsThis(P_MULTI_HEIGHT_BLANK1), maker_offset+44);
putlong_meta_raw_irq(get_imageParamsThis(P_MULTI_HEIGHT_BLANK2), maker_offset+48);
// putlong_meta_raw_irq(0x1234567, maker_offset+52); // just testing
putlong_meta_raw_irq(get_imageParamsThis(P_QUALITY) | ((get_imageParamsThis(P_PORTRAIT)&1)<<7) | (get_imageParamsThis(P_CORING_INDEX)<<16), maker_offset+52);
putlong_meta_raw_irq(get_globalParam(G_TEMPERATURE01), maker_offset+56); // data should be provided by a running daemon
putlong_meta_raw_irq(get_globalParam(G_TEMPERATURE23), maker_offset+60);
//get_globalParam(G_TASKLET_CTL)
// left 1 long spare (+44)
}
interframe->meta_index=store_meta();
}
/**
* @brief hardware IRQ service
* most urgent tasks
* @param irq
* @param dev_id
* @return
*/
static irqreturn_t elphel_FPGA_interrupt(int irq, void *dev_id) {
unsigned long irq_state;
irq_state = X313_IRQSTATE; //!making dummy read - see c353.h
DIS_INTERRUPTS;
PROFILE_NEXT(0);
/// read hardware write pointer (will only advance if compression was on)
///find out if compressor was running and update pointers, exif, ...?
if (updateIRQJPEG_wp()) { ///also fills P_FRAME ahead
updateIRQCircbuf();
updateIRQFocus(); ///NOTE: currently global (latest), not per-frame
struct interframe_params_t* interframe= updateIRQ_interframe(); /// fills jpeg_len, signffff
/// should we use memcpy as before here?
// interframe->frame_length=jpeg_len;
// interframe->signffff=0xffff;
updateIRQ_Exif(interframe);
updateFramePars(X3X3_I2C_FRAME, interframe);
wake_up_interruptible(&circbuf_wait_queue); /// only when frame is acquired
} else {
updateFramePars(X3X3_I2C_FRAME, NULL);
}
PROFILE_NOW(1);
wake_up_interruptible(&framepars_wait_queue); /// all interrupts, not just frames acquired
tasklet_schedule(&tasklet_fpga); /// trigger software interrupt
EN_INTERRUPT(SMART);
return IRQ_HANDLED;
}
/**
* @brief Handle interrupts from sensor channels. This handler is installed without SA_INTERRUPT
* flag meaning that interrupts are enabled during processing. Such behavior is recommended in LDD3.
* @param[in] irq interrupt number
* @param[in] dev_id pointer to driver's private data structure #jpeg_ptr_t corresponding to
* the channel which raise interrupt
* @return \e IRQ_HANDLED if interrupt was processed and \e IRQ_NONE otherwise
*/
static irqreturn_t frame_sync_irq_handler(int irq, void *dev_id)
{
update_frame_pars();
return IRQ_HANDLED;
}
/**
* @brief Handle interrupts from JPEG compressor channels. This handler is installed without SA_INTERRUPT
* flag meaning that interrupts are enabled during processing. Such behavior is recommended in LDD3.
* @param[in] irq interrupt number
* @param[in] dev_id pointer to driver's private data structure #jpeg_ptr_t corresponding to
* the channel which raise interrupt
* @return \e IRQ_HANDLED if interrupt was processed and \e IRQ_NONE otherwise
*/
static irqreturn_t compressor_irq_handler(int irq, void *dev_id)
{
return IRQ_HANDLED;
}
/**
* @brief Tasklet - software interrupt
* lower priority tasks
* try to implement some balancing - if job is not finished - reduce FPS for it (alternate jobs)?
* @param arg not used
*/
/*!TODO:
implement 2 modes of controlling when to calculate histograms:
1 - add mask to 3 frame number LSB (i.e. - 0/10000000/10001000/10101010/11111111) - 3 contol bits - en/dis and mode
2 - requested in advance (i.e. by autoexposure when writing new exposure or white balance - when writing balance
mode 1 will provide easy way to display histograms (no need to repetively request them),
mode 2 - useful for autoexposure
Modify waiting (LSEEK_*) for histogrames so they will only unfreeze if the histogram is available (skipping multiple frames))
For displaying histograms - try use latest available - not waiting fro a particular frame.
*/
/// HISTOGRAMS_WAKEUP_ALWAYS if 0 will only wakeup processes waiting for histograms when they become available, maybe never if they are disabled
/// if defined 1 - will wakeup each frame, regardless of the availability of the histograms
//#define HISTOGRAMS_WAKEUP_ALWAYS 0
void tasklet_fpga_function(unsigned long arg) {
int hist_en;
int tasklet_disable=get_globalParam(G_TASKLET_CTL);
unsigned long thisFrameNumber=getThisFrameNumber();
unsigned long prevFrameNumber=thisFrameNumber-1;
unsigned long * hash32p=&(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]);
unsigned long * framep= &(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]);
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
/// Histograms are available for the previous frame (that is already in circbuf if compressor was running)
/// Is Y histogram needed?
PROFILE_NOW(2);
switch ((tasklet_disable >> TASKLET_CTL_HISTY_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate
hist_en=0;
break;
case TASKLET_HIST_HALF: /// calculate each even (0,2,4,6 frme of 8)
hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<> TASKLET_CTL_HISTC_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate
hist_en=0;
break;
case TASKLET_HIST_HALF: /// calculate each even (0,2,4,6 frme of 8)
hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<dev;
const struct of_device_id *match;
const char **frame_sync_irq_names = { "frame_sync_irq_0", "frame_sync_irq_1",
"frame_sync_irq_2", "frame_sync_irq_3" };
const char **compressor_irq_names = { "compr_irq_0", "compr_irq_1",
"compr_irq_2", "compr_irq_3"
};
/* sanity check */
match = of_match_device(elphel393_sensor_of_match, dev);
if (!match)
return -EINVAL;
sensorproc= &s_sensorproc;
MDD1(printk("sensorproc=0x%x\n",(int) sensorproc));
for (i = 0; i < IMAGE_CHN_NUM; i++) {
irq = platform_get_irq_byname(pdev, frame_sync_irq_names[i]);
if (request_irq(irq,
frame_sync_irq_handler,
0, // no flags
frame_sync_irq_names[i],
&image_acq_priv.jpeg_ptr[i])) {
printk(KERN_ERR "Can not allocate Elphel FPGA interrupts");
return -EBUSY;
}
image_acq_priv.jpeg_ptr[i].irq_num_sens = irq;
}
for (i = 0; i < IMAGE_CHN_NUM; i++) {
irq = platform_get_irq_byname(pdev, compressor_irq_names[i]);
if (request_irq(irq,
compressor_irq_handler,
0, // no flags
compressor_irq_names[i],
&image_acq_priv.jpeg_ptr[i])) {
printk(KERN_ERR "Can not allocate Elphel FPGA interrupts");
return -EBUSY;
}
image_acq_priv.jpeg_ptr[i].irq_num_comp = irq;
}
#ifdef TEST_DISABLE_CODE
if(request_irq(EXT_INTR_VECT,
elphel_FPGA_interrupt,
SA_INTERRUPT, // SA_SHIRQ | SA_INTERRUPT if it is a shared one.
"Elphel FPGA interrupts",
NULL)) {
printk(KERN_ERR "Can't allocate Elphel FPGA interrupts");
return -EBUSY;
}
#endif
printk("Elphel FPGA interrupts initialized\n");
// init_waitqueue_head(&image_acq_wait_queue);
// DMA_buf_start=x313_dma_init();
MDD1(printk("reset_compressor()\n"));
reset_compressor(); /// reset compressor and buffer pointers
MDD1(printk("x313_dma_init()\n"));
//x313_dma_init(); /// initialize ETRAX FS DMA
MDD1(printk("init_pgm_proc ()\n"));
//init_pgm_proc (); /// setup pointers to functions (not sensor-specific)
MDD1(printk("reset_qtables()\n"));
reset_qtables(); /// force initialization at next access
return 0;
}
static int image_acq_stop(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id elphel393_sensor_of_match[] = {
{ .compatible = "elphel,elphel393-sensor-1.00" },
{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, elphel393_sensor_of_match);
static struct platform_driver elphel393_sensor_common = {
.probe = image_acq_init,
.remove = image_acq_stop,
.driver = {
.name = IMAGEACQ_DRIVER_NAME,
.of_match_table = elphel393_sensor_of_match,
}
};
module_platform_driver(elphel393_sensor_common);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov