Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
linux-elphel
Commits
da77e5ab
Commit
da77e5ab
authored
Dec 22, 2013
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
continue work on elphel393-pwr.c
parent
a56a0878
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
209 additions
and
0 deletions
+209
-0
elphel393-pwr.c
drivers/elphel/elphel393-pwr.c
+209
-0
No files found.
drivers/elphel/elphel393-pwr.c
View file @
da77e5ab
...
...
@@ -22,10 +22,219 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/i2c/ltc3589.h>
#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
struct
elphel393_pwr_data_t
{
int
chip_i2c_addr
[
3
];
int
simulate
;
/* do not perform actual i2c writes */
struct
mutex
lock
;
};
struct
pwr_gpio_t
{
const
char
*
label
;
int
pin
;
};
static
struct
pwr_gpio_t
pwr_gpio
[
16
]
=
{
/* 0x20: */
{
"PWR_MGB1"
,
0
},
/* 1.8V margining magnitude (0 - 5%, 1 - 10%, float - 15%) */
{
"PWR_MG1"
,
1
},
/* 1.8V margining enable 0 - negative margining, 1 - positive margining, float - no margining */
{
"PWR_MGB0"
,
2
},
/* 1.0V margining magnitude (0 - 5%, 1 - 10%, float - 15%) */
{
"PWR_MG0"
,
3
},
/* 1.0V margining enable 0 - negative margining, 1 - positive margining, float - no margining */
{
"PWR_FQ0"
,
4
},
/* float - nominal frequency (should float for SS), 0 - 0.67 nominal frequency, 1 - 1.5 nominal frequency */
{
"PWR_SS"
,
5
},
/* Spread spectrum, 0 or float - spread spectrum disabled */
{
"SENSPWREN0"
,
6
},
/* 1 - enable 3.3 power to sensor connectors J6 and J7 (0 or float - disable) */
{
"SENSPWREN1"
,
7
},
/* 1 - enable 3.3 power to sensor connectors J8 and J9 (0 or float - disable) */
/* 0x21: */
{
"NSHUTDOWN"
,
8
},
/* (pulled up). 0 - shutdown, 1 normal */
{
"DIS_POR"
,
9
},
/* (pulled down). 0 - normal, 1 - disable POR generation on PGOOD deassertion (needed whil changing voltages) */
{
NULL
,
10
},
/* Not connected */
{
NULL
,
11
},
/* Not connected */
{
NULL
,
12
},
/* Not connected */
{
NULL
,
13
},
/* Not connected */
{
"MGTAVTTGOOD"
,
14
},
/* (input) 1.2V linear regulator status (generated from 1.8V) */
{
"PGOOD18"
,
15
}
/* (input). Combines other voltages, can be monitored when DIS_POR is activated */
};
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
);
/* 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
DEVICE_ATTR
(
simulate
,
SYSFS_PERMISSIONS
,
simulate_show
,
simulate_store
);
static
struct
attribute
*
root_dev_attrs
[]
=
{
&
dev_attr_simulate
.
attr
,
NULL
};
static
const
struct
attribute_group
dev_attr_root_group
=
{
.
attrs
=
root_dev_attrs
,
.
name
=
NULL
,
};
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
));
sscanf
(
buf
,
"%du"
,
&
clientdata
->
simulate
);
return
count
;
}
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
;
}
return
retval
;
}
static
void
elphel393_pwr_init_of
(
struct
platform_device
*
pdev
)
{
const
__be32
*
config_data
;
// struct device *dev = &pdev->dev;
struct
device_node
*
node
=
pdev
->
dev
.
of_node
;
struct
elphel393_pwr_data_t
*
clientdata
=
platform_get_drvdata
(
pdev
);
int
len
,
i
;
if
(
node
)
{
config_data
=
of_get_property
(
node
,
"elphel393_pwr,i2c_chips"
,
&
len
);
if
(
config_data
){
len
/=
sizeof
(
*
config_data
);
dev_info
(
&
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
;
i
<
len
;
i
++
)
clientdata
->
chip_i2c_addr
[
i
]
=
be32_to_cpup
(
&
config_data
[
i
]);
}
}
}
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_info
(
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_info
(
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 +++"
);
clientdata
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
clientdata
),
GFP_KERNEL
);
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
);
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_info
(
&
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
;
i
<
ARRAY_SIZE
(
pwr_gpio
);
i
++
)
if
(
pwr_gpio
[
i
].
label
){
pwr_gpio
[
i
].
pin
=
base
[
i
>>
3
]
+
(
i
&
7
);
rc
=
gpio_request
(
pwr_gpio
[
i
].
pin
,
pwr_gpio
[
i
].
label
);
if
(
rc
<
0
){
dev_err
(
&
pdev
->
dev
,
" Failed to get GPIO[%d] with label %s
\n
"
,
pwr_gpio
[
i
].
pin
,
pwr_gpio
[
i
].
label
);
}
else
{
dev_info
(
&
pdev
->
dev
,
"Confirmed request GPIO[%d] with label %s
\n
"
,
pwr_gpio
[
i
].
pin
,
pwr_gpio
[
i
].
label
);
}
}
/* find ltc3589 */
ltc3489_dev
=
find_device_by_i2c_addr
(
LTC3589_ADDR
);
if
(
!
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
(
ltc3489_dev
);
dev_info
(
&
pdev
->
dev
,
"Located %s with i2c address 0x%02x
\n
"
,
ltc3589_client
->
name
,
LTC3589_ADDR
);
dev_info
(
&
pdev
->
dev
,
"LTC3589 status= 0x%02x
\n
"
,
read_field_ltc3589
(
ltc3589_client
,
LTC3589_AWE_PGSTAT
));
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 <andrey@elphel.com>"
);
MODULE_DESCRIPTION
(
"Elphel 10393 power supply control"
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment