Skip to content

eeprom: at24: Simplify WP management and make it optional #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: Nougat
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion arch/arm64/boot/dts/amlogic/gxtvbb_p301.dts
Original file line number Diff line number Diff line change
Expand Up @@ -1760,7 +1760,6 @@
pagesize = <8>;
write_ops_interval= <10>;/*Write operation interval at24c32 at24c64 is 10ms at24c128 is 5ms in spec*/
wp_gpios = <&gpio GPIOY_7 GPIO_ACTIVE_HIGH>;
write_gpio_port_status = <0>;
};
};
&pinmux {
Expand Down
134 changes: 49 additions & 85 deletions drivers/misc/eeprom/at24.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@
#include <linux/i2c.h>
#include <linux/platform_data/at24.h>
#include <linux/gpio.h>
#include <linux/amlogic/aml_gpio_consumer.h>
#include <linux/amlogic/gpio-amlogic.h>
#include <linux/io.h>
#include <linux/platform_device.h>

#include <linux/of_gpio.h>

/*
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
Expand Down Expand Up @@ -135,28 +133,23 @@ static const struct i2c_device_id at24_ids[] = {
{ /* END OF LIST */ }
};
MODULE_DEVICE_TABLE(i2c, at24_ids);
#define MODULE_NAME "at24"

static struct at24_data *gp_at24;
static ssize_t at24_wp_show(struct class *class,
struct class_attribute *attr, char *buf)
{

return sprintf(buf, "%d\n", gpiod_get_value(gp_at24->chip.wp_pin_desc));
return sprintf(buf, "%d\n", gpio_get_value(gp_at24->chip.wp_port));
}
static ssize_t at24_wp_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t count)
{
u8 wp;
u8 ret;
ret = sscanf(buf, "%x", (int *)&wp);
u8 ret;
ret = sscanf(buf, "%hhx", &wp);

mutex_lock(&gp_at24->lock);
if (wp == 0)
amlogic_gpio_direction_output(gp_at24->chip.wp_port , 0 ,
MODULE_NAME);
else if (wp == 1)
amlogic_gpio_direction_output(gp_at24->chip.wp_port , 1 ,
MODULE_NAME);
if (wp <= 1)
gpio_set_value(gp_at24->chip.wp_port, wp);
else
pr_info("only support 1 or 0\n");

Expand All @@ -168,39 +161,14 @@ struct class *at24_class;
static CLASS_ATTR(at24_wp , S_IWUSR | S_IRUGO , at24_wp_show , at24_wp_store);


/*eeprom protect gpio enable*/
void at24_wp_enable(struct at24_platform_data *chip)
{
int ret;
if (chip->wp_port > 0) {
ret = gpio_request(chip->wp_port , MODULE_NAME);
if (ret)
pr_info("faild to alloc write protect (%d)!\n" ,
chip->wp_port);
else
amlogic_gpio_direction_output(chip->wp_port ,
chip->wp_port_level , MODULE_NAME);
} else {
pr_info("wrong wp port\n");
}
}
/* enable write protect*/
void at24_enable_write_operation(struct at24_platform_data *chip)
static void at24_enable_write_operation(struct at24_platform_data *chip,
bool enable)
{
if (chip->wp_port > 0) {
chip->wp_port_level = chip->wp_port_level_save;
amlogic_gpio_direction_output(chip->wp_port ,
chip->wp_port_level , MODULE_NAME);
}
}
/* disable write protect*/
void at24_disable_write_operation(struct at24_platform_data *chip)
{
if (chip->wp_port > 0) {
chip->wp_port_level = !chip->wp_port_level_save;
amlogic_gpio_direction_output(chip->wp_port ,
chip->wp_port_level , MODULE_NAME);
}
if (gpio_is_valid(chip->wp_port))
gpio_set_value(chip->wp_port,
enable ? !chip->wp_port_active_level :
chip->wp_port_active_level);
}

/*-------------------------------------------------------------------------*/
Expand Down Expand Up @@ -469,7 +437,7 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
if (unlikely(!count))
return count;
/*enable write ops*/
at24_enable_write_operation(&at24->chip);
at24_enable_write_operation(&at24->chip, true);
mdelay(at24->chip.write_ops_interval);
/*
* Write data to chip, protecting against concurrent updates
Expand All @@ -496,7 +464,7 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
mutex_unlock(&at24->lock);

/*write protect*/
at24_disable_write_operation(&at24->chip);
at24_enable_write_operation(&at24->chip, false);

return retval;
}
Expand Down Expand Up @@ -561,43 +529,33 @@ static void at24_get_ofdata(struct i2c_client *client,
{ }
#endif /* CONFIG_OF */

void at24_dt_parse(struct i2c_client *client , struct at24_platform_data *chip)
static int at24_dt_parse(struct i2c_client *client,
struct at24_platform_data *chip)
{
/* const char *str;*/
int ret;
enum of_gpio_flags flags;

struct device_node *node = client->dev.of_node;
enum of_gpio_flags flags;
int ret;

ret = of_property_read_u32(node, "write_ops_interval",
&(chip->write_ops_interval));
if (ret)
pr_info("faild to get write interval time !\n");

chip->wp_pin_desc = of_get_named_gpiod_flags(node , "wp_gpios" ,
0 , &flags);
chip->wp_port = desc_to_gpio(chip->wp_pin_desc);

ret = of_property_read_u32(node , "write_gpio_port_status",
&(chip->wp_port_level));
if (ret)
pr_info("faild to get write interval time !\n");

if (!chip->wp_port_level)
chip->wp_port_level_save = chip->wp_port_level = 0;
/*at24_wp_enable(chip);*/
else
chip->wp_port_level_save = chip->wp_port_level = 1;
/*at24_wp_enable(chip);*/

chip->wp_port_level = !chip->wp_port_level_save;
at24_wp_enable(chip);
chip->write_ops_interval = 0;
of_property_read_u32(node, "write_ops_interval",
&chip->write_ops_interval);

chip->wp_port = of_get_named_gpio_flags(node, "wp_gpios", 0, &flags);
if (gpio_is_valid(chip->wp_port)) {
chip->wp_port_active_level = !(flags & OF_GPIO_ACTIVE_LOW);

ret = gpio_request_one(chip->wp_port,
chip->wp_port_active_level ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
dev_name(&client->dev));
if (ret) {
dev_err(&client->dev, "unable to request WP GPIO %d\n",
chip->wp_port);
return ret;
}
}

pr_info("EEPROM_AT%s " , client->name);
pr_info("write protect port level is %d" , chip->wp_port);
pr_info("wp_port=%d write_ops_interval=%dms\n" ,
chip->wp_port ,
chip->write_ops_interval);
return 0;
}


Expand Down Expand Up @@ -696,8 +654,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)

