pax_global_header 0000666 0000000 0000000 00000000064 12670664436 0014530 g ustar 00root root 0000000 0000000 52 comment=e01891ea01b9e56de87ef6c730fef801fbf319cb
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/ 0000775 0000000 0000000 00000000000 12670664436 0021371 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/.gitignore 0000664 0000000 0000000 00000000146 12670664436 0023362 0 ustar 00root root 0000000 0000000 bin
tmp
Debug
Release
linux
sysroots
.project
.cproject
.externalToolBuilders
.settings
.pydevproject
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/README.md 0000664 0000000 0000000 00000003622 12670664436 0022653 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-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/ 0000775 0000000 0000000 00000000000 12670664436 0025763 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.cproject 0000664 0000000 0000000 00000337203 12670664436 0027605 0 ustar 00root root 0000000 0000000
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.externalToolBuilders/ 0000775 0000000 0000000 00000000000 12670664436 0032213 5 ustar 00root root 0000000 0000000 bitbake compile -f [Builder].launch 0000664 0000000 0000000 00000001372 12670664436 0040467 0 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.externalToolBuilders
bitbake compile [Builder].launch 0000664 0000000 0000000 00000001552 12670664436 0040204 0 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.externalToolBuilders
bitbake deploy [Builder].launch 0000664 0000000 0000000 00000001762 12670664436 0040053 0 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.externalToolBuilders
kernel modules [Builder].launch 0000664 0000000 0000000 00000001257 12670664436 0040105 0 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.externalToolBuilders
org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder.launch 0000664 0000000 0000000 00000001361 12670664436 0046232 0 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.externalToolBuilders
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.project 0000664 0000000 0000000 00000005211 12670664436 0027431 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-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.pydevproject 0000664 0000000 0000000 00000000456 12670664436 0030507 0 ustar 00root root 0000000 0000000
Default
python 2.7
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.settings/ 0000775 0000000 0000000 00000000000 12670664436 0027701 5 ustar 00root root 0000000 0000000 language.settings.xml 0000664 0000000 0000000 00000001117 12670664436 0033766 0 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/eclipse_project_setup/.settings
org.eclipse.cdt.codan.core.prefs 0000664 0000000 0000000 00000024130 12670664436 0035660 0 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/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 12670664436 0034576 0 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/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-e01891ea01b9e56de87ef6c730fef801fbf319cb/run_bitbake.sh 0000775 0000000 0000000 00000000330 12670664436 0024211 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-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/ 0000775 0000000 0000000 00000000000 12670664436 0022160 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/ 0000775 0000000 0000000 00000000000 12670664436 0023636 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/ata/ 0000775 0000000 0000000 00000000000 12670664436 0024403 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/ata/Kconfig 0000664 0000000 0000000 00000062003 12670664436 0025707 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-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/ata/Makefile 0000664 0000000 0000000 00000011503 12670664436 0026043 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-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/ata/ahci_elphel.c 0000664 0000000 0000000 00000016411 12670664436 0027007 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 "ahci.h"
#define DRV_NAME "elphel-ahci"
/* 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[];
struct elphel_ahci_priv {
u32 clb_offs;
u32 fb_offs;
u32 base_addr;
};
// 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;
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");
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 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-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/clk/ 0000775 0000000 0000000 00000000000 12670664436 0024407 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/clk/clk-si5338.c 0000664 0000000 0000000 00000550572 12670664436 0026276 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-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/elphel/ 0000775 0000000 0000000 00000000000 12670664436 0025107 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/elphel/Kconfig 0000664 0000000 0000000 00000001722 12670664436 0026414 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 Elpel camera code on Microzed board.
endmenu
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/elphel/Makefile 0000664 0000000 0000000 00000001302 12670664436 0026543 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
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/elphel/elphel393-mem.c 0000664 0000000 0000000 00000041123 12670664436 0027540 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_pwr_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-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/elphel/elphel393-pwr.c 0000664 0000000 0000000 00000130717 12670664436 0027602 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-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/misc/ 0000775 0000000 0000000 00000000000 12670664436 0024571 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/misc/ltc3589.c 0000664 0000000 0000000 00000131465 12670664436 0026062 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : ltc3589.c
*! DESCRIPTION: control of the Linear Technology LTC3589 8-channel voltage regulator
*! Copyright (C) 2013 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*/
#undef DEBUG /* should be before linux/module.h - enables dev_dbg at boot in this file */
#include
#include
#include
#include
#include
#include
#include
#include
#define DRV_VERSION "1.0"
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
#define CACHE_INIT 1
#define CACHE_VOLAT 2
#define LAST_REG 0x33
struct ltc3589_cache_t {
u8 flags;
u8 data;
};
struct ltc3589_data_t {
int reg_addr; /* used for raw register r/w */
int simulate; /* do not perform actual i2c writes */
struct mutex lock;
struct ltc3589_cache_t cache[LAST_REG+1];
};
static struct i2c_device_id ltc3589_id[] = {
{ "ltc3589", 0 },
{ }
};
struct named_fields_t {
char *name;
u32 awe;
};
static const struct named_fields_t status_fields[]={
{"power_good", LTC3589_AWE_PGSTAT},
{"pgood_ldo1", LTC3589_AWE_PGSTAT_LDO1},
{"pgood_sd1", LTC3589_AWE_PGSTAT_SD1},
{"pgood_sd2", LTC3589_AWE_PGSTAT_SD2},
{"pgood_sd3", LTC3589_AWE_PGSTAT_SD3},
{"pgood_bb", LTC3589_AWE_PGSTAT_BB},
{"pgood_ldo2", LTC3589_AWE_PGSTAT_LDO2},
{"pgood_ldo3", LTC3589_AWE_PGSTAT_LDO3},
{"pgood_ldo4", LTC3589_AWE_PGSTAT_LDO4},
{"irqstat", LTC3589_AWE_IRQSTAT},
{"irqstat_pgoot_timeout",LTC3589_AWE_IRQSTAT_PGOOD_TIMOUT},
{"irqstat_near_uv", LTC3589_AWE_IRQSTAT_NEAR_UV},
{"irqstat_hard_uv", LTC3589_AWE_IRQSTAT_HARD_UV},
{"irqstat_near_therm", LTC3589_AWE_IRQSTAT_NEAR_THERM},
{"irqstat_hard_therm", LTC3589_AWE_IRQSTAT_HARD_THERM},
};
static const struct named_fields_t named_fields[]={
{"ref1_sd1", LTC3589_AWE_B1DTV1_REF},
{"ref2_sd1", LTC3589_AWE_B1DTV2_REF},
{"ref1_sd2", LTC3589_AWE_B2DTV1_REF},
{"ref2_sd2", LTC3589_AWE_B2DTV2_REF},
{"ref1_sd3", LTC3589_AWE_B3DTV1_REF},
{"ref2_sd3", LTC3589_AWE_B3DTV2_REF},
{"ref1_ldo2", LTC3589_AWE_L2DTV1_REF},
{"ref2_ldo2", LTC3589_AWE_L2DTV2_REF},
{"ref_ldo4", LTC3589_AWE_B1DTV1_REF},
{"dv_dt_sd1", LTC3589_AWE_B1DTV1_DVDT},
{"pgood_mask_sd1", LTC3589_AWE_B1DTV1_PGMASK},
{"pgood_mask_sd2", LTC3589_AWE_B2DTV1_PGMASK},
{"pgood_mask_sd3", LTC3589_AWE_B3DTV1_PGMASK},
{"pgood_mask_ldo21",LTC3589_AWE_L2DTV1_PGMASK},
{"clock_rate_sd1", LTC3589_AWE_B1DTV2_CLKRATE},
{"clock_rate_sd2", LTC3589_AWE_B2DTV2_CLKRATE},
{"clock_rate_sd3", LTC3589_AWE_B3DTV2_CLKRATE},
{"clock_phase_sd1", LTC3589_AWE_B1DTV2_PHASE},
{"clock_phase_sd2", LTC3589_AWE_B2DTV2_PHASE},
{"clock_phase_sd3", LTC3589_AWE_B3DTV2_PHASE},
{"keep_alive_sd1", LTC3589_AWE_B1DTV2_KEEP_ALIVE},
{"keep_alive_sd2", LTC3589_AWE_B2DTV2_KEEP_ALIVE},
{"keep_alive_sd3", LTC3589_AWE_B3DTV2_KEEP_ALIVE},
{"keep_alive_ldo2", LTC3589_AWE_L2DTV1_KEEP_ALIVE},
{"slew_rate_sd1", LTC3589_AWE_VRRCR_SD1},
{"slew_rate_sd2", LTC3589_AWE_VRRCR_SD2},
{"slew_rate_sd3", LTC3589_AWE_VRRCR_SD3},
{"slew_rate_ldo2", LTC3589_AWE_VRRCR_LDO2},
{"oven_ldo4", LTC3589_AWE_L2DTV2_MODE_LDO4},
{"oven_only", LTC3589_AWE_OVEN_ONLY},
};
static const int volatile_registers[]={LTC3589_AWE_IRQSTAT_PGOOD_TIMOUT, LTC3589_AWE_PGSTAT_LDO1, LTC3589_AWE_VCCR,-1};
static const char * chn_names[]={"SD1","SD2","SD3","BB","LDO1","LDO2","LDO3","LDO4"};
static const char * modes[]={"continuous","burst","pulse_skip","invalid"};
static const char * pwr_states[]={"power_off","power_on"};
static const char * wait_states[]={"no_wait", "wait"};
static const char * reference_sel[]={"reference_sel1", "reference_sel2"};
/* (register_address << 8) | mask */
static const u32 register_masks[]= {
0x07ff,0x12ff,0x20ff,0x24ff,0x25ff,0x26ff,0x27ff,
0x29ff,0x2aff,0x32ff,0x33ff,0x10ff};
static int make_status_fields(struct device *dev);
static int make_bit_fields(struct device *dev);
static ssize_t invalidate_cache_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t simulate_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t simulate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_data_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_address_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_data_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_all_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_help_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t power_wait_on_off_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t power_wait_on_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t pgood_timeout_inhibit_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t pgood_timeout_inhibit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t mode_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t reference_select_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t reference_select_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t reference_select_go_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t reference_select_go_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t field_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t get_field_value (struct device *dev, const char* name, char *buf, int newline);
static ssize_t irq_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t irq_show_txt (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t pwr_bad_good_show (struct device *dev, struct device_attribute *attr, char *buf);
static int get_chn_mode(struct device *dev, char *buf, int chn); /* 0..3 */
static int get_chn_pwr(struct device *dev, char *buf, int chn); /* 0..7 */
static int get_chn_wait(struct device *dev, char *buf, int chn); /* 0..7 */
static int get_ref_sel_go(struct device *dev, char *buf, int chn); /* 0..7 */
static int no_off(const char *str);
static int read_channel_mask(const char * str);
static int read_field (struct i2c_client *client, u32 awe);
static int write_field (struct i2c_client *client, u8 data, u32 awe);
static int write_adwe(struct i2c_client *client, u32 adwe);
static int write_reg(struct i2c_client *client, u8 reg, u8 val, u8 mask);
static int read_reg(struct i2c_client *client, u8 reg);
static void invalidate_cache(struct i2c_client *client);
static int ltc3589_sysfs_register(struct device *dev);
static void ltc3589_init_of(struct i2c_client *client);
static int ltc3589_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id);
static int ltc3589_i2c_remove(struct i2c_client *client);
int ltc3589_read_field (struct i2c_client *client, u32 awe)
{
return read_field (client, awe);
}
EXPORT_SYMBOL_GPL(ltc3589_read_field);
int ltc3589_write_field (struct i2c_client *client, u8 data, u32 awe)
{
return write_field (client, data, awe);
}
EXPORT_SYMBOL_GPL(ltc3589_write_field);
int ltc3589_write_adwe(struct i2c_client *client, u32 adwe)
{
return write_adwe(client, adwe);
}
EXPORT_SYMBOL_GPL(ltc3589_write_adwe);
void ltc3589_set_simulate(struct i2c_client *client, int simulate)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(client);
clientdata->simulate=simulate;
}
EXPORT_SYMBOL_GPL(ltc3589_set_simulate);
/* raw access to i2c registers, need to set address (9 bits) first, then r/w data */
static DEVICE_ATTR(invalidate_cache, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, invalidate_cache_store);
static DEVICE_ATTR(simulate, SYSFS_PERMISSIONS, simulate_show, simulate_store);
static DEVICE_ATTR(address, SYSFS_PERMISSIONS, raw_address_show, raw_address_store);
static DEVICE_ATTR(data, SYSFS_PERMISSIONS, raw_data_show, raw_data_store);
static DEVICE_ATTR(hex_address, SYSFS_PERMISSIONS, raw_hex_address_show,raw_hex_address_store);
static DEVICE_ATTR(hex_data, SYSFS_PERMISSIONS, raw_hex_data_show, raw_hex_data_store);
static DEVICE_ATTR(hex_all, SYSFS_PERMISSIONS & SYSFS_READONLY, raw_hex_all_show, NULL);
static DEVICE_ATTR(hex_adwe, SYSFS_PERMISSIONS, raw_hex_adwe_show, raw_hex_adwe_store);
static DEVICE_ATTR(hex_adwe_help, SYSFS_PERMISSIONS & SYSFS_READONLY, raw_hex_adwe_help_show, NULL);
static struct attribute *raw_dev_attrs[] = {
&dev_attr_invalidate_cache.attr,
&dev_attr_simulate.attr,
&dev_attr_address.attr,
&dev_attr_data.attr,
&dev_attr_hex_address.attr,
&dev_attr_hex_data.attr,
&dev_attr_hex_all.attr,
&dev_attr_hex_adwe.attr,
&dev_attr_hex_adwe_help.attr,
NULL
};
static const struct attribute_group dev_attr_raw_group = {
.attrs = raw_dev_attrs,
.name = "raw",
};
//static ssize_t irq_show (struct device *dev, struct device_attribute *attr, char *buf);
//static ssize_t irq_show_txt (struct device *dev, struct device_attribute *attr, char *buf);
//static ssize_t irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
//static ssize_t pwr_bad_good_show (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(power_good, SYSFS_PERMISSIONS & SYSFS_READONLY, pwr_bad_good_show, NULL);
static DEVICE_ATTR(power_bad, SYSFS_PERMISSIONS & SYSFS_READONLY, pwr_bad_good_show, NULL);
static DEVICE_ATTR(irq, SYSFS_PERMISSIONS, irq_show, irq_store);
static DEVICE_ATTR(irq_txt, SYSFS_PERMISSIONS, irq_show_txt, irq_store);
static DEVICE_ATTR(power_off, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(power_on, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(wait, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(no_wait, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(reference_sel1, SYSFS_PERMISSIONS, reference_select_show, reference_select_store);
static DEVICE_ATTR(reference_sel2, SYSFS_PERMISSIONS, reference_select_show, reference_select_store);
static DEVICE_ATTR(reference_sel_go, SYSFS_PERMISSIONS, reference_select_go_show, reference_select_go_store);
static DEVICE_ATTR(continuous, SYSFS_PERMISSIONS, mode_show, mode_store);
static DEVICE_ATTR(burst, SYSFS_PERMISSIONS, mode_show, mode_store);
static DEVICE_ATTR(pulse_skip, SYSFS_PERMISSIONS, mode_show, mode_store);
static DEVICE_ATTR(pgood_timeout_inhibit, SYSFS_PERMISSIONS, pgood_timeout_inhibit_show, pgood_timeout_inhibit_store);
static struct attribute *control_dev_attrs[] = {
&dev_attr_power_good.attr,
&dev_attr_power_bad.attr,
&dev_attr_irq.attr,
&dev_attr_irq_txt.attr,
&dev_attr_power_off.attr,
&dev_attr_power_on.attr,
&dev_attr_wait.attr,
&dev_attr_no_wait.attr,
&dev_attr_reference_sel1.attr,
&dev_attr_reference_sel2.attr,
&dev_attr_reference_sel_go.attr,
&dev_attr_continuous.attr,
&dev_attr_burst.attr,
&dev_attr_pulse_skip.attr,
&dev_attr_pgood_timeout_inhibit.attr,
NULL
};
static const struct attribute_group dev_attr_control_group = {
.attrs = control_dev_attrs,
.name = "control",
};
//status_fields[]
static int make_status_fields(struct device *dev)
{
int retval=-1;
int index;
struct attribute **pattrs; /* array of pointers to attibutes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
pattrs = devm_kzalloc(dev,(ARRAY_SIZE(status_fields)+1)*sizeof(pattrs[0]), GFP_KERNEL);
if (!pattrs) return -ENOMEM;
dev_attrs = devm_kzalloc(dev, ARRAY_SIZE(status_fields)*sizeof(dev_attrs[0]), GFP_KERNEL);
if (!dev_attrs) return -ENOMEM;
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
if (!attr_group) return -ENOMEM;
memset(dev_attrs, 0, ARRAY_SIZE(status_fields)*sizeof(dev_attrs[0]));
memset(attr_group, 0, sizeof(*attr_group));
for (index=0;indexname = "status";
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static int make_bit_fields(struct device *dev)
{
int retval=-1;
int index;
struct attribute **pattrs; /* array of pointers to attibutes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
pattrs = devm_kzalloc(dev,(ARRAY_SIZE(named_fields)+1)*sizeof(pattrs[0]), GFP_KERNEL);
if (!pattrs) return -ENOMEM;
dev_attrs = devm_kzalloc(dev, ARRAY_SIZE(named_fields)*sizeof(dev_attrs[0]), GFP_KERNEL);
if (!dev_attrs) return -ENOMEM;
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
if (!attr_group) return -ENOMEM;
memset(dev_attrs, 0, ARRAY_SIZE(named_fields)*sizeof(dev_attrs[0]));
memset(attr_group, 0, sizeof(*attr_group));
for (index=0;indexname = "bit_fields";
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static ssize_t invalidate_cache_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
invalidate_cache(client);
return count;
}
static ssize_t simulate_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%d\n",clientdata->simulate);
}
static ssize_t simulate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%du", &clientdata->simulate);
return count;
}
//clientdata->simulate
static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%d\n",clientdata->reg_addr);
}
static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%du", &clientdata->reg_addr);
return count;
}
static ssize_t raw_data_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data= read_reg(client, clientdata->reg_addr);
return sprintf(buf, "%d\n",data);
}
static ssize_t raw_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data;
sscanf(buf, "%du", &data);
write_reg(client, clientdata->reg_addr, data, 0xff); /* write all register, it is up to user to do R-mod-W */
return count;
}
static ssize_t raw_hex_address_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "0x%02x\n",clientdata->reg_addr);
}
static ssize_t raw_hex_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%x", &clientdata->reg_addr);
return count;
}
static ssize_t raw_hex_data_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data= read_reg(client, clientdata->reg_addr);
return sprintf(buf, "0x%02x\n",data);
}
static ssize_t raw_hex_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data;
sscanf(buf, "%x", &data);
write_reg(client, clientdata->reg_addr, data, 0xff); /* write all register, it is up to user to do R-mod-W */
return count;
}
static ssize_t raw_hex_all_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int low_addr=0,reg,data,rc,len=0, count=PAGE_SIZE;
struct i2c_client *client = to_i2c_client(dev);
// struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
for (reg=low_addr;reg<=LAST_REG;reg++) if (count>10){
if ((reg & 0xf) ==0){
rc=sprintf(buf, "%02x: ",reg);
buf+=rc;
len+=rc;
count-=rc;
}
data= read_reg(client, reg); //ignore errors
if (data<0) rc=sprintf(buf, "??");
else rc=sprintf(buf, "%02x",data);
buf+=rc;
len+=rc;
count-=rc;
if (((reg & 0xf) == 0xf) || (reg==LAST_REG)){
rc=sprintf(buf, "\n");
} else {
rc=sprintf(buf, " ");
}
buf+=rc;
len+=rc;
count-=rc;
}
return len;
}
static ssize_t raw_hex_adwe_help_show (struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Setting one/multiple registers with masks in the form [0x]AADDWW, where AA is register address\n" \
"DD - data byte and WW - write enable bits ( 1 - write, 0 - keep old)\n" \
"When read, provides current register data that can be used in device tree.\n");
}
//static const u32 register_masks[]= {
static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int i,data;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
for (i=0;i>8)))<0) return data;
buf+=sprintf(buf," 0x%x",((register_masks[i] & 0x1ff00)<<8) | (register_masks[i] & 0xff) | ((data & 0xff)<<8));
if (((i+1) & 0x7)==0) buf+=sprintf(buf,"\n");
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
/*
* accepts single or multiple data, each [0x]AAADDWW - AAA - register address, DD - data byte, WW - write enable mask (1 - write, 0 - keep).
* Ignores any other characters, so same format as in dts with hex data is OK
*/
static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
const char hex_digits[]="0123456789abcdefABCDEF";
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int adwe,rc=0;
int left=count,num_bytes;
char * cp;
mutex_lock(&clientdata->lock);
while ((left>0) && ((cp=strpbrk(buf,hex_digits))) && cp[0]){
left -= (cp-buf);
buf = cp;
dev_dbg(dev,"left=%d", left);
sscanf(buf, "%x%n", &adwe,&num_bytes);
left-=num_bytes;
buf+=num_bytes;
dev_dbg(dev,"left=%d num_bytes=%d, adwe=0x%08x", left,num_bytes,adwe);
if (((rc=write_adwe(client, adwe)))<0) {
mutex_unlock(&clientdata->lock);
return rc;
}
}
mutex_unlock(&clientdata->lock);
return count;
}
//static const char * chn_names[]={"SD1","SD2","SD3","BB","LDO1","LDO2","LDO3","LDO4"};
//static const char * pwr_states[]={"power_off","power_on"};
//static const char * wait_states[]={"no_wait", "wait"};
static ssize_t power_wait_on_off_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,i,invert;
char * cp=buf;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
awe= ((strcmp(attr->attr.name,wait_states[0])==0) || (strcmp(attr->attr.name,wait_states[1])==0))?LTC3589_AWE_SCR2:LTC3589_AWE_OVEN;
invert=((strcmp(attr->attr.name,pwr_states[0])==0) || (strcmp(attr->attr.name,wait_states[0])==0))?0xff:0;
if (((rc=read_field(client,awe)))<0) return rc;
rc=((rc & 0xf) | 0x10 | ((rc & 0x70)<<1)) ^ invert;
for (i=0;i<8;i++) if (rc & (1<attr.name,wait_states[0])==0) || (strcmp(attr->attr.name,wait_states[1])==0))?LTC3589_AWE_SCR2:LTC3589_AWE_OVEN;
data=((strcmp(attr->attr.name,pwr_states[0])==0) || (strcmp(attr->attr.name,wait_states[0])==0))?0:0xff;
mask=read_channel_mask(buf);
mask=(mask & 0xf) | ((mask >> 1) & 0x70);
awe = (awe & 0xff00) | mask;
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t pgood_timeout_inhibit_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_SCR2_PGOOD_SHTDN_INH)))<0) return rc;
return sprintf(buf, "%d\n",rc);
}
static ssize_t pgood_timeout_inhibit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,data;
struct i2c_client *client = to_i2c_client(dev);
sscanf(buf, "%d", &data);
if (((rc=write_field(client,data?1:0,LTC3589_AWE_SCR2_PGOOD_SHTDN_INH)))<0) return rc;
return count;
}
static ssize_t mode_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,m,i;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_SCR1)))<0) return rc;
for (m=0;mattr.name,modes[m])==0) break;
if (m>=ARRAY_SIZE(modes)) return -EINVAL;
for (i=0;i<4;i++) if (((rc>>(2*i)) & 3) == m) {
if (buf!=cp) buf+=sprintf(buf," ");
buf+=sprintf(buf,"%s",chn_names[i]);
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,mask,m,data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (m=0;mattr.name,modes[m])==0) break;
if (m>=ARRAY_SIZE(modes)) return -EINVAL;
mask=read_channel_mask(buf);
mask=((mask & 1)? 3:0) | ((mask & 2)? 0xc:0) | ((mask & 4)? 0x30:0) | ((mask & 8)? 0x40:0);
awe = (LTC3589_AWE_SCR1 & 0xff00) | mask;
data= m | (m<<2) | (m<<4) | (m<<6);
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t reference_select_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,m,i,chn;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_VCCR)))<0) return rc;
for (m=0;mattr.name,reference_sel[m])==0) break;
if (m>=ARRAY_SIZE(reference_sel)) return -EINVAL;
for (i=0;i<4;i++) if (((rc>>(2*i+1)) & 1)==m){
chn=i;
if (i==3) chn=5 ; /* LDO2 */
if (buf!=cp) buf+=sprintf(buf," ");
buf+=sprintf(buf,"%s",chn_names[chn]);
/* if ((rc>>(2*i)) & 1){
buf+=sprintf(buf,"(slewing)");
}
*/
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
/* not raising go */
static ssize_t reference_select_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,mask,m,data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (m=0;mattr.name,reference_sel[m])==0) break;
if (m>=ARRAY_SIZE(reference_sel)) return -EINVAL;
mask=read_channel_mask(buf);
mask=((mask & 1)? 2:0) | ((mask & 2)? 0x8:0) | ((mask & 4)? 0x20:0) | ((mask & 0x20)? 0x80:0);
awe = (LTC3589_AWE_VCCR & 0xff00) | mask;
data= m?0xff:0;
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t reference_select_go_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,i,chn;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_VCCR)))<0) return rc;
for (i=0;i<4;i++) if ((rc>>(2*i)) & 1){
chn=i;
if (i==3) chn=5 ; /* LDO2 */
if (buf!=cp) buf+=sprintf(buf," ");
buf+=sprintf(buf,"%s",chn_names[chn]);
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t reference_select_go_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,mask,data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
mask=read_channel_mask(buf);
mask=((mask & 1)? 1:0) | ((mask & 2)? 0x4:0) | ((mask & 4)? 0x10:0) | ((mask & 0x20)? 0x40:0);
awe = (LTC3589_AWE_VCCR & 0xff00) | mask;
data= 0xff;
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
//--------------------
static ssize_t field_show (struct device *dev, struct device_attribute *attr, char *buf)
{
return get_field_value (dev, attr->attr.name, buf, 1); /* with newline */
}
static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,i;
int data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (i=0;iattr.name,named_fields[i].name)==0) {
awe=named_fields[i].awe;
dev_dbg(dev,"i=%d, field name=%s awe=0x%04x\n", i, named_fields[i].name, (int) awe);
break;
}
if (i>=ARRAY_SIZE(named_fields)) {
for (i=0;iattr.name,status_fields[i].name)==0) {
awe=status_fields[i].awe;
dev_dbg(dev,"i=%d, status field name=%s awe=0x%04x\n", i, status_fields[i].name, (int) awe);
break;
}
if (i>=ARRAY_SIZE(status_fields)) return -EINVAL;
}
sscanf(buf, "%du", &data);
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t get_field_value (struct device *dev, const char* name, char *buf, int newline)
{
int rc,i;
char * cp=buf;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (i=0;i=ARRAY_SIZE(named_fields)) {
for (i=0;i=ARRAY_SIZE(status_fields)) return -EINVAL;
}
if (((rc=read_field(client,awe)))<0) return rc;
buf+=sprintf(buf,"%d",rc);
if (newline) buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t irq_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_IRQSTAT)))<0) return rc;
return sprintf(buf,"%d\n",rc);
}
static ssize_t irq_show_txt (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_IRQSTAT)))<0) return rc;
buf += sprintf(buf,"0x%02x",rc);
if (rc & LTC3589_AWE_IRQSTAT_PGOOD_TIMOUT) buf += sprintf(buf,"PGOOD timeout");
if (rc & LTC3589_AWE_IRQSTAT_NEAR_UV) buf += sprintf(buf,", Near undervoltage");
if (rc & LTC3589_AWE_IRQSTAT_HARD_UV) buf += sprintf(buf,", Hard undervoltage");
if (rc & LTC3589_AWE_IRQSTAT_NEAR_THERM) buf += sprintf(buf,", Near undervoltage");
if (rc & LTC3589_AWE_IRQSTAT_HARD_THERM) buf += sprintf(buf,", Hard undervoltage");
buf += sprintf(buf,"\n");
return buf-cp;
}
static ssize_t irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=write_field (client, 0, LTC3589_AWE_CLIRQ)))<0) return rc;
return count;
}
static ssize_t pwr_bad_good_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,i,pg;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,LTC3589_AWE_PGSTAT)))<0) return rc;
pg=(rc & 0xe0) | ((rc>>1) & 0xff) | ((rc << 4) & 0x10);
if (strstr(attr->attr.name,"bad")){
pg^=0xff;
}
for (i=0;i<8;i++) if (pg & (1<3)) return 0;
if (((rc=read_field(client,LTC3589_AWE_SCR1)))<0) return rc;
return sprintf (buf,"%s",modes[(rc >> (chn<<1)) &3]);
}
static int get_chn_pwr(struct device *dev, char *buf, int chn) /* 0..7 */
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if ((chn<0) || (chn>7)) return 0;
if (((rc=read_field(client,LTC3589_AWE_OVEN)))<0) return rc;
rc=(rc & 0xf) | 0x10 | ((rc & 0x70)<<1);
return sprintf (buf,"%s",pwr_states[(rc >> chn) & 1]);
}
static int get_chn_wait(struct device *dev, char *buf, int chn) /* 0..7 */
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if ((chn<0) || (chn>7)) return 0;
if (((rc=read_field(client,LTC3589_AWE_SCR2)))<0) return rc;
rc=(rc & 0xf) | 0x10 | ((rc & 0x70)<<1);
return sprintf (buf,"%s",wait_states[(rc >> chn) & 1]);
}
static int get_ref_sel_go(struct device *dev, char *buf, int chn) /* 0..7 */
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if ((chn<0) || ((chn>2) && (chn!=5))) return 0;
if (chn==5) chn=3;
if (((rc=read_field(client,LTC3589_AWE_VCCR)))<0) return rc;
rc =(rc >> (2*chn)) & 3;
return sprintf (buf,"%s%s",reference_sel[(rc>>1)&1],(rc&1)?" (slewing)":"");
}
static int no_off(const char *str)
{
return strstr(str,"_off")?0:1;
}
static int read_channel_mask(const char * str)
{
int mask =0, i;
for (i=0;i>8;
mask=awe&0xff;
if (mask!=0){
nshift=0;
while (((1<> nshift;
}
return 0;
}
static int write_field (struct i2c_client *client, u8 data, u32 awe)
{
int rc,nshift;
u8 mask,reg_data;
u8 reg;
reg=awe>>8;
mask=awe&0xff;
if (mask!=0){
nshift=0;
while (((1<>8) & 0xff;
u16 reg= (adwe>>16) & 0xff;
return write_reg(client, reg, data, we);
}
static int write_reg(struct i2c_client *client, u8 reg, u8 val, u8 mask)
{
int rc;
struct ltc3589_data_t *clientdata = i2c_get_clientdata(client);
if (reg>LAST_REG) return -EINVAL;
if (mask==0) return 0;
dev_dbg(&client->dev,"reg=0x%x, val=0x%x, mask=0x%x\n", (int) reg, (int) val, (int) mask);
if (mask !=0xff){
if (((rc=read_reg(client, reg)))<0) return rc;
val=((val ^ rc) & mask)^ rc;
if ((val==rc) && !(clientdata->cache[reg].flags & CACHE_VOLAT)) {
dev_dbg(&client->dev,"No change and not volatile -> no write\n");
return 0;
}
}
clientdata->cache[reg].data= val;
clientdata->cache[reg].flags |= CACHE_INIT;
if (clientdata->simulate){
dev_info(&client->dev,">>> Simulating LTC3589 register write: 0x%02x->[0x%02x]\n",(int) reg, (int) val);
return 0;
}
return i2c_smbus_write_byte_data(client, reg, val);
}
static int read_reg(struct i2c_client *client, u8 reg)
{
int rc;
struct ltc3589_data_t *clientdata = i2c_get_clientdata(client);
if (reg>LAST_REG) return -EINVAL;
if (clientdata && (clientdata->cache[reg].flags & CACHE_INIT) && !(clientdata->cache[reg].flags & CACHE_VOLAT)){
dev_dbg(&client->dev,"Using cached register: reg=0x%x -> 0x%x\n",reg,(int) clientdata->cache[reg].data);
return clientdata->cache[reg].data;
}
rc= i2c_smbus_read_byte_data(client, reg & 0xff);
dev_dbg(&client->dev,"reading i2c device : slave=0x%x, reg=0x%x -> 0x%x\n",(int) (client->addr),reg,rc);
if (rc<0) return rc;
if (clientdata){
clientdata->cache[reg].data= (u8) rc;
clientdata->cache[reg].flags |= CACHE_INIT;
}
return rc;
}
static void invalidate_cache(struct i2c_client *client)
{
int i;
struct ltc3589_data_t *clientdata = i2c_get_clientdata(client);
for (i=0;i<=LAST_REG;i++){
clientdata->cache[i].flags&= ~CACHE_INIT;
}
}
static int ltc3589_sysfs_register(struct device *dev)
{
int retval=0;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_raw_group)))<0) return retval;
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_control_group)))<0) return retval;
if (((retval = make_status_fields (dev)))<0) return retval;
if (((retval = make_bit_fields (dev)))<0) return retval;
}
return retval;
}
static void ltc3589_init_of(struct i2c_client *client)
{
// struct device *dev=&client->dev;
const __be32 * config_data;
const char * init_type_string;
int init_type=0; /* 0 - none, 1 - always, 2 - if not running (TODO) */
struct device_node *node = client->dev.of_node;
int len,i,n;
char buf[40];
struct ltc3589_setup_data {
u8 page;
u8 reg;
u8 data;
u8 mask;
};
struct ltc3589_setup_data setup_data;
__be32 * setup_data_be32= (__be32 *) &setup_data;
/* add stuff */
#if 0
if (node) {
init_type_string = of_get_property(client->dev.of_node, "ltc3589,init", &len);
if (init_type_string){
if (strcmp(init_type_string,"always")==0) init_type=1;
else if (strcmp(init_type_string,"if off")==0) init_type=2;
else {
dev_err(&client->dev,"Unrecognized ltc3589 initialization type '%s'. Only 'always' and 'if off' are permitted\n",init_type_string);
}
}
switch (init_type){
case 2:
// static int is_set_up(struct i2c_client *client);
i=is_set_up(client);
if (i<0){
dev_err(&client->dev,"Error reading i2c register, aborting initialization\n");
return;
} else if (i>0){
init_type=0;
dev_dbg(&client->dev,"Skipping conditional initialization (some driver variables will not be initialized)\n");
return;
}
init_type=1;
/* falling to initialization */
case 1:
pre_init(client,1); // clear outputs and muxes - they will be programmed later
break;
}
config_data = of_get_property(client->dev.of_node, "ltc3589,configuration_data", &len);
if (config_data){
len /= sizeof(*config_data);
dev_dbg(&client->dev,"Read %d values\n",len);
dev_dbg(&client->dev,"Found %d items in 'ltc3589,configuration_data' in the Device Tree\n",len);
for (i=0;idev,"page_reg=0x%03x, data=0x%02x, mask=0x%02x \n",
(int) page_reg,(int)setup_data.data,(int)setup_data.mask);
if (write_reg(client, page_reg, setup_data.data, setup_data.mask)<0) return;
}
}
/* input section */
/* setting input frequency here divides (if needed) and feeds it to the PLL reference. Other variants can use raw register writes */
for (n=0;in_freq_names[n];n++){
sprintf(buf,"ltc3589,%s",in_freq_names[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
dev_dbg(&client->dev,"Found '%s', value = %d (0x%x)\n",buf,(int)(be32_to_cpup(config_data)),(int)(be32_to_cpup(config_data)));
if (set_in_frequency(client, be32_to_cpup(config_data),n)<0) return; /* 32 bits are sufficient here */
}
}
/* setting PLL for the most important output frequency, sets analog parameters accordingly. Assumes input frequency set above */
for (n=0;pll_setup_names[n];n++){
sprintf(buf,"ltc3589,%s",pll_setup_names[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
len /= sizeof(*config_data);
freq[0]=be32_to_cpup(config_data);
if (len<3){
freq[1]=0;
freq[2]=1;
} else {
freq[1]=be32_to_cpup(&config_data[1]);
freq[2]=be32_to_cpup(&config_data[2]);
}
dev_dbg(&client->dev,"Found '%s', value = %lld+(%lld/%lld)\n",buf,freq[0],freq[1],freq[2]);
if (n & 2){ /* by output */
if (set_pll_freq_by_out(client, freq, n & 1)<0) return;
} else { /* directly set PLL frequency */
if (set_pll_freq (client, freq, n & 1)<0) return;
}
if (set_pll_paremeters(client)<0) return;
/* if (set_misc_registers(client)<0) return; */ /* moved to pre_init() */
}
}
/* setting MSn dividers (same channel as output), powering them up, setting output dividers and routing outputs */
for (n=0;out_freq_setup_names[n];n++){
sprintf(buf,"ltc3589,%s",out_freq_setup_names[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
len /= sizeof(*config_data);
freq[0]=be32_to_cpup(config_data);
if (len<3){
freq[1]=0;
freq[2]=1;
} else {
freq[1]=be32_to_cpup(&config_data[1]);
freq[2]=be32_to_cpup(&config_data[2]);
}
dev_dbg(&client->dev,"Found '%s', value = %lld+(%lld/%lld)\n",buf,freq[0],freq[1],freq[2]);
if (set_out_frequency_and_route(client, freq, n&3, n>>2)<0) return;
}
}
/* configure output driver standard */
for (n=0;drv_configs[n].description;n++){
sprintf(buf,"ltc3589,%s",drv_configs[n].description);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (configure_output_driver(&client->dev, drv_configs[n].description, setup_data.mask)<0) return;
}
}
}
/* configure disabled state of the output(s) */
for (n=0;out_dis_states[n];n++){
sprintf(buf,"ltc3589,%s",out_dis_states[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (set_drv_disable(client, n, setup_data.mask)<0) return;
}
}
}
/* configure powerdown state of the output(s) */
for (n=0;out_pwr_states[n];n++){
sprintf(buf,"ltc3589,%s",out_pwr_states[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (set_drv_powerdown(client, n, setup_data.mask)<0) return;
}
}
}
/* configure output enable state of the output(s) */
for (n=0;out_en_states[n];n++){
sprintf(buf,"ltc3589,%s",out_en_states[n]);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data){
len /= sizeof(*config_data);
for (i=0;idev,"Setting '%s', channel %d",buf,setup_data.mask);
if (set_drv_disable(client, n, setup_data.mask)<0) return;
}
}
}
/* setting spread spectrum parameters */
for (n=0;n<4;n++){
sprintf(buf,"ltc3589,spread_spectrum_%d",n);
config_data = of_get_property(client->dev.of_node, buf, &len);
if (config_data && (len>0)){
len /= sizeof(*config_data);
rate=get_ss_down_rate(client, n);
amp= get_ss_down_amplitude(client, n);
if (len>1) amp = be32_to_cpup(&config_data[1]);
if (len>2) rate = be32_to_cpup(&config_data[2]);
if (store_ss_down_parameters(client, rate, amp, n)==0){
dev_dbg(&client->dev,"Set spread spectrum parameters for MS%d, amplitude=%d (*0.01%%), rate=%d Hz, %s\n",
n,amp,rate,config_data[0]?"ON":"OFF");
} else {
dev_err(&client->dev,"Failed to set spread spectrum parameters for MS%d, amplitude=%d (*0.01%%), rate=%d Hz, %s\n",
n,amp,rate,config_data[0]?"ON":"OFF");
continue;
}
if (config_data[0]){ /* enable SS */
if ((set_ss_down(client, n)==0) && /* calculate and set SS registers */
(set_ss_state(client, 1, n)==0)){ // enable SS. Not using enable_spread_spectrum() as we'll reset MS later anyway
dev_dbg(&client->dev,"Spread spectrum enabled for MS%d\n",n);
} else {
dev_dbg(&client->dev,"Fail to enable spread spectrum for MS%d\n",n);
}
}
}
}
} else {
dev_info(&client->dev,"Device tree data not found for %s\n",client->name);
}
if (init_type){
if (post_init(client,INIT_TIMEOUT)<0) dev_err(&client->dev,"ltc3589 initialization failed\n");
else dev_info(&client->dev,"ltc3589 initialized\n");
}
#endif
}
static int ltc3589_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int i,rc=0;
struct ltc3589_data_t *clientdata = NULL;
/* initialize i2c ... */
if (read_field (client, LTC3589_AWE_IRQSTAT_PGOOD_TIMOUT)<0) {
dev_err(&client->dev, "%s: chip not detected\n",id->name);
return -EIO;
}
dev_info(&client->dev,
"Chip %s is found, driver version %s\n", id->name, DRV_VERSION);
clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata), GFP_KERNEL);
for (i=0;i<=LAST_REG;i++){
clientdata->cache[i].flags=0;
clientdata->cache[i].data=0;
}
for (i=0;volatile_registers[i]>=0;i++){
clientdata->cache[volatile_registers[i]>>8].flags |= CACHE_VOLAT;
}
clientdata->simulate=0;
clientdata->reg_addr=0;
//volatile_registers[]
i2c_set_clientdata(client, clientdata);
ltc3589_sysfs_register(&client->dev);
mutex_init(&clientdata->lock);
ltc3589_init_of(client);
return 0;
}
static int ltc3589_i2c_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_driver ltc3589_i2c_driver = {
.driver = {
.name = "ltc3589",
.owner = THIS_MODULE,
},
.probe = ltc3589_i2c_probe,
.remove = ltc3589_i2c_remove,
.id_table = ltc3589_id,
};
module_i2c_driver(ltc3589_i2c_driver);
MODULE_DEVICE_TABLE(i2c, ltc3589_id);
MODULE_AUTHOR("Andrey Filippov ");
MODULE_DESCRIPTION("LTC3589 I2C bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:ltc3589");
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/misc/vsc330x.c 0000664 0000000 0000000 00000145023 12670664436 0026153 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : vsc330x.c
*! DESCRIPTION: control of the VSC3304 4x4 crosspoint switch
*! Copyright (C) 2013 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#define DRV_VERSION "1.0"
/* TODO: Descriptions from vsc3312 - check differences */
#define I2C_PAGE_CONNECTION 0x00 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf) source
(input number) bit 4 (+0x10) - turn output off, bits 3:0 - source */
#define I2C_PAGE_INPUT_ISE 0x10 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf)
ISE (equalization): Bits 5:4 ISE short: 0 - off, 1 - minimal, 2 - moderate, 3 - maximal;
bits 3:2 ISE medium, bits 1:0 ISE Long time constant */
#define I2C_PAGE_INPUT_STATE 0x11 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf) enable,
polarity and termination (default 6)
Bit 2 (+4) Terminate to VDD ( 0 - connect, 1 - do not connect) - dedicated (0..7) inputs only
Bit 1 (+2) Input power (0 - on, 1 - off)
Bit 0 (+1) Invert signal at input */
#define I2C_INPUT_STATE_DATA 0x04 /* terminated,enabled, not inverted */
#define I2C_PAGE_INPUT_LOS 0x12 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf)
LOS (loss of signal) threshold
Bits 2:0 - level in mV for dedicated(bidirectional) inputs: 0,1,6,7 - unused, 2 - 150(170),
3 - 200(230), 4 - 250(280), 5 - 300(330) */
#define I2C_PAGE_OUTPUT_PRE_LONG 0x20 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
long time constant pre-emphasis
Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB), bits 2:0 - Pre-emphasis
decay (0x0 - fastest, 0x7 - slowest) in 500..1500 ps range */
#define I2C_PAGE_OUTPUT_PRE_SHORT 0x21 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
short time constant pre-emphasis
Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 30..500 ps range */
#define I2C_PAGE_OUTPUT_LEVEL 0x22 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
short time constant pre-emphasis
Bits 3:0 - peak-to-peak 0,1,0xe,0xf - unused, 0x2-405mV,0x3-425V,0x4-455mV,0x5-485mV,0x6-520mV,
0x7-555mV,0x8-605mV,0x9-655mV,0xa-720mV,0xb-790mV,0xc-890mV,0xd-990mV (+3.3VDC required)
bit 4 (+0x10) - for 8-15 used as inputs only: terminate inputs 8..15 to VDDIO-0.7V */
#define I2C_PAGE_OUTPUT_STATE 0x23 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
OOB signaling and output polarity
bits 4:1 - operation mode: 0xa - inverted, 0x5 - normal, 0x0 - suppressed
bit 0 - OOB control: 1 - enable LOS forwarding, 0 - ignore LOS */
#define I2C_PAGE_CHANNEL_STATUS 0xf0 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf monitor corresponding input (0..0xf) LOS status
bit 0 - LOS status: 1 - LOS detected (loss of signal), 0 - signal present (input has to be enabled,
otherwise 0 is read)when reading from address 0x10 of this page:
bit 0 - value of STAT0
bit 1 - value of STAT1 */
#define I2C_PAGE_STATUS0_CONFIGURE 0x80 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control selected input LOS to be OR-ed
to STAT0 output pin (and bit)
bit 0 : 1 - OR this input channel LOS status to STAT0 */
#define I2C_PAGE_STATUS1_CONFIGURE 0x81 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control selected input LOS to be OR-ed
to STAT1 output pin (and bit)
bit 0 : 1 - OR this input channel LOS status to STAT1 */
#define I2C_PAGE_STATUS_READ 0xf0 /* Read only from reg=0x10: bit 0 - status0, bit 1 - status 1 */
#define I2C_GLOBAL_CONNECTION 0x50 /* Bit 4 (+0x10) - disable all outputs, bits 3:0 - input number to connect to all outputs */
#define I2C_GLOBAL_INPUT_ISE 0x51 /* Bits 5:4 ISE short: 0 - off, 1 - minimal, 2 - moderate, 3 - maximal; bits 3:2 ISE medium,
bits 1:0 ISE Long time constant */
#define I2C_GLOBAL_INPUT_STATE 0x52 /* Bit 2 (+4) - terminate input to VDD (0..7 only) 0-connect, 1 Normal;
Bit 1 (+2) Input power off (0 - On, 1 - Off) bit0 (+1): Input polarity: 1 - inverted, 0 - normal */
#define I2C_GLOBAL_INPUT_LOS 0x53 /* Bits 2:0 - level in mV for dedicated(bidirectional) inputs: 0,1,6,7 - unused, 2 - 150(170),
3 - 200(230), 4 - 250(280), 5 - 300(330) */
#define I2C_GLOBAL_OUTPUT_PRE_LONG 0x54 /* Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 500..1500 ps range */
#define I2C_GLOBAL_OUTPUT_PRE_SHORT 0x55 /* Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 30..500 ps range */
#define I2C_GLOBAL_OUTPUT_LEVEL 0x56 /* Bits 3:0 - peak-to-peak 0,1,0xe,0xf - unused,0x2-405mV,0x3-425V,0x4-455mV,0x5-485mV,
0x6-520mV,0x7-555mV,0x8-605mV,0x9-655mV,0xa-720mV,0xb-790mV,0xc-890mV,0xd-990mV (+3.3VDC required)
bit 4 (+0x10) terminate inputs 8..15 to VDDIO-0.7V */
#define I2C_GLOBAL_OUTPUT_STATE 0x57 /* +1 (bit 0) - LOS, +0x15 - inverted, 0xa0 - normal, +0 - "Common mode" ? */
#define I2C_GLOBAL_OUTPUT_STATE_DATA 0x0b /* No inversion, enable OOB forwarding on all channels */
#define I2C_GLOBAL_STATUS0 0x58 /* Bit 0 - selected for Status0 chanel LOS on from all channels */
#define I2C_GLOBAL_STATUS1 0x59 /* Bit 0 - selected for Status1 chanel LOS on from all channels */
#define I2C_CORE_CONFIGURATION 0x75
#define I2C_CORE_CONFIGURATION_DATA 0x18 /* default 0x18 - 0x10 - leftEn, 0x8 - rightEn, 0x4 - DNU, 0x2 - BufferForceOn, 0x1 - Config polarity */
#define I2C_CORE_CONFIGURATION_DATAF 0x19 /* default with inverted Config polarity (freeze update) */
#define I2C_SLAVE_ADDRESS 0x78 /* programmed only, not hardwired */
#define I2C_INTERFACE_MODE 0x79
#define I2C_INTERFACE_MODE_DATA 0x02 /* i2c (1 - 4-wire) */
#define I2C_SOFTWARE_RESET 0x7a
//#define I2C_SOFTWARE_RESET_DATA 0x10 /* to reset, 0 - normal */ not used - but number 4 is used instead
#define I2C_CURRENT_PAGE 0x7f
#define PORT_PEFIX "port_"
#define ALL_PORTS "all"
#define MAX_PORTS 16
#define I2C_PAGE_GLOBAL -1 /* does not use paging access */
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
static const char port_names[][8]={
PORT_PEFIX "00",PORT_PEFIX "01",PORT_PEFIX "02",PORT_PEFIX "03",PORT_PEFIX "04",
PORT_PEFIX "05",PORT_PEFIX "06",PORT_PEFIX "07",PORT_PEFIX "08",PORT_PEFIX "09",
PORT_PEFIX "10",PORT_PEFIX "11",PORT_PEFIX "12",PORT_PEFIX "13",PORT_PEFIX "14",
PORT_PEFIX "15",PORT_PEFIX "16",PORT_PEFIX "17",PORT_PEFIX "18",PORT_PEFIX "19",
PORT_PEFIX "20",PORT_PEFIX "21",PORT_PEFIX "22",PORT_PEFIX "23",PORT_PEFIX "24",
PORT_PEFIX "25",PORT_PEFIX "26",PORT_PEFIX "27",PORT_PEFIX "28",PORT_PEFIX "29",
PORT_PEFIX "30",PORT_PEFIX "31"};
static const struct i2c_device_id vsc330x_id[] = {
{ "vsc3304", 0 },
{ "vsc3308", 1 },
{ "vsc3312", 2 },
{ }
};
MODULE_DEVICE_TABLE(i2c, vsc3304_id);
struct vsc330x_data_t {
int address_mode_data; // vsc3304 needs 6 to be written, otherwise weird modification of bit 3
int last_page;
u32 in_ports;
u32 out_ports;
};
static const struct vsc330x_data_t vsc330x_data[] = {
{.address_mode_data=6,
.in_ports=0xff00, .out_ports=0xff00}, /* 3304 - all ports I/O shared*/
{.address_mode_data=-1, // No data, unknown if it is needed for 3308
.in_ports=0x00ff, .out_ports=0x00ff}, /* 3308 - no ports I/O shared */
{.address_mode_data=-1, // No data, unknown if it is needed for 3308
.in_ports=0xffff, .out_ports=0xffff} /* 3312 - some ports I/O shared*/
};
static int init_device(struct i2c_client *client);
static int read_reg(struct i2c_client *client, u8 reg);
static int write_reg(struct i2c_client *client, u8 reg, u8 val);
static int read_field(struct i2c_client *client, u8 reg, int ls_bit_num, int width);
static int read_page_field(struct i2c_client *client, int page, u8 reg, int ls_bit_num, int width);
static int write_field(struct i2c_client *client, u8 reg, u8 val, int ls_bit_num, int width);
static int write_page_field(struct i2c_client *client, int page, u8 reg, u8 val, int ls_bit_num, int width);
static ssize_t field_show(struct device *dev, struct device_attribute *attr, char *buf,
int page, int ls_bit_num, int width);
static ssize_t field_show_reg(struct device *dev, char *buf, int page, int reg, int ls_bit_num, int width);
static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,
int page, int ls_bit_num, int width);
static ssize_t field_store_reg(struct device *dev, const char *buf, size_t count,
int page, int reg, int ls_bit_num, int width);
static ssize_t connection_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_ISE_short_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_ISE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_ISE_medium_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_ISE_medium_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_ISE_long_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_ISE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_state_off_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_state_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_state_invert_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_state_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_LOS_threshold_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_LOS_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_PRE_long_level_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_PRE_long_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_PRE_long_decay_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_PRE_long_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_PRE_short_level_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_PRE_short_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_PRE_short_decay_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_PRE_short_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
/* TODO - fix for vsc3312*/
static ssize_t input_terminate_low_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_terminate_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t input_terminate_high_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t input_terminate_high_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_level_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t output_mode_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t output_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t forward_OOB_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t forward_OOB_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t status_0_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t status_0_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t status_1_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t status_1_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t status_show (struct device *dev, struct device_attribute *attr, char *buf);
/* global */
static ssize_t global_connection_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_ISE_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_ISE_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_input_state_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_input_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_input_LOS_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_input_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_output_PRE_long_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_output_PRE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_output_PRE_short_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_output_PRE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_output_level_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_output_state_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_output_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_status_0_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_status_0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t global_status_1_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t global_status_1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_config_word_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_config_word_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_left_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_left_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_right_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_right_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_buffer_on_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_buffer_on_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t core_config_pin_invert_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t core_config_pin_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t soft_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t address_range_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t address_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t status_combo_show (struct device *dev, struct device_attribute *attr, char *buf);
/* Global registers - writes applied to all port registers. No sense to read (so write only), but functions preserved
* Placed in "globals" directory */
static DEVICE_ATTR(connection, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_connection_show, global_connection_store);
static DEVICE_ATTR(ISE, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_ISE_show, global_ISE_store);
static DEVICE_ATTR(input_state, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_input_state_show, global_input_state_store);
static DEVICE_ATTR(input_LOS, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_input_LOS_show, global_input_LOS_store);
static DEVICE_ATTR(output_PRE_long, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_output_PRE_long_show, global_output_PRE_long_store);
static DEVICE_ATTR(output_PRE_short, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_output_PRE_short_show, global_output_PRE_short_store);
static DEVICE_ATTR(output_level, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_output_level_show, global_output_level_store);
static DEVICE_ATTR(output_state, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_output_state_show, global_output_state_store);
static DEVICE_ATTR(status_0_on_LOS, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_status_0_show, global_status_0_store);
static DEVICE_ATTR(status_1_on_LOS, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, global_status_1_show, global_status_1_store);
/* control/status registers , placed in "control" directory */
static DEVICE_ATTR(core_word, SYSFS_PERMISSIONS, core_config_word_show, core_config_word_store);
static DEVICE_ATTR(core_left_bias_en, SYSFS_PERMISSIONS, core_left_bias_en_show, core_left_bias_en_store);
static DEVICE_ATTR(core_right_bias_en,SYSFS_PERMISSIONS, core_right_bias_en_show, core_right_bias_en_store);
static DEVICE_ATTR(core_buffer_on, SYSFS_PERMISSIONS, core_buffer_on_show, core_buffer_on_store);
static DEVICE_ATTR(core_config_pin_invert,SYSFS_PERMISSIONS, core_config_pin_invert_show, core_config_pin_invert_store);
static DEVICE_ATTR(soft_reset, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, soft_reset_store);
static DEVICE_ATTR(address_range, SYSFS_PERMISSIONS, address_range_show, address_range_store);
static DEVICE_ATTR(status, SYSFS_PERMISSIONS & SYSFS_READONLY, status_combo_show, NULL);
static struct attribute *globals_dev_attrs[] = {
&dev_attr_connection.attr,
&dev_attr_ISE.attr,
&dev_attr_input_state.attr,
&dev_attr_input_LOS.attr,
&dev_attr_output_PRE_long.attr,
&dev_attr_output_PRE_short.attr,
&dev_attr_output_level.attr,
&dev_attr_output_state.attr,
&dev_attr_status_0_on_LOS.attr,
&dev_attr_status_1_on_LOS.attr,
NULL
};
static const struct attribute_group dev_attr_globals_group = {
.attrs = globals_dev_attrs,
.name = "globals",
};
static struct attribute *control_dev_attrs[] = {
&dev_attr_core_word.attr,
&dev_attr_core_left_bias_en.attr,
&dev_attr_core_right_bias_en.attr,
&dev_attr_core_buffer_on.attr,
&dev_attr_core_config_pin_invert.attr,
&dev_attr_soft_reset.attr,
&dev_attr_address_range.attr,
&dev_attr_status.attr,
NULL
};
static const struct attribute_group dev_attr_control_group = {
.attrs = control_dev_attrs,
.name = "control",
};
/* seems we need to INITIALIZE all structures to zero - examples use static */
static int make_group (struct device *dev, const char * name, int port_mask, mode_t mode,
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf),
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count))
{
int retval=-1;
int port,index=0,num_regs;
struct attribute **pattrs; /* array of pointers to attibutes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
for (port=0,num_regs=1;portname = name;
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
index=0;
while ((*attr_group).attrs[index]){
dev_dbg(dev,"attr=%s\n",attr_group->attrs[index]->name);
index++;
}
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static int vsc330x_sysfs_register(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
int ports=clientdata->out_ports;
int retval=0;
if (&dev->kobj) {
if ((retval=make_group (dev, "connections", ports, SYSFS_PERMISSIONS, connection_show, connection_store))) return retval;
if ((retval=make_group (dev, "input_ISE_short", ports, SYSFS_PERMISSIONS, input_ISE_short_show, input_ISE_short_store))) return retval;
if ((retval=make_group (dev, "input_ISE_medium", ports, SYSFS_PERMISSIONS, input_ISE_medium_show, input_ISE_medium_store))) return retval;
if ((retval=make_group (dev, "input_ISE_long", ports, SYSFS_PERMISSIONS, input_ISE_long_show, input_ISE_long_store))) return retval;
if ((retval=make_group (dev, "input_state_off", ports, SYSFS_PERMISSIONS, input_state_off_show, input_state_off_store))) return retval;
if ((retval=make_group (dev, "input_state_invert", ports, SYSFS_PERMISSIONS, input_state_invert_show, input_state_invert_store))) return retval;
if ((retval=make_group (dev, "input_LOS_threshold", ports, SYSFS_PERMISSIONS, input_LOS_threshold_show, input_LOS_threshold_store))) return retval;
if ((retval=make_group (dev, "output_PRE_long_level", ports, SYSFS_PERMISSIONS, output_PRE_long_level_show, output_PRE_long_level_store))) return retval;
if ((retval=make_group (dev, "output_PRE_long_decay", ports, SYSFS_PERMISSIONS, output_PRE_long_decay_show, output_PRE_long_decay_store))) return retval;
if ((retval=make_group (dev, "output_PRE_short_level",ports, SYSFS_PERMISSIONS, output_PRE_short_level_show, output_PRE_short_level_store))) return retval;
if ((retval=make_group (dev, "output_PRE_short_decay",ports, SYSFS_PERMISSIONS, output_PRE_short_decay_show, output_PRE_short_decay_store))) return retval;
if ((retval=make_group (dev, "input_terminate_low", ports, SYSFS_PERMISSIONS, input_terminate_low_show, input_terminate_low_store))) return retval;
if ((retval=make_group (dev, "input_terminate_high", ports, SYSFS_PERMISSIONS, input_terminate_high_show, input_terminate_high_store))) return retval;
if ((retval=make_group (dev, "output_level", ports, SYSFS_PERMISSIONS, output_level_show, output_level_store))) return retval;
if ((retval=make_group (dev, "output_mode", ports, SYSFS_PERMISSIONS, output_mode_show, output_mode_store))) return retval;
if ((retval=make_group (dev, "forward_OOB", ports, SYSFS_PERMISSIONS, forward_OOB_show, forward_OOB_store))) return retval;
if ((retval=make_group (dev, "status_0_on_LOS", ports, SYSFS_PERMISSIONS, status_0_on_LOS_show, status_0_on_LOS_store))) return retval;
if ((retval=make_group (dev, "status_1_on_LOS", ports, SYSFS_PERMISSIONS, status_1_on_LOS_show, status_1_on_LOS_store))) return retval;
if ((retval=make_group (dev, "status", ports, SYSFS_PERMISSIONS & SYSFS_READONLY, status_show, NULL))) return retval;
if ((retval = sysfs_create_group(&dev->kobj, &dev_attr_globals_group))) return retval;
if ((retval = sysfs_create_group(&dev->kobj, &dev_attr_control_group))) return retval;
}
return retval;
}
static ssize_t field_show(struct device *dev, struct device_attribute *attr, char *buf,
int page, int ls_bit_num, int width)
{
int reg, port_mask, rc=0, len=0, count=PAGE_SIZE;
struct i2c_client *client = to_i2c_client(dev);
/* do for all ports - not used. TODO: we can try to output all of them in a row, but not sure if count will permit*/
if (strcmp(attr->attr.name,ALL_PORTS) == 0) {
port_mask=((struct vsc330x_data_t *) i2c_get_clientdata(to_i2c_client(dev)))->out_ports;
for (reg=0;reg5)) {
dev_dbg(dev, "name='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
attr->attr.name, reg, page, ls_bit_num, width);
rc = read_page_field(client, page, reg, ls_bit_num, width);
// rc=field_show_reg(dev, buf, page, reg, ls_bit_num, width);
if (rc<0) return rc;
rc=sprintf(buf, "%d ", rc);
buf+=rc;
len+=rc;
count-=rc;
}
if (len>0) {
len--;
count++;
buf--;
}
rc=sprintf(buf, "\n");
buf+=rc;
len+=rc;
count-=rc;
return len;
}
/* process single port */
sscanf(attr->attr.name+strlen(PORT_PEFIX), "%du", ®);
dev_dbg(dev, "name='%s' name+%d='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
attr->attr.name, strlen(PORT_PEFIX), ( attr->attr.name+strlen(PORT_PEFIX)), reg, page, ls_bit_num, width);
return field_show_reg(dev, buf, page, reg, ls_bit_num, width);
}
static ssize_t field_show_reg(struct device *dev, char *buf, int page, int reg, int ls_bit_num, int width)
{
struct i2c_client *client = to_i2c_client(dev);
int data=read_page_field(client, page, reg, ls_bit_num, width);
return sprintf(buf, "%d\n", data);
}
static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,
int page, int ls_bit_num, int width)
{
int reg, port_mask, rc;
/* do for all ports */
if (strcmp(attr->attr.name,ALL_PORTS) == 0) {
port_mask=((struct vsc330x_data_t *) i2c_get_clientdata(to_i2c_client(dev)))->out_ports;
for (reg=0;regattr.name, reg, page, ls_bit_num, width);
rc= field_store_reg(dev, buf, count, page, reg, ls_bit_num, width);
if (rc<0) return rc;
}
return count;
}
/* process single port */
sscanf(attr->attr.name+strlen(PORT_PEFIX), "%du", ®);
dev_dbg(dev, "name='%s' name+%d='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
attr->attr.name, strlen(PORT_PEFIX), ( attr->attr.name+strlen(PORT_PEFIX)), reg, page, ls_bit_num, width);
return field_store_reg(dev, buf, count, page, reg, ls_bit_num, width);
}
static ssize_t field_store_reg(struct device *dev, const char *buf, size_t count,
int page, int reg, int ls_bit_num, int width)
{
struct i2c_client *client = to_i2c_client(dev);
int val,rc;
sscanf(buf, "%du", &val);
rc=write_page_field(client, page, reg, val, ls_bit_num, width);
return count;
}
static ssize_t connection_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_CONNECTION, 0, 5);}
static ssize_t connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_CONNECTION, 0, 5);}
static ssize_t input_ISE_short_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_ISE, 4, 2);}
static ssize_t input_ISE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_ISE, 4, 2);}
static ssize_t input_ISE_medium_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_ISE, 2, 2);}
static ssize_t input_ISE_medium_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_ISE, 2, 2);}
static ssize_t input_ISE_long_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_ISE, 0, 2);}
static ssize_t input_ISE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_ISE, 0, 2);}
static ssize_t input_state_off_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_STATE, 1, 1);}
static ssize_t input_state_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_STATE, 1, 1);}
static ssize_t input_state_invert_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_STATE, 0, 1);}
static ssize_t input_state_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_STATE, 0, 1);}
static ssize_t input_LOS_threshold_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_LOS, 0, 3);}
static ssize_t input_LOS_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_LOS, 0, 3);}
static ssize_t output_PRE_long_level_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_LONG, 3, 4);}
static ssize_t output_PRE_long_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_LONG, 3, 4);}
static ssize_t output_PRE_long_decay_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_LONG, 0, 3);}
static ssize_t output_PRE_long_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_LONG, 0, 3);}
static ssize_t output_PRE_short_level_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_SHORT, 3, 4);}
static ssize_t output_PRE_short_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_SHORT, 3, 4);}
static ssize_t output_PRE_short_decay_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_SHORT, 0, 3);}
static ssize_t output_PRE_short_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_SHORT, 0, 3);}
/* TODO - fix for vsc3312*/
static ssize_t input_terminate_low_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_INPUT_STATE, 2, 1);}
static ssize_t input_terminate_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_STATE, 2, 1);}
static ssize_t input_terminate_high_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_LEVEL, 4, 1);}
static ssize_t input_terminate_high_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_LEVEL, 4, 1);}
static ssize_t output_level_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_LEVEL, 0, 4);}
static ssize_t output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_LEVEL, 0, 4);}
static ssize_t output_mode_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_STATE, 1, 4);}
static ssize_t output_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_STATE, 1, 4);}
static ssize_t forward_OOB_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_STATE, 0, 1);}
static ssize_t forward_OOB_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_STATE, 0, 1);}
static ssize_t status_0_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_STATUS0_CONFIGURE, 0, 1);}
static ssize_t status_0_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_STATUS0_CONFIGURE, 0, 1);}
static ssize_t status_1_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_STATUS1_CONFIGURE, 0, 1);}
static ssize_t status_1_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store(dev, attr, buf, count, I2C_PAGE_STATUS1_CONFIGURE, 0, 1);}
/* per-port LOS status */
static ssize_t status_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show(dev, attr, buf, I2C_PAGE_STATUS_READ, 0, 1);}
/* combined LOS status */
static ssize_t status_combo_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg(dev, buf, I2C_PAGE_STATUS_READ, 0x10, 0, 2);}
/* Global registers use all 8 bits (and control multiple features at once, because it is not possible to read-modify-write them */
static ssize_t global_connection_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_CONNECTION, 0, 8);}
static ssize_t global_connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_CONNECTION, 0, 8);}
static ssize_t global_ISE_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_ISE, 0, 8);}
static ssize_t global_ISE_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_ISE, 0, 8);}
static ssize_t global_input_state_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_STATE, 0, 8);}
static ssize_t global_input_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_STATE, 0, 8);}
static ssize_t global_input_LOS_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_LOS, 0, 8);}
static ssize_t global_input_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_LOS, 0, 8);}
static ssize_t global_output_PRE_long_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_LONG, 0, 8);}
static ssize_t global_output_PRE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_LONG, 0, 8);}
static ssize_t global_output_PRE_short_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_SHORT, 0, 8);}
static ssize_t global_output_PRE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_SHORT, 0, 8);}
static ssize_t global_output_level_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_LEVEL, 0, 8);}
static ssize_t global_output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_LEVEL, 0, 8);}
static ssize_t global_output_state_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_STATE, 0, 8);}
static ssize_t global_output_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_STATE, 0, 8);}
static ssize_t global_status_0_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS0, 0, 8);}
static ssize_t global_status_0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS0, 0, 8);}
static ssize_t global_status_1_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS1, 0, 8);}
static ssize_t global_status_1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS1, 0, 8);}
static ssize_t core_config_word_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 8);}
static ssize_t core_config_word_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 8);} /* 0x18/ 0x19 for 3312 */
static ssize_t core_left_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 4, 1);}
static ssize_t core_left_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 4, 1);}
static ssize_t core_right_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 3, 1);}
static ssize_t core_right_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 3, 1);}
static ssize_t core_buffer_on_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 1, 1);}
static ssize_t core_buffer_on_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 1, 1);}
static ssize_t core_config_pin_invert_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 1);}
static ssize_t core_config_pin_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 1);}
static ssize_t soft_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int rc;
if (((rc=field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_SOFTWARE_RESET, 4, 1)))<0) return rc;
if (((rc=init_device(client)))<0) return rc;
return count;
}
static ssize_t address_range_show (struct device *dev, struct device_attribute *attr, char *buf)
{return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_SOFTWARE_RESET, 0, 4);}
static ssize_t address_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_SOFTWARE_RESET, 0, 4);}
/* Setup i2c, write address_mode. Needed after soft reset and power up */
static int _init_device(struct i2c_client *client, int address_mode_data)
{
int rc;
if (((rc=write_reg(client, I2C_INTERFACE_MODE, I2C_INTERFACE_MODE_DATA)))<0) return rc;
if (address_mode_data >=0){ /* only write if needed, 3304 needs, 3312 - does not, 3308 - ? */
// if (((rc=write_reg(client, I2C_SOFTWARE_RESET_DATA, address_mode_data)))<0) return rc;
// this bug caused me to assemble a new board, urgently find vsc3304 chip,spend several days trying to troubleshoot...
// Just five extra characters!
if (((rc=write_reg(client, I2C_SOFTWARE_RESET, address_mode_data)))<0) return rc;
}
if (((rc=write_reg(client, I2C_CURRENT_PAGE, 0)))<0) return rc;
return 0;
}
static int init_device(struct i2c_client *client)
{
int rc;
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
dev_info(&client->dev,"Re-initializing %s\n",client->name);
if (((rc=_init_device(client, clientdata->address_mode_data)))<0) return rc;
clientdata->last_page=0;
return 0;
}
static int bitmask(int ls_bit_num, int width)
{
return ((1 << width) -1) << ls_bit_num;
}
//address_mode_data
static int read_reg(struct i2c_client *client, u8 reg)
{
int val;
val= i2c_smbus_read_byte_data(client, reg);
dev_dbg(&client->dev,"reading i2c device : slave=0x%x, reg=0x%x -> 0x%x\n",(int) (client->addr),reg,val);
return val;
}
static int write_reg(struct i2c_client *client, u8 reg, u8 val)
{
dev_dbg(&client->dev,"device write: slave=0x%x, reg=0x%x, val=0x%x\n", (int) (client->addr),reg,val);
return i2c_smbus_write_byte_data(client, reg, val);
}
static int read_field(struct i2c_client *client, u8 reg, int ls_bit_num, int width)
{
int rc;
if (((rc=read_reg(client, reg)))<0) return rc;
rc= (rc >> ls_bit_num) & bitmask(0, width);
dev_dbg(&client->dev,"reg=0x%x, ls_bit_num=%d, width=%d -> 0x%x\n", (int) reg, ls_bit_num,width,rc);
return rc;
}
static int read_page_field(struct i2c_client *client, int page, u8 reg, int ls_bit_num, int width)
{
int rc;
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
dev_dbg(&client->dev,"page=0x%x (last was 0x%x) reg=0x%x, ls_bit_num=%d, width=%d:\n",
page, (clientdata->last_page!=page), (int) reg, ls_bit_num, width);
if ((page>=0) && (clientdata->last_page!=page)) {
if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
clientdata->last_page=page;
}
rc= read_field(client, reg, ls_bit_num, width);
dev_dbg(&client->dev,"page=0x%x (last was 0x%x) reg=0x%x, ls_bit_num=%d, width=%d -> 0x%x\n",
page, (clientdata->last_page!=page), (int) reg, ls_bit_num, width,rc);
return rc;
}
static int write_field(struct i2c_client *client, u8 reg, u8 val, int ls_bit_num, int width)
{
int rc;
dev_dbg(&client->dev,"reg=0x%x, val=0x%x, ls_bit_num=%d, width=%d \n", (int) reg, (int) val,ls_bit_num,width);
if (((rc=read_reg(client, reg)))<0) return rc;
val<<=ls_bit_num;
return write_reg(client, reg, ((rc ^ val) & bitmask(ls_bit_num, width))^ rc);
}
static int write_page_field(struct i2c_client *client, int page, u8 reg, u8 val, int ls_bit_num, int width)
{
int rc;
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
dev_dbg(&client->dev,"page=0x%x (last was 0x%x), reg=0x%x, val=0x%x, ls_bit_num=%d, width=%d \n",
page,clientdata->last_page, (int) reg, (int) val,ls_bit_num,width);
if ((page>=0) && (clientdata->last_page!=page)) {
if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
clientdata->last_page=page;
}
return write_field(client, reg, val, ls_bit_num, width);
}
static int write_with_mask(struct i2c_client *client, u8 reg, u8 val, u8 mask)
{
int rc;
dev_dbg(&client->dev,"reg=0x%x, val=0x%x, mask=0x%x\n", (int) reg, (int) val, (int) mask);
if (mask !=0xff){
if (((rc=read_reg(client, reg)))<0) return rc;
val=((val ^ rc) & mask)^ rc;
}
return write_reg(client, reg, val);
}
static int write_page_with_mask(struct i2c_client *client, int page, u8 reg, u8 val , u8 mask)
{
int rc;
struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
dev_dbg(&client->dev,"page=0x%x (last was 0x%x), reg=0x%x, val=0x%x, mask=0x%x\n",
page,clientdata->last_page, (int) reg, (int) val,(int) mask);
if ((page>=0) && (clientdata->last_page!=page)) {
if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
clientdata->last_page=page;
}
return write_with_mask(client, reg, val, mask);
}
static void vsc330x_init_of(struct i2c_client *client)
{
// struct device *dev=&client->dev;
const __be32 * config_data;
struct device_node *node = client->dev.of_node;
int len,i,rc;
struct vsc330x_setup_data {
u8 page;
u8 reg;
u8 data;
u8 mask;
};
struct vsc330x_setup_data setup_data;
__be32 * setup_data_be32= (__be32 *) &setup_data;
const char * config_name;
if (node) {
config_name = of_get_property(client->dev.of_node, "vsc330x,configuration_name", &len);
if (config_name){
dev_info(&client->dev,"Initializing %s registers for \"%s\"\n",client->name,config_name);
}
config_data = of_get_property(client->dev.of_node, "vsc330x,configuration_data", &len);
if (config_data){
len /= sizeof(*config_data);
dev_dbg(&client->dev,"Read %d values\n",len);
for (i=0;idev,"0x%08x (0x%08x)\n", config_data[i],be32_to_cpup(config_data+i));
*setup_data_be32=config_data[i];
dev_dbg(&client->dev,"page=0x%02x, reg=0x%02x, data=0x%02x, mask=0x%02x \n",
(int)setup_data.page, (int)setup_data.reg,(int)setup_data.data,(int)setup_data.mask);
if (((rc=write_page_with_mask(client, (setup_data.page==0xff)?-1:setup_data.page, setup_data.reg,
setup_data.data, setup_data.mask)))<0) return;
}
} else {
dev_info(&client->dev,"'vsc330x,configuration_data' not found\n");
}
} else {
dev_info(&client->dev,"Device tree data not found for %s\n",client->name);
}
}
/*
dev_info(&client->dev,
*/
static int vsc330x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc=0;
struct vsc330x_data_t *clientdata = NULL;
/* initialize i2c mode and (if needed) address range bit field */
if (((rc=_init_device(client, vsc330x_data[id->driver_data].address_mode_data)))<0) goto wr_err;
dev_info(&client->dev,
"Chip %s found, driver version %s\n", id->name, DRV_VERSION);
clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata), GFP_KERNEL);
if (!clientdata) {
rc = -ENOMEM;
goto exit;
}
clientdata->last_page = 0;
clientdata->address_mode_data = vsc330x_data[id->driver_data].address_mode_data;
clientdata->in_ports = vsc330x_data[id->driver_data].in_ports;
clientdata->out_ports = vsc330x_data[id->driver_data].out_ports;
i2c_set_clientdata(client, clientdata);
rc = vsc330x_sysfs_register(&client->dev);
if (rc)
goto exit;
vsc330x_init_of(client);
return 0; /* found OK*/
wr_err:
rc = -EIO;
dev_err(&client->dev, "%s:%d error writing\n",__func__,__LINE__);
goto exit;
#if 0
rd_err:
rc = -EIO;
dev_err(&client->dev, "%s:%d error reading\n",__func__,__LINE__);
goto exit;
#endif
exit:
return rc;
}
static int vsc330x_i2c_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_driver vsc330x_i2c_driver = {
.driver = {
.name = "vsc330x",
.owner = THIS_MODULE,
},
.probe = vsc330x_i2c_probe,
.remove = vsc330x_i2c_remove,
.id_table = vsc330x_id,
};
module_i2c_driver(vsc330x_i2c_driver);
MODULE_AUTHOR("Andrey Filippov ");
MODULE_DESCRIPTION("VSC330x I2C bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:vsc330x");
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/mtd/ 0000775 0000000 0000000 00000000000 12670664436 0024422 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/mtd/nand/ 0000775 0000000 0000000 00000000000 12670664436 0025342 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/mtd/nand/Kconfig 0000664 0000000 0000000 00000044037 12670664436 0026655 0 ustar 00root root 0000000 0000000 config MTD_NAND_ECC
tristate
config MTD_NAND_ECC_SMC
bool "NAND ECC Smart Media byte order"
depends on MTD_NAND_ECC
default n
help
Software ECC according to the Smart Media Specification.
The original Linux implementation had byte 0 and 1 swapped.
menuconfig MTD_NAND
tristate "NAND Device Support"
depends on MTD
select MTD_NAND_IDS
select MTD_NAND_ECC
help
This enables support for accessing all type of NAND flash
devices. For further information see
.
if MTD_NAND
config MTD_NAND_BCH
tristate
select BCH
depends on MTD_NAND_ECC_BCH
default MTD_NAND
config MTD_NAND_ECC_BCH
bool "Support software BCH ECC"
default n
help
This enables support for software BCH error correction. Binary BCH
codes are more powerful and cpu intensive than traditional Hamming
ECC codes. They are used with NAND devices requiring more than 1 bit
of error correction.
config MTD_NAND_OTP
bool "Support access to one-time programmable area of some Micron chips"
select HAVE_MTD_OTP
help
This enables support for reading and writing to the OTP area of some
Micron chips.
config MTD_SM_COMMON
tristate
default n
config MTD_NAND_DENALI
tristate "Support Denali NAND controller"
depends on HAS_DMA
help
Enable support for the Denali NAND controller. This should be
combined with either the PCI or platform drivers to provide device
registration.
config MTD_NAND_DENALI_PCI
tristate "Support Denali NAND controller on Intel Moorestown"
depends on PCI && MTD_NAND_DENALI
help
Enable the driver for NAND flash on Intel Moorestown, using the
Denali NAND controller core.
config MTD_NAND_DENALI_DT
tristate "Support Denali NAND controller as a DT device"
depends on HAVE_CLK && MTD_NAND_DENALI
help
Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device.
config MTD_NAND_DENALI_SCRATCH_REG_ADDR
hex "Denali NAND size scratch register address"
default "0xFF108018"
depends on MTD_NAND_DENALI_PCI
help
Some platforms place the NAND chip size in a scratch register
because (some versions of) the driver aren't able to automatically
determine the size of certain chips. Set the address of the
scratch register here to enable this feature. On Intel Moorestown
boards, the scratch register is at 0xFF108018.
config MTD_NAND_GPIO
tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB
help
This enables a NAND flash driver where control signals are
connected to GPIO pins, and commands and data are communicated
via a memory mapped interface.
config MTD_NAND_AMS_DELTA
tristate "NAND Flash device on Amstrad E3"
depends on MACH_AMS_DELTA
default y
help
Support for NAND flash on Amstrad E3 (Delta).
config MTD_NAND_OMAP2
tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
depends on ARCH_OMAP2PLUS
help
Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
platforms.
config MTD_NAND_OMAP_BCH
depends on MTD_NAND_OMAP2
bool "Support hardware based BCH error correction"
default n
select BCH
help
This config enables the ELM hardware engine, which can be used to
locate and correct errors when using BCH ECC scheme. This offloads
the cpu from doing ECC error searching and correction. However some
legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
so this is optional for them.
config MTD_NAND_OMAP_BCH_BUILD
def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
config MTD_NAND_IDS
tristate
config MTD_NAND_RICOH
tristate "Ricoh xD card reader"
default n
depends on PCI
select MTD_SM_COMMON
help
Enable support for Ricoh R5C852 xD card reader
You also need to enable ether
NAND SSFDC (SmartMedia) read only translation layer' or new
expermental, readwrite
'SmartMedia/xD new translation layer'
config MTD_NAND_AU1550
tristate "Au1550/1200 NAND support"
depends on MIPS_ALCHEMY
help
This enables the driver for the NAND flash controller on the
AMD/Alchemy 1550 SOC.
config MTD_NAND_BF5XX
tristate "Blackfin on-chip NAND Flash Controller driver"
depends on BF54x || BF52x
help
This enables the Blackfin on-chip NAND flash controller
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
This driver can also be built as a module. If so, the module
will be called bf5xx-nand.
config MTD_NAND_BF5XX_HWECC
bool "BF5XX NAND Hardware ECC"
default y
depends on MTD_NAND_BF5XX
help
Enable the use of the BF5XX's internal ECC generator when
using NAND.
config MTD_NAND_BF5XX_BOOTROM_ECC
bool "Use Blackfin BootROM ECC Layout"
default n
depends on MTD_NAND_BF5XX_HWECC
help
If you wish to modify NAND pages and allow the Blackfin on-chip
BootROM to boot from them, say Y here. This is only necessary
if you are booting U-Boot out of NAND and you wish to update
U-Boot from Linux' userspace. Otherwise, you should say N here.
If unsure, say N.
config MTD_NAND_S3C2410
tristate "NAND Flash support for Samsung S3C SoCs"
depends on ARCH_S3C24XX || ARCH_S3C64XX
help
This enables the NAND flash controller on the S3C24xx and S3C64xx
SoCs
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_S3C2410_DEBUG
bool "Samsung S3C NAND driver debug"
depends on MTD_NAND_S3C2410
help
Enable debugging of the S3C NAND driver
config MTD_NAND_S3C2410_HWECC
bool "Samsung S3C NAND Hardware ECC"
depends on MTD_NAND_S3C2410
help
Enable the use of the controller's internal ECC generator when
using NAND. Early versions of the chips have had problems with
incorrect ECC generation, and if using these, the default of
software ECC is preferable.
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on 4xx
select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
config MTD_NAND_S3C2410_CLKSTOP
bool "Samsung S3C NAND IDLE clock stop"
depends on MTD_NAND_S3C2410
default n
help
Stop the clock to the NAND controller when there is no chip
selected to save power. This will mean there is a small delay
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
depends on HAS_IOMEM
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
This is a reimplementation of M-Systems DiskOnChip 2000,
Millennium and Millennium Plus as a standard NAND device driver,
as opposed to the earlier self-contained MTD device drivers.
This should enable, among other things, proper JFFS2 operation on
these devices.
config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
depends on MTD_NAND_DISKONCHIP
help
This option allows you to specify nonstandard address at which to
probe for a DiskOnChip, or to change the detection options. You
are unlikely to need any of this unless you are using LinuxBIOS.
Say 'N'.
config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
depends on MTD_NAND_DISKONCHIP
default "0"
---help---
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option allows you to specify a single address at which to probe
for the device, which is useful if you have other devices in that
range which get upset when they are probed.
(Note that on PowerPC, the normal probe will only check at
0xE4000000.)
Normally, you should leave this set to zero, to allow the probe at
the normal addresses.
config MTD_NAND_DISKONCHIP_PROBE_HIGH
bool "Probe high addresses"
depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
help
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option changes to make it probe between 0xFFFC8000 and
0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be
useful to you. Say 'N'.
config MTD_NAND_DISKONCHIP_BBTWRITE
bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
depends on MTD_NAND_DISKONCHIP
help
On DiskOnChip devices shipped with the INFTL filesystem (Millennium
and 2000 TSOP/Alon), Linux reserves some space at the end of the
device for the Bad Block Table (BBT). If you have existing INFTL
data on your device (created by non-Linux tools such as M-Systems'
DOS drivers), your data might overlap the area Linux wants to use for
the BBT. If this is a concern for you, leave this option disabled and
Linux will not write BBT data into this area.
The downside of leaving this option disabled is that if bad blocks
are detected by Linux, they will not be recorded in the BBT, which
could cause future problems.
Once you enable this option, new filesystems (INFTL or others, created
in Linux or other operating systems) will not use the reserved area.
The only reason not to enable this option is to prevent damage to
preexisting filesystems.
Even if you leave this disabled, you can enable BBT writes at module
load time (assuming you build diskonchip as a module) with the module
parameter "inftl_bbt_write=1".
config MTD_NAND_DOCG4
tristate "Support for DiskOnChip G4"
depends on HAS_IOMEM
select BCH
select BITREVERSE
help
Support for diskonchip G4 nand flash, found in various smartphones and
PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
Portege G900, Asus P526, and O2 XDA Zinc.
With this driver you will be able to use UBI and create a ubifs on the
device, so you may wish to consider enabling UBI and UBIFS as well.
These devices ship with the Mys/Sandisk SAFTL formatting, for which
there is currently no mtd parser, so you may want to use command line
partitioning to segregate write-protected blocks. On the Treo680, the
first five erase blocks (256KiB each) are write-protected, followed
by the block containing the saftl partition table. This is probably
typical.
config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on ARCH_PXA
config MTD_NAND_CAFE
tristate "NAND support for OLPC CAFÉ chip"
depends on PCI
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
Use NAND flash attached to the CAFÉ chip designed for the OLPC
laptop.
config MTD_NAND_CS553X
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
depends on X86_32
help
The CS553x companion chips for the AMD Geode processor
include NAND flash controllers with built-in hardware ECC
capabilities; enabling this option will allow you to use
these. The driver will check the MSRs to verify that the
controller is enabled for NAND, and currently requires that
the controller be in MMIO mode.
If you say "m", the module will be called cs553x_nand.
config MTD_NAND_ATMEL
tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32"
depends on ARCH_AT91 || AVR32
help
Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 and AVR32 processors.
config MTD_NAND_PXA3xx
tristate "NAND support on PXA3xx and Armada 370/XP"
depends on PXA3xx || ARCH_MMP || PLAT_ORION
help
This enables the driver for the NAND flash device found on
PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
config MTD_NAND_SLC_LPC32XX
tristate "NXP LPC32xx SLC Controller"
depends on ARCH_LPC32XX
help
Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
chips) NAND controller. This is the default for the PHYTEC 3250
reference board which contains a NAND256R3A2CZA6 chip.
Please check the actual NAND chip connected and its support
by the SLC NAND controller.
config MTD_NAND_MLC_LPC32XX
tristate "NXP LPC32xx MLC Controller"
depends on ARCH_LPC32XX
help
Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
controller. This is the default for the WORK92105 controller
board.
Please check the actual NAND chip connected and its support
by the MLC NAND controller.
config MTD_NAND_CM_X270
tristate "Support for NAND Flash on CM-X270 modules"
depends on MACH_ARMCORE
config MTD_NAND_PASEMI
tristate "NAND support for PA Semi PWRficient"
depends on PPC_PASEMI
help
Enables support for NAND Flash interface on PA Semi PWRficient
based boards
config MTD_NAND_TMIO
tristate "NAND Flash device on Toshiba Mobile IO Controller"
depends on MFD_TMIO
help
Support for NAND flash connected to a Toshiba Mobile IO
Controller in some PDAs, including the Sharp SL6000x.
config MTD_NAND_NANDSIM
tristate "Support for NAND Flash Simulator"
help
The simulator may simulate various NAND flash chips for the
MTD nand layer.
config MTD_NAND_GPMI_NAND
tristate "GPMI NAND Flash Controller driver"
depends on MTD_NAND && MXS_DMA
help
Enables NAND Flash support for IMX23, IMX28 or IMX6.
The GPMI controller is very powerful, with the help of BCH
module, it can do the hardware ECC. The GPMI supports several
NAND flashs at the same time. The GPMI may conflicts with other
block, such as SD card. So pay attention to it when you enable
the GPMI.
config MTD_NAND_BCM47XXNFLASH
tristate "Support for NAND flash on BCM4706 BCMA bus"
depends on BCMA_NFLASH
help
BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for
NAND flash memories. For now only BCM4706 is supported.
config MTD_NAND_PLATFORM
tristate "Support for generic platform NAND driver"
depends on HAS_IOMEM
help
This implements a generic NAND driver for on-SOC platform
devices. You will need to provide platform-specific functions
via platform_data.
config MTD_NAND_ORION
tristate "NAND Flash support for Marvell Orion SoC"
depends on PLAT_ORION
help
This enables the NAND flash controller on Orion machines.
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on PPC
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
Controller Module with built-in hardware ECC capabilities.
Enabling this option will enable you to use this to control
external NAND devices.
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on MTD_NAND && FSL_SOC
select FSL_IFC
select MEMORY
help
Various Freescale chips e.g P1010, include a NAND Flash machine
with built-in hardware ECC capabilities.
Enabling this option will enable you to use this to control
external NAND devices.
config MTD_NAND_FSL_UPM
tristate "Support for NAND on Freescale UPM"
depends on PPC_83xx || PPC_85xx
select FSL_LBC
help
Enables support for NAND Flash chips wired onto Freescale PowerPC
processor localbus with User-Programmable Machine support.
config MTD_NAND_MPC5121_NFC
tristate "MPC5121 built-in NAND Flash Controller support"
depends on PPC_MPC512x
help
This enables the driver for the NAND flash controller on the
MPC5121 SoC.
config MTD_NAND_MXC
tristate "MXC NAND support"
depends on ARCH_MXC
help
This enables the driver for the NAND flash controller on the
MXC processors.
config MTD_NAND_SH_FLCTL
tristate "Support for NAND on Renesas SuperH FLCTL"
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
depends on HAS_IOMEM
depends on HAS_DMA
help
Several Renesas SuperH CPU has FLCTL. This option enables support
for NAND Flash using FLCTL.
config MTD_NAND_DAVINCI
tristate "Support NAND on DaVinci/Keystone SoC"
depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
help
Enable the driver for NAND flash chips on Texas Instruments
DaVinci/Keystone processors.
config MTD_NAND_TXX9NDFMC
tristate "NAND Flash support for TXx9 SoC"
depends on SOC_TX4938 || SOC_TX4939
help
This enables the NAND flash controller on the TXx9 SoCs.
config MTD_NAND_SOCRATES
tristate "Support for NAND on Socrates board"
depends on SOCRATES
help
Enables support for NAND Flash chips wired onto Socrates board.
config MTD_NAND_NUC900
tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
depends on ARCH_W90X900
help
This enables the driver for the NAND Flash on evaluation board based
on w90p910 / NUC9xx.
config MTD_NAND_PL35X
tristate "ARM Pl35X NAND flash driver"
depends on MTD_NAND && ARM
depends on PL35X_SMC
help
This enables access to the NAND flash device on PL351/PL353
SMC controller.
config MTD_NAND_JZ4740
tristate "Support for JZ4740 SoC NAND controller"
depends on MACH_JZ4740
help
Enables support for NAND Flash on JZ4740 SoC based boards.
config MTD_NAND_FSMC
tristate "Support for NAND on ST Micros FSMC"
depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
help
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
config MTD_NAND_XWAY
tristate "Support for NAND on Lantiq XWAY SoC"
depends on LANTIQ && SOC_TYPE_XWAY
select MTD_NAND_PLATFORM
help
Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
to the External Bus Unit (EBU).
config MTD_NAND_SUNXI
tristate "Support for NAND on Allwinner SoCs"
depends on ARCH_SUNXI
help
Enables support for NAND Flash chips on Allwinner SoCs.
config MTD_NAND_ARASAN
tristate "Support for Arasan Nand Flash controller"
depends on MTD_NAND
help
Enables the driver for the Arasan Nand Flash controller in ZynqMP SoC.
config MTD_NAND_HISI504
tristate "Support for NAND controller on Hisilicon SoC Hip04"
depends on HAS_DMA
help
Enables support for NAND controller on Hisilicon SoC Hip04.
endif # MTD_NAND
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/mtd/nand/Makefile 0000664 0000000 0000000 00000004665 12670664436 0027015 0 ustar 00root root 0000000 0000000 #
# linux/drivers/nand/Makefile
#
obj-$(CONFIG_MTD_NAND) += nand.o
obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_DENALI) += denali.o
obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o
obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o
obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
obj-$(CONFIG_MTD_NAND_PL35X) += pl35x_nand.o
obj-$(CONFIG_MTD_NAND_ARASAN) += arasan_nfc.o
obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nandchip-micron.o
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/mtd/nand/nand.h 0000664 0000000 0000000 00000000663 12670664436 0026440 0 ustar 00root root 0000000 0000000 #include
#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0)
int nand_get_device(struct mtd_info *mtd, int new_state);
void nand_release_device(struct mtd_info *mtd);
int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops);
int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops);
void nandchip_micron_init(struct mtd_info *mtd, int dev_id);
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/mtd/nand/nandchip-micron.c 0000664 0000000 0000000 00000012474 12670664436 0030567 0 ustar 00root root 0000000 0000000 #include
#include
#include
#include
#include
#include "nand.h"
#define MICRON_SETFEATURE_ARRAYOP 0x90
#define MICRON_SETFEATURE_ARRAYOP_NORMAL ((uint8_t[]){0,0,0,0})
#define MICRON_SETFEATURE_ARRAYOP_OTP ((uint8_t[]){1,0,0,0})
#define MICRON_SETFEATURE_ARRAYOP_OTPPROTECT ((uint8_t[]){3,0,0,0})
#define MICRON_NUM_OTP_FIRSTPAGE 2
#define MICRON_NUM_OTP_PAGES 30
static int mt29f_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
size_t len)
{
int i;
if (len < MICRON_NUM_OTP_PAGES * sizeof(*buf))
return -ENOSPC;
for (i = 0; i < MICRON_NUM_OTP_PAGES; ++i) {
buf->start = i * mtd->writesize;
buf->length = mtd->writesize;
/*
* XXX: don't know how to find out, if a page is locked
*/
buf->locked = 0;
buf++;
}
return MICRON_NUM_OTP_PAGES * sizeof(*buf);
}
static int mt29f_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
size_t len, size_t *retlen, uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
struct mtd_oob_ops ops;
int ret;
u8 get_feature,i;
/* Valid pages in otp are 02h-1Fh. */
if (from > MICRON_NUM_OTP_PAGES << chip->page_shift)
return -EIO;
if (from + len > MICRON_NUM_OTP_PAGES << chip->page_shift)
len = (MICRON_NUM_OTP_PAGES << chip->page_shift) - from;
from += MICRON_NUM_OTP_FIRSTPAGE << chip->page_shift;
/* XXX: FL_READING? */
nand_get_device(mtd, FL_READING);
chip->select_chip(mtd, 0);
ret = chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,MICRON_SETFEATURE_ARRAYOP_OTP);
ndelay(1000);
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, MICRON_SETFEATURE_ARRAYOP, -1);
get_feature = readb(chip->IO_ADDR_R);
pr_debug("Feature on: 0x%02x\n",get_feature);
if (ret)
goto out;
ops.len = len;
ops.datbuf = buf;
ops.oobbuf = NULL;
ops.mode = 0;
/*
* XXX: some things in nand_do_read_ops might be wrong for OTP. e.g.
* chip->pagemask, chip->pagebuf handling, caching
*/
ret = nand_do_read_ops(mtd, from, &ops);
*retlen = ops.retlen;
/* nand_do_read_ops deselects the chip so reselect here */
chip->select_chip(mtd, 0);
chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,MICRON_SETFEATURE_ARRAYOP_NORMAL);
ndelay(1000);
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, MICRON_SETFEATURE_ARRAYOP, -1);
get_feature = readb(chip->IO_ADDR_R);
pr_debug("Feature off: 0x%02x\n",get_feature);
out:
nand_release_device(mtd);
return ret;
}
static int mt29f_write_user_prot_reg(struct mtd_info *mtd, loff_t to,
size_t len, size_t *retlen, uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
struct mtd_oob_ops ops;
int ret;
pr_debug("mt29f_write_user_prot_reg start!!!");
/* Valid pages in otp are 02h-1Fh. */
if (to > MICRON_NUM_OTP_PAGES << chip->page_shift)
return -EIO;
if (to + len > MICRON_NUM_OTP_PAGES << chip->page_shift)
len = (MICRON_NUM_OTP_PAGES << chip->page_shift) - to;
to += MICRON_NUM_OTP_FIRSTPAGE << chip->page_shift;
nand_get_device(mtd, FL_WRITING);
chip->select_chip(mtd, 0);
ret = chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,
MICRON_SETFEATURE_ARRAYOP_OTP);
if (ret)
goto out;
ops.len = len;
ops.datbuf = buf;
ops.oobbuf = NULL;
ops.mode = 0;
/*
* some things in nand_do_write_ops might be wrong for OTP. e.g.
* chip->pagemask, chip->pagebuf handling
*/
ret = nand_do_write_ops(mtd, to, &ops);
*retlen = ops.retlen;
/* nand_do_write_ops deselects the chip so reselect here */
chip->select_chip(mtd, 0);
chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,
MICRON_SETFEATURE_ARRAYOP_NORMAL);
out:
nand_release_device(mtd);
return ret;
}
static int mt29f_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
size_t len)
{
struct nand_chip *chip = mtd->priv;
int ret;
int i;
/* assert from and len are aligned */
if (NOTALIGNED(from) || NOTALIGNED(len)) {
pr_notice("%s: attempt to lock non page aligned data\n",
__func__);
return -EINVAL;
}
if (!len)
return 0;
if (from > MICRON_NUM_OTP_PAGES << chip->page_shift)
return -EINVAL;
if (from + len > MICRON_NUM_OTP_PAGES << chip->page_shift)
return -EINVAL;
from += MICRON_NUM_OTP_FIRSTPAGE << chip->page_shift;
nand_get_device(mtd, FL_WRITING);
chip->select_chip(mtd, 0);
ret = chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,
MICRON_SETFEATURE_ARRAYOP_OTPPROTECT);
if (ret)
goto out;
for (i = 0; i < len << chip->page_shift; ++i) {
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0,
(from << chip->page_shift) + i);
chip->write_byte(mtd, 0);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
}
chip->onfi_set_features(mtd, chip, MICRON_SETFEATURE_ARRAYOP,
MICRON_SETFEATURE_ARRAYOP_NORMAL);
out:
nand_release_device(mtd);
return ret;
}
void nandchip_micron_init(struct mtd_info *mtd, int dev_id)
{
/*
* OTP is available on (at least) Micron's MT29F2G{08,16}AB[AB]EA,
* MT29F[48]G{08,16}AB[AB]DA, MT29F16G08AJADA having device IDs:
* 0xda, 0xca, 0xaa, 0xba;
* 0xdc, 0xcc, 0xac, 0xbc, 0xa3, 0xb3, 0xd3, 0xc3;
* 0xd3
*/
if (IS_ENABLED(CONFIG_MTD_NAND_OTP) &&
((dev_id + 0x20) & 0xc0) == 0xc0 &&
((dev_id & 0x09) == 8 || (dev_id & 0x0f) == 3)) {
mtd->_get_user_prot_info = mt29f_get_user_prot_info;
mtd->_read_user_prot_reg = mt29f_read_user_prot_reg;
mtd->_write_user_prot_reg = mt29f_write_user_prot_reg;
mtd->_lock_user_prot_reg = mt29f_lock_user_prot_reg;
}
}
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/drivers/mtd/nand/pl35x_nand.c 0000664 0000000 0000000 00000107043 12670664436 0027466 0 ustar 00root root 0000000 0000000 /*
* ARM PL35X NAND Flash Controller Driver
*
* Copyright (C) 2009 - 2014 Xilinx, Inc.
*
* This driver is based on plat_nand.c and mxc_nand.c drivers
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PL35X_NAND_DRIVER_NAME "pl35x-nand"
/* NAND flash driver defines */
#define PL35X_NAND_CMD_PHASE 1 /* End command valid in command phase */
#define PL35X_NAND_DATA_PHASE 2 /* End command valid in data phase */
#define PL35X_NAND_ECC_SIZE 512 /* Size of data for ECC operation */
/* Flash memory controller operating parameters */
#define PL35X_NAND_ECC_CONFIG (BIT(4) | /* ECC read at end of page */ \
(0 << 5)) /* No Jumping */
/* AXI Address definitions */
#define START_CMD_SHIFT 3
#define END_CMD_SHIFT 11
#define END_CMD_VALID_SHIFT 20
#define ADDR_CYCLES_SHIFT 21
#define CLEAR_CS_SHIFT 21
#define ECC_LAST_SHIFT 10
#define COMMAND_PHASE (0 << 19)
#define DATA_PHASE BIT(19)
#define PL35X_NAND_ECC_LAST BIT(ECC_LAST_SHIFT) /* Set ECC_Last */
#define PL35X_NAND_CLEAR_CS BIT(CLEAR_CS_SHIFT) /* Clear chip select */
#define ONDIE_ECC_FEATURE_ADDR 0x90
#define PL35X_NAND_ECC_BUSY_TIMEOUT (1 * HZ)
#define PL35X_NAND_DEV_BUSY_TIMEOUT (1 * HZ)
#define PL35X_NAND_LAST_TRANSFER_LENGTH 4
/* Inline function for the NAND controller register write */
static inline void pl35x_nand_write32(void __iomem *addr, u32 val)
{
writel_relaxed((val), (addr));
}
/**
* struct pl35x_nand_command_format - Defines NAND flash command format
* @start_cmd: First cycle command (Start command)
* @end_cmd: Second cycle command (Last command)
* @addr_cycles: Number of address cycles required to send the address
* @end_cmd_valid: The second cycle command is valid for cmd or data phase
*/
struct pl35x_nand_command_format {
int start_cmd;
int end_cmd;
u8 addr_cycles;
u8 end_cmd_valid;
};
/**
* struct pl35x_nand_info - Defines the NAND flash driver instance
* @chip: NAND chip information structure
* @mtd: MTD information structure
* @parts: Pointer to the mtd_partition structure
* @nand_base: Virtual address of the NAND flash device
* @end_cmd_pending: End command is pending
* @end_cmd: End command
* @row_addr_cycles: Row address cycles
* @col_addr_cycles: Column address cycles
*/
struct pl35x_nand_info {
struct nand_chip chip;
struct mtd_info mtd;
struct mtd_partition *parts;
void __iomem *nand_base;
unsigned long end_cmd_pending;
unsigned long end_cmd;
u8 row_addr_cycles;
u8 col_addr_cycles;
};
/*
* The NAND flash operations command format
*/
static const struct pl35x_nand_command_format pl35x_nand_commands[] = {
{NAND_CMD_READ0, NAND_CMD_READSTART, 5, PL35X_NAND_CMD_PHASE},
{NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, PL35X_NAND_CMD_PHASE},
{NAND_CMD_READID, NAND_CMD_NONE, 1, NAND_CMD_NONE},
{NAND_CMD_STATUS, NAND_CMD_NONE, 0, NAND_CMD_NONE},
{NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5, PL35X_NAND_DATA_PHASE},
{NAND_CMD_RNDIN, NAND_CMD_NONE, 2, NAND_CMD_NONE},
{NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3, PL35X_NAND_CMD_PHASE},
{NAND_CMD_RESET, NAND_CMD_NONE, 0, NAND_CMD_NONE},
{NAND_CMD_PARAM, NAND_CMD_NONE, 1, NAND_CMD_NONE},
{NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE},
{NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE},
{NAND_CMD_UNLOCK1, NAND_CMD_NONE, 3, NAND_CMD_NONE},
{NAND_CMD_UNLOCK2, NAND_CMD_NONE, 3, NAND_CMD_NONE},
{NAND_CMD_LOCK, NAND_CMD_NONE, 0, NAND_CMD_NONE},
{NAND_CMD_NONE, NAND_CMD_NONE, 0, 0},
/* Add all the flash commands supported by the flash device and Linux */
/*
* The cache program command is not supported by driver because driver
* cant differentiate between page program and cached page program from
* start command, these commands can be differentiated through end
* command, which doesn't fit in to the driver design. The cache program
* command is not supported by NAND subsystem also, look at 1612 line
* number (in nand_write_page function) of nand_base.c file.
* {NAND_CMD_SEQIN, NAND_CMD_CACHEDPROG, 5, PL35X_NAND_YES},
*/
};
/* Define default oob placement schemes for large and small page devices */
static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 3,
.eccpos = {0, 1, 2},
.oobfree = {
{.offset = 8,
. length = 8} }
};
static struct nand_ecclayout nand_oob_64 = {
.eccbytes = 12,
.eccpos = {
52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63},
.oobfree = {
{.offset = 2,
.length = 50} }
};
static struct nand_ecclayout ondie_nand_oob_64 = {
.eccbytes = 32,
.eccpos = {
8, 9, 10, 11, 12, 13, 14, 15,
24, 25, 26, 27, 28, 29, 30, 31,
40, 41, 42, 43, 44, 45, 46, 47,
56, 57, 58, 59, 60, 61, 62, 63
},
.oobfree = {
{ .offset = 4, .length = 4 },
{ .offset = 20, .length = 4 },
{ .offset = 36, .length = 4 },
{ .offset = 52, .length = 4 }
}
};
/* Generic flash bbt decriptors */
static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
static struct nand_bbt_descr bbt_main_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
.offs = 4,
.len = 4,
.veroffs = 20,
.maxblocks = 4,
.pattern = bbt_pattern
};
static struct nand_bbt_descr bbt_mirror_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
.offs = 4,
.len = 4,
.veroffs = 20,
.maxblocks = 4,
.pattern = mirror_pattern
};
/**
* pl35x_nand_calculate_hwecc - Calculate Hardware ECC
* @mtd: Pointer to the mtd_info structure
* @data: Pointer to the page data
* @ecc_code: Pointer to the ECC buffer where ECC data needs to be stored
*
* This function retrieves the Hardware ECC data from the controller and returns
* ECC data back to the MTD subsystem.
*
* Return: 0 on success or error value on failure
*/
static int pl35x_nand_calculate_hwecc(struct mtd_info *mtd,
const u8 *data, u8 *ecc_code)
{
u32 ecc_value, ecc_status;
u8 ecc_reg, ecc_byte;
unsigned long timeout = jiffies + PL35X_NAND_ECC_BUSY_TIMEOUT;
/* Wait till the ECC operation is complete or timeout */
do {
if (pl35x_smc_ecc_is_busy())
cpu_relax();
else
break;
} while (!time_after_eq(jiffies, timeout));
if (time_after_eq(jiffies, timeout)) {
pr_err("%s timed out\n", __func__);
return -ETIMEDOUT;
}
for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) {
/* Read ECC value for each block */
ecc_value = pl35x_smc_get_ecc_val(ecc_reg);
ecc_status = (ecc_value >> 24) & 0xFF;
/* ECC value valid */
if (ecc_status & 0x40) {
for (ecc_byte = 0; ecc_byte < 3; ecc_byte++) {
/* Copy ECC bytes to MTD buffer */
*ecc_code = ecc_value & 0xFF;
ecc_value = ecc_value >> 8;
ecc_code++;
}
} else {
pr_warn("%s status failed\n", __func__);
return -1;
}
}
return 0;
}
/**
* onehot - onehot function
* @value: Value to check for onehot
*
* This function checks whether a value is onehot or not.
* onehot is if and only if onebit is set.
*
* Return: 1 if it is onehot else 0
*/
static int onehot(unsigned short value)
{
return (value & (value - 1)) == 0;
}
/**
* pl35x_nand_correct_data - ECC correction function
* @mtd: Pointer to the mtd_info structure
* @buf: Pointer to the page data
* @read_ecc: Pointer to the ECC value read from spare data area
* @calc_ecc: Pointer to the calculated ECC value
*
* This function corrects the ECC single bit errors & detects 2-bit errors.
*
* Return: 0 if no ECC errors found
* 1 if single bit error found and corrected.
* -1 if multiple ECC errors found.
*/
static int pl35x_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
unsigned char *read_ecc,
unsigned char *calc_ecc)
{
unsigned char bit_addr;
unsigned int byte_addr;
unsigned short ecc_odd, ecc_even, read_ecc_lower, read_ecc_upper;
unsigned short calc_ecc_lower, calc_ecc_upper;
read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) & 0xfff;
read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) & 0xfff;
calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) & 0xfff;
calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) & 0xfff;
ecc_odd = read_ecc_lower ^ calc_ecc_lower;
ecc_even = read_ecc_upper ^ calc_ecc_upper;
if ((ecc_odd == 0) && (ecc_even == 0))
return 0; /* no error */
if (ecc_odd == (~ecc_even & 0xfff)) {
/* bits [11:3] of error code is byte offset */
byte_addr = (ecc_odd >> 3) & 0x1ff;
/* bits [2:0] of error code is bit offset */
bit_addr = ecc_odd & 0x7;
/* Toggling error bit */
buf[byte_addr] ^= (1 << bit_addr);
return 1;
}
if (onehot(ecc_odd | ecc_even) == 1)
return 1; /* one error in parity */
return -1; /* Uncorrectable error */
}
/**
* pl35x_nand_read_oob - [REPLACABLE] the most common OOB data read function
* @mtd: Pointer to the mtd info structure
* @chip: Pointer to the NAND chip info structure
* @page: Page number to read
*
* Return: Always return zero
*/
static int pl35x_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
unsigned long data_phase_addr;
uint8_t *p;
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
p = chip->oob_poi;
chip->read_buf(mtd, p,
(mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH));
p += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH);
data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
data_phase_addr |= PL35X_NAND_CLEAR_CS;
chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
chip->read_buf(mtd, p, PL35X_NAND_LAST_TRANSFER_LENGTH);
return 0;
}
/**
* pl35x_nand_write_oob - [REPLACABLE] the most common OOB data write function
* @mtd: Pointer to the mtd info structure
* @chip: Pointer to the NAND chip info structure
* @page: Page number to write
*
* Return: Zero on success and EIO on failure
*/
static int pl35x_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
int status = 0;
const uint8_t *buf = chip->oob_poi;
unsigned long data_phase_addr;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
chip->write_buf(mtd, buf,
(mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH));
buf += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH);
data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
data_phase_addr |= PL35X_NAND_CLEAR_CS;
data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr;
chip->write_buf(mtd, buf, PL35X_NAND_LAST_TRANSFER_LENGTH);
/* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return (status & NAND_STATUS_FAIL) ? -EIO : 0;
}
/**
* pl35x_nand_read_page_raw - [Intern] read raw page data without ecc
* @mtd: Pointer to the mtd info structure
* @chip: Pointer to the NAND chip info structure
* @buf: Pointer to the data buffer
* @oob_required: Caller requires OOB data read to chip->oob_poi
* @page: Page number to read
*
* Return: Always return zero
*/
static int pl35x_nand_read_page_raw(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
unsigned long data_phase_addr;
uint8_t *p;
chip->read_buf(mtd, buf, mtd->writesize);
p = chip->oob_poi;
chip->read_buf(mtd, p,
(mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH));
p += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH);
data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
data_phase_addr |= PL35X_NAND_CLEAR_CS;
chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
chip->read_buf(mtd, p, PL35X_NAND_LAST_TRANSFER_LENGTH);
return 0;
}
/**
* pl35x_nand_write_page_raw - [Intern] raw page write function
* @mtd: Pointer to the mtd info structure
* @chip: Pointer to the NAND chip info structure
* @buf: Pointer to the data buffer
* @oob_required: Caller requires OOB data read to chip->oob_poi
*
* Return: Always return zero
*/
static int pl35x_nand_write_page_raw(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
unsigned long data_phase_addr;
uint8_t *p;
chip->write_buf(mtd, buf, mtd->writesize);
p = chip->oob_poi;
chip->write_buf(mtd, p,
(mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH));
p += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH);
data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
data_phase_addr |= PL35X_NAND_CLEAR_CS;
data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr;
chip->write_buf(mtd, p, PL35X_NAND_LAST_TRANSFER_LENGTH);
return 0;
}
/**
* nand_write_page_hwecc - Hardware ECC based page write function
* @mtd: Pointer to the mtd info structure
* @chip: Pointer to the NAND chip info structure
* @buf: Pointer to the data buffer
* @oob_required: Caller requires OOB data read to chip->oob_poi
*
* This functions writes data and hardware generated ECC values in to the page.
*
* Return: Always return zero
*/
static int pl35x_nand_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf,
int oob_required)
{
int i, eccsize = chip->ecc.size;
int eccsteps = chip->ecc.steps;
uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
uint32_t *eccpos = chip->ecc.layout->eccpos;
unsigned long data_phase_addr;
uint8_t *oob_ptr;
for ( ; (eccsteps - 1); eccsteps--) {
chip->write_buf(mtd, p, eccsize);
p += eccsize;
}
chip->write_buf(mtd, p, (eccsize - PL35X_NAND_LAST_TRANSFER_LENGTH));
p += (eccsize - PL35X_NAND_LAST_TRANSFER_LENGTH);
/* Set ECC Last bit to 1 */
data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
data_phase_addr |= PL35X_NAND_ECC_LAST;
chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr;
chip->write_buf(mtd, p, PL35X_NAND_LAST_TRANSFER_LENGTH);
/* Wait for ECC to be calculated and read the error values */
p = buf;
chip->ecc.calculate(mtd, p, &ecc_calc[0]);
for (i = 0; i < chip->ecc.total; i++)
chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]);
/* Clear ECC last bit */
data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
data_phase_addr &= ~PL35X_NAND_ECC_LAST;
chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr;
/* Write the spare area with ECC bytes */
oob_ptr = chip->oob_poi;
chip->write_buf(mtd, oob_ptr,
(mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH));
data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
data_phase_addr |= PL35X_NAND_CLEAR_CS;
data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr;
oob_ptr += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH);
chip->write_buf(mtd, oob_ptr, PL35X_NAND_LAST_TRANSFER_LENGTH);
return 0;
}
/**
* pl35x_nand_write_page_swecc - [REPLACABLE] software ecc based page write function
* @mtd: Pointer to the mtd info structure
* @chip: Pointer to the NAND chip info structure
* @buf: Pointer to the data buffer
* @oob_required: Caller requires OOB data read to chip->oob_poi
*
* Return: Always return zero
*/
static int pl35x_nand_write_page_swecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf,
int oob_required)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
uint32_t *eccpos = chip->ecc.layout->eccpos;
/* Software ecc calculation */
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
for (i = 0; i < chip->ecc.total; i++)
chip->oob_poi[eccpos[i]] = ecc_calc[i];
chip->ecc.write_page_raw(mtd, chip, buf, 1);
return 0;
}
/**
* pl35x_nand_read_page_hwecc - Hardware ECC based page read function
* @mtd: Pointer to the mtd info structure
* @chip: Pointer to the NAND chip info structure
* @buf: Pointer to the buffer to store read data
* @oob_required: Caller requires OOB data read to chip->oob_poi
* @page: Page number to read
*
* This functions reads data and checks the data integrity by comparing hardware
* generated ECC values and read ECC values from spare area.
*
* Return: 0 always and updates ECC operation status in to MTD structure
*/
static int pl35x_nand_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
int i, stat, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *ecc_calc = chip->buffers->ecccalc;
uint8_t *ecc_code = chip->buffers->ecccode;
uint32_t *eccpos = chip->ecc.layout->eccpos;
unsigned long data_phase_addr;
uint8_t *oob_ptr;
for ( ; (eccsteps - 1); eccsteps--) {
chip->read_buf(mtd, p, eccsize);
p += eccsize;
}
chip->read_buf(mtd, p, (eccsize - PL35X_NAND_LAST_TRANSFER_LENGTH));
p += (eccsize - PL35X_NAND_LAST_TRANSFER_LENGTH);
/* Set ECC Last bit to 1 */
data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
data_phase_addr |= PL35X_NAND_ECC_LAST;
chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
chip->read_buf(mtd, p, PL35X_NAND_LAST_TRANSFER_LENGTH);
/* Read the calculated ECC value */
p = buf;
chip->ecc.calculate(mtd, p, &ecc_calc[0]);
/* Clear ECC last bit */
data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
data_phase_addr &= ~PL35X_NAND_ECC_LAST;
chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
/* Read the stored ECC value */
oob_ptr = chip->oob_poi;
chip->read_buf(mtd, oob_ptr,
(mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH));
/* de-assert chip select */
data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
data_phase_addr |= PL35X_NAND_CLEAR_CS;
chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
oob_ptr += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH);
chip->read_buf(mtd, oob_ptr, PL35X_NAND_LAST_TRANSFER_LENGTH);
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = ~(chip->oob_poi[eccpos[i]]);
eccsteps = chip->ecc.steps;
p = buf;
/* Check ECC error for all blocks and correct if it is correctable */
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
}
return 0;
}
/**
* pl35x_nand_read_page_swecc - [REPLACABLE] software ecc based page read function
* @mtd: Pointer to the mtd info structure
* @chip: Pointer to the NAND chip info structure
* @buf: Pointer to the buffer to store read data
* @oob_required: Caller requires OOB data read to chip->oob_poi
* @page: Page number to read
*
* Return: Always return zero
*/
static int pl35x_nand_read_page_swecc(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *ecc_calc = chip->buffers->ecccalc;
uint8_t *ecc_code = chip->buffers->ecccode;
uint32_t *eccpos = chip->ecc.layout->eccpos;
chip->ecc.read_page_raw(mtd, chip, buf, page, 1);
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];
eccsteps = chip->ecc.steps;
p = buf;
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
}
return 0;
}
/**
* pl35x_nand_select_chip - Select the flash device
* @mtd: Pointer to the mtd info structure
* @chip: Pointer to the NAND chip info structure
*
* This function is empty as the NAND controller handles chip select line
* internally based on the chip address passed in command and data phase.
*/
static void pl35x_nand_select_chip(struct mtd_info *mtd, int chip)
{
return;
}
/**
* pl35x_nand_cmd_function - Send command to NAND device
* @mtd: Pointer to the mtd_info structure
* @command: The command to be sent to the flash device
* @column: The column address for this command, -1 if none
* @page_addr: The page address for this command, -1 if none
*/
static void pl35x_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
if (command == NAND_CMD_READ0) pr_debug("NAND READ\n");
if (command == NAND_CMD_UNLOCK1) pr_debug("NAND UNLOCK1\n");
if (command == NAND_CMD_SET_FEATURES) pr_debug("NAND NAND_CMD_SET_FEATURES\n");
struct nand_chip *chip = mtd->priv;
const struct pl35x_nand_command_format *curr_cmd = NULL;
struct pl35x_nand_info *xnand =
container_of(mtd, struct pl35x_nand_info, mtd);
void __iomem *cmd_addr;
unsigned long cmd_data = 0, end_cmd_valid = 0;
unsigned long cmd_phase_addr, data_phase_addr, end_cmd, i;
unsigned long timeout = jiffies + PL35X_NAND_DEV_BUSY_TIMEOUT;
u32 addrcycles;
if (xnand->end_cmd_pending) {
/*
* Check for end command if this command request is same as the
* pending command then return
*/
if (xnand->end_cmd == command) {
xnand->end_cmd = 0;
xnand->end_cmd_pending = 0;
return;
}
}
/* Emulate NAND_CMD_READOOB for large page device */
if ((mtd->writesize > PL35X_NAND_ECC_SIZE) &&
(command == NAND_CMD_READOOB)) {
column += mtd->writesize;
command = NAND_CMD_READ0;
}
/* Get the command format */
for (i = 0; (pl35x_nand_commands[i].start_cmd != NAND_CMD_NONE ||
pl35x_nand_commands[i].end_cmd != NAND_CMD_NONE); i++)
if (command == pl35x_nand_commands[i].start_cmd)
curr_cmd = &pl35x_nand_commands[i];
if (curr_cmd == NULL)
return;
/* Clear interrupt */
pl35x_smc_clr_nand_int();
/* Get the command phase address */
if (curr_cmd->end_cmd_valid == PL35X_NAND_CMD_PHASE)
end_cmd_valid = 1;
if (curr_cmd->end_cmd == NAND_CMD_NONE)
end_cmd = 0x0;
else
end_cmd = curr_cmd->end_cmd;
if (command == NAND_CMD_READ0 || command == NAND_CMD_SEQIN)
addrcycles = xnand->row_addr_cycles + xnand->col_addr_cycles;
else if (command == NAND_CMD_ERASE1)
addrcycles = xnand->row_addr_cycles;
else
addrcycles = curr_cmd->addr_cycles;
cmd_phase_addr = (unsigned long __force)xnand->nand_base |
(addrcycles << ADDR_CYCLES_SHIFT) |
(end_cmd_valid << END_CMD_VALID_SHIFT) |
(COMMAND_PHASE) |
(end_cmd << END_CMD_SHIFT) |
(curr_cmd->start_cmd << START_CMD_SHIFT);
cmd_addr = (void __iomem * __force)cmd_phase_addr;
/* Get the data phase address */
end_cmd_valid = 0;
data_phase_addr = (unsigned long __force)xnand->nand_base |
(0x0 << CLEAR_CS_SHIFT) |
(end_cmd_valid << END_CMD_VALID_SHIFT) |
(DATA_PHASE) |
(end_cmd << END_CMD_SHIFT) |
(0x0 << ECC_LAST_SHIFT);
chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
chip->IO_ADDR_W = chip->IO_ADDR_R;
/* Command phase AXI write */
/* Read & Write */
if (column != -1 && page_addr != -1) {
/* Adjust columns for 16 bit bus width */
if (chip->options & NAND_BUSWIDTH_16)
column >>= 1;
cmd_data = column;
if (mtd->writesize > PL35X_NAND_ECC_SIZE) {
cmd_data |= page_addr << 16;
/* Another address cycle for devices > 128MiB */
if (chip->chipsize > (128 << 20)) {
pl35x_nand_write32(cmd_addr, cmd_data);
cmd_data = (page_addr >> 16);
}
} else {
cmd_data |= page_addr << 8;
}
} else if (page_addr != -1) {
/* Erase */
cmd_data = page_addr;
} else if (column != -1) {
/*
* Change read/write column, read id etc
* Adjust columns for 16 bit bus width
*/
if ((chip->options & NAND_BUSWIDTH_16) &&
((command == NAND_CMD_READ0) ||
(command == NAND_CMD_SEQIN) ||
(command == NAND_CMD_RNDOUT) ||
(command == NAND_CMD_RNDIN)))
column >>= 1;
cmd_data = column;
}
pl35x_nand_write32(cmd_addr, cmd_data);
if (curr_cmd->end_cmd_valid) {
xnand->end_cmd = curr_cmd->end_cmd;
xnand->end_cmd_pending = 1;
}
ndelay(100);
if ((command == NAND_CMD_READ0) ||
(command == NAND_CMD_RESET) ||
(command == NAND_CMD_PARAM) ||
(command == NAND_CMD_GET_FEATURES)) {
/* Wait till the device is ready or timeout */
do {
if (chip->dev_ready(mtd))
break;
else
cpu_relax();
} while (!time_after_eq(jiffies, timeout));
if (time_after_eq(jiffies, timeout))
pr_err("%s timed out\n", __func__);
return;
}
}
/**
* pl35x_nand_read_buf - read chip data into buffer
* @mtd: Pointer to the mtd info structure
* @buf: Pointer to the buffer to store read data
* @len: Number of bytes to read
*/
static void pl35x_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
struct nand_chip *chip = mtd->priv;
unsigned long *ptr = (unsigned long *)buf;
len >>= 2;
for (i = 0; i < len; i++)
ptr[i] = readl(chip->IO_ADDR_R);
}
/**
* pl35x_nand_write_buf - write buffer to chip
* @mtd: Pointer to the mtd info structure
* @buf: Pointer to the buffer to store read data
* @len: Number of bytes to write
*/
static void pl35x_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
int len)
{
int i;
struct nand_chip *chip = mtd->priv;
unsigned long *ptr = (unsigned long *)buf;
pr_debug("pl35x_nand_write_buf: datasize=%d len=%d len>>2=%d\n",sizeof(ptr[0]),len,len>>2);
len >>= 2;
for (i = 0; i < len; i++)
writel(ptr[i], chip->IO_ADDR_W);
//writeb(byte, chip->IO_ADDR_W);
}
/**
* pl35x_nand_device_ready - Check device ready/busy line
* @mtd: Pointer to the mtd_info structure
*
* Return: 0 on busy or 1 on ready state
*/
static int pl35x_nand_device_ready(struct mtd_info *mtd)
{
if (pl35x_smc_get_nand_int_status_raw()) {
pl35x_smc_clr_nand_int();
return 1;
}
return 0;
}
/**
* pl35x_nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
* @mtd: MTD device structure
* @chip: nand chip info structure
* @addr: feature address.
* @subfeature_param: the subfeature parameters, a four bytes array.
*/
static int pl35x_nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param)
{
int status;
int i;
uint8_t ondie_ecc_feature;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
if (addr==ONDIE_ECC_FEATURE_ADDR){
//keep ondie ecc on;
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
ondie_ecc_feature = readb(chip->IO_ADDR_R);
subfeature_param[0] |= (ondie_ecc_feature&0x08);
}
chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
writeb(subfeature_param[i], chip->IO_ADDR_W);
//chip->write_byte(mtd, subfeature_param[i]);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
/**
* nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
* @mtd: MTD device structure
* @chip: nand chip info structure
* @addr: feature address.
* @subfeature_param: the subfeature parameters, a four bytes array.
*/
static int pl35x_nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param)
{
int i;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
/* clear the sub feature parameters */
memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
*subfeature_param++ = chip->read_byte(mtd);
return 0;
}
/**
* pl35x_nand_detect_ondie_ecc - Get the flash ondie ecc state
* @mtd: Pointer to the mtd_info structure
*
* This function enables the ondie ecc for the Micron ondie ecc capable devices
*
* Return: 1 on detect, 0 if fail to detect
*/
static int pl35x_nand_detect_ondie_ecc(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd->priv;
u8 maf_id, dev_id, i, get_feature;
u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 };
/* Check if On-Die ECC flash */
nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
maf_id = readb(nand_chip->IO_ADDR_R);
dev_id = readb(nand_chip->IO_ADDR_R);
if ((maf_id == NAND_MFR_MICRON) &&
((dev_id == 0xf1) || (dev_id == 0xa1) ||
(dev_id == 0xb1) || (dev_id == 0xaa) ||
(dev_id == 0xba) || (dev_id == 0xda) ||
(dev_id == 0xca) || (dev_id == 0xac) ||
(dev_id == 0xbc) || (dev_id == 0xdc) ||
(dev_id == 0xcc) || (dev_id == 0xa3) ||
(dev_id == 0xb3) ||
(dev_id == 0xd3) || (dev_id == 0xc3))) {
nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
ONDIE_ECC_FEATURE_ADDR, -1);
get_feature = readb(nand_chip->IO_ADDR_R);
if (get_feature & 0x08) {
return 1;
} else {
nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES,
ONDIE_ECC_FEATURE_ADDR, -1);
for (i = 0; i < 4; i++)
writeb(set_feature[i], nand_chip->IO_ADDR_W);
ndelay(1000);
nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
ONDIE_ECC_FEATURE_ADDR, -1);
get_feature = readb(nand_chip->IO_ADDR_R);
if (get_feature & 0x08)
return 1;
}
}
return 0;
}
/**
* pl35x_nand_ecc_init - Initialize the ecc information as per the ecc mode
* @mtd: Pointer to the mtd_info structure
* @ondie_ecc_state: ondie ecc status
*
* This function initializes the ecc block and functional pointers as per the
* ecc mode
*/
static void pl35x_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state)
{
struct nand_chip *nand_chip = mtd->priv;
nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.read_oob = pl35x_nand_read_oob;
nand_chip->ecc.read_page_raw = pl35x_nand_read_page_raw;
nand_chip->ecc.strength = 1;
nand_chip->ecc.write_oob = pl35x_nand_write_oob;
nand_chip->ecc.write_page_raw = pl35x_nand_write_page_raw;
if (ondie_ecc_state) {
/* bypass the controller ECC block */
pl35x_smc_set_ecc_mode(PL35X_SMC_ECCMODE_BYPASS);
/*
* The software ECC routines won't work with the
* SMC controller
*/
nand_chip->ecc.bytes = 0;
nand_chip->ecc.layout = &ondie_nand_oob_64;
nand_chip->ecc.read_page = pl35x_nand_read_page_raw;
nand_chip->ecc.write_page = pl35x_nand_write_page_raw;
nand_chip->ecc.size = mtd->writesize;
/*
* On-Die ECC spare bytes offset 8 is used for ECC codes
* Use the BBT pattern descriptors
*/
nand_chip->bbt_td = &bbt_main_descr;
nand_chip->bbt_md = &bbt_mirror_descr;
} else {
/* Hardware ECC generates 3 bytes ECC code for each 512 bytes */
nand_chip->ecc.bytes = 3;
nand_chip->ecc.calculate = pl35x_nand_calculate_hwecc;
nand_chip->ecc.correct = pl35x_nand_correct_data;
nand_chip->ecc.hwctl = NULL;
nand_chip->ecc.read_page = pl35x_nand_read_page_hwecc;
nand_chip->ecc.size = PL35X_NAND_ECC_SIZE;
nand_chip->ecc.write_page = pl35x_nand_write_page_hwecc;
pl35x_smc_set_ecc_pg_size(mtd->writesize);
switch (mtd->writesize) {
case 512:
case 1024:
case 2048:
pl35x_smc_set_ecc_mode(PL35X_SMC_ECCMODE_APB);
break;
default:
/*
* The software ECC routines won't work with the
* SMC controller
*/
nand_chip->ecc.calculate = nand_calculate_ecc;
nand_chip->ecc.correct = nand_correct_data;
nand_chip->ecc.read_page = pl35x_nand_read_page_swecc;
nand_chip->ecc.write_page = pl35x_nand_write_page_swecc;
nand_chip->ecc.size = 256;
break;
}
if (mtd->oobsize == 16)
nand_chip->ecc.layout = &nand_oob_16;
else if (mtd->oobsize == 64)
nand_chip->ecc.layout = &nand_oob_64;
}
}
/**
* pl35x_nand_probe - Probe method for the NAND driver
* @pdev: Pointer to the platform_device structure
*
* This function initializes the driver data structures and the hardware.
*
* Return: 0 on success or error value on failure
*/
static int pl35x_nand_probe(struct platform_device *pdev)
{
struct pl35x_nand_info *xnand;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
struct resource *res;
struct mtd_part_parser_data ppdata;
int ondie_ecc_state;
xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL);
if (!xnand)
return -ENOMEM;
/* Map physical address of NAND flash */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xnand->nand_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xnand->nand_base))
return PTR_ERR(xnand->nand_base);
/* Link the private data with the MTD structure */
mtd = &xnand->mtd;
nand_chip = &xnand->chip;
nand_chip->priv = xnand;
mtd->priv = nand_chip;
mtd->owner = THIS_MODULE;
mtd->name = PL35X_NAND_DRIVER_NAME;
/* Set address of NAND IO lines */
nand_chip->IO_ADDR_R = xnand->nand_base;
nand_chip->IO_ADDR_W = xnand->nand_base;
/* Set the driver entry points for MTD */
nand_chip->cmdfunc = pl35x_nand_cmd_function;
nand_chip->dev_ready = pl35x_nand_device_ready;
nand_chip->select_chip = pl35x_nand_select_chip;
nand_chip->onfi_set_features = pl35x_nand_onfi_set_features;
nand_chip->onfi_get_features = pl35x_nand_onfi_get_features;
/* If we don't set this delay driver sets 20us by default */
nand_chip->chip_delay = 30;
/* Buffer read/write routines */
nand_chip->read_buf = pl35x_nand_read_buf;
nand_chip->write_buf = pl35x_nand_write_buf;
/* Set the device option and flash width */
nand_chip->options = NAND_BUSWIDTH_AUTO;
nand_chip->bbt_options = NAND_BBT_USE_FLASH;
platform_set_drvdata(pdev, xnand);
ondie_ecc_state = pl35x_nand_detect_ondie_ecc(mtd);
/* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, 1, NULL)) {
dev_err(&pdev->dev, "nand_scan_ident for NAND failed\n");
return -ENXIO;
}
xnand->row_addr_cycles = nand_chip->onfi_params.addr_cycles & 0xF;
xnand->col_addr_cycles =
(nand_chip->onfi_params.addr_cycles >> 4) & 0xF;
pl35x_nand_ecc_init(mtd, ondie_ecc_state);
if (nand_chip->options & NAND_BUSWIDTH_16)
pl35x_smc_set_buswidth(PL35X_SMC_MEM_WIDTH_16);
/* second phase scan */
if (nand_scan_tail(mtd)) {
dev_err(&pdev->dev, "nand_scan_tail for NAND failed\n");
return -ENXIO;
}
//elphel393 modification for Micron NAND chips
//TODO: add Micron chip ID checking
mtd->_unlock = nand_unlock;
mtd->_lock = nand_lock;
ppdata.of_node = pdev->dev.of_node;
mtd_device_parse_register(&xnand->mtd, NULL, &ppdata, NULL, 0);
return 0;
}
/**
* pl35x_nand_remove - Remove method for the NAND driver
* @pdev: Pointer to the platform_device structure
*
* This function is called if the driver module is being unloaded. It frees all
* resources allocated to the device.
*
* Return: 0 on success or error value on failure
*/
static int pl35x_nand_remove(struct platform_device *pdev)
{
struct pl35x_nand_info *xnand = platform_get_drvdata(pdev);
/* Release resources, unregister device */
nand_release(&xnand->mtd);
/* kfree(NULL) is safe */
kfree(xnand->parts);
return 0;
}
/* Match table for device tree binding */
static const struct of_device_id pl35x_nand_of_match[] = {
{ .compatible = "arm,pl353-nand-r2p1" },
{},
};
MODULE_DEVICE_TABLE(of, pl35x_nand_of_match);
/*
* pl35x_nand_driver - This structure defines the NAND subsystem platform driver
*/
static struct platform_driver pl35x_nand_driver = {
.probe = pl35x_nand_probe,
.remove = pl35x_nand_remove,
.driver = {
.name = PL35X_NAND_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = pl35x_nand_of_match,
},
};
module_platform_driver(pl35x_nand_driver);
MODULE_AUTHOR("Xilinx, Inc.");
MODULE_ALIAS("platform:" PL35X_NAND_DRIVER_NAME);
MODULE_DESCRIPTION("ARM PL35X NAND Flash Driver");
MODULE_LICENSE("GPL");
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/helpers/ 0000775 0000000 0000000 00000000000 12670664436 0023622 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/helpers/si5338_register_map_dts.py 0000775 0000000 0000000 00000006403 12670664436 0030553 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
#***************************************************************************
# FILE NAME : si5338_register_map_dts.py
# DESCRIPTION: convert si5338 register map file generated by Silicon Labs
# ClockBuilder(tm) Desktop Software into a device tree fragment, compatible
# with drivers/misc/si5338.c
# AUTHOR: Oleg Dzhimiev
# 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.
#
# The four essential freedoms with GNU GPL software:
# * to run the program for any purpose
# * to study how the program works and change it to make it do what you wish
# * to redistribute copies so you can help your neighbor
# * to distribute copies of your modified versions to others
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
# -----------------------------------------------------------------------------**
__author__ = "Oleg Dzhimiev"
__copyright__ = "Copyright 2013, Elphel, Inc."
__license__ = "GPL"
__version__ = "3.0+"
__maintainer__ = "Oleg Dzhimiev"
__email__ = "oleg@elphel.com"
__status__ = "Development"
import sys
try:
File = sys.argv[1]
except IndexError:
print '''
Usage - terminal:
a) ./register_map_dts.py
b) python register_map_dts.py
where is a *.h generated by Si5338 ClockBuilder
Example:
./register_map_dts.py register_map.h
Output:
.dts
'''
sys.exit()
dts_record_start = '''ps7_axi_interconnect_0: amba@0 {
ps7_i2c_0: ps7-i2c@e0004000 {
si5338@70 {
compatible = "sil,si5338";
reg = <0x70>;
si5338,init="always"; /* initialize PLL, wait for lock. Other option is 'if off'*/
si5338,configuration_data=<
'''
dts_record_end = '''
>;
};
};
};
'''
class RegisterMapParser:
def __init__(self,File):
self.File = File
def generate_dts(self):
print "Parsing "+self.File+".\n"
i,page,tmpstr = 0,0,""
with open(self.File,'r') as f_r:
for line in f_r:
if line[0]=='{':
# i+=1
line = line[line.find('{')+1:line.find('}')]
values = line.split(',')
if values[0]=='255':
page = int(values[1],16)
else:
if int(values[2],16) != 0 :
result = hex(((256*page+int(values[0]))<<16)+(int(values[1],16)<<8)+int(values[2],16))
tmpstr += result+" "
i+=1
if i%8==0 : tmpstr += "\n\t\t\t"
return tmpstr
Parser = RegisterMapParser(File)
with open(File+".dts",'w') as f_w:
f_w.write(dts_record_start+Parser.generate_dts()+dts_record_end)
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/include/ 0000775 0000000 0000000 00000000000 12670664436 0023603 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/include/elphel/ 0000775 0000000 0000000 00000000000 12670664436 0025054 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/include/elphel/elphel393-mem.h 0000664 0000000 0000000 00000002700 12670664436 0027510 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : elphel393-mem.h
*! DESCRIPTION:
*! 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 .
*!****************************************************************************/
struct elphel_buf_t
{
// 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;
};
extern struct elphel_buf_t *pElphel_buf;
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/include/linux/ 0000775 0000000 0000000 00000000000 12670664436 0024742 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/include/linux/i2c/ 0000775 0000000 0000000 00000000000 12670664436 0025417 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/include/linux/i2c/ltc3589.h 0000664 0000000 0000000 00000013275 12670664436 0026713 0 ustar 00root root 0000000 0000000 /*!***************************************************************************
*! FILE NAME : ltc3589.c
*! DESCRIPTION: control of the Linear Technology LTC3589 8-channel voltage regulator
*! Copyright (C) 2013 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*/
#ifndef __LINUX_LTC3589_H
#define __LINUX_LTC3589_H
#include
#include
#include
int ltc3589_read_field(struct i2c_client *client, u32 awe);
int ltc3589_write_field(struct i2c_client *client, u8 data, u32 awe);
int ltc3589_write_adwe(struct i2c_client *client, u32 adwe);
void ltc3589_set_simulate(struct i2c_client *client, int simulate);
#define LTC3589_AWE_SCR1 0x07ff
#define LTC3589_AWE_SCR1_MODE_SD1 0x0703
#define LTC3589_AWE_SCR1_MODE_SD2 0x070c
#define LTC3589_AWE_SCR1_MODE_SD3 0x0730
#define LTC3589_AWE_SCR1_MODE_BB 0x0740
#define LTC3589_AWE_OVEN 0x10ff
#define LTC3589_AWE_OVEN_EN_SD1 0x1001
#define LTC3589_AWE_OVEN_EN_SD2 0x1002
#define LTC3589_AWE_OVEN_EN_SD3 0x1004
#define LTC3589_AWE_OVEN_EN_BB 0x1008
#define LTC3589_AWE_OVEN_EN_LDO2 0x1010
#define LTC3589_AWE_OVEN_EN_LDO3 0x1020
#define LTC3589_AWE_OVEN_EN_LDO4 0x1040
#define LTC3589_AWE_OVEN_ONLY 0x1080
#define LTC3589_AWE_SCR2 0x12ff
#define LTC3589_AWE_SCR2_NOWAIT_SD1 0x1201
#define LTC3589_AWE_SCR2_NOWAIT_SD2 0x1202
#define LTC3589_AWE_SCR2_NOWAIT_SD3 0x1204
#define LTC3589_AWE_SCR2_NOWAIT_BB 0x1208
#define LTC3589_AWE_SCR2_NOWAIT_LDO2 0x1210
#define LTC3589_AWE_SCR2_NOWAIT_LDO3 0x1220
#define LTC3589_AWE_SCR2_NOWAIT_LDO4 0x1240
#define LTC3589_AWE_SCR2_PGOOD_SHTDN_INH 0x1280
#define LTC3589_AWE_VCCR 0x20ff
#define LTC3589_AWE_VCCR_SLEW_SD1 0x2001 /* self clearing bit */
#define LTC3589_AWE_VCCR_REF_SEL_SD1 0x2002
#define LTC3589_AWE_VCCR_SLEW_SD2 0x2004 /* self clearing bit */
#define LTC3589_AWE_VCCR_REF_SEL_SD2 0x2008
#define LTC3589_AWE_VCCR_SLEW_SD3 0x2010 /* self clearing bit */
#define LTC3589_AWE_VCCR_REF_SEL_SD3 0x2020
#define LTC3589_AWE_VCCR_SLEW_LDO2 0x2040 /* self clearing bit */
#define LTC3589_AWE_VCCR_REF_SEL_LDO2 0x2080
#define LTC3589_AWE_CLIRQ 0x21ff
#define LTC3589_AWE_B1DTV1 0x23ff
#define LTC3589_AWE_B1DTV1_REF 0x231f
#define LTC3589_AWE_B1DTV1_PGMASK 0x2320
#define LTC3589_AWE_B1DTV1_DVDT 0x23c0
#define LTC3589_AWE_B1DTV2 0x24ff
#define LTC3589_AWE_B1DTV2_REF 0x241f
#define LTC3589_AWE_B1DTV2_CLKRATE 0x2420
#define LTC3589_AWE_B1DTV2_PHASE 0x2440
#define LTC3589_AWE_B1DTV2_KEEP_ALIVE 0x2480
#define LTC3589_AWE_VRRCR 0x25ff
#define LTC3589_AWE_VRRCR_SD1 0x2503
#define LTC3589_AWE_VRRCR_SD2 0x250c
#define LTC3589_AWE_VRRCR_SD3 0x2530
#define LTC3589_AWE_VRRCR_LDO2 0x25c0
#define LTC3589_AWE_B2DTV1 0x26ff
#define LTC3589_AWE_B2DTV1_REF 0x261f
#define LTC3589_AWE_B2DTV1_PGMASK 0x2620
#define LTC3589_AWE_B2DTV2 0x27ff
#define LTC3589_AWE_B2DTV2_REF 0x271f
#define LTC3589_AWE_B2DTV2_CLKRATE 0x2720
#define LTC3589_AWE_B2DTV2_PHASE 0x2740
#define LTC3589_AWE_B2DTV2_KEEP_ALIVE 0x2780
#define LTC3589_AWE_B3DTV1 0x29ff
#define LTC3589_AWE_B3DTV1_REF 0x291f
#define LTC3589_AWE_B3DTV1_PGMASK 0x2920
#define LTC3589_AWE_B3DTV2 0x2aff
#define LTC3589_AWE_B3DTV2_REF 0x2a1f
#define LTC3589_AWE_B3DTV2_CLKRATE 0x2a20
#define LTC3589_AWE_B3DTV2_PHASE 0x2a40
#define LTC3589_AWE_B3DTV2_KEEP_ALIVE 0x2a80
#define LTC3589_AWE_L2DTV1 0x32ff
#define LTC3589_AWE_L2DTV1_REF 0x321f
#define LTC3589_AWE_L2DTV1_PGMASK 0x3220
#define LTC3589_AWE_L2DTV1_KEEP_ALIVE 0x3280
#define LTC3589_AWE_L2DTV2 0x33ff
#define LTC3589_AWE_L2DTV2_REF 0x331f
#define LTC3589_AWE_L2DTV2_REF_LDO4 0x3360
#define LTC3589_AWE_L2DTV2_MODE_LDO4 0x3380
#define LTC3589_AWE_IRQSTAT 0x02ff
#define LTC3589_AWE_IRQSTAT_PGOOD_TIMOUT 0x0208
#define LTC3589_AWE_IRQSTAT_NEAR_UV 0x0210
#define LTC3589_AWE_IRQSTAT_HARD_UV 0x0220
#define LTC3589_AWE_IRQSTAT_NEAR_THERM 0x0240
#define LTC3589_AWE_IRQSTAT_HARD_THERM 0x0280
#define LTC3589_AWE_PGSTAT 0x13ff
#define LTC3589_AWE_PGSTAT_LDO1 0x1301
#define LTC3589_AWE_PGSTAT_SD1 0x1302
#define LTC3589_AWE_PGSTAT_SD2 0x1304
#define LTC3589_AWE_PGSTAT_SD3 0x1308
#define LTC3589_AWE_PGSTAT_BB 0x1310
#define LTC3589_AWE_PGSTAT_LDO2 0x1320
#define LTC3589_AWE_PGSTAT_LDO3 0x1340
#define LTC3589_AWE_PGSTAT_LDO4 0x1380
#endif /* __LINUX_LTC3589_H */
linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/other/ 0000775 0000000 0000000 00000000000 12670664436 0023301 5 ustar 00root root 0000000 0000000 linux-elphel-e01891ea01b9e56de87ef6c730fef801fbf319cb/src/other/mem.py 0000664 0000000 0000000 00000003551 12670664436 0024435 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2013, Elphel.inc.
# configuration of the DDR-related registers
# 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 .
__author__ = "Andrey Filippov"
__copyright__ = "Copyright 2014, Elphel, Inc."
__license__ = "GPL"
__version__ = "3.0+"
__maintainer__ = "Andrey Filippov"
__email__ = "andrey@elphel.com"
__status__ = "Development"
import mmap
import sys
import struct
PAGE_SIZE=4096
endian="<" # little, ">" for big
if len(sys.argv)<1:
print "Usage: ", sys.argv[0]+" address [data]"
exit (0)
addr=int(sys.argv[1],16) & 0xfffffffc
data=0
writeMode=len(sys.argv)>2
if (writeMode):
data=int(sys.argv[2],16)
with open("/dev/mem", "r+b") as f:
page_addr=addr & (~(PAGE_SIZE-1))
page_offs=addr-page_addr
#in python 2.7.11 works w/o negation
#if (page_addr>=0x80000000):
# page_addr-= (1<<32)
mm = mmap.mmap(f.fileno(), PAGE_SIZE, offset=page_addr)
if writeMode:
packedData=struct.pack(endian+"L",data)
d=struct.unpack(endian+"L",packedData)[0]
mm[page_offs:page_offs+4]=packedData
print ("0x%08x <== 0x%08x (%d)"%(addr,d,d))
else:
data=struct.unpack(endian+"L",mm[page_offs:page_offs+4])
d=data[0]
print ("0x%08x ==> 0x%08x (%d)"%(addr,d,d))
mm.close()