writable = !(chip.flags & AT24_FLAG_READONLY);
if (writable) {
err = at24_dt_parse(client, &at24->chip);
if (err)
return err;

at24_dt_parse(client , &at24->chip);
if (!use_smbus || i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {

Expand Down Expand Up @@ -758,10 +718,12 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* export data to kernel code */
if (chip.setup)
chip.setup(&at24->macc, chip.context);
at24_class = class_create(THIS_MODULE , "at24_wp");
err = class_create_file(at24_class , &class_attr_at24_wp);
if (writable && gpio_is_valid(chip.wp_port)) {
at24_class = class_create(THIS_MODULE , "at24_wp");
err = class_create_file(at24_class , &class_attr_at24_wp);
}

return 0;
return err;

err_clients:
for (i = 1; i < num_addresses; i++)
Expand All @@ -782,7 +744,9 @@ static int at24_remove(struct i2c_client *client)
for (i = 1; i < at24->num_addresses; i++)
i2c_unregister_device(at24->client[i]);

class_destroy(at24_class);
if (!(at24->chip.flags & AT24_FLAG_READONLY) &&
gpio_is_valid(at24->chip.wp_port))
class_destroy(at24_class);
return 0;
}

Expand Down
10 changes: 2 additions & 8 deletions include/linux/platform_data/at24.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,11 @@ struct at24_platform_data {
#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */
#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */
#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */
unsigned int wp_port;
unsigned int wp_port_level;
unsigned int wp_port_level_save;
int wp_port;
unsigned int wp_port_active_level;
unsigned int write_ops_interval;
struct gpio_desc *wp_pin_desc;
void (*setup)(struct memory_accessor *, void *context);
void *context;
};
extern int amlogic_gpio_name_map_num(const char *name);
extern int amlogic_gpio_direction_output(unsigned int pin, int value,
const char *owner);
extern int amlogic_gpio_request(unsigned int pin, const char *label);

#endif /* _LINUX_AT24_H */